Flow123d  last_with_con_2.0.0-4-g42e6930
field.impl.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file field.impl.hh
15  * @brief
16  */
17 
18 #ifndef FIELD_IMPL_HH_
19 #define FIELD_IMPL_HH_
20 
21 #include <boost/foreach.hpp>
22 
23 #include "field.hh"
24 #include "mesh/region.hh"
26 #include "input/accessors.hh"
27 #include "io/observe.hh"
28 
29 
30 /******************************************************************************************
31  * Implementation of Field<...>
32  */
33 
34 template<int spacedim, class Value>
36 : data_(std::make_shared<SharedData>())
37 {
38  // n_comp is nonzero only for variable size vectors Vector, VectorEnum, ..
39  // this invariant is kept also by n_comp setter
40  shared_->n_comp_ = (Value::NRows_ ? 0 : 1);
41  this->add_factory( std::make_shared<FactoryBase>() );
42 
43  this->multifield_ = false;
44 }
45 
46 
47 template<int spacedim, class Value>
48 Field<spacedim,Value>::Field(const string &name, bool bc)
49 : data_(std::make_shared<SharedData>())
50 
51 {
52  // n_comp is nonzero only for variable size vectors Vector, VectorEnum, ..
53  // this invariant is kept also by n_comp setter
54  shared_->n_comp_ = (Value::NRows_ ? 0 : 1);
55  shared_->bc_=bc;
56  this->name( name );
57  this->add_factory( std::make_shared<FactoryBase>() );
58  this->multifield_ = false;
59 }
60 
61 
62 
63 template<int spacedim, class Value>
64 Field<spacedim,Value>::Field(unsigned int component_index, string input_name, string name, bool bc)
65 : data_(std::make_shared<SharedData>())
66 {
67  // n_comp is nonzero only for variable size vectors Vector, VectorEnum, ..
68  // this invariant is kept also by n_comp setter
69  shared_->n_comp_ = (Value::NRows_ ? 0 : 1);
70  this->set_component_index(component_index);
71  this->name_ = (name=="") ? input_name : name;
72  this->shared_->input_name_ = input_name;
73  shared_->bc_ = bc;
74 
75  this->multifield_ = false;
76 }
77 
78 
79 template<int spacedim, class Value>
81 : FieldCommon(other),
82  data_(other.data_),
84  factories_(other.factories_)
85 {
86  if (other.no_check_control_field_)
87  no_check_control_field_ = make_shared<ControlField>(*other.no_check_control_field_);
88 
89  this->multifield_ = false;
90 }
91 
92 
93 template<int spacedim, class Value>
95 {
96  //OLD_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());
97  OLD_ASSERT(other.shared_->mesh_, "Must call set_mesh before assign to other field.\n");
98  OLD_ASSERT( !shared_->mesh_ || (shared_->mesh_==other.shared_->mesh_),
99  "Assignment between fields with different meshes.\n");
100 
101  // check for self assignement
102  if (&other == this) return *this;
103 
104  // class members derived from FieldCommon
105  shared_ = other.shared_;
106  shared_->is_fully_initialized_ = false;
108  last_time_ = other.last_time_;
112  this->multifield_ = false;
113 
114  // class members of Field class
115  data_ = other.data_;
116  factories_ = other.factories_;
118 
119  if (other.no_check_control_field_) {
120  no_check_control_field_ = make_shared<ControlField>(*other.no_check_control_field_);
121  }
122 
123  return *this;
124 }
125 
126 
127 
128 template<int spacedim, class Value>
130  return FieldBaseType::get_input_type_instance(shared_->input_element_selection_);
131 }
132 
133 
134 
135 template<int spacedim, class Value>
137  OLD_ASSERT(false, "This method can't be used for Field");
138 
139  it::Array arr = it::Array( it::Integer() );
140  return arr;
141 }
142 
143 
144 
145 template<int spacedim, class Value>
147  const Field<spacedim, typename FieldValue<spacedim>::Enum > &control_field,
148  const vector<FieldEnum> &value_list) -> Field &
149 {
150  no_check_control_field_=std::make_shared<ControlField>(control_field);
151  shared_->no_check_values_=value_list;
152  return *this;
153 }
154 
155 template<int spacedim, class Value>
156 void Field<spacedim,Value>::set_mesh(const Mesh &in_mesh) {
157  // since we allow copy of fields before set_mesh is called
158  // we have to check that all copies set the same mesh
159  if (shared_->mesh_ && shared_->mesh_ != &in_mesh) {
160  THROW(ExcFieldMeshDifference() << EI_Field(name()) );
161  }
162 
163  shared_->mesh_ = &in_mesh;
164 
165  // initialize table if it is empty, we assume that the RegionDB is closed at this moment
166  region_fields_.resize( mesh()->region_db().size() );
167  RegionHistory init_history(history_length_limit_); // capacity
168  data_->region_history_.resize( mesh()->region_db().size(), init_history );
169 
170  if (no_check_control_field_) no_check_control_field_->set_mesh(in_mesh);
171 }
172 
173 
174 /*
175 template<int spacedim, class Value>
176 boost::shared_ptr< typename Field<spacedim,Value>::FieldBaseType >
177 Field<spacedim,Value>::operator[] (Region reg)
178 {
179  OLD_ASSERT_LESS(reg.idx(), this->region_fields_.size());
180  return this->region_fields_[reg.idx()];
181 }
182 */
183 
184 
185 template <int spacedim, class Value>
187  OLD_ASSERT(this->set_time_result_ != TimeStatus::unknown, "Unknown time status.\n");
188  OLD_ASSERT_LESS(reg.idx(), this->region_fields_.size());
189  FieldBasePtr region_field = this->region_fields_[reg.idx()];
190  return (region_field && typeid(*region_field) == typeid(FieldConstant<spacedim, Value>));
191 }
192 
193 
194 template<int spacedim, class Value>
196  const RegionSet &domain,
197  FieldBasePtr field,
198  double time)
199 {
200  OLD_ASSERT(field, "Null field pointer.\n");
201 
202  OLD_ASSERT( mesh(), "Null mesh pointer, set_mesh() has to be called before set_field().\n");
203  if (domain.size() == 0) return;
204 
205  OLD_ASSERT_EQUAL( field->n_comp() , n_comp());
206  field->set_mesh( mesh() , is_bc() );
207 
208  HistoryPoint hp = HistoryPoint(time, field);
209  for(const Region &reg: domain) {
210  RegionHistory &region_history = data_->region_history_[reg.idx()];
211  // insert hp into descending time sequence
212  OLD_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",
213  hp.first, region_history[0].first );
214  region_history.push_front(hp);
215  }
217 }
218 
219 
220 
221 template<int spacedim, class Value>
223  const RegionSet &domain,
224  const Input::AbstractRecord &a_rec,
225  double time)
226 {
227  set_field(domain, FieldBaseType::function_factory(a_rec, n_comp()), time);
228 }
229 
230 
231 
232 
233 template<int spacedim, class Value>
234 bool Field<spacedim, Value>::set_time(const TimeStep &time_step, LimitSide limit_side)
235 {
236  OLD_ASSERT( mesh() , "NULL mesh pointer of field '%s'. set_mesh must be called before.\n",name().c_str());
237 
238  // Skip setting time if the new time is equal to current time of the field
239  // and if either the field is continuous in that time or the current limit side is same as the new one.
240  if (time_step.end() == last_time_) {
241  if ( ! is_jump_time() ||
242  limit_side == last_limit_side_) {
243  last_limit_side_ = limit_side;
244  return changed();
245  }
246  }
247 
248  last_time_=time_step.end();
249  last_limit_side_ = limit_side;
250 
251  // possibly update our control field
253  no_check_control_field_->set_time(time_step, limit_side);
254  }
255 
257 
258  // read all descriptors satisfying time.ge(input_time)
259  update_history(time_step);
261 
262  //
263  is_jump_time_=false;
264  // set time_step on all regions
265  // for regions that match type of the field domain
266  for(const Region &reg: mesh()->region_db().get_region_set("ALL") ) {
267  auto rh = data_->region_history_[reg.idx()];
268 
269  // skip regions with no matching BC flag
270  // skipping regions with empty history - no_check regions
271  if (reg.is_boundary() == is_bc() && !rh.empty() ) {
272  double last_time_in_history = rh.front().first;
273  unsigned int history_size=rh.size();
274  unsigned int i_history;
275  OLD_ASSERT(time_step.ge(last_time_in_history), "Setting field time back in history not fully supported yet!");
276 
277  // set history index
278  if ( time_step.gt(last_time_in_history) ) {
279  // in smooth time_step
280  i_history=0;
281  } else {
282  // time_step .eq. input_time; i.e. jump time
283  is_jump_time_=true;
284  if (limit_side == LimitSide::right) {
285  i_history=0;
286  } else {
287  i_history=1;
288  }
289  }
290  i_history=min(i_history, history_size - 1);
291  OLD_ASSERT(i_history >= 0, "Empty field history.");
292  // possibly update field pointer
293  auto new_ptr = rh.at(i_history).second;
294  if (new_ptr != region_fields_[reg.idx()]) {
295  region_fields_[reg.idx()]=new_ptr;
297  }
298  // let FieldBase implementation set the time
299  if ( new_ptr->set_time(time_step) ) set_time_result_ = TimeStatus::changed;
300 
301  }
302  }
303 
304  return changed();
305 }
306 
307 
308 template<int spacedim, class Value>
310  ASSERT( flags().match(FieldFlag::equation_input))(other.name().c_str())(this->name().c_str())
311  .error("Can not copy to the non-input field.");
312 
313  // do not use copy if the field have its own input
315  && this->shared_->input_list_.size() != 0 ) return;
316 
317  if (typeid(other) == typeid(*this)) {
318  auto const &other_field = dynamic_cast< Field<spacedim, Value> const &>(other);
319  this->operator=(other_field);
320  }
321 }
322 
323 
324 
325 template<int spacedim, class Value>
326 void Field<spacedim, Value>::output(std::shared_ptr<OutputTime> stream)
327 {
328  // currently we cannot output boundary fields
329  if (!is_bc())
330  stream->register_data(this->output_type(), *this);
331 }
332 
333 
334 template<int spacedim, class Value>
335 void Field<spacedim, Value>::observe_output(std::shared_ptr<Observe> observe)
336 {
337  observe->compute_field_values(*this);
338 }
339 
340 
341 
342 template<int spacedim, class Value>
344 
345  FieldResult result_all = result_none;
346  for(Region &reg : region_set) {
347  auto f = region_fields_[reg.idx()];
348  if (f) {
349  FieldResult fr = f->field_result();
350  if (result_all == result_none) // first region
351  result_all = fr;
352  else if (fr != result_all)
353  result_all = result_other; // if results from individual regions are different
354  } else return result_none; // if field is undefined on any region of the region set
355  }
356 
357  if (result_all == result_constant && region_set.size() > 1)
358  return result_other; // constant result for individual regions could be non-constant on the whole region set
359 
360  return result_all;
361 
362 }
363 
364 
365 
366 template<int spacedim, class Value>
368  OLD_ASSERT( mesh(), "Null mesh pointer, set_mesh() has to be called before.\n");
369 
370  // read input up to given time
371  double input_time;
372  if (shared_->input_list_.size() != 0) {
373  while( shared_->list_idx_ < shared_->input_list_.size()
374  && time.ge( input_time = shared_->input_list_[shared_->list_idx_].val<double>("time") ) ) {
375 
376  const Input::Record & actual_list_item = shared_->input_list_[shared_->list_idx_];
377  // get domain specification
378  RegionSet domain;
379  Input::Array domain_name_array;
380  unsigned int id;
381  if (actual_list_item.opt_val("region", domain_name_array)) {
382  std::vector<string> domain_names = mesh()->region_db().get_and_check_operands(domain_name_array);
383  domain = mesh()->region_db().union_set(domain_names);
384 
385  } else if (actual_list_item.opt_val("rid", id)) {
386  Region region;
387  try {
388  region = mesh()->region_db().find_id(id);
389  } catch (RegionDB::ExcUniqueRegionId &e) {
390  e << actual_list_item.ei_address();
391  throw;
392  }
393  if (region.is_valid())
394  domain.push_back(region);
395  else
396  THROW(RegionDB::ExcUnknownRegion() << RegionDB::EI_ID(id) );
397  } else {
398  THROW(ExcMissingDomain()
399  << actual_list_item.ei_address() );
400  }
401 
402  // get field instance
403  for(auto rit = factories_.rbegin() ; rit != factories_.rend(); ++rit) {
404  FieldBasePtr field_instance = (*rit)->create_field(actual_list_item, *this);
405  if (field_instance) // skip descriptors without related keys
406  {
407  // add to history
408  OLD_ASSERT_EQUAL( field_instance->n_comp() , n_comp());
409  field_instance->set_mesh( mesh() , is_bc() );
410  for(const Region &reg: domain) {
411  data_->region_history_[reg.idx()].push_front(
412  HistoryPoint(input_time, field_instance)
413  );
414  }
415  break;
416  }
417  }
418 
419  ++shared_->list_idx_;
420  }
421  }
422 }
423 
424 template<int spacedim, class Value>
426  OLD_ASSERT(mesh(), "Null mesh pointer.");
427  if (shared_->is_fully_initialized_) return;
428 
429  // check there are no empty field pointers, collect regions to be initialized from default value
430  RegionSet regions_to_init; // empty vector
431 
432  for(const Region &reg : mesh()->region_db().get_region_set("ALL") )
433  if (reg.is_boundary() == is_bc()) { // for regions that match type of the field domain
434  RegionHistory &rh = data_->region_history_[reg.idx()];
435  if ( rh.empty() || ! rh[0].second) // empty region history
436  {
437  // test if check is turned on and control field is FieldConst
438  if (no_check_control_field_ && no_check_control_field_->is_constant(reg) ) {
439  // get constant enum value
440  auto elm = ElementAccessor<spacedim>(mesh(), reg);
441  FieldEnum value = no_check_control_field_->value(elm.centre(),elm);
442  // check that the value is in the disable list
443  if ( std::find(shared_->no_check_values_.begin(), shared_->no_check_values_.end(), value)
444  != shared_->no_check_values_.end() )
445  continue; // the field is not needed on this region
446  }
447  if (shared_->input_default_ != "") { // try to use default
448  regions_to_init.push_back( reg );
449  } else {
450  xprintf(UsrErr, "Missing value of the input field '%s' ('%s') on region ID: %d label: %s.\n",
451  input_name().c_str(), name().c_str(), reg.id(), reg.label().c_str() );
452  }
453  }
454  }
455 
456  // possibly set from default value
457  if ( regions_to_init.size() ) {
458  std::string region_list;
459  // has to deal with fact that reader can not deal with input consisting of simple values
460  string default_input=input_default();
461  auto input_type = get_input_type().make_instance().first;
462  Input::ReaderToStorage reader( default_input, *input_type, Input::FileFormat::format_JSON );
463 
464  auto a_rec = reader.get_root_interface<Input::AbstractRecord>();
465  auto field_ptr = FieldBaseType::function_factory( a_rec , n_comp() );
466  field_ptr->set_mesh( mesh(), is_bc() );
467  for(const Region &reg: regions_to_init) {
468  data_->region_history_[reg.idx()]
469  .push_front(HistoryPoint( 0.0, field_ptr) );
470  region_list+=" "+reg.label();
471  }
472  WarningOut().fmt("Using default value '{}' for part of the input field '{}' ('{}').\n"
473  "regions: {}\n",
474  input_default(), input_name(), name(), region_list);
475 
476  }
477  shared_->is_fully_initialized_ = true;
478 }
479 
480 
481 template<int spacedim, class Value>
482 void Field<spacedim,Value>::add_factory(const std::shared_ptr<FactoryBase> factory) {
483  factories_.push_back( factory );
484 }
485 
486 
487 template<int spacedim, class Value>
489  Input::AbstractRecord field_record;
490  if (rec.opt_val(field.input_name(), field_record))
491  return FieldBaseType::function_factory(field_record, field.n_comp() );
492  else
493  return FieldBasePtr();
494 }
495 
496 
497 template<int spacedim, class Value>
499  return in_rec.find<Input::AbstractRecord>(input_name);
500 }
501 
502 
503 
504 
505 template<int spacedim, class Value>
507  if (! flags().match(FieldFlag::declare_input)) return;
508 
509  // check that times forms ascending sequence
510  double time,last_time=0.0;
511 
513  it != list.end();
514  ++it) {
515  for(auto rit = factories_.rbegin() ; rit != factories_.rend(); ++rit) {
516  if ( (*rit)->is_active_field_descriptor( (*it), this->input_name() ) ) {
517  shared_->input_list_.push_back( Input::Record( *it ) );
518  time = it->val<double>("time");
519  if (time < last_time) {
520  THROW( ExcNonascendingTime()
521  << EI_Time(time)
522  << EI_Field(input_name())
523  << it->ei_address());
524  }
525  last_time = time;
526 
527  break;
528  }
529  }
530  }
531 
532 }
533 
534 
535 
536 #endif /* FIELD_IMPL_HH_ */
void check_initialized_region_fields_()
Definition: field.impl.hh:425
Iterator< ValueType > begin() const
Common abstract parent of all Field<...> classes.
Definition: field_common.hh:60
virtual bool is_active_field_descriptor(const Input::Record &in_rec, const std::string &input_name)
Definition: field.impl.hh:498
pair< double, FieldBasePtr > HistoryPoint
Pair: time, pointer to FieldBase instance.
Definition: field.hh:291
bool is_jump_time_
Accessor to input data conforming to declared Array.
Definition: accessors.hh:552
unsigned int size() const
Number of subfields that compose the multi-field.
Definition: multi_field.hh:172
MakeInstanceReturnType make_instance(std::vector< ParameterPair > vec=std::vector< ParameterPair >()) override
Implements TypeBase::make_instance.
static const Input::Type::Instance & get_input_type_instance(Input::Type::Selection value_selection=Input::Type::Selection())
RegionSet union_set(std::vector< string > set_names) const
Definition: region.cc:472
Reader for (slightly) modified input files.
FieldResult field_result(RegionSet region_set) const override
Indicates special field states.
Definition: field.impl.hh:343
std::string name_
Class template representing a field with values dependent on: point, element, and region...
Definition: field.hh:62
unsigned int component_index_
Definition: mesh.h:95
Iterator< Ret > find(const string &key) const
void update_history(const TimeStep &time)
Definition: field.impl.hh:367
Helper class that stores data of generic types.
Definition: type_generic.hh:88
void set_input_list(const Input::Array &list) override
Definition: field.impl.hh:506
void observe_output(std::shared_ptr< Observe > observe) override
Definition: field.impl.hh:335
void output(std::shared_ptr< OutputTime > stream) override
Definition: field.impl.hh:326
double last_time_
const std::string & input_default() const
bool set_time(const TimeStep &time, LimitSide limit_side) override
Definition: field.impl.hh:234
const RegionDB & region_db() const
Definition: mesh.h:152
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:347
Class for declaration of the integral input data.
Definition: type_base.hh:465
virtual FieldBasePtr create_field(Input::Record rec, const FieldCommon &field)
Definition: field.impl.hh:488
IT::Instance get_input_type() override
Definition: field.impl.hh:129
virtual void value_list(const std::vector< Point > &point_list, const ElementAccessor< spacedim > &elm, std::vector< typename Value::return_type > &value_list) const
Definition: field.hh:356
Field()
Definition: field.impl.hh:35
Class for declaration of inputs sequences.
Definition: type_base.hh:321
std::shared_ptr< SharedData > data_
Definition: field.hh:305
constexpr bool match(Mask mask) const
Definition: flag_array.hh:163
std::shared_ptr< SharedData > shared_
IteratorBase end() const
OutputTime::DiscreteSpace output_type() const
EI_Address ei_address() const
Definition: accessors.cc:170
#define OLD_ASSERT(...)
Definition: global_defs.h:131
bool opt_val(const string &key, Ret &value) const
double time() const
const std::string & name() const
bool ge(double other_time) const
unsigned int FieldEnum
Definition: field_values.hh:41
FieldFlag::Flags & flags()
Region find_id(unsigned int id, unsigned int dim) const
Definition: region.cc:180
std::vector< string > get_and_check_operands(const Input::Array &operands) const
Definition: region.cc:312
T get_root_interface() const
Returns the root accessor.
Accessor to the data with type Type::Record.
Definition: accessors.hh:277
IT::Array get_multifield_input_type() override
Definition: field.impl.hh:136
#define xprintf(...)
Definition: system.hh:87
std::shared_ptr< ControlField > no_check_control_field_
Definition: field.hh:315
#define OLD_ASSERT_LESS(a, b)
Definition: global_defs.h:134
virtual Value::return_type const & value(const Point &p, const ElementAccessor< spacedim > &elm) const
Definition: field.hh:342
static std::shared_ptr< FieldAlgorithmBase< spacedim, Value > > function_factory(const Input::AbstractRecord &rec, unsigned int n_comp=0)
LimitSide last_limit_side_
double end() const
std::vector< FieldBasePtr > region_fields_
Definition: field.hh:320
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:444
FieldResult
Definition: system.hh:59
bool is_jump_time()
std::shared_ptr< FieldBaseType > FieldBasePtr
Definition: field.hh:66
std::vector< std::shared_ptr< FactoryBase > > factories_
Definition: field.hh:322
auto disable_where(const Field< spacedim, typename FieldValue< spacedim >::Enum > &control_field, const vector< FieldEnum > &value_list) -> Field &
Definition: field.impl.hh:146
boost::circular_buffer< HistoryPoint > RegionHistory
Nearest history of one region.
Definition: field.hh:293
void set_component_index(unsigned int idx)
bool is_constant(Region reg) override
Definition: field.impl.hh:186
void add_factory(std::shared_ptr< FactoryBase > factory)
Definition: field.impl.hh:482
void set_field(const RegionSet &domain, FieldBasePtr field, double time=0.0)
Definition: field.impl.hh:195
bool gt(double other_time) const
const Mesh * mesh() const
#define WarningOut()
Macro defining &#39;warning&#39; record of log.
Definition: logger.hh:234
FieldCommon & name(const string &name)
Definition: field_common.hh:86
unsigned int n_comp() const
#define OLD_ASSERT_EQUAL(a, b)
Definition: global_defs.h:133
bool changed() const
void set_mesh(const Mesh &mesh) override
Definition: field.impl.hh:156
void set_history_changed()
bool is_valid() const
Returns false if the region has undefined/invalid value.
Definition: region.hh:77
const std::string & input_name() const
void copy_from(const FieldCommon &other) override
Definition: field.impl.hh:309
static constexpr Mask equation_input
The field is data parameter of the owning equation. (default on)
Definition: field_flag.hh:33
bool is_bc() const
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:45
Representation of one time step..
TimeStatus set_time_result_
Field & operator=(const Field &other)
Definition: field.impl.hh:94
static const unsigned int history_length_limit_
LimitSide
Definition: field_common.hh:47
static constexpr Mask declare_input
The field can be set from input. The key in input field descriptor is declared. (default on) ...
Definition: field_flag.hh:35
unsigned int idx() const
Returns a global index of the region.
Definition: region.hh:81