Flow123d
field_set.hh
Go to the documentation of this file.
1 /*
2  * field_set.hh
3  *
4  * Created on: Mar 8, 2014
5  * Author: jb
6  */
7 
8 #ifndef FIELD_SET_HH_
9 #define FIELD_SET_HH_
10 
11 
12 #include <system/exceptions.hh>
13 #include <fields/field.hh>
14 
15 
16 
17 /**
18  * TODO: implementation robust against destroying fields before the FieldSet.
19  */
20 class FieldSet {
21 public:
22  DECLARE_EXCEPTION(ExcUnknownField, << "Field set has no field with name: " << FieldCommonBase::EI_Field::qval);
23 
24  /**
25  * Add an existing Field to the list. It stores just pointer to the field.
26  * Be careful to not destroy passed Field before the FieldSet.
27  *
28  * Using operator allows elegant setting and adding of a field to the field set:
29  * @code
30  * Field<...> init_quantity; // member of a FieldSet descendant
31  *
32  * field_set +=
33  * some_field
34  * .disable_where(type, {dirichlet, neumann}); // this must come first since it is not member of FieldCommonBase
35  * .name("init_temperature")
36  * .description("Initial temperature");
37  *
38  */
39  FieldSet &operator +=(FieldCommonBase &field) {
40  FieldCommonBase *found_field = field_by_name(field.name());
41  if (found_field) {
42  ASSERT(&field==found_field, "Another field of the same name exists when adding field: %s\n", field.name().c_str());
43  } else {
44  field_list.push_back(&field);
45  if (mesh_) field.set_mesh(*mesh_);
48  }
49  return *this;
50  }
51 
52  /**
53  * Add other FieldSet to current one.
54  */
55  FieldSet &operator +=(const FieldSet &other) {
56  for(auto field_ptr : other.field_list) this->operator +=(*field_ptr);
57  return *this;
58  }
59 
60  /**
61  * Make new FieldSet as a subset of *this. The new FieldSet contains fields with names given by the @p names parameter.
62  */
63  FieldSet subset(std::vector<std::string> names) const {
64  FieldSet set;
65  for(auto name : names) set += this->get_field( name);
66  return set;
67  }
68 
69  unsigned int size() const {
70  return field_list.size();
71  }
72 
73  /**
74  * Returns input type for a field descriptor, that can contain any of the fields in the set.
75  * Typical usage is from derived class, where we add fields in the constructor and make auxiliary temporary instance
76  * to get the record odf the field descriptor. Simplest example:
77  *
78  * @code
79  * class EqData : public FieldSet {
80  * public:
81  * // fields
82  * Field<..> field_a;
83  * Field<..> field_b
84  * EqData() {
85  * add(field_a);
86  * add(field_b);
87  * }
88  * }
89  *
90  * Input::Type::Record SomEquation::input_type=
91  * Record("SomeEquation","equation's description")
92  * .declare_key("data",Input::Type::Array(EqData().make_field_descriptor_type()),"List of field descriptors.");
93  * @endcode
94  */
95  Input::Type::Record make_field_descriptor_type(const std::string &equation_name) const {
97  for(auto field : field_list) {
98  if (!field->is_just_copy()) {
99  string units = field->units();
100  string description = field->desc();
101 
102  // Adding units is not so simple.
103  // 1) It must be correct for Latex.
104  // 2) It should be consistent with rest of documentation.
105  // 3) Should be specified for all fields.
106  //if (units != "") description+= " [" +field->units() + "]";
107  rec.declare_key(field->name(), field->get_input_type(), description);
108  }
109 
110  }
111  return rec;
112  }
113 
114 
115  /**
116  * Make Selection with strings for all field names in the FieldSet.
117  */
118  Input::Type::Selection make_output_field_selection(const string &name, const string &desc = "") {
119  namespace IT=Input::Type;
120  IT::Selection sel(name, desc);
121  int i=0;
122  // add value for each field excluding boundary fields
123  for( auto field : field_list)
124  {
125  if (!field->is_bc())
126  {
127  string desc = "Output of field " + field->name(); // + " [" + field->units() + "]";
128  if (field->desc().length() > 0)
129  desc += " (" + field->desc() + ").";
130  else
131  desc += ".";
132  sel.add_value(i, field->name(), desc);
133  i++;
134  }
135  }
136 // sel.close();
137 
138  return sel;
139  }
140 
141 
142  /**
143  * Use @p FieldCommonBase::copy_from() to set field of the field set given by the first parameter @p dest_field_name.
144  * The source field is given as the second parameter @p source. The field copies share same input descriptor list
145  * and same instances of FieldBase classes but each copy can be set to different time and different limit side.
146  */
147  void set_field(const std::string &dest_field_name, FieldCommonBase &source) {
148  auto &field = get_field(dest_field_name);
149  field.copy_from(source);
150  if (mesh_) ASSERT_EQUAL(mesh_, field.mesh() );
152  }
153 
154  /**
155  * Returns pointer to the field given by name @p field_name. Throws if the field with given name is not found.
156  */
157  FieldCommonBase &get_field(const std::string &field_name) const {
158  FieldCommonBase *found_field=field_by_name(field_name);
159  if (found_field) return *found_field;
160 
161  THROW(ExcUnknownField() << FieldCommonBase::EI_Field(field_name));
162  return *field_list[0]; // formal to prevent compiler warning
163  }
164 
165 
166  /**
167  * Collective interface to @p FieldCommonBase::set_mesh().
168  */
169  void set_mesh(const Mesh &mesh) {
170  mesh_ = &mesh;
171  for(auto field : field_list) field->set_mesh(mesh);
172  }
173 
174  /**
175  * Collective interface to @p FieldCommonBase::set_mesh().
176  */
177  void set_input_list(Input::Array input_list) {
178  input_list_ = input_list;
179  for(auto field : field_list) field->set_input_list(input_list);
180  }
181 
182  /**
183  * Collective interface to @p FieldCommonBase::set_mesh().
184  */
186  side_ = side;
187  for(auto field : field_list) field->set_limit_side(side);
188  }
189  /**
190  * Collective interface to @p FieldCommonBase::mar_input_times().
191  */
193  for(auto field : field_list) field->mark_input_times(mark_type);
194  }
195  /**
196  * Collective interface to @p FieldCommonBase::set_mesh().
197  */
198  bool changed() const {
199  bool changed_all=false;
200  for(auto field : field_list) changed_all = changed_all || field->changed();
201  return changed_all;
202  }
203 
204  /**
205  * Collective interface to @p FieldCommonBase::set_mesh().
206  */
207  bool is_constant(Region reg) const {
208  bool const_all=true;
209  for(auto field : field_list) const_all = const_all && field->is_constant(reg);
210  return const_all;
211  }
212 
213  /**
214  * Collective interface to @p FieldCommonBase::set_mesh().
215  */
216  void set_time(const TimeGovernor &time) {
217  for(auto field : field_list) field->set_time(time);
218  }
219 
220  /**
221  * Collective interface to @p FieldCommonBase::output_type().
222  * @param rt Discrete function space (element, node or corner data).
223  */
225  for (auto field : field_list) field->output_type(rt);
226  }
227 
228  /**
229  * Collective interface to @p FieldCommonBase::output().
230  */
231  void output(OutputTime *stream) {
232  for(auto field : field_list) field->output(stream);
233  }
234 
235 
236  /**
237  * Adds given field into list of fields for group operations on fields.
238  * Parameters are: @p field pointer, @p name of the key in the input, @p desc - description of the key, and optional parameter
239  * @p d_val with default value. This method is rather called through the macro ADD_FIELD
240  */
241  FieldCommonBase &add_field( FieldCommonBase *field, const string &name, const string &desc, const string & d_val="") {
242  *this += field->name(name).desc(desc).input_default(d_val);
243  return *field;
244  }
245 
246 protected:
247  /**
248  * Return pointer to the field of given name. REturn nullptr if not found.
249  */
250  FieldCommonBase *field_by_name(const std::string &field_name) const {
251  for(auto field : field_list)
252  if (field->name() ==field_name) return field;
253  return nullptr;
254  }
255 
256 
257  /// List of all fields.
259 
260  /// value set by last set_mesh(); set the same to added fields
261  const Mesh *mesh_ = nullptr;
262 
263  /// value set by last set_input_list(); set the same to added fields
265 
266  /// value set by last set_time_limit(); set the same to added fields
268  };
269 
270 
271 /**
272  * (OBSOLETE)
273  * Macro to simplify call of FieldSet::add_field method. Two forms are supported:
274  *
275  *
276  *
277  * ADD_FIELD(some_field, description);
278  * ADD_FIELD(some_field, description, Default);
279  *
280  * The first form adds name "some_field" to the field member some_field, also adds description of the field. No default
281  * value is specified, so the user must initialize the field on all regions (This is checked in the Field<..>::set_time method)
282  *
283  * The second form adds also default value to the field, that is Default(".."), or Default::read_time(), other default value specifications are
284  * meaningless. The automatic conversion to FieldConst is used, e.g. Default::("0.0") is automatically converted to
285  * { TYPE="FieldConst", value=[ 0.0 ] } for a vector valued field, so you get zero vector on output on regions with default value.
286  */
287 
288 #define ADD_FIELD(name, ...) this->add_field(&name, string(#name), __VA_ARGS__)
289 
290 
291 #endif /* FIELD_SET_HH_ */