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