Flow123d  master-f44eb46
region.cc
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 region.cc
15  * @brief
16  */
17 
18 #include <string>
19 #include <sstream>
20 
21 #include "mesh/region.hh"
22 #include "system/exceptions.hh"
23 #include "system/system.hh"
24 
25 #include "input/input_type.hh"
26 #include "input/type_base.hh"
27 #include "input/accessors.hh"
28 
29 using namespace std;
30 
31 
32 std::string Region::label() const
33  { return db_->get_label(idx_); }
34 
35 
36 
37 unsigned int Region::id() const
38  { return db_->get_id(idx_); }
39 
40 
41 
42 unsigned int Region::dim() const
43  { return db_->get_dim(idx_); }
44 
45 bool Region::is_in_region_set(const RegionSet &set) const
46 {
47  for(const Region &reg : set)
48  if (reg.idx_ == this->idx_) return true;
49  return false;
50 }
51 
52 /**************************************************************************************************
53  * Implementation of RegionDB
54  */
55 
56 
57 
58 const unsigned int RegionDB::max_n_regions = 10000;
59 const unsigned int RegionDB::undefined_dim = 10;
60 
61 
62 /// Default constructor
64 : closed_(false), n_boundary_(0), n_bulk_(0), max_id_(0) {
65 
66  // adding implicit boundary and bulk regions
67  // How to deal with dimension, clean solution is to have implicit region for every
68  // dimension, or we can allow regions of mixed dimension
69  //implicit_bulk_ = add_region(Region::undefined-1, "IMPLICIT BULK", 0, Region::bulk);
70  //implicit_boundary_ = ;
71 
72 }
73 
74 
77  if ( it_id!=region_table_.get<DimId>().end() ) {
78  return Region(it_id->index, *this);
79  }
80 
81  return insert_region(Region::undefined-2, ".IMPLICIT_BOUNDARY", undefined_dim, Region::boundary, "");
82 }
83 
84 
85 Region RegionDB::add_region( unsigned int id, const std::string &label, unsigned int dim, const std::string &address) {
86  bool boundary = is_boundary(label);
87  DimIDIter it_id = region_table_.get<DimId>().find(DimID(dim,id));
88  if (it_id != region_table_.get<DimId>().end() ) {
89  // Find existing region
90  return find_by_dimid(it_id, id, label, boundary);
91  }
92 
93  DimIDIter it_undef_dim = region_table_.get<DimId>().find(DimID(undefined_dim,id));
94  if (it_undef_dim != region_table_.get<DimId>().end() ) {
95  // Region with same ID and undefined_dim exists, replace undefined_dim
96  return replace_region_dim(it_undef_dim, dim, boundary);
97  }
98 
99  LabelIter it_label = region_table_.get<Label>().find(label);
100  if (it_label != region_table_.get<Label>().end() ) {
101  // ID is free, not label
102  THROW(ExcNonuniqueLabel() << EI_Label(label) << EI_ID(id) << EI_IDOfOtherLabel(it_label->get_id()) );
103  }
104 
105  return insert_region(id, label, dim, boundary, address);
106 }
107 
108 
109 Region RegionDB::rename_region( Region reg, const std::string &new_label ) {
110  ASSERT(reg.is_valid())(new_label).error("Non-existing region can't be renamed.\n");
111 
112  // test if region with new_label exists
113  LabelIter it_label = region_table_.get<Label>().find(new_label);
114  if (it_label != region_table_.get<Label>().end() ) {
115  if ( reg.id() == it_label->index ) {
116  return reg;
117  } else {
118  // region with same label and other ID exists
119  THROW(ExcNonuniqueLabel() << EI_Label(new_label) << EI_ID(reg.id()) << EI_IDOfOtherLabel(it_label->get_id()) );
120  }
121  }
122 
123  // replace region label
124  unsigned int index = reg.idx();
125  RegionSetTable::iterator it = sets_.find(reg.label()); // rename set
126  std::swap(sets_[new_label], it->second);
127  sets_.erase(it);
128  bool old_boundary_flag = reg.is_boundary(); // check old x new boundary flag - take account in adding to sets
129 
130  RegionItem item(index, reg.id(), new_label, reg.dim(), this->get_region_address(index));
131  region_table_.replace(
132  region_table_.get<Index>().find(index),
133  item);
134 
135  if (old_boundary_flag != reg.is_boundary()) { // move region between BULK and .BOUNDARY sets
136  WarningOut().fmt("Change boundary flag of region with id {} and label {}.\n", reg.id(), new_label);
137  if (old_boundary_flag) {
138  erase_from_set(".BOUNDARY", reg );
139  add_to_set("BULK", reg );
140  } else {
141  erase_from_set("BULK", reg );
142  add_to_set(".BOUNDARY", reg );
143  }
144  }
145 
146  return Region(index, *this);
147 }
148 
149 
150 Region RegionDB::get_region(unsigned int id, unsigned int dim) {
151  DimIDIter it_id = region_table_.get<DimId>().find(DimID(dim,id));
152  if ( it_id!=region_table_.get<DimId>().end() ) {
153  // Region found.
154  return Region(it_id->index, *this);
155  }
156 
157  DimIDIter it_undef_dim = region_table_.get<DimId>().find(DimID(undefined_dim,id));
158  if (it_undef_dim == region_table_.get<DimId>().end() ) {
159  // Region doesn't exist.
160  return Region();
161  } else {
162  // Region with same ID and undefined_dim exists, replace undefined_dim
163  bool boundary = is_boundary(it_undef_dim->label);
164  return replace_region_dim(it_undef_dim, dim, boundary);
165  }
166 }
167 
168 
169 Region RegionDB::find_label(const std::string &label) const
170 {
171  LabelIter it_label = region_table_.get<Label>().find(label);
172  if (it_label==region_table_.get<Label>().end() ) return Region();
173  return Region(it_label->index, *this);
174 }
175 
176 
177 
178 
179 
180 Region RegionDB::find_id(unsigned int id, unsigned int dim) const
181 {
182  DimIDIter it_id = region_table_.get<DimId>().find(DimID(dim, id));
183  if ( it_id==region_table_.get<DimId>().end() ) return Region();
184  return Region(it_id->index, *this);
185 }
186 
187 
188 
189 
190 Region RegionDB::find_id(unsigned int id) const
191 {
192  if (region_table_.get<OnlyID>().count(id) > 1) {
193  THROW( ExcUniqueRegionId() << EI_ID( id ) );
194  }
195  OnlyIDIter it_id = region_table_.get<OnlyID>().find(id);
196  if ( it_id==region_table_.get<OnlyID>().end() ) return Region();
197  return Region(it_id->index, *this);
198 }
199 
200 
201 
202 
203 const std::string & RegionDB::get_label(unsigned int idx) const {
204  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
205  ASSERT( it!= region_table_.get<Index>().end() )(idx).error("No region with given idx\n");
206  return it->label;
207 }
208 
209 
210 
211 unsigned int RegionDB::get_id(unsigned int idx) const {
212  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
213  ASSERT( it!= region_table_.get<Index>().end() )(idx).error("No region with given idx\n");
214  return it->get_id();
215 }
216 
217 
218 
219 unsigned int RegionDB::get_dim(unsigned int idx) const {
220  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
221  ASSERT( it!= region_table_.get<Index>().end() )(idx).error("No region with given idx\n");
222  return it->dim();
223 }
224 
225 
226 
227 const std::string & RegionDB::get_region_address(unsigned int idx) const {
228  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
229  ASSERT( it!= region_table_.get<Index>().end() )(idx).error("No region with given idx\n");
230  return it->address;
231 }
232 
233 
234 
235 void RegionDB::mark_used_region(unsigned int idx) {
236  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
237  ASSERT( it!= region_table_.get<Index>().end() )(idx).error("No region with given idx\n");
238  if ( !it->used ) {
239  unsigned int index = it->index;
240  RegionItem item(index, it->get_id(), it->label, it->dim(), it->address, true);
241  region_table_.replace(
242  region_table_.get<Index>().find(index),
243  item);
244  }
245 }
246 
247 
248 
250  closed_=true;
251 }
252 
253 
254 unsigned int RegionDB::size() const {
255  ASSERT(closed_).error("RegionDB not closed yet.\n");
256  return 2* max(n_boundary_, n_bulk_);
257 }
258 
259 
260 
261 unsigned int RegionDB::boundary_size() const {
262  ASSERT(closed_).error("RegionDB not closed yet.\n");
263  return n_boundary_;
264 }
265 
266 
267 
268 unsigned int RegionDB::bulk_size() const {
269  ASSERT(closed_).error("RegionDB not closed yet.\n");
270  return n_bulk_;
271 }
272 
273 
274 
275 
276 void RegionDB::add_to_set( const string& set_name, Region region) {
277  RegionSetTable::iterator it = sets_.find(set_name);
278 
279  if (it == sets_.end()) {
280  RegionSet set;
281  set.push_back(region);
282 
283  sets_.insert( std::make_pair(set_name, set) );
284  } else {
285  RegionSet & set = (*it).second;
286  if ( std::find(set.begin(), set.end(), region)==set.end() ) {
287  set.push_back(region); // add region if doesn't exist
288  }
289  }
290 }
291 
292 
293 void RegionDB::add_set( const string& set_name, const RegionSet & set) {
294  // add region only if it is not in the set
295  if (sets_.find(set_name) == sets_.end()) {
296  sets_.insert( std::make_pair(set_name, set) );
297  }
298 }
299 
300 
301 void RegionDB::erase_from_set( const string& set_name, Region region) {
302  RegionSetTable::iterator it = sets_.find(set_name);
303  ASSERT_PERMANENT(it != sets_.end())(set_name).error("Region set doesn't exist.");
304  RegionSet & set = (*it).second;
305 
306  auto set_it = std::find(set.begin(), set.end(), region);
307  ASSERT_PERMANENT(set_it != set.end())(set_name).error("Erased region was not found in set.");
308  set.erase(set_it);
309 }
310 
311 
313 {
314  vector<string> names;
315  operands.copy_to(names);
316 
317  for (string name : names) {
318  if ( sets_.find( name ) == sets_.end() )
319  THROW( ExcUnknownSet() << EI_Label( name )
320  << operands.ei_address() );
321  }
322 
323  return names;
324 }
325 
326 
327 
328 RegionSet RegionDB::get_region_set(const string & set_name) const {
329  RegionSetTable::const_iterator it = sets_.find(set_name);
330  if ( it == sets_.end() ) {
331  return RegionSet();
332  }
333  return (*it).second;
334 }
335 
336 
337 string RegionDB::create_label_from_id(unsigned int id) const {
338  stringstream ss;
339  ss << "region_" << id;
340  return ss.str();
341 }
342 
343 Region RegionDB::insert_region(unsigned int id, const std::string &label, unsigned int dim, bool boundary, const std::string &address) {
344  if (closed_) THROW( ExcAddingIntoClosed() << EI_Label(label) << EI_ID(id) );
345 
346  unsigned int index;
347  if (boundary) {
348  index = (n_boundary_ <<1);
349  n_boundary_++;
350  } else {
351  index = (n_bulk_ << 1)+1;
352  n_bulk_++;
353  }
354 
355  if ( ! region_table_.insert( RegionItem(index, id, label, dim, address) ).second )
356  THROW( ExcCantAdd() << EI_Label(label) << EI_ID(id) );
357  if (max_id_ < id) {
358  max_id_ = id;
359  }
360 
361  Region reg = Region(index, *this);
362  // add region to sets
363  RegionSet region_set;
364  region_set.push_back( reg );
365  this->add_set(reg.label(), region_set);
366  add_to_set("ALL", reg);
367  if (reg.is_boundary()) {
368  add_to_set(".BOUNDARY", reg );
369  } else {
370  add_to_set("BULK", reg );
371  }
372 
373  return reg;
374 }
375 
376 Region RegionDB::replace_region_dim(DimIDIter it_undef_dim, unsigned int dim, bool boundary) {
377  unsigned int reg_id = it_undef_dim->get_id();
378  ASSERT_PERMANENT_EQ( it_undef_dim->dim(), undefined_dim )(reg_id)
379  .error("Dimension of replaced region with 'reg_id' must be undefined_dim\n");
380 
381  unsigned int index = it_undef_dim->index;
382 
383  RegionItem item(index, reg_id, it_undef_dim->label, dim, this->get_region_address(index));
384  region_table_.replace(
385  region_table_.get<Index>().find(index),
386  item);
387 
388  Region r_id=Region(index, *this);
389  // check boundary
390  if ( r_id.is_boundary() != boundary )
391  THROW(ExcInconsistentBoundary() << EI_Label(it_undef_dim->label) << EI_ID(reg_id) );
392 
393  return r_id;
394 }
395 
396 Region RegionDB::find_by_dimid(DimIDIter it_id, unsigned int id, const std::string &label, bool boundary) {
397  unsigned int index = it_id->index;
398  LabelIter it_label = region_table_.get<Label>().find(label);
399  if ( it_label == region_table_.get<Label>().end() || index != it_label->index )
400  THROW(ExcNonuniqueID() << EI_Label(label) << EI_ID(id) << EI_LabelOfOtherID(it_id->label) );
401 
402  Region r_id=Region(index, *this);
403  // check boundary
404  if ( r_id.is_boundary() != boundary )
405  THROW(ExcInconsistentBoundary() << EI_Label(label) << EI_ID(id) );
406 
407  return r_id;
408 }
409 
410 void RegionDB::print_region_table(ostream& stream) const {
411  ASSERT(closed_).error("RegionDB not closed yet.\n");
412 
413  // stratified regions by type
414  std::vector<std::string> boundaries, bulks, sets;
415  for (RegionSetTable::const_iterator it = sets_.begin(); it != sets_.end(); ++it) { // iterates through RegionSets
416  string rset_label = it->first;
417  LabelIter label_it = region_table_.get<Label>().find(rset_label);
418  if ( label_it != region_table_.get<Label>().end() ) { // checks if Region with same label as RegionSet exists
419  if ( (rset_label.size() > 0) && (rset_label[0] == '.') ) boundaries.push_back(rset_label);
420  else bulks.push_back(rset_label);
421  } else {
422  sets.push_back(rset_label);
423  }
424 
425  }
426 
427  // print table
428  stream << "----------- Table of all regions: -----------";
429  if (boundaries.size()) {
430  stream << endl << " - Boundary elementary regions -" << endl;
431  stream << std::setfill(' ') << "name" << setw(14) << "" << setw(6) << "id" << " dim" << endl; // table header
432  for (std::vector<std::string>::iterator it = boundaries.begin(); it < boundaries.end(); ++it) {
433  LabelIter label_it = region_table_.get<Label>().find(*it);
434  stream << std::left << setw(18) << (*it) << std::right << setw(6) << label_it->get_id() << setw(4) << label_it->dim() << endl;
435  }
436  }
437  if (bulks.size()) {
438  stream << endl << " - Bulk elementary regions -" << endl;
439  stream << "name" << setw(14) << "" << setw(6) << "id" << " dim" << endl; // table header
440  for (std::vector<std::string>::iterator it = bulks.begin(); it < bulks.end(); ++it) {
441  LabelIter label_it = region_table_.get<Label>().find(*it);
442  stream << std::left << setw(18) << (*it) << std::right << setw(6) << label_it->get_id() << setw(4) << label_it->dim() << endl;
443  }
444  }
445  if (sets.size()) {
446  stream << endl << " - Sets of regions -" << endl;
447  stream << "name" << setw(14) << "" << "contains regions" << endl; // table header
448  for (std::vector<std::string>::const_iterator it = sets.begin(); it < sets.end(); ++it) {
449  RegionSetTable::const_iterator set_it = sets_.find(*it);
450  stream << std::left << setw(18) << (*it) << std::right << "[";
451  for (RegionSet::const_iterator r_it = set_it->second.begin(); r_it!=set_it->second.end(); ++r_it) {
452  if (r_it != set_it->second.begin()) stream << ", ";
453  stream << "\"" << r_it->label() << "\"";
454  }
455  stream << "]" << endl;
456  }
457  }
458  stream << std::setfill('-') << setw(45) << "" << std::setfill(' ') << endl << endl;
459 }
460 
461 
463  ASSERT(closed_).error("RegionDB not closed yet.");
464 
466  WarningOut().fmt("Too many regions are defined (bulk {} + boundary {} >= {}). This may have negative impact on performace.\n"
467  "The user is adviced to simplify the input data and to decrease the number of regions (e.g. using FieldFE input).\n",
469  }
470 
471  for (RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().begin();
472  it!= region_table_.get<Index>().end();
473  ++it) {
474  if(! it->used){
475  WarningOut().fmt("Region [id = {}, label = '{}'] is not used in any element.",
476  it->get_id(), it->label);
477  }
478  }
479 }
480 
481 
483  std::set<Region, bool (*)(const Region&, const Region&)> set(Region::comp);
484 
485  for (string set_name : set_names) {
486  RegionSet r_set = get_region_set(set_name);
487  set.insert(r_set.begin(), r_set.end());
488  }
489 
490  return RegionSet(set.begin(), set.end());
491 }
#define ASSERT(expr)
Definition: asserts.hh:351
#define ASSERT_PERMANENT(expr)
Allow use shorter versions of macro names if these names is not used with external library.
Definition: asserts.hh:348
#define ASSERT_PERMANENT_EQ(a, b)
Definition of comparative assert macro (EQual)
Definition: asserts.hh:329
Accessor to input data conforming to declared Array.
Definition: accessors.hh:566
EI_Address ei_address() const
Definition: accessors.cc:314
void copy_to(Container &out) const
RegionTable::index< DimId >::type::iterator DimIDIter
Definition: region.hh:539
void mark_used_region(unsigned int idx)
Definition: region.cc:235
Region add_region(unsigned int id, const std::string &label, unsigned int dim, const std::string &address="implicit")
Definition: region.cc:85
Region rename_region(Region reg, const std::string &new_label)
Definition: region.cc:109
RegionTable::index< Label >::type::iterator LabelIter
Definition: region.hh:538
unsigned int boundary_size() const
Definition: region.cc:261
std::string create_label_from_id(unsigned int id) const
Definition: region.cc:337
void check_regions()
Definition: region.cc:462
Region get_region(unsigned int id, unsigned int dim)
Definition: region.cc:150
void close()
Definition: region.cc:249
Region find_label(const std::string &label) const
Definition: region.cc:169
void print_region_table(std::ostream &stream) const
Definition: region.cc:410
Region replace_region_dim(DimIDIter it_undef_dim, unsigned int dim, bool boundary)
Definition: region.cc:376
unsigned int n_bulk_
Number of bulk regions.
Definition: region.hh:551
Region find_id(unsigned int id, unsigned int dim) const
Definition: region.cc:180
RegionSet get_region_set(const std::string &set_name) const
Definition: region.cc:328
unsigned int bulk_size() const
Definition: region.cc:268
RegionSetTable sets_
Map of region sets.
Definition: region.hh:556
RegionDB()
Default constructor.
Definition: region.cc:63
Region insert_region(unsigned int id, const std::string &label, unsigned int dim, bool boundary, const std::string &address)
Definition: region.cc:343
Region find_by_dimid(DimIDIter it_id, unsigned int id, const std::string &label, bool boundary)
Definition: region.cc:396
unsigned int size() const
Definition: region.cc:254
bool is_boundary(const std::string &label)
Definition: region.hh:605
void add_set(const std::string &set_name, const RegionSet &set)
Definition: region.cc:293
std::pair< unsigned int, unsigned int > DimID
Definition: region.hh:491
void add_to_set(const std::string &set_name, Region region)
Definition: region.cc:276
void erase_from_set(const std::string &set_name, Region region)
Definition: region.cc:301
const std::string & get_region_address(unsigned int idx) const
Definition: region.cc:227
RegionTable region_table_
Database of all regions (both boundary and bulk).
Definition: region.hh:544
Region implicit_boundary_region()
Definition: region.cc:75
static const unsigned int undefined_dim
Definition: region.hh:331
std::vector< std::string > get_and_check_operands(const Input::Array &operands) const
Definition: region.cc:312
unsigned int n_boundary_
Number of boundary regions.
Definition: region.hh:549
unsigned int get_dim(unsigned int idx) const
Definition: region.cc:219
unsigned int max_id_
Maximal value of Region::id()
Definition: region.hh:553
static const unsigned int max_n_regions
Definition: region.hh:327
bool closed_
flag for closed database, no regions can be added, but you can add region sets
Definition: region.hh:547
RegionSet union_set(std::vector< std::string > set_names) const
Definition: region.cc:482
const std::string & get_label(unsigned int idx) const
Definition: region.cc:203
RegionSet boundary
Definition: region.hh:559
RegionTable::index< OnlyID >::type::iterator OnlyIDIter
Definition: region.hh:540
unsigned int get_id(unsigned int idx) const
Definition: region.cc:211
unsigned int idx() const
Returns a global index of the region.
Definition: region.hh:81
bool is_boundary() const
Returns true if it is a Boundary region and false if it is a Bulk region.
Definition: region.hh:73
bool is_valid() const
Returns false if the region has undefined/invalid value.
Definition: region.hh:77
static const unsigned int undefined
index for undefined region
Definition: region.hh:118
bool is_in_region_set(const RegionSet &set) const
Definition: region.cc:45
static bool comp(const Region &a, const Region &b)
Comparative method of two regions.
Definition: region.hh:172
unsigned int id() const
Returns id of the region (using RegionDB)
Definition: region.cc:37
std::string label() const
Returns label of the region (using RegionDB)
Definition: region.cc:32
unsigned int dim() const
Returns dimension of the region.
Definition: region.cc:42
@ boundary
Definition: region.hh:153
@ boundary
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
#define WarningOut()
Macro defining 'warning' record of log.
Definition: logger.hh:278
void swap(nlohmann::json &j1, nlohmann::json &j2) noexcept(is_nothrow_move_constructible< nlohmann::json >::value and is_nothrow_move_assignable< nlohmann::json >::value)
exchanges the values of two JSON objects
Definition: json.hpp:8688
std::vector< Region > RegionSet
Definition: region.hh:129
One item in region database.
Definition: region.hh:494