Flow123d  release_3.0.0-1193-g9220a69
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 #include <boost/foreach.hpp>
29 
30 using namespace std;
31 
32 
33 std::string Region::label() const
34  { return db_->get_label(idx_); }
35 
36 
37 
38 unsigned int Region::id() const
39  { return db_->get_id(idx_); }
40 
41 
42 
43 unsigned int Region::dim() const
44  { return db_->get_dim(idx_); }
45 
46 bool Region::is_in_region_set(const RegionSet &set) const
47 {
48  for(const Region &reg : set)
49  if (reg.idx_ == this->idx_) return true;
50  return false;
51 }
52 
53 /**************************************************************************************************
54  * Implementation of RegionDB
55  */
56 
57 
58 
59 const unsigned int RegionDB::max_n_regions = 10000;
60 const unsigned int RegionDB::undefined_dim = 10;
61 
62 
63 /// Default constructor
65 : closed_(false), n_boundary_(0), n_bulk_(0), max_id_(0) {
66 
67  // adding implicit boundary and bulk regions
68  // How to deal with dimension, clean solution is to have implicit region for every
69  // dimension, or we can allow regions of mixed dimension
70  //implicit_bulk_ = add_region(Region::undefined-1, "IMPLICIT BULK", 0, Region::bulk);
71  //implicit_boundary_ = ;
72 
73 }
74 
75 
78  if ( it_id!=region_table_.get<DimId>().end() ) {
79  return Region(it_id->index, *this);
80  }
81 
82  return insert_region(Region::undefined-2, ".IMPLICIT_BOUNDARY", undefined_dim, Region::boundary, "");
83 }
84 
85 
86 Region RegionDB::add_region( unsigned int id, const std::string &label, unsigned int dim, const std::string &address) {
87  bool boundary = is_boundary(label);
88  DimIDIter it_id = region_table_.get<DimId>().find(DimID(dim,id));
89  if (it_id != region_table_.get<DimId>().end() ) {
90  // Find existing region
91  return find_by_dimid(it_id, id, label, boundary);
92  }
93 
94  DimIDIter it_undef_dim = region_table_.get<DimId>().find(DimID(undefined_dim,id));
95  if (it_undef_dim != region_table_.get<DimId>().end() ) {
96  // Region with same ID and undefined_dim exists, replace undefined_dim
97  return replace_region_dim(it_undef_dim, dim, boundary);
98  }
99 
100  LabelIter it_label = region_table_.get<Label>().find(label);
101  if (it_label != region_table_.get<Label>().end() ) {
102  // ID is free, not label
103  THROW(ExcNonuniqueLabel() << EI_Label(label) << EI_ID(id) << EI_IDOfOtherLabel(it_label->get_id()) );
104  }
105 
106  return insert_region(id, label, dim, boundary, address);
107 }
108 
109 
110 Region RegionDB::rename_region( Region reg, const std::string &new_label ) {
111  OLD_ASSERT(reg.is_valid(), "Non-existing region can't be renamed to '%s'.\n", new_label.c_str());
112 
113  // test if region with new_label exists
114  LabelIter it_label = region_table_.get<Label>().find(new_label);
115  if (it_label != region_table_.get<Label>().end() ) {
116  if ( reg.id() == it_label->index ) {
117  return reg;
118  } else {
119  // region with same label and other ID exists
120  THROW(ExcNonuniqueLabel() << EI_Label(new_label) << EI_ID(reg.id()) << EI_IDOfOtherLabel(it_label->get_id()) );
121  }
122  }
123 
124  // replace region label
125  unsigned int index = reg.idx();
126  RegionSetTable::iterator it = sets_.find(reg.label()); // rename set
127  std::swap(sets_[new_label], it->second);
128  sets_.erase(it);
129  bool old_boundary_flag = reg.is_boundary(); // check old x new boundary flag - take account in adding to sets
130 
131  RegionItem item(index, reg.id(), new_label, reg.dim(), this->get_region_address(index));
132  region_table_.replace(
133  region_table_.get<Index>().find(index),
134  item);
135 
136  if (old_boundary_flag != reg.is_boundary()) { // move region between BULK and .BOUNDARY sets
137  WarningOut().fmt("Change boundary flag of region with id {} and label {}.\n", reg.id(), new_label);
138  if (old_boundary_flag) {
139  erase_from_set(".BOUNDARY", reg );
140  add_to_set("BULK", reg );
141  } else {
142  erase_from_set("BULK", reg );
143  add_to_set(".BOUNDARY", reg );
144  }
145  }
146 
147  return Region(index, *this);
148 }
149 
150 
151 Region RegionDB::get_region(unsigned int id, unsigned int dim) {
152  DimIDIter it_id = region_table_.get<DimId>().find(DimID(dim,id));
153  if ( it_id!=region_table_.get<DimId>().end() ) {
154  // Region found.
155  return Region(it_id->index, *this);
156  }
157 
158  DimIDIter it_undef_dim = region_table_.get<DimId>().find(DimID(undefined_dim,id));
159  if (it_undef_dim == region_table_.get<DimId>().end() ) {
160  // Region doesn't exist.
161  return Region();
162  } else {
163  // Region with same ID and undefined_dim exists, replace undefined_dim
164  bool boundary = is_boundary(it_undef_dim->label);
165  return replace_region_dim(it_undef_dim, dim, boundary);
166  }
167 }
168 
169 
170 Region RegionDB::find_label(const std::string &label) const
171 {
172  LabelIter it_label = region_table_.get<Label>().find(label);
173  if (it_label==region_table_.get<Label>().end() ) return Region();
174  return Region(it_label->index, *this);
175 }
176 
177 
178 
179 
180 
181 Region RegionDB::find_id(unsigned int id, unsigned int dim) const
182 {
183  DimIDIter it_id = region_table_.get<DimId>().find(DimID(dim, id));
184  if ( it_id==region_table_.get<DimId>().end() ) return Region();
185  return Region(it_id->index, *this);
186 }
187 
188 
189 
190 
191 Region RegionDB::find_id(unsigned int id) const
192 {
193  if (region_table_.get<OnlyID>().count(id) > 1) {
194  THROW( ExcUniqueRegionId() << EI_ID( id ) );
195  }
196  OnlyIDIter it_id = region_table_.get<OnlyID>().find(id);
197  if ( it_id==region_table_.get<OnlyID>().end() ) return Region();
198  return Region(it_id->index, *this);
199 }
200 
201 
202 
203 
204 const std::string & RegionDB::get_label(unsigned int idx) const {
205  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
206  OLD_ASSERT( it!= region_table_.get<Index>().end(), "No region with index: %u\n", idx);
207  return it->label;
208 }
209 
210 
211 
212 unsigned int RegionDB::get_id(unsigned int idx) const {
213  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
214  OLD_ASSERT( it!= region_table_.get<Index>().end(), "No region with index: %u\n", idx);
215  return it->get_id();
216 }
217 
218 
219 
220 unsigned int RegionDB::get_dim(unsigned int idx) const {
221  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
222  OLD_ASSERT( it!= region_table_.get<Index>().end(), "No region with index: %u\n", idx);
223  return it->dim();
224 }
225 
226 
227 
228 const std::string & RegionDB::get_region_address(unsigned int idx) const {
229  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
230  OLD_ASSERT( it!= region_table_.get<Index>().end(), "No region with index: %u\n", idx);
231  return it->address;
232 }
233 
234 
235 
236 void RegionDB::mark_used_region(unsigned int idx) {
237  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
238  OLD_ASSERT( it!= region_table_.get<Index>().end(), "No region with index: %u\n", idx);
239  if ( !it->used ) {
240  unsigned int index = it->index;
241  RegionItem item(index, it->get_id(), it->label, it->dim(), it->address, true);
242  region_table_.replace(
243  region_table_.get<Index>().find(index),
244  item);
245  }
246 }
247 
248 
249 
251  closed_=true;
252 }
253 
254 
255 unsigned int RegionDB::size() const {
256  OLD_ASSERT(closed_, "RegionDB not closed yet.\n");
257  return 2* max(n_boundary_, n_bulk_);
258 }
259 
260 
261 
262 unsigned int RegionDB::boundary_size() const {
263  OLD_ASSERT(closed_, "RegionDB not closed yet.\n");
264  return n_boundary_;
265 }
266 
267 
268 
269 unsigned int RegionDB::bulk_size() const {
270  OLD_ASSERT(closed_, "RegionDB not closed yet.\n");
271  return n_bulk_;
272 }
273 
274 
275 
276 
277 void RegionDB::add_to_set( const string& set_name, Region region) {
278  RegionSetTable::iterator it = sets_.find(set_name);
279 
280  if (it == sets_.end()) {
281  RegionSet set;
282  set.push_back(region);
283 
284  sets_.insert( std::make_pair(set_name, set) );
285  } else {
286  RegionSet & set = (*it).second;
287  if ( std::find(set.begin(), set.end(), region)==set.end() ) {
288  set.push_back(region); // add region if doesn't exist
289  }
290  }
291 }
292 
293 
294 void RegionDB::add_set( const string& set_name, const RegionSet & set) {
295  // add region only if it is not in the set
296  if (sets_.find(set_name) == sets_.end()) {
297  sets_.insert( std::make_pair(set_name, set) );
298  }
299 }
300 
301 
302 void RegionDB::erase_from_set( const string& set_name, Region region) {
303  RegionSetTable::iterator it = sets_.find(set_name);
304  OLD_ASSERT(it != sets_.end(), "Region set '%s' doesn't exist.", set_name.c_str());
305  RegionSet & set = (*it).second;
306 
307  auto set_it = std::find(set.begin(), set.end(), region);
308  OLD_ASSERT(set_it != set.end(), "Erased region was not found in set '%s'", set_name.c_str());
309  set.erase(set_it);
310 }
311 
312 
314 {
315  vector<string> names;
316  operands.copy_to(names);
317 
318  for (string name : names) {
319  if ( sets_.find( name ) == sets_.end() )
320  THROW( ExcUnknownSet() << EI_Label( name )
321  << operands.ei_address() );
322  }
323 
324  return names;
325 }
326 
327 
328 
329 RegionSet RegionDB::get_region_set(const string & set_name) const {
330  RegionSetTable::const_iterator it = sets_.find(set_name);
331  if ( it == sets_.end() ) {
332  return RegionSet();
333  }
334  return (*it).second;
335 }
336 
337 
338 string RegionDB::create_label_from_id(unsigned int id) const {
339  stringstream ss;
340  ss << "region_" << id;
341  return ss.str();
342 }
343 
344 Region RegionDB::insert_region(unsigned int id, const std::string &label, unsigned int dim, bool boundary, const std::string &address) {
345  if (closed_) THROW( ExcAddingIntoClosed() << EI_Label(label) << EI_ID(id) );
346 
347  unsigned int index;
348  if (boundary) {
349  index = (n_boundary_ <<1);
350  n_boundary_++;
351  } else {
352  index = (n_bulk_ << 1)+1;
353  n_bulk_++;
354  }
355 
356  if ( ! region_table_.insert( RegionItem(index, id, label, dim, address) ).second )
357  THROW( ExcCantAdd() << EI_Label(label) << EI_ID(id) );
358  if (max_id_ < id) {
359  max_id_ = id;
360  }
361 
362  Region reg = Region(index, *this);
363  // add region to sets
364  RegionSet region_set;
365  region_set.push_back( reg );
366  this->add_set(reg.label(), region_set);
367  add_to_set("ALL", reg);
368  if (reg.is_boundary()) {
369  add_to_set(".BOUNDARY", reg );
370  } else {
371  add_to_set("BULK", reg );
372  }
373 
374  return reg;
375 }
376 
377 Region RegionDB::replace_region_dim(DimIDIter it_undef_dim, unsigned int dim, bool boundary) {
378  OLD_ASSERT( it_undef_dim->dim() == undefined_dim,
379  "Dimension of replaced region with id=%u must be undefined_dim, actually is: %u\n", it_undef_dim->get_id(), it_undef_dim->dim());
380 
381  unsigned int index = it_undef_dim->index;
382 
383  RegionItem item(index, it_undef_dim->get_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(it_undef_dim->get_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  ASSERT(it->used)(it->label)(it->get_id()).warning("Region with given id and label is not used in any element.");
475  }
476 }
477 
478 
480  std::set<Region, bool (*)(const Region&, const Region&)> set(Region::comp);
481 
482  for (string set_name : set_names) {
483  RegionSet r_set = get_region_set(set_name);
484  set.insert(r_set.begin(), r_set.end());
485  }
486 
487  return RegionSet(set.begin(), set.end());
488 }
unsigned int size() const
Definition: region.cc:255
const std::string & get_label(unsigned int idx) const
Definition: region.cc:204
RegionSet get_region_set(const std::string &set_name) const
Definition: region.cc:329
Accessor to input data conforming to declared Array.
Definition: accessors.hh:567
EI_Address ei_address() const
Definition: accessors.cc:314
bool is_boundary() const
Returns true if it is a Boundary region and false if it is a Bulk region.
Definition: region.hh:74
Region rename_region(Region reg, const std::string &new_label)
Definition: region.cc:110
unsigned int bulk_size() const
Definition: region.cc:269
RegionSetTable sets_
Map of region sets.
Definition: region.hh:557
static bool comp(const Region &a, const Region &b)
Comparative method of two regions.
Definition: region.hh:173
static const unsigned int undefined
index for undefined region
Definition: region.hh:119
unsigned int max_id_
Maximal value of Region::id()
Definition: region.hh:554
void add_to_set(const std::string &set_name, Region region)
Definition: region.cc:277
std::string create_label_from_id(unsigned int id) const
Definition: region.cc:338
RegionSet union_set(std::vector< std::string > set_names) const
Definition: region.cc:479
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:346
Region replace_region_dim(DimIDIter it_undef_dim, unsigned int dim, bool boundary)
Definition: region.cc:377
unsigned int idx_
Definition: region.hh:116
One item in region database.
Definition: region.hh:495
std::vector< Region > RegionSet
Definition: region.hh:130
Region get_region(unsigned int id, unsigned int dim)
Definition: region.cc:151
#define OLD_ASSERT(...)
Definition: global_defs.h:131
Region find_by_dimid(DimIDIter it_id, unsigned int id, const std::string &label, bool boundary)
Definition: region.cc:396
Region find_id(unsigned int id, unsigned int dim) const
Definition: region.cc:181
std::vector< std::string > get_and_check_operands(const Input::Array &operands) const
Definition: region.cc:313
void add_set(const std::string &set_name, const RegionSet &set)
Definition: region.cc:294
RegionTable::index< Label >::type::iterator LabelIter
Definition: region.hh:539
bool is_boundary(const std::string &label)
Definition: region.hh:606
void close()
Definition: region.cc:250
Region implicit_boundary_region()
Definition: region.cc:76
unsigned int n_bulk_
Number of bulk regions.
Definition: region.hh:552
std::pair< unsigned int, unsigned int > DimID
Definition: region.hh:492
RegionDB()
Default constructor.
Definition: region.cc:64
void swap(nlohmann::json &j1, nlohmann::json &j2) noexcept(is_nothrow_move_constructible< nlohmann::json >::value andis_nothrow_move_assignable< nlohmann::json >::value)
exchanges the values of two JSON objects
Definition: json.hpp:8688
RegionTable::index< OnlyID >::type::iterator OnlyIDIter
Definition: region.hh:541
RegionSet boundary
Definition: region.hh:560
RegionTable::index< DimId >::type::iterator DimIDIter
Definition: region.hh:540
void check_regions()
Definition: region.cc:462
void mark_used_region(unsigned int idx)
Definition: region.cc:236
Region add_region(unsigned int id, const std::string &label, unsigned int dim, const std::string &address="implicit")
Definition: region.cc:86
const std::string & get_region_address(unsigned int idx) const
Definition: region.cc:228
Region insert_region(unsigned int id, const std::string &label, unsigned int dim, bool boundary, const std::string &address)
Definition: region.cc:344
void copy_to(Container &out) const
static const unsigned int max_n_regions
Definition: region.hh:328
unsigned int get_id(unsigned int idx) const
Definition: region.cc:212
unsigned int boundary_size() const
Definition: region.cc:262
RegionTable region_table_
Database of all regions (both boundary and bulk).
Definition: region.hh:545
void erase_from_set(const std::string &set_name, Region region)
Definition: region.cc:302
bool is_in_region_set(const RegionSet &set) const
Definition: region.cc:46
unsigned int get_dim(unsigned int idx) const
Definition: region.cc:220
void print_region_table(std::ostream &stream) const
Definition: region.cc:410
#define WarningOut()
Macro defining &#39;warning&#39; record of log.
Definition: logger.hh:246
static const unsigned int undefined_dim
Definition: region.hh:332
Region find_label(const std::string &label) const
Definition: region.cc:170
bool is_valid() const
Returns false if the region has undefined/invalid value.
Definition: region.hh:78
std::string label() const
Returns label of the region (using RegionDB)
Definition: region.cc:33
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
bool closed_
flag for closed database, no regions can be added, but you can add region sets
Definition: region.hh:548
unsigned int n_boundary_
Number of boundary regions.
Definition: region.hh:550
unsigned int id() const
Returns id of the region (using RegionDB)
Definition: region.cc:38
unsigned int dim() const
Returns dimension of the region.
Definition: region.cc:43
unsigned int idx() const
Returns a global index of the region.
Definition: region.hh:82