21#ifndef B2_ELEMENT_HEAT_H_
22#define B2_ELEMENT_HEAT_H_
24#include "b2element_continuum_util.H"
25#include "elements/properties/b2heat_material.H"
26#include "model/b2element.H"
28#include "model_imp/b2hnode.H"
31#include "utils/b2linear_algebra.H"
38template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS>
39class GenericInterpolation {
41 static const int nb_dimensions = SHAPE::num_dimensions;
42 static const int nb_nodes = SHAPE::num_nodes;
43 static const int nb_gauss = NB_GAUSS;
45 GenericInterpolation() {
46 b2linalg::Vector<double, b2linalg::Vdense> v(nb_nodes);
47 b2linalg::Matrix<double, b2linalg::Mrectangle> m(nb_dimensions, nb_nodes);
48 INTEGRATION integration;
49 integration.set_num(NB_GAUSS);
50 if (NB_GAUSS != integration.get_num()) {
51 Exception() <<
"Cannot found an integration schemas that contain " << NB_GAUSS
52 <<
" integration points." <<
THROW;
55 for (
int l = 0; l != nb_gauss; ++l) {
56 integration.get_point(l, ip_id, array[l].weight);
57 for (
int i = 0; i != nb_dimensions; ++i) { array[l].IntCoor[i] = ip_id[i]; }
58 SHAPE::eval_h(array[l].IntCoor, v);
59 std::copy(v.begin(), v.end(), array[l].N);
60 SHAPE::eval_h_derived(array[l].IntCoor, m);
61 for (
size_t i = 0; i != m.size1(); ++i) {
62 for (
size_t j = 0; j != m.size2(); ++j) { array[l].dN[j][i] = m(i, j); }
69 double IntCoor[nb_dimensions];
78 double dN[nb_nodes][nb_dimensions];
81 static OnePoint array[nb_gauss];
84template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS>
85typename GenericInterpolation<SHAPE, INTEGRATION, NB_GAUSS>::OnePoint
86 GenericInterpolation<SHAPE, INTEGRATION, NB_GAUSS>::array[nb_gauss];
88template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS>
89const int GenericInterpolation<SHAPE, INTEGRATION, NB_GAUSS>::nb_dimensions;
91template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS>
92const int GenericInterpolation<SHAPE, INTEGRATION, NB_GAUSS>::nb_nodes;
94template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS>
95const int GenericInterpolation<SHAPE, INTEGRATION, NB_GAUSS>::nb_gauss;
97template <
int NB_DIMMENSION>
98struct HeatMaterialType;
101struct HeatMaterialType<2> {
102 typedef HeatMaterial2D heat_material_type;
103 static double get_thickness(
104 const heat_material_type* properties,
const Element* element,
105 b2linalg::Vector<double, b2linalg::Vdense_constref> nodes_interpolation) {
106 return properties->get_thickness(element, nodes_interpolation);
111struct HeatMaterialType<3> {
112 typedef HeatMaterial3D heat_material_type;
113 static double get_thickness(
114 const heat_material_type* properties,
const Element* element,
115 b2linalg::Vector<double, b2linalg::Vdense_constref> nodes_interpolation) {
120template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS,
bool AXISYMMETRIC = false>
121class ElementHeatConduction :
public TypedElement<double> {
123 using N_t = GenericInterpolation<SHAPE, INTEGRATION, NB_GAUSS>;
125 static const int nb_dimensions = N_t::nb_dimensions;
127 using node_type = node::HNode<
128 coordof::Coor<coordof::Trans<coordof::X, coordof::Y, coordof::Z>>,
129 coordof::Dof<coordof::Temperature>>;
131 using heat_material_type =
typename HeatMaterialType<nb_dimensions>::heat_material_type;
133 using type_t = ObjectTypeComplete<ElementHeatConduction, typename TypedElement<double>::type_t>;
135 void set_nodes(std::pair<int, Node* const*> nodes_)
override {
136 if (nodes_.first != N_t::nb_nodes) {
137 Exception() <<
"This element has " << N_t::nb_nodes <<
" nodes." <<
THROW;
139 for (
int i = 0; i != N_t::nb_nodes; ++i) { nodes[i] = nodes_.second[i]; }
142 std::pair<int, Node* const*> get_nodes()
const override {
143 return std::pair<int, Node* const*>(N_t::nb_nodes, nodes);
146 void set_property(ElementProperty* property_)
override {
147 property =
dynamic_cast<heat_material_type*
>(property_);
149 TypeError() <<
"Bad property type " <<
typeid(*property_)
150 <<
" for heat element (forgot MID or PID element attribute?)" <<
THROW;
154 const ElementProperty* get_property()
const override {
return property; }
156 void get_dof_numbering(b2linalg::Index& dof_numbering)
override {
157 dof_numbering.resize(N_t::nb_nodes);
158 size_t* ptr = &dof_numbering[0];
159 for (
int k = 0; k != N_t::nb_nodes; ++k) {
160 ptr = node_type::get_global_dof_numbering_s(ptr, nodes[k]);
164 const std::vector<VariableInfo> get_value_info()
const override {
169 Model& model,
const bool linear,
const EquilibriumSolution equilibrium_solution,
170 const double time,
const double delta_time,
171 const b2linalg::Matrix<double, b2linalg::Mrectangle_constref>& dof,
172 GradientContainer* gradient_container, SolverHints* solver_hints,
173 b2linalg::Index& dof_numbering, b2linalg::Vector<double, b2linalg::Vdense>& value,
174 const std::vector<bool>& d_value_d_dof_flags,
175 std::vector<b2linalg::Matrix<double, b2linalg::Mpacked>>& d_value_d_dof,
176 b2linalg::Vector<double, b2linalg::Vdense>& d_value_d_time)
override;
178 int edge_field_order(
const int edge_id,
const std::string& field_name)
override {
179 return SHAPE::edge_shape_type_0::order;
182 bool edge_field_linear_on_dof(
const int edge_id,
const std::string& field_name)
override {
186 int edge_field_polynomial_sub_edge(
187 const int edge_id,
const std::string& field_name,
188 b2linalg::Vector<double, b2linalg::Vdense>& sub_nodes)
override {
190 sub_nodes.reserve(2);
191 sub_nodes.push_back(-1);
192 sub_nodes.push_back(1);
197 const int edge_id,
const double internal_coor, b2linalg::Vector<double>& geom,
198 b2linalg::Vector<double>& d_geom_d_icoor)
override {
199 typedef typename SHAPE::edge_shape_type_0 edge_shape;
200 const int* edge_node = SHAPE::edge_node[edge_id - 1];
201 double node_coor[edge_shape::num_nodes][3];
202 for (
int k = 0; k != edge_shape::num_nodes; ++k) {
203 node_type::get_coor_s(node_coor[k], nodes[edge_node[k]]);
205 if (!geom.is_null()) {
206 b2linalg::Vector<double> shape(edge_shape::num_nodes);
207 edge_shape::eval_h(&internal_coor, shape);
209 for (
size_t i = 0; i != 3; ++i) {
211 for (
int k = 0; k != edge_shape::num_nodes; ++k) {
212 tmp += shape[k] * node_coor[k][i];
217 if (!d_geom_d_icoor.is_null()) {
218 b2linalg::Matrix<double> d_shape(1, edge_shape::num_nodes);
219 edge_shape::eval_h_derived(&internal_coor, d_shape);
220 d_geom_d_icoor.resize(3);
221 for (
size_t i = 0; i != 3; ++i) {
223 for (
int k = 0; k != edge_shape::num_nodes; ++k) {
224 tmp += d_shape(0, k) * node_coor[k][i];
226 d_geom_d_icoor[i] = tmp;
231 void edge_field_value(
232 const int edge_id,
const std::string& field_name,
const double internal_coor,
233 const b2linalg::Matrix<double, b2linalg::Mrectangle_constref>& dof,
const double time,
234 b2linalg::Vector<double, b2linalg::Vdense>& value,
235 b2linalg::Vector<double, b2linalg::Vdense>& d_value_d_icoor,
236 b2linalg::Index& dof_numbering,
237 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_value_d_dof,
238 b2linalg::Index& d_value_d_dof_dep)
override {
239 typedef typename SHAPE::edge_shape_type_0 edge_shape;
240 const int* edge_node = SHAPE::edge_node[edge_id - 1];
241 size_t dn[edge_shape::num_nodes];
243 size_t* ptr = &dn[0];
244 for (
int k = 0; k != edge_shape::num_nodes; ++k) {
245 ptr = node_type::get_global_dof_numbering_s(ptr, nodes[edge_node[k]]);
248 if (!value.is_null()) {
249 b2linalg::Vector<double> shape(edge_shape::num_nodes);
250 edge_shape::eval_h(&internal_coor, shape);
252 double& tmp = value[0];
254 for (
int k = 0; k != edge_shape::num_nodes; ++k) { tmp += shape[k] * dof(0, dn[k]); }
256 if (!d_value_d_icoor.is_null()) {
257 b2linalg::Matrix<double> d_shape(1, edge_shape::num_nodes);
258 edge_shape::eval_h_derived(&internal_coor, d_shape);
259 d_value_d_icoor.resize(1);
260 double& tmp = d_value_d_icoor[0];
262 for (
int k = 0; k != edge_shape::num_nodes; ++k) {
263 tmp += d_shape(0, k) * dof(0, dn[k]);
266 if (!d_value_d_dof.is_null()) {
267 dof_numbering.resize(edge_shape::num_nodes);
268 std::copy(dn, dn + edge_shape::num_nodes, dof_numbering.begin());
269 b2linalg::Vector<double> shape(edge_shape::num_nodes);
270 edge_shape::eval_h(&internal_coor, shape);
271 d_value_d_dof.resize(1, edge_shape::num_nodes);
272 d_value_d_dof.set_zero();
273 for (
int k = 0; k != edge_shape::num_nodes; ++k) { d_value_d_dof(0, k) = shape[k]; }
277 int face_field_order(
const int face_id,
const std::string& field_name)
override {
278 switch (SHAPE::face_type_index[face_id - 1]) {
280 return SHAPE::face_shape_type_0::order;
282 return SHAPE::face_shape_type_1::order;
287 bool face_field_linear_on_dof(
const int face_id,
const std::string& field_name)
override {
291 int face_field_polynomial_sub_face(
292 const int face_id,
const std::string& field_name,
293 b2linalg::Matrix<double, b2linalg::Mrectangle>& sub_nodes,
294 std::vector<Triangle>& sub_faces)
override {
295 if (SHAPE::is_t_face[face_id]) {
296 sub_nodes.resize(2, 3);
304 sub_faces.reserve(1);
305 sub_faces.push_back(Triangle(0, 1, 2));
308 sub_nodes.resize(2, 4);
309 sub_nodes(0, 0) = -1;
310 sub_nodes(1, 0) = -1;
312 sub_nodes(1, 1) = -1;
315 sub_nodes(0, 3) = -1;
318 sub_faces.reserve(2);
319 sub_faces.push_back(Triangle(0, 1, 2));
320 sub_faces.push_back(Triangle(2, 3, 0));
322 return face_field_order(face_id, field_name);
325 template <
typename FACE_SHAPE>
326 void face_geom_for_face(
328 const b2linalg::Vector<double, b2linalg::Vdense_constref>& internal_coor,
329 b2linalg::Vector<double>& geom,
330 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_geom_d_icoor) {
331 const int* edge_node = SHAPE::face_node[face_id - 1];
332 double node_coor[FACE_SHAPE::num_nodes][3];
333 for (
int k = 0; k != FACE_SHAPE::num_nodes; ++k) {
334 node_type::get_coor_s(node_coor[k], nodes[edge_node[k]]);
336 if (!geom.is_null()) {
337 b2linalg::Vector<double> shape(FACE_SHAPE::num_nodes);
338 FACE_SHAPE::eval_h(&internal_coor[0], shape);
340 for (
size_t i = 0; i != 3; ++i) {
342 for (
int k = 0; k != FACE_SHAPE::num_nodes; ++k) {
343 tmp += shape[k] * node_coor[k][i];
348 if (!d_geom_d_icoor.is_null()) {
349 b2linalg::Matrix<double> d_shape(2, FACE_SHAPE::num_nodes);
350 FACE_SHAPE::eval_h_derived(&internal_coor[0], d_shape);
351 d_geom_d_icoor.resize(3, 2);
352 for (
size_t i = 0; i != 3; ++i) {
353 for (
size_t j = 0; j != 2; ++j) {
355 for (
int k = 0; k != FACE_SHAPE::num_nodes; ++k) {
356 tmp += d_shape(j, k) * node_coor[k][i];
358 d_geom_d_icoor(i, j) = tmp;
366 const b2linalg::Vector<double, b2linalg::Vdense_constref>& internal_coor,
367 b2linalg::Vector<double>& geom,
368 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_geom_d_icoor)
override {
369 switch (SHAPE::face_type_index[face_id - 1]) {
371 face_geom_for_face<typename SHAPE::face_shape_type_0>(
372 face_id, internal_coor, geom, d_geom_d_icoor);
375 face_geom_for_face<typename SHAPE::face_shape_type_1>(
376 face_id, internal_coor, geom, d_geom_d_icoor);
381 template <
typename FACE_SHAPE>
382 void face_field_value_for_face(
383 const int face_id,
const std::string& field_name,
384 const b2linalg::Vector<double, b2linalg::Vdense_constref>& internal_coor,
385 const b2linalg::Matrix<double, b2linalg::Mrectangle_constref>& dof,
const double time,
386 b2linalg::Vector<double, b2linalg::Vdense>& value,
387 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_value_d_icoor,
388 b2linalg::Index& dof_numbering,
389 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_value_d_dof,
390 b2linalg::Index& d_value_d_dof_dep_col) {
391 const int* edge_node = SHAPE::face_node[face_id - 1];
392 size_t dn[FACE_SHAPE::num_nodes];
394 size_t* ptr = &dn[0];
395 for (
int k = 0; k != FACE_SHAPE::num_nodes; ++k) {
396 ptr = node_type::get_global_dof_numbering_s(ptr, nodes[edge_node[k]]);
399 if (!value.is_null()) {
400 b2linalg::Vector<double> shape(FACE_SHAPE::num_nodes);
401 FACE_SHAPE::eval_h(&internal_coor[0], shape);
403 double& tmp = value[0];
405 if (!dof.is_null()) {
406 for (
int k = 0; k != FACE_SHAPE::num_nodes; ++k) {
407 tmp += shape[k] * dof(0, dn[k]);
411 if (!d_value_d_icoor.is_null()) {
412 b2linalg::Matrix<double> d_shape(2, FACE_SHAPE::num_nodes);
413 FACE_SHAPE::eval_h_derived(&internal_coor[0], d_shape);
414 d_value_d_icoor.resize(1, 2);
415 for (
int i = 0; i != 2; ++i) {
416 double& tmp = d_value_d_icoor(0, i);
418 if (!dof.is_null()) {
419 for (
int k = 0; k != FACE_SHAPE::num_nodes; ++k) {
420 tmp += d_shape(i, k) * dof(0, dn[k]);
425 if (!d_value_d_dof.is_null()) {
426 dof_numbering.resize(FACE_SHAPE::num_nodes);
427 std::copy(dn, dn + FACE_SHAPE::num_nodes, dof_numbering.begin());
428 b2linalg::Vector<double> shape(FACE_SHAPE::num_nodes);
429 FACE_SHAPE::eval_h(&internal_coor[0], shape);
430 d_value_d_dof.resize(1, FACE_SHAPE::num_nodes);
431 d_value_d_dof.set_zero();
432 for (
int k = 0; k != FACE_SHAPE::num_nodes; ++k) { d_value_d_dof(0, k) = shape[k]; }
436 void face_field_value(
437 const int face_id,
const std::string& field_name,
438 const b2linalg::Vector<double, b2linalg::Vdense_constref>& internal_coor,
439 const b2linalg::Matrix<double, b2linalg::Mrectangle_constref>& dof,
const double time,
440 b2linalg::Vector<double, b2linalg::Vdense>& value,
441 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_value_d_icoor,
442 b2linalg::Index& dof_numbering,
443 b2linalg::Matrix<double, b2linalg::Mrectangle>& d_value_d_dof,
444 b2linalg::Index& d_value_d_dof_dep_col)
override {
445 switch (SHAPE::face_type_index[face_id - 1]) {
447 face_field_value_for_face<typename SHAPE::face_shape_type_0>(
448 face_id, field_name, internal_coor, dof, time, value, d_value_d_icoor,
449 dof_numbering, d_value_d_dof, d_value_d_dof_dep_col);
452 face_field_value_for_face<typename SHAPE::face_shape_type_1>(
453 face_id, field_name, internal_coor, dof, time, value, d_value_d_icoor,
454 dof_numbering, d_value_d_dof, d_value_d_dof_dep_col);
460 const VDC& dof,
const VDC& dofdot,
const VDC& dofdotdot,
const Field<double>& field,
461 b2linalg::Index& dof_numbering, VD& discretised_field,
462 MP& d_discretised_field_d_dof)
override {
465 if (!discretised_field.is_null()) {
466 discretised_field.resize(N_t::nb_nodes);
467 discretised_field.set_zero();
471 get_dof_numbering(dof_numbering);
474 double node_coor[N_t::nb_nodes][3];
475 for (
int k = 0; k != N_t::nb_nodes; ++k) { node_type::get_coor_s(node_coor[k], nodes[k]); }
478 for (
int ng = 0; ng != N_t::nb_gauss; ++ng) {
479 const typename N_t::OnePoint& N = N_t::array[ng];
483 double J[nb_dimensions][nb_dimensions];
484 for (
int j = 0; j != nb_dimensions; ++j) {
485 for (
int i = 0; i != nb_dimensions; ++i) {
487 for (
int n = 0; n != N_t::nb_nodes; ++n) { v += N.dN[n][i] * node_coor[n][j]; }
493 double inv_J[nb_dimensions][nb_dimensions];
494 double volume =
invert_x_x(J, inv_J) * N.weight;
495 if (nb_dimensions == 2) {
499 for (
int n = 0; n != N_t::nb_nodes; ++n) {
500 thickness += N.N[n] * node_coor[n][1];
502 thickness = std::abs(thickness) * 2 * M_PIl;
504 thickness = HeatMaterialType<nb_dimensions>::get_thickness(
506 b2linalg::Vector<double, b2linalg::Vdense_constref>(N_t::nb_nodes, N.N));
515 const double lcoor[3] = {
516 N.IntCoor[0], N.IntCoor[1], nb_dimensions > 2 ? N.IntCoor[2] : 0};
519 double coor[nb_dimensions];
520 for (
int i = 0; i != nb_dimensions; ++i) {
522 for (
int n = 0; n != N_t::nb_nodes; ++n) { v += N.N[n] * node_coor[n][i]; }
527 b2linalg::Vector<double, b2linalg::Vdense> value;
529 b2linalg::Vector<double, b2linalg::Vdense_constref>(3, lcoor),
530 b2linalg::Vector<double, b2linalg::Vdense_constref>(nb_dimensions, coor),
531 b2linalg::Vector<double, b2linalg::Vdense_constref>(nb_dimensions, coor),
532 b2linalg::Matrix<double, b2linalg::Mrectangle_constref>(
533 nb_dimensions, nb_dimensions, &J[0][0]),
534 b2linalg::Matrix<double, b2linalg::Mrectangle_constref>(
535 nb_dimensions, nb_dimensions, &J[0][0]),
540 if (!discretised_field.is_null()) {
542 for (
int k = 0; k != N_t::nb_nodes; ++k) {
543 discretised_field[k] += volume * value[0] * N.N[k];
553 Node* nodes[N_t::nb_nodes];
556 heat_material_type* property;
558 static N_t internal_n_t;
561template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS,
bool AXISYMMETRIC>
562typename ElementHeatConduction<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::type_t
563 ElementHeatConduction<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::type(
564 std::string(SHAPE::name) +
".HEAT.CONDUCTION"
565 + (SHAPE::num_dimensions == 2 ? (AXISYMMETRIC ?
".AXISYMMETRIC" :
".2D") :
""),
566 "", StringList(), element::module, &TypedElement<double>::type);
568template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS,
bool AXISYMMETRIC>
569typename ElementHeatConduction<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::N_t
570 ElementHeatConduction<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::internal_n_t;
572class ElementHeatRadConvBase :
public TypedElement<double> {
574 virtual bool has_radiation_property()
const = 0;
576 virtual void get_radiation_property_at_internal_coor(
577 Model& model,
const double coordinates[3],
const double internal_coor[2],
578 const double temperature,
double& heat_radiation_unit,
double& diffuse_reflectivity,
579 b2linalg::Vector<double, b2linalg::Vdense>& dof_interpolation) = 0;
582template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS,
bool AXISYMMETRIC = false>
583class ElementHeatRadConv :
public ElementHeatRadConvBase {
585 typedef GenericInterpolation<SHAPE, INTEGRATION, NB_GAUSS> N_t;
587 coordof::Coor<coordof::Trans<coordof::X, coordof::Y, coordof::Z>>,
588 coordof::Dof<coordof::Temperature>>
590 static const int nb_dimensions = N_t::nb_dimensions;
591 typedef typename HeatMaterialType<nb_dimensions + 1>::heat_material_type heat_material_type;
593 void set_nodes(std::pair<int, Node* const*> nodes_)
override {
594 if (nodes_.first != N_t::nb_nodes) {
595 Exception() <<
"This element has " << N_t::nb_nodes <<
" nodes." <<
THROW;
597 for (
int i = 0; i != N_t::nb_nodes; ++i) { nodes[i] = nodes_.second[i]; }
600 std::pair<int, Node* const*> get_nodes()
const override {
601 return std::pair<int, Node* const*>(N_t::nb_nodes, nodes);
604 void set_property(ElementProperty* property_)
override {
605 property =
dynamic_cast<heat_material_type*
>(property_);
607 TypeError() <<
"Bad property type " <<
typeid(*property_)
608 <<
" for heat element (forgot MID element option?)." <<
THROW;
612 const ElementProperty* get_property()
const override {
return property; }
614 void get_dof_numbering(b2linalg::Index& dof_numbering)
override {
615 dof_numbering.resize(N_t::nb_nodes);
616 size_t* ptr = &dof_numbering[0];
617 for (
int k = 0; k != N_t::nb_nodes; ++k) {
618 ptr = node_type::get_global_dof_numbering_s(ptr, nodes[k]);
622 const std::vector<VariableInfo> get_value_info()
const override {
627 Model& model,
const bool linear,
const EquilibriumSolution equilibrium_solution,
628 const double time,
const double delta_time,
629 const b2linalg::Matrix<double, b2linalg::Mrectangle_constref>& dof,
630 GradientContainer* gradient_container, SolverHints* solver_hints,
631 b2linalg::Index& dof_numbering, b2linalg::Vector<double, b2linalg::Vdense>& value,
632 const std::vector<bool>& d_value_d_dof_flags,
633 std::vector<b2linalg::Matrix<double, b2linalg::Mpacked>>& d_value_d_dof,
634 b2linalg::Vector<double, b2linalg::Vdense>& d_value_d_time)
override;
636 bool has_radiation_property()
const override;
638 void get_radiation_property_at_internal_coor(
639 Model& model,
const double coordinates[3],
const double internal_coor[nb_dimensions],
640 const double temperature,
double& heat_radiation_unit,
double& diffuse_reflectivity,
641 b2linalg::Vector<double, b2linalg::Vdense>& dof_interpolation)
override;
643 using type_t = ObjectTypeComplete<ElementHeatRadConv, typename TypedElement<double>::type_t>;
649 Node* nodes[N_t::nb_nodes];
652 heat_material_type* property;
654 static N_t internal_n_t;
657template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS,
bool AXISYMMETRIC>
658typename ElementHeatRadConv<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::type_t
659 ElementHeatRadConv<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::type(
660 std::string(SHAPE::name) +
".HEAT.RADCONV"
661 + (SHAPE::num_dimensions == 1 ? (AXISYMMETRIC ?
".AXISYMMETRIC" :
".2D") :
""),
662 "", StringList(), element::module, &TypedElement<double>::type);
664template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS,
bool AXISYMMETRIC>
665typename ElementHeatRadConv<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::N_t
666 ElementHeatRadConv<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::internal_n_t;
670template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS,
bool AXISYMMETRIC>
671void b2000::ElementHeatConduction<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::get_value(
672 Model& model,
const bool linear,
const EquilibriumSolution equilibrium_solution,
673 const double time,
const double delta_time,
674 const b2linalg::Matrix<double, b2linalg::Mrectangle_constref>& dof,
675 GradientContainer* gradient_container, SolverHints* solver_hints,
676 b2linalg::Index& dof_numbering, b2linalg::Vector<double, b2linalg::Vdense>& value,
677 const std::vector<bool>& d_value_d_dof_flags,
678 std::vector<b2linalg::Matrix<double, b2linalg::Mpacked>>& d_value_d_dof,
679 b2linalg::Vector<double, b2linalg::Vdense>& d_value_d_time) {
680 get_dof_numbering(dof_numbering);
681 if (!value.is_null()) {
682 value.resize(dof_numbering.size());
685 for (
size_t i = 0; i != d_value_d_dof_flags.size(); ++i) {
686 if (d_value_d_dof_flags[i]) {
687 d_value_d_dof[i].resize(dof_numbering.size(),
true);
688 d_value_d_dof[i].set_zero();
691 if (!d_value_d_time.is_null()) {
692 d_value_d_time.resize(dof_numbering.size());
693 d_value_d_time.set_zero();
695 const bool compute_d_value_d_dof = (d_value_d_dof_flags.size() > 0 && d_value_d_dof_flags[0]);
696 const bool compute_d_value_d_dofdot =
697 (d_value_d_dof_flags.size() > 1 && d_value_d_dof_flags[1]);
700 double NodeCoor[N_t::nb_nodes][3];
701 for (
int k = 0; k != N_t::nb_nodes; ++k) { node_type::get_coor_s(NodeCoor[k], nodes[k]); }
703#ifdef LUMPED_CAPACITY
707 for (
int ng = 0; ng != N_t::nb_gauss; ++ng) {
708 const typename N_t::OnePoint& N = N_t::array[ng];
712 double J[nb_dimensions][nb_dimensions];
713 for (
int j = 0; j != nb_dimensions; ++j) {
714 for (
int i = 0; i != nb_dimensions; ++i) {
716 for (
int n = 0; n != N_t::nb_nodes; ++n) { v += N.dN[n][i] * NodeCoor[n][j]; }
722 double inv_J[nb_dimensions][nb_dimensions];
723 const double weight =
invert_x_x(J, inv_J) * N.weight;
724#ifdef LUMPED_CAPACITY
728 Exception() <<
"The initial configuration of the element " << this->get_object_name()
729 <<
" is invalid (negative Jacobian determinant)." <<
THROW;
734 double B[N_t::nb_nodes][nb_dimensions];
736 'N',
'N', nb_dimensions, N_t::nb_nodes, nb_dimensions, 1.0, inv_J[0], nb_dimensions,
737 N.dN[0], nb_dimensions, 0.0, B[0], nb_dimensions);
740 for (
int i = 0; i != nb_dimensions; ++i) {
742 for (
int n = 0; n != N_t::nb_nodes; ++n) { v += N.N[n] * NodeCoor[n][i]; }
745 if (gradient_container) {
746 const GradientContainer::InternalElementPosition ip = {
747 N.IntCoor[0], N.IntCoor[1], nb_dimensions > 2 ? N.IntCoor[2] : 0, 0};
748 gradient_container->set_current_position(ip, weight);
750 static const GradientContainer::FieldDescription coor_descr = {
752 nb_dimensions > 2 ?
"x.y.z" :
"x.y",
753 "Physical coordinate of the point "
754 "in the reference configuration",
761 if (gradient_container->compute_field_value(coor_descr.name)) {
762 gradient_container->set_field_value(coor_descr, coor);
766 double heat_conduction[nb_dimensions];
767 double d_heat_conduction_d_temperature[nb_dimensions];
768 double d_heat_conduction_d_grad_temperature[(nb_dimensions * (nb_dimensions + 1)) / 2];
769 double heat_capacity;
770 double d_heat_capacity_d_temperature;
771 double d_heat_capacity_d_temperature_dot;
772 if (dof.size2() == 0) {
773 property->get_conduction_and_capacity_heat(
775 b2linalg::Vector<double, b2linalg::Vdense_constref>(N_t::nb_nodes, N.N),
776 N.IntCoor, 0, J, 0, 0, 0, time, linear, heat_conduction,
777 (compute_d_value_d_dof ? d_heat_conduction_d_temperature : 0),
778 (compute_d_value_d_dof ? d_heat_conduction_d_grad_temperature : 0), heat_capacity,
779 d_heat_capacity_d_temperature, d_heat_capacity_d_temperature_dot,
780 gradient_container, solver_hints);
782 double temperature = 0;
783 double grad_temperature[nb_dimensions];
784 std::fill_n(grad_temperature, nb_dimensions, 0.0);
785 for (
int n = 0; n != N_t::nb_nodes; ++n) {
786 const double v = dof(dof_numbering[n], 0);
787 temperature += v * N.N[n];
788 for (
int i = 0; i != nb_dimensions; ++i) { grad_temperature[i] += v * B[n][i]; }
790 if (dof.size2() == 1) {
791 property->get_conduction_and_capacity_heat(
793 b2linalg::Vector<double, b2linalg::Vdense_constref>(N_t::nb_nodes, N.N),
794 N.IntCoor, 0, J, temperature, 0, grad_temperature, time, linear,
796 (compute_d_value_d_dof ? d_heat_conduction_d_temperature : 0),
797 (compute_d_value_d_dof ? d_heat_conduction_d_grad_temperature : 0),
798 heat_capacity, d_heat_capacity_d_temperature,
799 d_heat_capacity_d_temperature_dot, gradient_container, solver_hints);
801 double temperature_dot = 0;
802 for (
int n = 0; n != N_t::nb_nodes; ++n) {
803 temperature_dot += dof(dof_numbering[n], 1) * N.N[n];
805 property->get_conduction_and_capacity_heat(
807 b2linalg::Vector<double, b2linalg::Vdense_constref>(N_t::nb_nodes, N.N),
808 N.IntCoor, 0, J, temperature, temperature_dot, grad_temperature, time, linear,
810 (compute_d_value_d_dof ? d_heat_conduction_d_temperature : 0),
811 (compute_d_value_d_dof ? d_heat_conduction_d_grad_temperature : 0),
812 heat_capacity, d_heat_capacity_d_temperature,
813 d_heat_capacity_d_temperature_dot, gradient_container, solver_hints);
817 if (nb_dimensions == 2) {
821 for (
int n = 0; n != N_t::nb_nodes; ++n) { thickness += N.N[n] * NodeCoor[n][1]; }
822 thickness = std::abs(thickness) * 2 * M_PIl;
824 thickness = HeatMaterialType<nb_dimensions>::get_thickness(
826 b2linalg::Vector<double, b2linalg::Vdense_constref>(N_t::nb_nodes, N.N));
828 heat_conduction[0] *= thickness;
829 heat_conduction[1] *= thickness;
830 if (compute_d_value_d_dof) {
831 d_heat_conduction_d_temperature[0] *= thickness;
832 d_heat_conduction_d_temperature[1] *= thickness;
833 d_heat_conduction_d_grad_temperature[0] *= thickness;
834 d_heat_conduction_d_grad_temperature[1] *= thickness;
835 d_heat_conduction_d_grad_temperature[2] *= thickness;
837 heat_capacity *= thickness;
838 d_heat_capacity_d_temperature *= thickness;
839 d_heat_capacity_d_temperature_dot *= thickness;
842 if (!value.is_null()) {
843 for (
int n = 0; n != N_t::nb_nodes; ++n) {
845 for (
int i = 0; i != nb_dimensions; ++i) { tmp += B[n][i] * heat_conduction[i]; }
848#ifndef LUMPED_CAPACITY
849 + N.N[n] * heat_capacity
855 if (compute_d_value_d_dof) {
856 double tmp[N_t::nb_nodes];
857 for (
int i = 0; i != N_t::nb_nodes; ++i) {
858 tmp[i] = B[i][0] * d_heat_conduction_d_temperature[0]
859 + B[i][1] * d_heat_conduction_d_temperature[1];
860 if (nb_dimensions == 3) { tmp[i] += B[i][2] * d_heat_conduction_d_temperature[2]; }
862 double* ptr = &d_value_d_dof[0](0, 0);
863 for (
int i = 0; i != N_t::nb_nodes; ++i) {
864 if (nb_dimensions == 3) {
865 const double a0 = d_heat_conduction_d_grad_temperature[0] * B[i][0]
866 + d_heat_conduction_d_grad_temperature[1] * B[i][1]
867 + d_heat_conduction_d_grad_temperature[2] * B[i][2];
868 const double a1 = d_heat_conduction_d_grad_temperature[1] * B[i][0]
869 + d_heat_conduction_d_grad_temperature[3] * B[i][1]
870 + d_heat_conduction_d_grad_temperature[4] * B[i][2];
871 const double a2 = d_heat_conduction_d_grad_temperature[2] * B[i][0]
872 + d_heat_conduction_d_grad_temperature[4] * B[i][1]
873 + d_heat_conduction_d_grad_temperature[5] * B[i][2];
874 for (
int j = 0; j <= i; ++j, ++ptr) {
876 * (B[j][0] * a0 + B[j][1] * a1 + B[j][2] * a2
877 + 0.5 * (tmp[i] * N.N[j] + tmp[j] * N.N[i])
878#ifndef LUMPED_CAPACITY
879 + d_heat_capacity_d_temperature * N.N[i] * N.N[j]
884 const double a0 = d_heat_conduction_d_grad_temperature[0] * B[i][0]
885 + d_heat_conduction_d_grad_temperature[1] * B[i][1];
886 const double a1 = d_heat_conduction_d_grad_temperature[1] * B[i][0]
887 + d_heat_conduction_d_grad_temperature[2] * B[i][1];
888 for (
int j = 0; j <= i; ++j, ++ptr) {
890 * (B[j][0] * a0 + B[j][1] * a1
891 + 0.5 * (tmp[i] * N.N[j] + tmp[j] * N.N[i])
892#ifndef LUMPED_CAPACITY
893 + d_heat_capacity_d_temperature * N.N[i] * N.N[j]
901#ifndef LUMPED_CAPACITY
902 if (compute_d_value_d_dofdot) {
903 double* ptr = &d_value_d_dof[1](0, 0);
904 for (
int i = 0; i != N_t::nb_nodes; ++i) {
905 for (
int j = 0; j <= i; ++j, ++ptr) {
906 *ptr += weight * (N.N[i] * N.N[j] * d_heat_capacity_d_temperature_dot);
913#ifdef LUMPED_CAPACITY
914 volume /= N_t::nb_nodes;
915 double* ptr = &d_value_d_dof[1](0, 0);
916 for (
int n = 0; n != N_t::nb_nodes; ++n) {
917 double temperature = 0;
918 double temperature_dot = 0;
919 if (dof.size2() != 0) {
920 temperature = dof(dof_numbering[n], 0);
921 if (dof.size2() > 1) { temperature_dot = dof(dof_numbering[n], 1); }
923 double heat_capacity;
924 double d_heat_capacity_d_temperature;
925 double d_heat_capacity_d_temperature_dot;
926 double N[N_t::nb_nodes];
927 std::fill_n(N, N_t::nb_nodes, 0);
929 double IntCoor[3] = {};
930 double J[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
931 property->get_conduction_and_capacity_heat(
932 &model,
this, Vector<double, Vdense_constref>(N_t::nb_nodes, N), IntCoor, 0, J,
933 temperature, temperature_dot, 0, time, linear, 0, 0, 0, heat_capacity,
934 d_heat_capacity_d_temperature, d_heat_capacity_d_temperature_dot, 0);
935 if (!value.is_null()) { value[n] += volume * heat_capacity; }
936 if (compute_d_value_d_dofdot) {
937 *ptr += volume * d_heat_capacity_d_temperature_dot;
944template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS,
bool AXISYMMETRIC>
945void b2000::ElementHeatRadConv<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::get_value(
946 Model& model,
const bool linear,
const EquilibriumSolution equilibrium_solution,
947 const double time,
const double delta_time,
948 const b2linalg::Matrix<double, b2linalg::Mrectangle_constref>& dof,
949 GradientContainer* gradient_container, SolverHints* solver_hints,
950 b2linalg::Index& dof_numbering, b2linalg::Vector<double, b2linalg::Vdense>& value,
951 const std::vector<bool>& d_value_d_dof_flags,
952 std::vector<b2linalg::Matrix<double, b2linalg::Mpacked>>& d_value_d_dof,
953 b2linalg::Vector<double, b2linalg::Vdense>& d_value_d_time) {
954 get_dof_numbering(dof_numbering);
955 if (!value.is_null()) {
956 value.resize(dof_numbering.size());
959 for (
size_t i = 0; i != d_value_d_dof_flags.size(); ++i) {
960 if (d_value_d_dof_flags[i]) {
961 d_value_d_dof[i].resize(dof_numbering.size(),
true);
962 d_value_d_dof[i].set_zero();
965 if (!d_value_d_time.is_null()) {
966 d_value_d_time.resize(dof_numbering.size());
967 d_value_d_time.set_zero();
969 const bool compute_d_value_d_dof = (d_value_d_dof_flags.size() > 0 && d_value_d_dof_flags[0]);
972 double NodeCoor[N_t::nb_nodes][3];
973 for (
int k = 0; k != N_t::nb_nodes; ++k) { node_type::get_coor_s(NodeCoor[k], nodes[k]); }
976 for (
int ng = 0; ng != N_t::nb_gauss; ++ng) {
977 const typename N_t::OnePoint& N = N_t::array[ng];
983 double J[nb_dimensions + 1][nb_dimensions];
984 for (
int j = 0; j != nb_dimensions + 1; ++j) {
985 for (
int i = 0; i != nb_dimensions; ++i) {
987 for (
int n = 0; n != N_t::nb_nodes; ++n) { v += N.dN[n][i] * NodeCoor[n][j]; }
991 if (nb_dimensions == 2) {
992 const double outer[3] = {
993 J[1][0] * J[2][1] - J[2][0] * J[1][1], J[2][0] * J[0][1] - J[0][0] * J[2][1],
994 J[0][0] * J[1][1] - J[1][0] * J[0][1]};
996 weight = std::sqrt(outer[0] * outer[0] + outer[1] * outer[1] + outer[2] * outer[2])
999 weight = std::sqrt(J[0][0] * J[0][0] + J[1][0] * J[1][0]) * N.weight;
1003 double coor[3] = {};
1004 for (
int i = 0; i != nb_dimensions + 1; ++i) {
1006 for (
int n = 0; n != N_t::nb_nodes; ++n) { v += N.N[n] * NodeCoor[n][i]; }
1009 if (gradient_container) {
1010 const GradientContainer::InternalElementPosition ip = {
1011 N.IntCoor[0], nb_dimensions > 1 ? N.IntCoor[1] : 0, 0, 0};
1012 gradient_container->set_current_position(ip, weight);
1014 static const GradientContainer::FieldDescription coor_descr = {
1016 nb_dimensions > 1 ?
"x.y.z" :
"x.y",
1017 "Physical coordinate of the point "
1018 "in the reference configuration",
1025 if (gradient_container->compute_field_value(coor_descr.name)) {
1026 gradient_container->set_field_value(coor_descr, coor);
1031 double d_heat_d_temperature;
1032 double temperature = 0;
1033 if (dof.size2() == 0) {
1034 property->get_radiation_and_convection_heat(
1036 b2linalg::Vector<double, b2linalg::Vdense_constref>(N_t::nb_nodes, N.N),
1037 N.IntCoor, 0, time, linear, heat, d_heat_d_temperature, gradient_container,
1040 for (
int n = 0; n != N_t::nb_nodes; ++n) {
1041 temperature += dof(dof_numbering[n], 0) * N.N[n];
1043 property->get_radiation_and_convection_heat(
1045 b2linalg::Vector<double, b2linalg::Vdense_constref>(N_t::nb_nodes, N.N),
1046 N.IntCoor, temperature, time, linear, heat, d_heat_d_temperature,
1047 gradient_container, solver_hints);
1050 if (nb_dimensions == 1) {
1054 for (
int n = 0; n != N_t::nb_nodes; ++n) { thickness += N.N[n] * NodeCoor[n][1]; }
1055 thickness = std::abs(thickness) * 2 * M_PIl;
1057 thickness = HeatMaterialType<nb_dimensions + 1>::get_thickness(
1059 b2linalg::Vector<double, b2linalg::Vdense_constref>(N_t::nb_nodes, N.N));
1062 d_heat_d_temperature *= thickness;
1065 if (!value.is_null()) {
1066 for (
int n = 0; n != N_t::nb_nodes; ++n) { value[n] += weight * N.N[n] * heat; }
1069 if (compute_d_value_d_dof) {
1070 double* ptr = &d_value_d_dof[0](0, 0);
1071 for (
int i = 0; i != N_t::nb_nodes; ++i) {
1072 for (
int j = 0; j <= i; ++j, ++ptr) {
1073 *ptr += weight * d_heat_d_temperature * N.N[i] * N.N[j];
1080template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS,
bool AXISYMMETRIC>
1081bool b2000::ElementHeatRadConv<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::has_radiation_property()
1083 double emisivity, receptivity;
1084 return property->get_radiation_properties(
1085 0,
this, 0, b2linalg::Vector<double, b2linalg::Vdense_constref>::null, 0, 0, emisivity,
1089template <
typename SHAPE,
typename INTEGRATION,
int NB_GAUSS,
bool AXISYMMETRIC>
1090void b2000::ElementHeatRadConv<SHAPE, INTEGRATION, NB_GAUSS, AXISYMMETRIC>::
1091 get_radiation_property_at_internal_coor(
1092 Model& model,
const double coordinates[3],
const double internal_coor[nb_dimensions],
1093 const double temperature,
double& heat_radiation_unit,
double& diffuse_reflectivity,
1094 b2linalg::Vector<double, b2linalg::Vdense>& dof_interpolation) {
1095 dof_interpolation.resize(N_t::nb_nodes);
1096 SHAPE::eval_h(internal_coor, dof_interpolation);
1097 property->get_radiation_properties(
1098 &model,
this, coordinates, dof_interpolation, internal_coor, temperature,
1099 heat_radiation_unit, diffuse_reflectivity);
#define THROW
Definition b2exception.H:198
@ nonlinear
Definition b2element.H:619
@ linear
Definition b2element.H:615
const std::string & get_object_name() const override
Definition b2element.H:220
virtual void get_value(Model &model, const bool linear, const EquilibriumSolution equilibrium_solution, const double time, const double delta_time, const b2linalg::Matrix< double, b2linalg::Mrectangle_constref > &dof, GradientContainer *gradient_container, SolverHints *solver_hints, b2linalg::Index &dof_numbering, b2linalg::Vector< double, b2linalg::Vdense > &value, const std::vector< bool > &d_value_d_dof_flags, std::vector< b2linalg::Matrix< double, b2linalg::Mrectangle > > &d_value_d_dof, b2linalg::Vector< double, b2linalg::Vdense > &d_value_d_time)
Compute the internal forces and their derivatives of the element.
Definition b2element.H:1619
virtual void field_volume_integration(const b2linalg::Vector< double, b2linalg::Vdense_constref > &dof, const b2linalg::Vector< double, b2linalg::Vdense_constref > &dofdot, const b2linalg::Vector< double, b2linalg::Vdense_constref > &dofdotdot, const Field< double > &f, b2linalg::Index &dof_numbering, b2linalg::Vector< double, b2linalg::Vdense > &discretised_field, b2linalg::Matrix< double, b2linalg::Mpacked > &d_discretised_field_d_dof)
Definition b2element.H:1256
Contains the base classes for implementing Finite Elements.
Definition b2boundary_condition.H:32
T invert_x_x(const T a[2][2], T b[2][2])
Definition b2tensor_calculus.H:742
GenericException< TypeError_name > TypeError
Definition b2exception.H:325
GenericException< UnimplementedError_name > UnimplementedError
Definition b2exception.H:314