Flow123d  jenkins-Flow123d-windows32-release-multijob-51
field.impl.hh
Go to the documentation of this file.
1 /*
2  * field.impl.hh
3  *
4  * Created on: Feb 13, 2014
5  * Author: jb
6  */
7 
8 #ifndef FIELD_IMPL_HH_
9 #define FIELD_IMPL_HH_
10 
11 #include <boost/foreach.hpp>
12 
13 #include "field.hh"
14 #include "mesh/region.hh"
15 #include "input/json_to_storage.hh"
16 
17 
18 /******************************************************************************************
19  * Implementation of Field<...>
20  */
21 
22 template<int spacedim, class Value>
24 : read_field_descriptor_hook( &read_field_descriptor ),
25  data_(std::make_shared<SharedData>())
26 
27 {
28  // n_comp is nonzero only for variable size vectors Vector, VectorEnum, ..
29  // this invariant is kept also by n_comp setter
30  shared_->n_comp_ = (Value::NRows_ ? 0 : 1);
31 }
32 
33 
34 template<int spacedim, class Value>
35 Field<spacedim,Value>::Field(const string &name, bool bc)
36 : read_field_descriptor_hook( &read_field_descriptor ),
37  data_(std::make_shared<SharedData>())
38 
39 {
40  // n_comp is nonzero only for variable size vectors Vector, VectorEnum, ..
41  // this invariant is kept also by n_comp setter
42  shared_->n_comp_ = (Value::NRows_ ? 0 : 1);
43  shared_->bc_=bc;
44  this->name( name );
45 }
46 
47 
48 
49 template<int spacedim, class Value>
51 : FieldCommon(other),
52  read_field_descriptor_hook( other.read_field_descriptor_hook ),
53  data_(other.data_)
54 {
55  if (other.no_check_control_field_)
56  no_check_control_field_ = make_shared<ControlField>(*other.no_check_control_field_);
57 
58  // initialize region_fields_ vector
59  // shared_is already same as other.shared_
60  if (shared_->mesh_) this->set_mesh( *(shared_->mesh_) );
61 
62 }
63 
64 
65 template<int spacedim, class Value>
67 {
68  ASSERT( flags().match( FieldFlag::input_copy ) , "Try to assign to non-copy field '%s' from the field '%s'.", this->name().c_str(), other.name().c_str());
69  ASSERT(other.shared_->mesh_, "Must call set_mesh before assign to other field.\n");
70  ASSERT( !shared_->mesh_ || (shared_->mesh_==other.shared_->mesh_),
71  "Assignment between fields with different meshes.\n");
72 
73  // check for self assignement
74  if (&other == this) return *this;
75 
76  shared_ = other.shared_;
77  shared_->is_fully_initialized_ = false;
78  set_time_result_ = TimeStatus::unknown;
79 
80  read_field_descriptor_hook = other.read_field_descriptor_hook;
81  data_ = other.data_;
82 
83  if (other.no_check_control_field_) {
84  no_check_control_field_ = make_shared<ControlField>(*other.no_check_control_field_);
85  }
86 
87  // initialize region_fields_ vector
88  // shared_is already same as other.shared_
89  this->set_mesh( *(shared_->mesh_) );
90 
91 
92  return *this;
93 }
94 
95 
96 
97 template<int spacedim, class Value>
99  /*
100  * List of AbstratRecord types created by make_input_tree() in get_input_type() implementation.
101  * We have to return reference, which may be reference to not yet initialized static object.
102  *
103  * TODO: Have method to get persistent copy of an Input Type (which exists nevertheless)
104  */
105  static vector<it::AbstractRecord> ar_list;
106 
107  if (is_enum_valued) {
108  ar_list.push_back(make_input_tree());
109  return ar_list.back();
110  } else {
111  return FieldBaseType::input_type;
112  }
113 }
114 
115 
116 
117 /// ---------- Helper function template for make_input_tree method
118 template <class FieldBaseType>
120 {
121  ASSERT( sel != nullptr,
122  "NULL pointer to selection in Field::get_input_type(), while Value==FieldEnum.\n");
123  return FieldBaseType::get_input_type(sel);
124 }
125 
126 
127 template <class FieldBaseType>
129 {
130  return FieldBaseType::get_input_type(nullptr);
131 }
132 /// ---------- end helper function template
133 
134 
135 
136 
137 template<int spacedim, class Value>
139  ASSERT(is_enum_valued,
140  "Can not use make_input_tree() for non-enum valued fields, use get_inout_type() instead.\n" );
141  return get_input_type_resolution<FieldBaseType>(
142  shared_->input_element_selection_ ,
143  boost::is_same<typename Value::element_type, FieldEnum>());
144 }
145 
146 
147 
148 template<int spacedim, class Value>
150  const Field<spacedim, typename FieldValue<spacedim>::Enum > &control_field,
151  const vector<FieldEnum> &value_list) -> Field &
152 {
153  no_check_control_field_=std::make_shared<ControlField>(control_field);
154  shared_->no_check_values_=value_list;
155  return *this;
156 }
157 
158 template<int spacedim, class Value>
159 void Field<spacedim,Value>::set_mesh(const Mesh &in_mesh) {
160  // since we allow copy of fields before set_mesh is called
161  // we have to check that all copies set the same mesh
162  if (shared_->mesh_ && shared_->mesh_ != &in_mesh) {
163  THROW(ExcFieldMeshDifference() << EI_Field(name()) );
164  }
165 
166  shared_->mesh_ = &in_mesh;
167 
168  // initialize table if it is empty, we assume that the RegionDB is closed at this moment
169  region_fields_.resize( mesh()->region_db().size() );
170  RegionHistory init_history(history_length_limit_); // capacity
171  data_->region_history_.resize( mesh()->region_db().size(), init_history );
172 
173  if (no_check_control_field_) no_check_control_field_->set_mesh(in_mesh);
174 }
175 
176 
177 /*
178 template<int spacedim, class Value>
179 boost::shared_ptr< typename Field<spacedim,Value>::FieldBaseType >
180 Field<spacedim,Value>::operator[] (Region reg)
181 {
182  ASSERT_LESS(reg.idx(), this->region_fields_.size());
183  return this->region_fields_[reg.idx()];
184 }
185 */
186 
187 
188 template <int spacedim, class Value>
190  ASSERT_LESS(reg.idx(), this->region_fields_.size());
191  FieldBasePtr region_field = this->region_fields_[reg.idx()];
192  return (region_field && typeid(*region_field) == typeid(FieldConstant<spacedim, Value>));
193 }
194 
195 
196 template<int spacedim, class Value>
198  const RegionSet &domain,
199  FieldBasePtr field,
200  double time)
201 {
202  ASSERT(field, "Null field pointer.\n");
203 
204  ASSERT( mesh(), "Null mesh pointer, set_mesh() has to be called before set_field().\n");
205  if (domain.size() == 0) return;
206 
207  ASSERT_EQUAL( field->n_comp() , n_comp());
208  field->set_mesh( mesh() , is_bc() );
209 
210  HistoryPoint hp = HistoryPoint(time, field);
211  for(const Region &reg: domain) {
212  RegionHistory &region_history = data_->region_history_[reg.idx()];
213  // insert hp into descending time sequence
214  ASSERT( region_history.size() == 0 || region_history[0].first < hp.first, "Can not insert smaller time %g then last time %g in field's history.\n",
215  hp.first, region_history[0].first );
216  region_history.push_front(hp);
217  }
218  set_history_changed();
219 }
220 
221 
222 
223 template<int spacedim, class Value>
225  const RegionSet &domain,
226  const Input::AbstractRecord &a_rec,
227  double time)
228 {
229  set_field(domain, FieldBaseType::function_factory(a_rec, n_comp()), time);
230 }
231 
232 
233 
234 template<int spacedim, class Value>
236 {
237  Input::AbstractRecord field_record;
238  if (rec.opt_val(field.input_name(), field_record))
239  return FieldBaseType::function_factory(field_record, field.n_comp() );
240  else
241  return FieldBasePtr();
242 }
243 
244 
245 
246 
247 template<int spacedim, class Value>
249 {
250  ASSERT( mesh() , "NULL mesh pointer of field '%s'. set_mesh must be called before.\n",name().c_str());
251  ASSERT( limit_side_ != LimitSide::unknown, "Must set limit side on field '%s' before calling set_time.\n",name().c_str());
252 
253  // We perform set_time only once for every time.
254  if (time.t() == last_time_) return changed();
255  last_time_=time.t();
256 
257  // possibly update our control field
258  if (no_check_control_field_) {
259  no_check_control_field_->set_limit_side(limit_side_);
260  no_check_control_field_->set_time(time);
261  }
262 
263  set_time_result_ = TimeStatus::constant;
264 
265  // read all descriptors satisfying time.ge(input_time)
266  update_history(time);
267  check_initialized_region_fields_();
268 
269  // set time on all regions
270  // for regions that match type of the field domain
271  for(const Region &reg: mesh()->region_db().get_region_set("ALL") ) {
272  auto rh = data_->region_history_[reg.idx()];
273 
274  // skip regions with no matching BC flag
275  // skipping regions with empty history - no_check regions
276  if (reg.is_boundary() == is_bc() && !rh.empty() ) {
277  double last_time_in_history = rh.front().first;
278  unsigned int history_size=rh.size();
279  unsigned int i_history;
280  // set history index
281  if ( time.gt(last_time_in_history) ) {
282  // in smooth time
283  i_history=0;
284  } else {
285  // time .eq. input_time; i.e. jump time
286  if (limit_side_ == LimitSide::right) {
287  i_history=0;
288  } else {
289  i_history=1;
290  }
291  }
292  i_history=min(i_history, history_size - 1);
293  ASSERT(i_history >= 0, "Empty field history.");
294  // possibly update field pointer
295  auto new_ptr = rh.at(i_history).second;
296  if (new_ptr != region_fields_[reg.idx()]) {
297  region_fields_[reg.idx()]=new_ptr;
298  set_time_result_ = TimeStatus::changed;
299  }
300  // let FieldBase implementation set the time
301  if ( new_ptr->set_time(time.t()) ) set_time_result_ = TimeStatus::changed;
302 
303  }
304  }
305 
306  return changed();
307 }
308 
309 
310 template<int spacedim, class Value>
312  ASSERT( flags().match(FieldFlag::input_copy), "Try to call copy from the field '%s' to the non-copy field '%s'.",
313  other.name().c_str(), this->name().c_str());
314  if (typeid(other) == typeid(*this)) {
315  auto const &other_field = dynamic_cast< Field<spacedim, Value> const &>(other);
316  this->operator=(other_field);
317  }
318 }
319 
320 
321 
322 template<int spacedim, class Value>
324 {
325  // currently we cannot output boundary fields
326  if (!is_bc())
327  stream->register_data(this->output_type(), *this);
328 }
329 
330 
331 
332 template<int spacedim, class Value>
334  auto f = region_fields_[elm.region().idx()];
335  if (f) return f->field_result();
336  else return result_none;
337 }
338 
339 
340 
341 template<int spacedim, class Value>
343  ASSERT( mesh(), "Null mesh pointer, set_mesh() has to be called before.\n");
344 
345  // read input up to given time
346  double input_time;
347  if (shared_->input_list_.size() != 0) {
348  while( shared_->list_it_ != shared_->input_list_.end()
349  && time.ge( input_time = shared_->list_it_->val<double>("time") ) ) {
350 
351  // get domain specification
352  RegionSet domain;
353  std::string domain_name;
354  unsigned int id;
355  if (shared_->list_it_->opt_val("r_set", domain_name)) {
356  domain = mesh()->region_db().get_region_set(domain_name);
357 
358  } else if (shared_->list_it_->opt_val("region", domain_name)) {
359  // try find region by label
360  Region region = mesh()->region_db().find_label(domain_name);
361  if(region.is_valid())
362  domain.push_back(region);
363  else
364  xprintf(Warn, "Unknown region with label: '%s'\n", domain_name.c_str());
365 
366  } else if (shared_->list_it_->opt_val("rid", id)) {
367  try {
368  Region region = mesh()->region_db().find_id(id);
369  if(region.is_valid())
370  domain.push_back(region);
371  else
372  xprintf(Warn, "Unknown region with id: '%d'\n", id);
373  } catch (RegionDB::ExcUniqueRegionId &e) {
374  e << shared_->input_list_.ei_address();
375  throw;
376  }
377  } else {
378  THROW(ExcMissingDomain()
379  << shared_->list_it_->ei_address() );
380  }
381 
382  if (domain.size() == 0) {
383  ++shared_->list_it_;
384  continue;
385  }
386  // get field instance
387  FieldBasePtr field_instance = read_field_descriptor_hook(*(shared_->list_it_), *this);
388  if (field_instance) // skip descriptors without related keys
389  {
390  // add to history
391  ASSERT_EQUAL( field_instance->n_comp() , n_comp());
392  field_instance->set_mesh( mesh() , is_bc() );
393  for(const Region &reg: domain) {
394  data_->region_history_[reg.idx()].push_front(
395  HistoryPoint(input_time, field_instance)
396  );
397  }
398  }
399  ++shared_->list_it_;
400  }
401  }
402 }
403 
404 template<int spacedim, class Value>
406  ASSERT(mesh(), "Null mesh pointer.");
407  if (shared_->is_fully_initialized_) return;
408 
409  // check there are no empty field pointers, collect regions to be initialized from default value
410  RegionSet regions_to_init; // empty vector
411 
412  for(const Region &reg : mesh()->region_db().get_region_set("ALL") )
413  if (reg.is_boundary() == is_bc()) { // for regions that match type of the field domain
414  RegionHistory &rh = data_->region_history_[reg.idx()];
415  if ( rh.empty() || ! rh[0].second) // empty region history
416  {
417  // test if check is turned on and control field is FieldConst
418  if (no_check_control_field_ && no_check_control_field_->is_constant(reg) ) {
419  // get constant enum value
420  auto elm = ElementAccessor<spacedim>(mesh(), reg);
421  FieldEnum value = no_check_control_field_->value(elm.centre(),elm);
422  // check that the value is in the disable list
423  if ( std::find(shared_->no_check_values_.begin(), shared_->no_check_values_.end(), value)
424  != shared_->no_check_values_.end() )
425  continue; // the field is not needed on this region
426  }
427  if (shared_->input_default_ != "") { // try to use default
428  regions_to_init.push_back( reg );
429  } else {
430  xprintf(UsrErr, "Missing value of the input field '%s' ('%s') on region ID: %d label: %s.\n",
431  input_name().c_str(), name().c_str(), reg.id(), reg.label().c_str() );
432  }
433  }
434  }
435 
436  // possibly set from default value
437  if ( regions_to_init.size() ) {
438  xprintf(Warn, "Using default value '%s' for part of the input field '%s' ('%s').\n",
439  input_default().c_str(), input_name().c_str(), name().c_str());
440 
441  // has to deal with fact that reader can not deal with input consisting of simple values
442  string default_input=input_default();
443  auto input_type = get_input_type();
444  Input::JSONToStorage reader( default_input, input_type );
445 
446  auto a_rec = reader.get_root_interface<Input::AbstractRecord>();
447  auto field_ptr = FieldBaseType::function_factory( a_rec , n_comp() );
448  field_ptr->set_mesh( mesh(), is_bc() );
449  for(const Region &reg: regions_to_init) {
450  data_->region_history_[reg.idx()]
451  .push_front(HistoryPoint( 0.0, field_ptr) );
452  }
453  }
454  shared_->is_fully_initialized_;
455 }
456 
457 
458 
459 
460 
461 /******************************************************************************************
462  * Implementation of MultiField<...>
463  */
464 
465 template<int spacedim, class Value>
467 : FieldCommon()
468 {}
469 
470 
471 
472 template<int spacedim, class Value>
474  sub_fields_.resize( names.size() );
475  sub_names_ = names;
476  for(unsigned int i_comp=0; i_comp < size(); i_comp++)
477  {
478  sub_fields_[i_comp].units( units() );
479 
480  if (sub_names_[i_comp].length() == 0)
481  sub_fields_[i_comp].name( name() );
482  else
483  sub_fields_[i_comp].name( sub_names_[i_comp] + "_" + name());
484  }
485 }
486 
487 
488 
489 #pragma GCC diagnostic push
490 #pragma GCC diagnostic ignored "-Wreturn-type"
491 template<int spacedim, class Value>
493 }
494 #pragma GCC diagnostic pop
495 
496 
497 template<int spacedim, class Value>
499 {
500  for ( SubFieldType &field : sub_fields_)
501  field.set_limit_side(side);
502 }
503 
504 
505 template<int spacedim, class Value>
507  const TimeGovernor &time)
508 {
509  bool any=false;
510  for( SubFieldType &field : sub_fields_) {
511  if (field.set_time(time))
512  any = true;
513  }
514  return any;
515 }
516 
517 
518 
519 template<int spacedim, class Value>
521  shared_->mesh_ = &mesh;
522  for(unsigned int i_comp=0; i_comp < size(); i_comp++)
523  sub_fields_[i_comp].set_mesh(mesh);
524 }
525 
526 
527 template<int spacedim, class Value>
529  if (typeid(other) == typeid(*this)) {
530  auto const &other_field = dynamic_cast< MultiField<spacedim, Value> const &>(other);
531  this->operator=(other_field);
532  } else if (typeid(other) == typeid(SubFieldType)) {
533  auto const &other_field = dynamic_cast< SubFieldType const &>(other);
534  sub_fields_.resize(1);
535  sub_fields_[0] = other_field;
536  }
537 }
538 
539 
540 
541 template<int spacedim, class Value>
543 {
544  // currently we cannot output boundary fields
545  if (!is_bc())
546  stream->register_data(this->output_type(), *this);
547 }
548 
549 
550 
551 
552 
553 template<int spacedim, class Value>
555  bool const_all=false;
556  for(auto field : sub_fields_) const_all = const_all || field.is_constant(reg);
557  return const_all;
558 }
559 
560 
561 
562 
563 
564 #endif /* FIELD_IMPL_HH_ */
void check_initialized_region_fields_()
Definition: field.impl.hh:405
Common abstract parent of all Field<...> classes.
Definition: field_common.hh:45
pair< double, FieldBasePtr > HistoryPoint
Pair: time, pointer to FieldBase instance.
Definition: field.hh:234
void init(const vector< string > &names)
Definition: field.impl.hh:473
void output(OutputTime *stream) override
Definition: field.impl.hh:323
void set_limit_side(LimitSide side) override
Definition: field.impl.hh:498
void update_history(const TimeGovernor &time)
Definition: field.impl.hh:342
FieldBasePtr(* read_field_descriptor_hook)(Input::Record rec, const FieldCommon &field)
Definition: field.hh:71
IT::AbstractRecord make_input_tree()
-------— end helper function template
Definition: field.impl.hh:138
void copy_from(const FieldCommon &other) override
Definition: field.impl.hh:528
Class template representing a field with values dependent on: point, element, and region...
Definition: field.hh:48
void register_data(const DiscreteSpace type, MultiField< spacedim, Value > &multi_field)
Generic method for registering output data stored in MultiField.
Definition: output.h:243
bool ge(double other_time) const
Definition: mesh.h:108
double t() const
Basic time management functionality for unsteady (and steady) solvers (class Equation).
Field()
Definition: field.impl.hh:23
std::shared_ptr< SharedData > data_
Definition: field.hh:248
FieldResult field_result(ElementAccessor< spacedim > &elm) const
Definition: field.impl.hh:333
IT::AbstractRecord & get_input_type() override
Definition: field.impl.hh:98
std::shared_ptr< SharedData > shared_
#define ASSERT(...)
Definition: global_defs.h:121
Definition: system.hh:72
const std::string & name() const
unsigned int FieldEnum
Definition: field_values.hh:65
static constexpr Mask input_copy
A field that is input of its equation and cna not read from input, thus muzt be set by copy...
Definition: field_flag.hh:29
#define ASSERT_EQUAL(a, b)
Definition: global_defs.h:136
Accessor to the data with type Type::Record.
Definition: accessors.hh:308
#define xprintf(...)
Definition: system.hh:100
#define ASSERT_LESS(a, b)
Definition: global_defs.h:164
std::shared_ptr< ControlField > no_check_control_field_
Definition: field.hh:258
Class for declaration of polymorphic Record.
Definition: type_record.hh:463
IT::AbstractRecord & get_input_type() override
Definition: field.impl.hh:492
The class for outputing data during time.
Definition: output_time.hh:37
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:423
Region region() const
Definition: accessors.hh:88
IT::AbstractRecord get_input_type_resolution(const Input::Type::Selection *sel, const boost::true_type &)
-------— Helper function template for make_input_tree method
Definition: field.impl.hh:119
FieldResult
Result type have sense only for larger Value types like vectors and tensors.
Definition: system.hh:72
std::shared_ptr< FieldBaseType > FieldBasePtr
Definition: field.hh:52
bool is_constant(Region reg) override
Definition: field.impl.hh:554
auto disable_where(const Field< spacedim, typename FieldValue< spacedim >::Enum > &control_field, const vector< FieldEnum > &value_list) -> Field &
Definition: field.impl.hh:149
boost::circular_buffer< HistoryPoint > RegionHistory
Nearest history of one region.
Definition: field.hh:236
bool is_constant(Region reg) override
Definition: field.impl.hh:189
void set_field(const RegionSet &domain, FieldBasePtr field, double time=0.0)
Definition: field.impl.hh:197
bool set_time(const TimeGovernor &time) override
Definition: field.impl.hh:248
bool set_time(const TimeGovernor &time) override
Definition: field.impl.hh:506
FieldCommon & name(const string &name)
Definition: field_common.hh:71
void set_mesh(const Mesh &mesh) override
Definition: field.impl.hh:159
static FieldBasePtr read_field_descriptor(Input::Record rec, const FieldCommon &field)
Definition: field.impl.hh:235
void output(OutputTime *stream) override
Definition: field.impl.hh:542
Class for representation of a vector of fields of the same physical quantity.
Definition: field.hh:309
bool is_valid() const
Returns false if the region has undefined/invalid value.
Definition: region.hh:67
void copy_from(const FieldCommon &other) override
Definition: field.impl.hh:311
bool gt(double other_time) const
Reader for (slightly) modified JSON files.
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:34
void set_mesh(const Mesh &mesh) override
Definition: field.impl.hh:520
Template for classes storing finite set of named values.
Field & operator=(const Field &other)
Definition: field.impl.hh:66
LimitSide
Definition: field_common.hh:31
unsigned int idx() const
Returns a global index of the region.
Definition: region.hh:71