21#ifndef B2ELEMENT_FIELD_TRANSFER_H_
22#define B2ELEMENT_FIELD_TRANSFER_H_
27#include "model/b2element.H"
28#include "model_imp/b2hnode.H"
35const std::string geometry(
"GEOMETRY");
36const std::string temperature(
"TEMPERATURE");
37const std::string heat_flux(
"HEATFLUX");
38const std::string displacement(
"DISPLACEMENT");
39const std::string traction(
"TRACTION");
40const std::string all(
"ALL");
43class CFDMaterial :
virtual public ElementProperty {
45 double get_internal_pressure() {
return internal_pressure; }
48 void set_internal_pressure(
double p) { internal_pressure = p; }
51 double internal_pressure;
56class ElementCFDPressureTraction2DFieldL2 :
public TypedElement<double> {
58 std::pair<int, Node* const*> get_nodes()
const override {
59 return std::pair<int, Node* const*>(2, nodes);
62 void set_nodes(std::pair<int, Node* const*> nodes_)
override {
63 if (nodes_.first != 2) { Exception() <<
"This element must have 2 nodes." <<
THROW; }
64 for (
int i = 0; i != 2; ++i) { nodes[i] = nodes_.second[i]; }
67 int edge_field_order(
const int edge_id,
const std::string& field_name)
override {
return 1; }
69 bool edge_field_linear_on_dof(
const int edge_id,
const std::string& field_name)
override {
70 if (field_name == traction) {
return false; }
74 int edge_field_polynomial_sub_edge(
75 const int edge_id,
const std::string& field_name,
76 b2linalg::Vector<double, b2linalg::Vdense>& sub_nodes)
override {
78 if (field_name == all || field_name == traction) {
80 sub_nodes.push_back(0);
81 sub_nodes.push_back(0.5);
82 sub_nodes.push_back(1);
85 sub_nodes.push_back(0);
86 sub_nodes.push_back(1);
91 void set_property(ElementProperty* property_)
override {
92 property =
dynamic_cast<CFDMaterial*
>(property_);
93 if (property ==
nullptr) {
94 TypeError() <<
"Bad property type " <<
typeid(*property_)
95 <<
" for ElementCFD2DFieldL2 element."
96 <<
"(forgot MID or PID element attribute?)" <<
THROW;
100 const ElementProperty* get_property()
const override {
return property; }
106 CFDMaterial* property;
109class ElementCFDPressure2DFieldL2 :
public ElementCFDPressureTraction2DFieldL2 {
112 coordof::Coor<coordof::Trans<coordof::X, coordof::Y>>,
113 coordof::Dof<coordof::DTrans<coordof::DX, coordof::DY>, coordof::Pressure>>
117 const int edge_id,
const double internal_coor, b2linalg::Vector<double>& geom,
118 b2linalg::Vector<double>& d_geom_d_icoor)
override {
119 double node_coor[2][2];
120 for (
int k = 0; k != 2; ++k) { node_type::get_coor_s(node_coor[k], nodes[k]); }
121 if (!geom.is_null()) {
123 for (
size_t i = 0; i != 2; ++i) {
124 geom[i] = node_coor[0][i] * (1 - internal_coor) + node_coor[1][i] * internal_coor;
127 if (!d_geom_d_icoor.is_null()) {
128 d_geom_d_icoor.resize(2);
129 for (
size_t i = 0; i != 2; ++i) {
130 d_geom_d_icoor[i] = -node_coor[0][i] + node_coor[1][i];
135 void edge_field_value(
136 const int edge_id,
const std::string& field_name,
const double internal_coor,
137 const b2linalg::Matrix<double, b2linalg::Mrectangle_constref>& dof,
const double time,
138 b2linalg::Vector<double, b2linalg::Vdense>& value,
139 b2linalg::Vector<double, b2linalg::Vdense>& d_value_d_icoor,
140 b2linalg::Index& dof_numbering,
141 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_value_d_dof,
142 b2linalg::Index& d_value_d_dof_dep)
override {
143 double node_coor[2][2];
144 for (
int k = 0; k != 2; ++k) { node_type::get_coor_s(node_coor[k], nodes[k]); }
148 for (
int k = 0; k != 2; ++k) {
149 ptr = node_type::get_global_dof_numbering_s(ptr, nodes[k]);
152 if (field_name == displacement) {
153 if (!value.is_null()) {
155 for (
int i = 0; i != 2; ++i) {
157 dof(dn[i], 0) * (1 - internal_coor) + dof(dn[i + 3], 0) * internal_coor;
160 if (!d_value_d_icoor.is_null()) {
161 d_value_d_icoor.resize(2);
162 for (
int i = 0; i != 2; ++i) {
163 d_value_d_icoor[i] = -dof(dn[i], 0) + dof(dn[i + 3], 0);
166 if (!d_value_d_dof.is_null()) {
167 dof_numbering.resize(4);
168 dof_numbering[0] = dn[0];
169 dof_numbering[1] = dn[1];
170 dof_numbering[2] = dn[3];
171 dof_numbering[3] = dn[4];
172 d_value_d_dof.resize(2, 4);
173 d_value_d_dof.set_zero();
174 d_value_d_dof(0, 0) = 1 - internal_coor;
175 d_value_d_dof(0, 2) = internal_coor;
176 d_value_d_dof(1, 1) = 1 - internal_coor;
177 d_value_d_dof(1, 3) = internal_coor;
180 if (field_name == traction) {
181 const int pos = internal_coor < 0.5 ? 0 : 3;
182 double n[2] = {node_coor[0][1] - node_coor[1][1], node_coor[1][0] - node_coor[0][0]};
183 const double inv_L = 1 / std::sqrt(n[0] * n[0] + n[1] * n[1]);
184 double s = -
property->get_internal_pressure();
186 n[0] += dof(dn[1], 0) - dof(dn[4], 0);
187 n[1] += dof(dn[3], 0) - dof(dn[0], 0);
188 s += dof(dn[2 + pos], 0);
193 if (!value.is_null()) {
198 if (!d_value_d_icoor.is_null()) {
199 d_value_d_icoor.resize(2);
200 d_value_d_icoor[0] = 0;
201 d_value_d_icoor[1] = 0;
203 if (!d_value_d_dof.is_null()) {
204 dof_numbering.resize(5);
205 std::copy(dn, dn + 5, dof_numbering.begin());
206 dof_numbering[2] = dn[2 + pos];
207 d_value_d_dof.resize(2, 5);
208 d_value_d_dof(0, 0) = 0;
209 d_value_d_dof(0, 1) = inv_L * s;
210 d_value_d_dof(0, 2) = n[0];
211 d_value_d_dof(0, 3) = 0;
212 d_value_d_dof(0, 4) = -inv_L * s;
213 d_value_d_dof(1, 0) = -inv_L * s;
214 d_value_d_dof(1, 1) = 0;
215 d_value_d_dof(1, 2) = n[1];
216 d_value_d_dof(1, 3) = inv_L * s;
217 d_value_d_dof(1, 4) = 0;
221 using type_t = ObjectTypeComplete<ElementCFDPressure2DFieldL2, TypedElement<double>::type_t>;
226class ElementCFDTraction2DFieldL2 :
public ElementCFDPressureTraction2DFieldL2 {
229 coordof::Coor<coordof::Trans<coordof::X, coordof::Y>>,
231 coordof::DTrans<coordof::DX, coordof::DY>, coordof::Pressure,
232 coordof::DTrans<coordof::TX, coordof::TY>>>
236 const int edge_id,
const double internal_coor, b2linalg::Vector<double>& geom,
237 b2linalg::Vector<double>& d_geom_d_icoor)
override {
238 double node_coor[2][2];
239 for (
int k = 0; k != 2; ++k) { node_type::get_coor_s(node_coor[k], nodes[k]); }
240 if (!geom.is_null()) {
242 for (
size_t i = 0; i != 2; ++i) {
243 geom[i] = node_coor[0][i] * (1 - internal_coor) + node_coor[1][i] * internal_coor;
246 if (!d_geom_d_icoor.is_null()) {
247 d_geom_d_icoor.resize(2);
248 for (
size_t i = 0; i != 2; ++i) {
249 d_geom_d_icoor[i] = -node_coor[0][i] + node_coor[1][i];
254 void edge_field_value(
255 const int edge_id,
const std::string& field_name,
const double internal_coor,
256 const b2linalg::Matrix<double, b2linalg::Mrectangle_constref>& dof,
const double time,
257 b2linalg::Vector<double, b2linalg::Vdense>& value,
258 b2linalg::Vector<double, b2linalg::Vdense>& d_value_d_icoor,
259 b2linalg::Index& dof_numbering,
260 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_value_d_dof,
261 b2linalg::Index& d_value_d_dof_dep)
override {
262 double node_coor[2][2];
263 for (
int k = 0; k != 2; ++k) { node_type::get_coor_s(node_coor[k], nodes[k]); }
267 for (
int k = 0; k != 2; ++k) {
268 ptr = node_type::get_global_dof_numbering_s(ptr, nodes[k]);
271 if (field_name == displacement) {
272 if (!value.is_null()) {
274 for (
int i = 0; i != 2; ++i) {
276 dof(dn[i], 0) * (1 - internal_coor) + dof(dn[i + 5], 0) * internal_coor;
279 if (!d_value_d_icoor.is_null()) {
280 d_value_d_icoor.resize(2);
281 for (
int i = 0; i != 2; ++i) {
282 d_value_d_icoor[i] = -dof(dn[i], 0) + dof(dn[i + 5], 0);
285 if (!d_value_d_dof.is_null()) {
286 dof_numbering.resize(4);
287 dof_numbering[0] = dn[0];
288 dof_numbering[1] = dn[1];
289 dof_numbering[2] = dn[5];
290 dof_numbering[3] = dn[6];
291 d_value_d_dof.resize(2, 4);
292 d_value_d_dof.set_zero();
293 d_value_d_dof(0, 0) = 1 - internal_coor;
294 d_value_d_dof(0, 2) = internal_coor;
295 d_value_d_dof(1, 1) = 1 - internal_coor;
296 d_value_d_dof(1, 3) = internal_coor;
299 if (field_name == traction) {
300 const int pos = internal_coor < 0.5 ? 0 : 5;
301 const double ip = -
property->get_internal_pressure();
302 if (!value.is_null()) {
304 node_coor[1][0] - node_coor[0][0], node_coor[1][1] - node_coor[0][1]};
305 const double inv_L = 1 / std::sqrt(n[0] * n[0] + n[1] * n[1]);
307 n[0] += dof(dn[5], 0) - dof(dn[0], 0);
308 n[1] += dof(dn[6], 0) - dof(dn[1], 0);
312 const double s = std::sqrt(n[0] * n[0] + n[1] * n[1]) * inv_L;
314 if (dof.size2() == 0) {
315 value[0] = -n[1] * ip;
316 value[1] = n[0] * ip;
318 const double ip_ep = ip + dof(dn[2 + pos], 0);
319 value[0] = dof(dn[3 + pos], 0) * s - n[1] * ip_ep;
320 value[1] = dof(dn[4 + pos], 0) * s + n[0] * ip_ep;
323 if (!d_value_d_icoor.is_null()) {
324 d_value_d_icoor.resize(2);
325 d_value_d_icoor[0] = 0;
326 d_value_d_icoor[1] = 0;
328 if (!d_value_d_dof.is_null()) {
329 dof_numbering.resize(7);
330 std::copy(dn, dn + 7, dof_numbering.begin());
331 for (
int i = 2; i != 5; ++i) { dof_numbering[i] = dn[i + pos]; }
333 const double tmp0 = node_coor[1][1] - node_coor[0][1];
334 const double tmp1 = node_coor[1][0] - node_coor[0][0];
335 const double tmp2 = tmp1 + dof(dn[5], 0) - dof(dn[0], 0);
336 const double tmp4 = 1 /
sqrt(tmp0 * tmp0 + tmp1 * tmp1);
337 const double tmp5 = tmp0 + dof(dn[6], 0) - dof(dn[1], 0);
338 const double tmp6 = std::sqrt(tmp5 * tmp5 + tmp2 * tmp2);
339 const double tmp7 = 1 / tmp6;
340 const double tmp8 = ip + dof(dn[2 + pos], 0);
341 const double tmp9 = -tmp8 * tmp4;
342 const double tmp10 = tmp8 * tmp4;
343 const double tmp11 = tmp4 * tmp6;
344 const double t_0 = dof(dn[3 + pos], 0);
345 const double t_1 = dof(dn[4 + pos], 0);
347 d_value_d_dof.resize(2, 7);
348 d_value_d_dof(0, 0) = -t_0 * tmp2 * tmp4 * tmp7;
349 d_value_d_dof(0, 1) = tmp10 - t_0 * tmp5 * tmp4 * tmp7;
350 d_value_d_dof(0, 2) = -tmp5 * tmp4;
351 d_value_d_dof(0, 3) = tmp11;
352 d_value_d_dof(0, 4) = 0;
353 d_value_d_dof(0, 5) = t_0 * tmp2 * tmp4 * tmp7;
354 d_value_d_dof(0, 6) = t_0 * tmp5 * tmp4 * tmp7 + tmp9;
355 d_value_d_dof(1, 0) = tmp9 - t_1 * tmp2 * tmp4 * tmp7;
356 d_value_d_dof(1, 1) = -t_1 * tmp5 * tmp4 * tmp7;
357 d_value_d_dof(1, 2) = tmp2 * tmp4;
358 d_value_d_dof(1, 3) = 0;
359 d_value_d_dof(1, 4) = tmp11;
360 d_value_d_dof(1, 5) = t_1 * tmp2 * tmp4 * tmp7 + tmp10;
361 d_value_d_dof(1, 6) = t_1 * tmp5 * tmp4 * tmp7;
365 using type_t = ObjectTypeComplete<ElementCFDTraction2DFieldL2, TypedElement<double>::type_t>;
373template <
typename SHAPE,
bool EULER>
376 using node_type = node::HNode<
377 coordof::Coor<coordof::Trans<coordof::X, coordof::Y, coordof::Z>>,
379 coordof::DTrans<coordof::DX, coordof::DY, coordof::DZ>, coordof::Pressure,
380 coordof::DTrans<coordof::TX, coordof::TY, coordof::TZ>>>;
382 using node_type_euler = node::HNode<
383 coordof::Coor<coordof::Trans<coordof::X, coordof::Y, coordof::Z>>,
384 coordof::Dof<coordof::DTrans<coordof::DX, coordof::DY, coordof::DZ>, coordof::Pressure>>;
388 std::pair<int, Node* const*>
get_nodes()
const override {
389 return std::pair<int, Node* const*>(2, nodes);
392 void set_nodes(std::pair<int, Node* const*> nodes_)
override {
393 if (nodes_.first != SHAPE::num_nodes) {
394 Exception() <<
"This element must have " << SHAPE::num_nodes <<
" nodes." <<
THROW;
396 for (
int i = 0; i != SHAPE::num_nodes; ++i) { nodes[i] = nodes_.second[i]; }
404 if (field_name == traction) {
return false; }
408 int face_field_polynomial_sub_edge(
409 const int face_id,
const std::string& field_name,
410 b2linalg::Matrix<double, b2linalg::Mrectangle>& sub_nodes,
411 std::vector<Element::Triangle>& sub_faces) {
413 if (SHAPE::name ==
"Q4") {
414 if (field_name == all || field_name == traction) {
415 sub_nodes.resize(2, 9);
417 for (
int j = -1; j <= 1; ++j) {
418 for (
int i = -1; i <= 1; ++i, ++k) {
423 sub_faces.reserve(8);
424 sub_faces.push_back(Element::Triangle(0, 1, 4));
425 sub_faces.push_back(Element::Triangle(0, 4, 3));
426 sub_faces.push_back(Element::Triangle(1, 2, 5));
427 sub_faces.push_back(Element::Triangle(1, 5, 4));
428 sub_faces.push_back(Element::Triangle(3, 4, 7));
429 sub_faces.push_back(Element::Triangle(3, 7, 6));
430 sub_faces.push_back(Element::Triangle(4, 5, 8));
431 sub_faces.push_back(Element::Triangle(4, 8, 7));
433 sub_nodes.resize(2, 4);
435 for (
int j = -1; j <= 1; j += 2) {
436 for (
int i = -1; i <= 1; i += 2, ++k) {
441 sub_faces.reserve(2);
442 sub_faces.push_back(Element::Triangle(0, 1, 3));
443 sub_faces.push_back(Element::Triangle(0, 3, 2));
445 }
else if (SHAPE::name ==
"T3") {
446 if (field_name == all || field_name == traction) {
447 sub_nodes.resize(2, 7);
448 sub_nodes.set_zero();
449 sub_nodes(0, 1) = 0.5;
451 sub_nodes(0, 3) = 0.5;
452 sub_nodes(1, 3) = 0.5;
454 sub_nodes(1, 5) = 0.5;
455 sub_nodes(0, 6) = 1.0 / 3;
456 sub_nodes(1, 6) = 1.0 / 3;
457 sub_faces.reserve(6);
458 sub_faces.push_back(Element::Triangle(0, 1, 6));
459 sub_faces.push_back(Element::Triangle(1, 2, 6));
460 sub_faces.push_back(Element::Triangle(2, 3, 6));
461 sub_faces.push_back(Element::Triangle(3, 4, 6));
462 sub_faces.push_back(Element::Triangle(4, 5, 6));
463 sub_faces.push_back(Element::Triangle(5, 0, 6));
465 sub_nodes.resize(2, 3);
466 sub_nodes.set_zero();
469 sub_faces.reserve(1);
470 sub_faces.push_back(Element::Triangle(0, 1, 2));
478 const b2linalg::Vector<double, b2linalg::Vdense_constref>& internal_coor,
479 b2linalg::Vector<double>& geom,
480 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_geom_d_icoor)
override {
481 double node_coor[SHAPE::num_nodes][3];
482 for (
int k = 0; k != SHAPE::num_nodes; ++k) {
484 node_type_euler::get_coor_s(node_coor[k], nodes[k]);
486 node_type::get_coor_s(node_coor[k], nodes[k]);
490 if (!geom.is_null()) {
491 b2linalg::Vector<double> shape(SHAPE::num_nodes);
492 SHAPE::eval_h(&internal_coor[0], shape);
494 for (
size_t i = 0; i != 3; ++i) {
496 for (
int k = 0; k != SHAPE::num_nodes; ++k) { tmp += shape[k] * node_coor[k][i]; }
501 if (!d_geom_d_icoor.is_null()) {
502 b2linalg::Matrix<double> d_shape(2, SHAPE::num_nodes);
503 SHAPE::eval_h_derived(&internal_coor[0], d_shape);
504 d_geom_d_icoor.resize(3, 2);
505 for (
size_t i = 0; i != 3; ++i) {
506 for (
size_t j = 0; j != 2; ++j) {
508 for (
int k = 0; k != SHAPE::num_nodes; ++k) {
509 tmp += d_shape(j, k) * node_coor[k][i];
511 d_geom_d_icoor(i, j) = tmp;
517 void edge_field_value(
518 const int edge_id,
const std::string& field_name,
const double internal_coor,
519 const b2linalg::Matrix<double, b2linalg::Mrectangle_constref>& dof,
const double time,
520 b2linalg::Vector<double, b2linalg::Vdense>& value,
521 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_value_d_icoor,
522 b2linalg::Index& dof_numbering,
523 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_value_d_dof,
524 b2linalg::Index& d_value_d_dof_dep) {
525 size_t dn[SHAPE::num_nodes * (EULER ? 4 : 7)];
526 double node_coor[SHAPE::num_nodes][3];
529 for (
int k = 0; k != SHAPE::num_nodes; ++k) {
531 ptr = node_type_euler::get_global_dof_numbering_s(ptr, nodes[k]);
532 node_type_euler::get_coor_s(node_coor[k], nodes[k]);
534 ptr = node_type::get_global_dof_numbering_s(ptr, nodes[k]);
535 node_type::get_coor_s(node_coor[k], nodes[k]);
540 if (field_name == displacement) {
541 if (!value.is_null()) {
542 b2linalg::Vector<double> shape(SHAPE::num_nodes);
543 SHAPE::eval_h(internal_coor, shape);
545 for (
size_t i = 0; i != 3; ++i) {
547 for (
int k = 0; k != SHAPE::num_nodes; ++k) {
548 tmp += shape[k] * dof(dn[k * (EULER ? 4 : 7) + i], 0);
553 if (!d_value_d_icoor.is_null()) {
554 b2linalg::Matrix<double> d_shape(2, SHAPE::num_nodes);
555 SHAPE::eval_h_derived(internal_coor, d_shape);
556 d_value_d_icoor.resize(3, 2);
557 for (
size_t i = 0; i != 3; ++i) {
558 for (
size_t j = 0; j != 2; ++j) {
560 for (
int k = 0; k != SHAPE::num_nodes; ++k) {
561 tmp += d_shape(j, k) * dof(dn[k * (EULER ? 4 : 7) + i], 0);
563 d_value_d_icoor(i, j) = tmp;
567 if (!d_value_d_dof.is_null()) {
568 dof_numbering.resize(SHAPE::num_nodes * 3);
569 b2linalg::Vector<double> shape(SHAPE::num_nodes);
570 SHAPE::eval_h(internal_coor, shape);
571 d_value_d_dof.resize(3, dof_numbering.size());
572 d_value_d_dof.set_zero();
574 for (
int k = 0; k != SHAPE::num_nodes; ++k) {
575 for (
size_t i = 0; i != 3; ++i, ++i_ptr) {
576 dof_numbering[i_ptr] = dn[k * (EULER ? 4 : 7) + i];
577 d_value_d_dof(i, i_ptr + i) = shape[k];
583 if (field_name == traction) {
586 Exception() <<
THROW;
609 double d_n_d_dof[SHAPE::num_nodes * 3][3];
610 double d_scale_d_dof[SHAPE::num_nodes * 3];
612 b2linalg::Matrix<double> d_shape(2, SHAPE::num_nodes);
613 SHAPE::eval_h_derived(internal_coor, d_shape);
614 double d_geom_d_icoor_tmp[2][3];
615 for (
size_t i = 0; i != 3; ++i) {
616 for (
size_t j = 0; j != 2; ++j) {
618 for (
int k = 0; k != SHAPE::num_nodes; ++k) {
619 tmp += d_shape(j, k) * node_coor[k][i];
621 d_geom_d_icoor_tmp[j][i] = tmp;
624 double inv_undef_area =
627 for (
size_t i = 0; i != 3; ++i) {
628 for (
size_t j = 0; j != 2; ++j) {
630 for (
int k = 0; k != SHAPE::num_nodes; ++k) {
631 tmp += d_shape(j, k) * dof(dn[k * (EULER ? 4 : 7) + i], 0);
633 d_geom_d_icoor_tmp[j][i] += tmp;
637 scale = std::sqrt(
dot_3(n, n)) * inv_undef_area;
641 for (
int i = 0; i != 3; ++i) { n[i] *= inv_undef_area; }
642 if (!d_value_d_dof.is_null()) {
643 for (
int k = 0; k != SHAPE::num_nodes; ++k) {
644 for (
int j = 0; j != 3; ++j) {
645 double tmp_u[3] = {};
646 tmp_u[j] = d_shape(0, k);
647 double tmp_v[3] = {};
648 tmp_v[j] = d_shape(1, k);
649 double* res = d_n_d_dof + k * 3 + j;
652 for (
int i = 0; i != 3; ++i) { res[i] *= inv_undef_area; }
655 double s = 2 / scale;
656 for (
int k = 0; k != SHAPE::num_nodes * 3; ++k) {
658 for (
int i = 0; i != 3; ++i) { tmp += n[i] * d_n_d_dof[k][i]; }
659 d_scale_d_dof[k] = s * tmp;
664 double p =
property->get_internal_pressure();
665 if (dof.size2()) { p -= dof(dn[(EULER ? 4 : 7) * pos_node], 0); }
667 if (!value.is_null()) {
670 const size_t s_trac = pos_node * (EULER ? 4 : 7) + 4;
671 for (
int i = 0; i != 3; ++i) {
672 value[i] = scale * dof(dn[s_trac + i], 0) + n[i] * p;
675 for (
int i = 0; i != 3; ++i) { value[i] = n[i] * p; }
679 if (!d_value_d_icoor.is_null()) {
680 d_value_d_icoor.resize(3, 2);
681 d_value_d_icoor.set_zero();
684 if (!d_value_d_dof.is_null()) {
685 dof_numbering.resize(SHAPE::num_nodes * 3 + (EULER ? 1 : 4));
688 for (
int k = 0; k != SHAPE::num_nodes; ++k, i += 3) {
690 dn + k * (EULER ? 4 : 7), dn + k * (EULER ? 4 : 7) + 3,
694 dn + pos_node * (EULER ? 4 : 7) + 3,
695 dn + (pos_node + 1) * (EULER ? 4 : 7), &dof_numbering[i]);
698 const size_t s_trac = pos_node * (EULER ? 4 : 7) + 4;
699 d_value_d_dof.resize(3, dof_numbering.size());
700 for (
int k = 0; k != SHAPE::num_nodes; ++k) {
701 for (
int j = 0; j != 3; ++j) {
702 for (
int i = 0; i != 3; ++i) {
703 d_value_d_dof(i, k * 3 + j) =
704 d_scale_d_dof[k * 3 + j] * dof(dn[s_trac + i], 0)
705 + d_n_d_dof[k * 3 + j][i] * p;
709 for (
int i = 0; i != 3; ++i) {
710 d_value_d_dof(i, SHAPE::num_nodes * 3) = -n[i];
711 for (
int j = 0; j != 3; ++j) {
712 d_value_d_dof(i, SHAPE::num_nodes * 3 + 1 + j) = scale;
720 property =
dynamic_cast<CFDMaterial*
>(property_);
721 if (property ==
nullptr) {
722 TypeError() <<
"Bad property type " <<
typeid(*property_)
723 <<
" for ElementCFD2DFieldL2 element." <<
THROW;
732 Node* nodes[SHAPE::num_nodes];
735 CFDMaterial* property;
742template <
bool FLUX,
bool AXISYMMETRIC>
746 node::HNode<coordof::Coor<coordof::Trans<coordof::X, coordof::Y>>, coordof::Dof<>>;
751 std::pair<int, Node* const*>
get_nodes()
const override {
752 return std::pair<int, Node* const*>(2, nodes);
755 void set_nodes(std::pair<int, Node* const*> nodes_)
override {
756 if (nodes_.first != 2) {
Exception() <<
"This element must have 2 nodes." <<
THROW; }
757 for (
int i = 0; i != 2; ++i) { nodes[i] = nodes_.second[i]; }
764 return index + (FLUX ? 2 : 1);
768 return std::pair<size_t, size_t>(dof_index, dof_index + (FLUX ? 2 : 1));
772 return AXISYMMETRIC && FLUX ? 2 : 0;
780 const int edge_id,
const std::string& field_name,
781 b2linalg::Vector<double, b2linalg::Vdense>& sub_nodes)
override {
783 sub_nodes.reserve(2);
784 sub_nodes.push_back(0);
785 sub_nodes.push_back(1);
790 const int edge_id,
const double internal_coor, b2linalg::Vector<double>& geom,
791 b2linalg::Vector<double>& d_geom_d_icoor)
override {
792 double node_coor[2][2];
793 for (
int k = 0; k != 2; ++k) { node_type::get_coor_s(node_coor[k], nodes[k]); }
794 if (!geom.is_null()) {
796 for (
size_t i = 0; i != 2; ++i) {
797 geom[i] = node_coor[0][i] * (1 - internal_coor) + node_coor[1][i] * internal_coor;
800 if (!d_geom_d_icoor.is_null()) {
801 d_geom_d_icoor.resize(2);
802 for (
size_t i = 0; i != 2; ++i) {
803 d_geom_d_icoor[i] = -node_coor[0][i] + node_coor[1][i];
809 const int edge_id,
const std::string& field_name,
const double internal_coor,
810 const b2linalg::Matrix<double, b2linalg::Mrectangle_constref>& dof,
const double time,
811 b2linalg::Vector<double, b2linalg::Vdense>& value,
812 b2linalg::Vector<double, b2linalg::Vdense>& d_value_d_icoor,
813 b2linalg::Index& dof_numbering,
814 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_value_d_dof,
815 b2linalg::Index& d_value_d_dof_dep)
override {
816 if (!FLUX || field_name ==
"Temperature") {
817 if (!value.is_null()) {
819 if (dof.size2() > 0) {
820 value[0] = dof(dof_index, 0);
825 if (!d_value_d_icoor.is_null()) {
826 d_value_d_icoor.resize(1);
827 d_value_d_icoor[0] = 0;
829 if (!d_value_d_dof.is_null()) {
830 dof_numbering.resize(1);
831 dof_numbering[0] = dof_index;
832 d_value_d_dof.resize(1, 1);
833 d_value_d_dof(0, 0) = 1;
835 }
else if (FLUX && field_name ==
"HeatFlux") {
836 double tickness, lenght;
838 double node_coor[2][2];
839 for (
int k = 0; k != 2; ++k) { node_type::get_coor_s(node_coor[k], nodes[k]); }
842 * (internal_coor * node_coor[0][1] + (1 - internal_coor) * node_coor[1][1]);
843 lenght = node_coor[0][1] - node_coor[1][1];
847 if (!value.is_null()) {
849 if (dof.size2() > 0) {
850 value[0] = dof(dof_index + 1, 0) * tickness;
855 if (!d_value_d_icoor.is_null()) {
856 d_value_d_icoor.resize(1);
857 if (AXISYMMETRIC && dof.size2() > 0) {
858 d_value_d_icoor[0] = dof(dof_index + 1, 0) * 2 * M_PIl * lenght;
860 d_value_d_icoor[0] = 0;
863 if (!d_value_d_dof.is_null()) {
864 dof_numbering.resize(1);
865 dof_numbering[0] = dof_index + 1;
866 d_value_d_dof.resize(1, 1);
867 d_value_d_dof(0, 0) = tickness;
csda< T > sqrt(const csda< T > &a)
Square root of a csda number.
Definition b2csda.H:396
#define THROW
Definition b2exception.H:198
Definition b2element_field_transfer.H:374
std::pair< int, Node *const * > get_nodes() const override
Definition b2element_field_transfer.H:388
const ElementProperty * get_property() const override
Definition b2element_field_transfer.H:727
void set_nodes(std::pair< int, Node *const * > nodes_) override
Definition b2element_field_transfer.H:392
void face_geom(const int face_id, const b2linalg::Vector< double, b2linalg::Vdense_constref > &internal_coor, b2linalg::Vector< double > &geom, b2linalg::Matrix< double, b2linalg::Mrectangle > &d_geom_d_icoor) override
Definition b2element_field_transfer.H:476
int face_field_order(const int face_id, const std::string &field_name) override
Definition b2element_field_transfer.H:399
void set_property(ElementProperty *property_) override
Definition b2element_field_transfer.H:719
bool face_field_linear_on_dof(const int edge_id, const std::string &field_name) override
Definition b2element_field_transfer.H:403
Definition b2element_field_transfer.H:743
int edge_field_order(const int edge_id, const std::string &field_name) override
Definition b2element_field_transfer.H:771
int get_number_of_dof() const override
Definition b2element_field_transfer.H:760
void edge_field_value(const int edge_id, const std::string &field_name, const double internal_coor, const b2linalg::Matrix< double, b2linalg::Mrectangle_constref > &dof, const double time, b2linalg::Vector< double, b2linalg::Vdense > &value, b2linalg::Vector< double, b2linalg::Vdense > &d_value_d_icoor, b2linalg::Index &dof_numbering, b2linalg::Matrix< double, b2linalg::Mrectangle > &d_value_d_dof, b2linalg::Index &d_value_d_dof_dep) override
Definition b2element_field_transfer.H:808
bool edge_field_linear_on_dof(const int edge_id, const std::string &field_name) override
Definition b2element_field_transfer.H:775
void set_nodes(std::pair< int, Node *const * > nodes_) override
Definition b2element_field_transfer.H:755
size_t set_global_dof_numbering(size_t index) override
Definition b2element_field_transfer.H:762
std::pair< size_t, size_t > get_global_dof_numbering() const override
Definition b2element_field_transfer.H:767
std::pair< int, Node *const * > get_nodes() const override
Definition b2element_field_transfer.H:751
void edge_geom(const int edge_id, const double internal_coor, b2linalg::Vector< double > &geom, b2linalg::Vector< double > &d_geom_d_icoor) override
Definition b2element_field_transfer.H:789
int edge_field_polynomial_sub_edge(const int edge_id, const std::string &field_name, b2linalg::Vector< double, b2linalg::Vdense > &sub_nodes) override
Definition b2element_field_transfer.H:779
Definition b2element.H:71
Definition b2exception.H:131
Definition b2object.H:415
Definition b2element.H:1054
Contains the base classes for implementing Finite Elements.
Definition b2boundary_condition.H:32
T norm_outer_product_3(const T a[3], const T b[3])
Definition b2tensor_calculus.H:407
void outer_product_3(const T1 a[3], const T2 b[3], T3 c[3])
Definition b2tensor_calculus.H:389
GenericException< TypeError_name > TypeError
Definition b2exception.H:325
void outer_product_add_3(const T1 a[3], const T2 b[3], T3 c[3])
Definition b2tensor_calculus.H:398
T dot_3(const T a[3], const T b[3])
Definition b2tensor_calculus.H:328