54 template <
int spacedim,
class Value>
61 "GMSH mesh with data. Can be different from actual computational mesh.")
63 "Section where to find the field.\n Some sections are specific to file format: "
64 "point_data/node_data, cell_data/element_data, -/element_node_data, native/-.\n"
65 "If not given by a user, we try to find the field in all sections, but we report an error "
66 "if it is found in more than one section.")
68 "The values of the Field are read from the ```$ElementData``` section with field name given by this key.")
70 "Default value is set on elements which values have not been listed in the mesh data file.")
72 "Definition of the unit of all times defined in the mesh data file.")
74 "This key allows reading field data from the mesh data file shifted in time. Considering the time 't', field descriptor with time 'T', "
75 "time shift 'S', then if 't > T', we read the time frame 't + S'.")
77 IT::Default(
"\"equivalent_mesh\""),
"Type of interpolation applied to the input spatial data.\n"
78 "The default value 'equivalent_mesh' assumes the data being constant on elements living on the same mesh "
79 "as the computational mesh, but possibly with different numbering. In the case of the same numbering, "
80 "the user can set 'identical_mesh' to omit algorithm for guessing node and element renumbering. "
81 "Alternatively, in case of different input mesh, several interpolation algorithms are available.")
85 template <
int spacedim,
class Value>
89 "Specify the section in mesh input file where field data is listed.\nSome sections are specific to file format.")
90 .
add_value(OutputTime::DiscreteSpace::NODE_DATA,
"node_data",
"point_data (VTK) / node_data (GMSH)")
91 .
add_value(OutputTime::DiscreteSpace::ELEM_DATA,
"element_data",
"cell_data (VTK) / element_data (GMSH)")
92 .
add_value(OutputTime::DiscreteSpace::CORNER_DATA,
"element_node_data",
"element_node_data (only for GMSH)")
93 .
add_value(OutputTime::DiscreteSpace::NATIVE_DATA,
"native_data",
"native_data (only for VTK)")
97 template <
int spacedim,
class Value>
100 return it::Selection(
"interpolation",
"Specify interpolation of the input data from its input mesh to the computational mesh.")
101 .
add_value(DataInterpolation::identic_msh,
"identic_mesh",
"Topology and indices of nodes and elements of"
102 "the input mesh and the computational mesh are identical. "
103 "This interpolation is typically used for GMSH input files containing only the field values without "
104 "explicit mesh specification.")
105 .
add_value(DataInterpolation::equivalent_msh,
"equivalent_mesh",
"Topologies of the input mesh and the computational mesh "
106 "are the same, the node and element numbering may differ. "
107 "This interpolation can be used also for VTK input data.")
108 .
add_value(DataInterpolation::gauss_p0,
"P0_gauss",
"Topologies of the input mesh and the computational mesh may differ. "
109 "Constant values on the elements of the computational mesh are evaluated using the Gaussian quadrature of the fixed order 4, "
110 "where the quadrature points and their values are found in the input mesh and input data using the BIH tree search."
112 .
add_value(DataInterpolation::interp_p0,
"P0_intersection",
"Topologies of the input mesh and the computational mesh may differ. "
113 "Can be applied only for boundary fields. For every (boundary) element of the computational mesh the "
114 "intersection with the input mesh is computed. Constant values on the elements of the computational mesh "
115 "are evaluated as the weighted average of the (constant) values on the intersecting elements of the input mesh.")
119 template <
int spacedim,
class Value>
121 Input::register_class< FieldFE<spacedim, Value>,
unsigned int >(
"FieldFE") +
126 template <
int spacedim,
class Value>
131 this->is_constant_in_space_ =
false;
135 template <
int spacedim,
class Value>
137 unsigned int component_index,
VectorMPI dof_values)
140 if (dof_values.
size()==0) {
141 data_vec_ = dh_->create_vector();
144 data_vec_ = dof_values;
147 unsigned int ndofs = dh_->max_elem_dofs();
148 dof_indices_.
resize(ndofs);
154 init_data.
ndofs = ndofs;
155 init_data.
n_comp = this->n_comp();
159 value_handler0_.initialize(init_data);
160 value_handler1_.initialize(init_data);
161 value_handler2_.initialize(init_data);
162 value_handler3_.initialize(init_data);
165 discretization_ = OutputTime::DiscreteSpace::UNDEFINED;
166 interpolation_ = DataInterpolation::equivalent_msh;
175 template <
int spacedim,
class Value>
180 return value_handler0_.value(p, elm);
182 return value_handler1_.value(p, elm);
184 return value_handler2_.value(p, elm);
186 return value_handler3_.value(p, elm);
188 ASSERT(
false).error(
"Invalid element dimension!");
191 return this->r_value_;
199 template <
int spacedim,
class Value>
203 ASSERT_EQ( point_list.size(), value_list.size() ).error();
207 value_handler0_.value_list(point_list, elm, value_list);
210 value_handler1_.value_list(point_list, elm, value_list);
213 value_handler2_.value_list(point_list, elm, value_list);
216 value_handler3_.value_list(point_list, elm, value_list);
219 ASSERT(
false).error(
"Invalid element dimension!");
225 template <
int spacedim,
class Value>
227 this->init_unit_conversion_coefficient(rec, init_data);
229 flags_ = init_data.
flags_;
234 field_name_ = rec.
val<std::string>(
"field_name");
236 discretization_ = OutputTime::DiscreteSpace::UNDEFINED;
239 interpolation_ = DataInterpolation::equivalent_msh;
241 if (! rec.
opt_val(
"default_value", default_value_) ) {
242 default_value_ = numeric_limits<double>::signaling_NaN();
248 template <
int spacedim,
class Value>
252 ASSERT(field_name_ !=
"").error(
"Uninitialized FieldFE, did you call init_from_input()?\n");
253 this->boundary_domain_ = boundary_domain;
254 this->make_dof_handler(mesh);
255 switch (this->interpolation_) {
256 case DataInterpolation::identic_msh:
259 case DataInterpolation::equivalent_msh:
261 this->interpolation_ = DataInterpolation::gauss_p0;
262 WarningOut().fmt(
"Source mesh of FieldFE '{}' is not compatible with target mesh.\nInterpolation of input data will be changed to 'P0_gauss'.\n",
266 case DataInterpolation::gauss_p0:
272 case DataInterpolation::interp_p0:
276 if (!boundary_domain) {
277 this->interpolation_ = DataInterpolation::gauss_p0;
278 WarningOut().fmt(
"Interpolation 'P0_intersection' of FieldFE '{}' can't be used on bulk region.\nIt will be changed to 'P0_gauss'.\n", field_name_);
288 template <
int spacedim,
class Value>
290 ASSERT(this->boundary_domain_);
292 auto bc_mesh = dh_->mesh()->get_bc_mesh();
293 unsigned int n_comp = this->value_.n_rows() * this->value_.n_cols();
294 boundary_dofs_ = std::make_shared< std::vector<LongIdx> >( n_comp * bc_mesh->n_elements() );
298 for (
auto ele : bc_mesh->elements_range()) {
299 LongIdx elm_shift = n_comp * ele.idx();
300 for (
unsigned int i=0; i<n_comp; ++i, ++j) {
301 in_vec[j] = elm_shift + i;
305 value_handler0_.set_boundary_dofs_vector(boundary_dofs_);
306 value_handler1_.set_boundary_dofs_vector(boundary_dofs_);
307 value_handler2_.set_boundary_dofs_vector(boundary_dofs_);
308 value_handler3_.set_boundary_dofs_vector(boundary_dofs_);
310 data_vec_.resize(boundary_dofs_->size());
315 template <
int spacedim,
class Value>
318 switch (this->value_.n_rows() * this->value_.n_cols()) {
327 std::shared_ptr< FiniteElement<0> > fe0_ptr = std::make_shared< FE_P_disc<0> >(0);
328 std::shared_ptr< FiniteElement<1> > fe1_ptr = std::make_shared< FE_P_disc<1> >(0);
329 std::shared_ptr< FiniteElement<2> > fe2_ptr = std::make_shared< FE_P_disc<2> >(0);
330 std::shared_ptr< FiniteElement<3> > fe3_ptr = std::make_shared< FE_P_disc<3> >(0);
338 std::shared_ptr< FiniteElement<0> > fe0_ptr = std::make_shared< FE_P_disc<0> >(0);
339 std::shared_ptr< FiniteElement<1> > fe1_ptr = std::make_shared< FE_P_disc<1> >(0);
340 std::shared_ptr< FiniteElement<2> > fe2_ptr = std::make_shared< FE_P_disc<2> >(0);
341 std::shared_ptr< FiniteElement<3> > fe3_ptr = std::make_shared< FE_P_disc<3> >(0);
349 ASSERT(
false).error(
"Should not happen!\n");
353 std::shared_ptr<DiscreteSpace> ds = std::make_shared<EqualOrderDiscreteSpace>( &
const_cast<Mesh &
>(*mesh), fe0_, fe1_, fe2_, fe3_);
356 unsigned int ndofs = dh_->max_elem_dofs();
357 dof_indices_.resize(ndofs);
359 if (this->boundary_domain_) fill_boundary_dofs();
366 init_data.
ndofs = ndofs;
367 init_data.
n_comp = this->n_comp();
371 value_handler0_.initialize(init_data);
372 value_handler1_.initialize(init_data);
373 value_handler2_.initialize(init_data);
374 value_handler3_.initialize(init_data);
379 template <
int spacedim,
class Value>
383 ASSERT(field_name_ !=
"").error(
"Uninitialized FieldFE, did you call init_from_input()?\n");
384 ASSERT_PTR(dh_)(field_name_).error(
"Null target mesh pointer of finite element field, did you call set_mesh()?\n");
385 if ( reader_file_ ==
FilePath() )
return false;
387 unsigned int n_components = this->value_.n_rows() * this->value_.n_cols();
388 double time_unit_coef = time.
read_coef(in_rec_.find<
string>(
"time_unit"));
390 double read_time = (time.
end()+time_shift) / time_unit_coef;
395 unsigned int n_entities;
396 bool is_native = (header_query.
discretization == OutputTime::DiscreteSpace::NATIVE_DATA);
398 if (is_native || this->interpolation_==DataInterpolation::identic_msh || this->interpolation_==DataInterpolation::equivalent_msh) {
399 n_entities = dh_->mesh()->n_elements();
400 boundary = this->boundary_domain_;
405 auto input_data_cache =
ReaderCache::get_reader(reader_file_)->template get_element_data<double>(n_entities, n_components,
406 boundary, this->component_idx_);
408 this->unit_conversion_coefficient_, default_value_);
412 THROW( ExcUndefElementValue() << EI_Field(field_name_) );
415 if (is_native || this->interpolation_==DataInterpolation::identic_msh || this->interpolation_==DataInterpolation::equivalent_msh) {
416 this->calculate_native_values(input_data_cache);
417 }
else if (this->interpolation_==DataInterpolation::gauss_p0) {
418 this->interpolate_gauss(input_data_cache);
420 this->interpolate_intersection(input_data_cache);
429 template <
int spacedim,
class Value>
432 static const unsigned int quadrature_order = 4;
437 unsigned int quadrature_size;
439 unsigned int elem_count;
446 q_points.resize(quad.
size());
447 q_weights.resize(quad.
size());
451 if (this->boundary_domain_) mesh = dh_->mesh()->
get_bc_mesh();
452 else mesh = dh_->mesh();
454 std::fill(elem_value.begin(), elem_value.end(), 0.0);
455 switch (ele->dim()) {
458 q_points[0] = ele.node(0)->point();
462 quadrature_size = value_handler1_.compute_quadrature(q_points, q_weights, ele, quadrature_order);
465 quadrature_size = value_handler2_.compute_quadrature(q_points, q_weights, ele, quadrature_order);
468 quadrature_size = value_handler3_.compute_quadrature(q_points, q_weights, ele, quadrature_order);
471 searched_elements.clear();
472 source_mesh->get_bih_tree().find_bounding_box(ele.bounding_box(), searched_elements);
474 for (
unsigned int i=0; i<quadrature_size; ++i) {
475 std::fill(sum_val.begin(), sum_val.end(), 0.0);
480 switch (elm->
dim()) {
482 contains = arma::norm(elm.
node(0)->
point()-q_points[i], 2) < 4*std::numeric_limits<double>::epsilon();
485 contains = value_handler1_.get_mapping()->contains_point(q_points[i], elm);
488 contains = value_handler2_.get_mapping()->contains_point(q_points[i], elm);
491 contains = value_handler3_.get_mapping()->contains_point(q_points[i], elm);
494 ASSERT(
false).error(
"Invalid element dimension!");
498 unsigned int index = sum_val.size() * (*it);
499 for (
unsigned int j=0; j < sum_val.size(); j++) {
500 sum_val[j] += (*data_vec)[index+j];
506 if (elem_count > 0) {
507 for (
unsigned int j=0; j < sum_val.size(); j++) {
508 elem_value[j] += (sum_val[j] / elem_count) * q_weights[i];
513 if (this->boundary_domain_) value_handler1_.get_dof_indices( ele, dof_indices_);
518 for (
unsigned int i=0; i < elem_value.size(); i++) {
520 data_vec_[dof_indices_[i]] = elem_value[i] * this->unit_conversion_coefficient_;
526 template <
int spacedim,
class Value>
532 double total_measure, measure;
535 if (this->boundary_domain_) mesh = dh_->mesh()->
get_bc_mesh();
536 else mesh = dh_->mesh();
538 if (elm.dim() == 3) {
539 xprintf(
Err,
"Dimension of element in target mesh must be 0, 1 or 2! elm.idx() = %d\n", elm.idx());
542 double epsilon = 4* numeric_limits<double>::epsilon() * elm.measure();
545 if (elm.dim() == 0) {
546 searched_elements.clear();
547 source_mesh->get_bih_tree().find_point(elm.node(0)->point(), searched_elements);
550 searched_elements.clear();
551 source_mesh->get_bih_tree().find_bounding_box(bb, searched_elements);
567 if (ele->
dim() == 3) {
571 arma::vec::fixed<3> real_point = elm.node(0)->point();
572 arma::mat::fixed<3, 4> elm_map = mapping.
element_map(ele);
575 measure = (std::fabs(arma::sum( unit_point )-1) <= 1e-14
576 && arma::min( unit_point ) >= 0)
603 if (measure > epsilon) {
604 unsigned int index =
value.size() * (*it);
606 for (
unsigned int i=0; i <
value.size(); i++) {
607 value[i] += vec[index+i] * measure;
609 total_measure += measure;
615 if (total_measure > epsilon) {
617 if (this->boundary_domain_) value_handler1_.get_dof_indices( elm, dof_indices_ );
622 for (
unsigned int i=0; i <
value.size(); i++) {
623 (*data_vector)[ dof_indices_[i] ] =
value[i] / total_measure;
626 WarningOut().fmt(
"Processed element with idx {} is out of source mesh!\n", elm.idx());
634 template <
int spacedim,
class Value>
638 unsigned int dof_size, data_vec_i;
640 data_vec_.zero_entries();
645 if (this->boundary_domain_) mesh = dh_->mesh()->
get_bc_mesh();
646 else mesh = dh_->mesh();
648 if (this->boundary_domain_) dof_size = value_handler1_.get_dof_indices( ele, dof_indices_ );
649 else dof_size = dh_->get_loc_dof_indices( ele, dof_indices_ );
650 data_vec_i = ele.idx() * dof_indices_.size();
651 for (
unsigned int i=0; i<dof_size; ++i, ++data_vec_i) {
652 (*data_vector)[ dof_indices_[i] ] += (*data_cache)[data_vec_i];
653 ++count_vector[ dof_indices_[i] ];
668 for (
unsigned int i=0; i<data_vec_.size(); ++i) {
669 if (count_vector[i]>0) (*data_vector)[i] /= count_vector[i];
674 template <
int spacedim,
class Value>
678 double loc_values[output_data_cache.
n_comp()];
679 unsigned int i, dof_filled_size;
682 for (
auto dh_cell : dh_->own_range()) {
683 dof_filled_size = dh_->get_loc_dof_indices(dh_cell.elm(), dof_indices_);
684 for (i=0; i<dof_filled_size; ++i) loc_values[i] = (*data_vec)[ dof_indices_[i] ];
685 for ( ; i<output_data_cache.
n_comp(); ++i) loc_values[i] = numeric_limits<double>::signaling_NaN();
686 output_data_cache.
store_value( dh_cell.local_idx(), loc_values );
694 template <
int spacedim,
class Value>
696 return data_vec_.size();
701 template <
int spacedim,
class Value>