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