Multiscale Universal Interface  2.0
A Concurrent Framework for Coupling Heterogeneous Solvers
geometry.h
Go to the documentation of this file.
1 /*****************************************************************************
2 * Multiscale Universal Interface Code Coupling Library *
3 * *
4 * Copyright (C) 2019 Y. H. Tang, S. Kudo, X. Bian, Z. Li, G. E. Karniadakis *
5 * *
6 * This software is jointly licensed under the Apache License, Version 2.0 *
7 * and the GNU General Public License version 3, you may use it according *
8 * to either. *
9 * *
10 * ** Apache License, version 2.0 ** *
11 * *
12 * Licensed under the Apache License, Version 2.0 (the "License"); *
13 * you may not use this file except in compliance with the License. *
14 * You may obtain a copy of the License at *
15 * *
16 * http://www.apache.org/licenses/LICENSE-2.0 *
17 * *
18 * Unless required by applicable law or agreed to in writing, software *
19 * distributed under the License is distributed on an "AS IS" BASIS, *
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
21 * See the License for the specific language governing permissions and *
22 * limitations under the License. *
23 * *
24 * ** GNU General Public License, version 3 ** *
25 * *
26 * This program is free software: you can redistribute it and/or modify *
27 * it under the terms of the GNU General Public License as published by *
28 * the Free Software Foundation, either version 3 of the License, or *
29 * (at your option) any later version. *
30 * *
31 * This program is distributed in the hope that it will be useful, *
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
34 * GNU General Public License for more details. *
35 * *
36 * You should have received a copy of the GNU General Public License *
37 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
38 *****************************************************************************/
39 
48 #ifndef MUI_GEOMETRY_H
49 #define MUI_GEOMETRY_H
50 
51 #include <memory>
52 
53 #include "../config.h"
54 #include "../storage/stream.h"
55 #include "../storage/stream_string.h"
56 
57 namespace mui {
58 namespace geometry{
59 
60 enum struct shape_type: std::int8_t {
61  universe = 0,
62  or_set,
63  point,
64  sphere,
65  box
66 };
67 
68 template<typename CONFIG> class shape;
69 template<typename CONFIG> class any_shape;
70 template<typename CONFIG> class box;
71 template<typename CONFIG> std::unique_ptr<shape<CONFIG> > shape_factory( shape_type );
72 
73 template<typename CONFIG>
74 class shape {
75 protected: // make those ctors & copies protected to prevent slicing
76  shape() = default;
77  shape(shape&&) noexcept = default;
78  shape(const shape&) = default;
79  shape& operator=(shape&&) noexcept = default;
80  shape& operator=(const shape&) = default;
81 public:
82  virtual ~shape(){}
83  virtual shape* clone() const = 0;
84  virtual shape_type type() const noexcept = 0;
85  virtual box<CONFIG> bbox() const = 0;
86 
87  virtual void serialize(ostream& stream) const = 0;
88  virtual void deserialize(istream& stream) = 0;
89 };
90 
91 template<typename CONFIG>
92 class any_shape {
93 public:
94  any_shape() = default;
95  any_shape( const any_shape& rhs )
96  : content(rhs.content ? rhs.content->clone() : 0) {}
97  any_shape( any_shape&& ) noexcept = default;
98  any_shape( const shape<CONFIG>& rhs ) : content(rhs.clone()) {}
100  rhs.swap(*this);
101  return *this;
102  }
103 
104  explicit operator bool() const noexcept { return static_cast<bool>(content); }
105  bool empty() const noexcept { return !static_cast<bool>(content); }
106  void swap( any_shape& rhs ) noexcept { content.swap(rhs.content); }
107 
108  shape<CONFIG>& get() { return *content; }
109  const shape<CONFIG>& get() const { return *content; }
110 
111  shape_type type() const noexcept { return content ? content->type() : shape_type::universe; }
112  box<CONFIG> bbox() const;
113 
114  friend ostream& operator<<(ostream& stream, const any_shape& obj){
115  stream << static_cast<std::int8_t>(obj.type());
116  if( !obj.empty() ) obj.get().serialize(stream);
117  return stream;
118  }
119  friend istream& operator>>(istream& stream, any_shape& obj){
120  std::int8_t tp;
121  stream >> tp;
122  if( static_cast<shape_type>(tp) == shape_type::universe ) obj = any_shape();
123  else {
124  auto tmp = shape_factory<CONFIG>(static_cast<shape_type>(tp));
125  tmp->deserialize(stream);
126  obj.content.swap(tmp);
127  }
128  return stream;
129  }
130 
131 private:
132  std::unique_ptr<shape<CONFIG> > content;
133 };
134 template<typename CONFIG> any_shape<CONFIG> get_universe_set() { return any_shape<CONFIG>(); }
135 
136 template<typename CONFIG>
137 class point: public shape<CONFIG> {
138  typedef typename CONFIG::point_type coordinate_type;
139  typedef typename CONFIG::REAL REAL;
140 public:
141  point() = default;
142  point(const coordinate_type& c__) : center(c__) {}
143 
144  coordinate_type& get_center() { return center; }
145  coordinate_type get_center() const { return center; }
146 
147  shape<CONFIG>* clone() const { return static_cast<shape<CONFIG>*>(new point(*this)); }
148  shape_type type() const noexcept { return shape_type::point; }
149  box<CONFIG> bbox() const;
150 
151  void serialize(ostream& stream) const { stream << center; }
152  void deserialize(istream& stream) { stream >> center; }
153 private:
154  coordinate_type center;
155 };
156 
157 template<typename CONFIG>
158 class sphere: public shape<CONFIG> {
159  typedef typename CONFIG::point_type coordinate_type;
160  typedef typename CONFIG::REAL REAL;
161 public:
162  sphere() = default;
163  sphere(const coordinate_type& c__, REAL r__) : center(c__), radius(r__) {}
164 
165  coordinate_type& get_center() { return center; }
166  coordinate_type get_center() const { return center; }
167  REAL& get_radius() { return radius; }
168  REAL get_radius() const { return radius; }
169 
170  shape<CONFIG>* clone() const { return static_cast<shape<CONFIG>*>(new sphere(*this)); }
171  shape_type type() const noexcept { return shape_type::sphere; }
172  box<CONFIG> bbox() const;
173 
174  void serialize(ostream& stream) const {
175  stream << center;
176  stream << radius;
177  }
178  void deserialize(istream& stream) {
179  stream >> center;
180  stream >> radius;
181  }
182 private:
183  coordinate_type center;
184  REAL radius;
185 };
186 
187 template<typename CONFIG>
188 class box: public shape<CONFIG> {
189  typedef typename CONFIG::point_type coordinate_type;
190  typedef typename CONFIG::REAL REAL;
191 public:
192  box() = default;
193  box(const coordinate_type& p1, const coordinate_type& p2){
194  // there are four different (p1,p2) pair for same box.
195  // box only allows min[i] <= max[i] for all i.
196  for( uint i=0; i<CONFIG::D; ++i ){
197  min[i] = std::min(p1[i],p2[i]);
198  max[i] = std::max(p1[i],p2[i]);
199  }
200  }
201 
202  coordinate_type get_min() const { return min; }
203  coordinate_type& get_min() { return min; }
204  coordinate_type get_max() const { return max; }
205  coordinate_type& get_max() { return max; }
206 
207  shape<CONFIG>* clone() const { return static_cast<shape<CONFIG>*>(new box(*this)); }
208  shape_type type() const noexcept { return shape_type::box; }
209  box<CONFIG> bbox() const;
210 
211  void serialize(ostream& stream) const {
212  stream << min;
213  stream << max;
214  }
215  void deserialize(istream& stream) {
216  stream >> min;
217  stream >> max;
218  }
219 private:
220  coordinate_type min, max; // only use the two vertex of box such that min[i] < max[i] for all i.
221 };
222 
223 template<typename CONFIG>
224 class or_set: public shape<CONFIG> {
225  typedef typename CONFIG::point_type coordinate_type;
226  typedef typename CONFIG::REAL REAL;
227 public:
228  or_set() = default;
229  or_set(any_shape<CONFIG> obj1, any_shape<CONFIG>& obj2): lhs_(std::move(obj1)), rhs_(std::move(obj2)) {}
230 
231  const any_shape<CONFIG>& left() const { return lhs_; }
232  any_shape<CONFIG>& left() { return lhs_; }
233  const any_shape<CONFIG>& right() const { return rhs_; }
234  any_shape<CONFIG>& right() { return rhs_; }
235 
236  shape<CONFIG>* clone() const { return static_cast<shape<CONFIG>*>(new or_set(*this)); }
237  shape_type type() const noexcept { return shape_type::or_set; }
238  box<CONFIG> bbox() const;
239 
240  void serialize(ostream& stream) const {
241  stream << lhs_;
242  stream << rhs_;
243  }
244  void deserialize(istream& stream) {
245  stream >> lhs_;
246  stream >> rhs_;
247  }
248 private:
249  any_shape<CONFIG> lhs_, rhs_;
250 };
251 
252 template<typename CONFIG> std::unique_ptr<shape<CONFIG> > shape_factory(shape_type type)
253 {
254  shape<CONFIG>* ptr;
255  switch(type){
256  case shape_type::or_set: ptr = new or_set<CONFIG>; break;
257  case shape_type::point: ptr = new point<CONFIG>; break;
258  case shape_type::sphere: ptr = new sphere<CONFIG>; break;
259  case shape_type::box: ptr = new box<CONFIG>; break;
260  default: ptr = 0; break;
261  }
262  return std::unique_ptr<shape<CONFIG> >(ptr);
263 }
264 
265 namespace {
266 #define CASE(LHS, RHS) case shape_type::RHS : \
267  return collide(static_cast<const LHS<CONFIG>&>(lhs), static_cast<const RHS<CONFIG>&>(rhs))
268 template<typename CONFIG> bool collide_impl_(const shape<CONFIG>& lhs, const shape<CONFIG>& rhs)
269 {
270  switch(lhs.type()){
272  return true;
273  case shape_type::or_set : {
274  auto& obj = static_cast<const or_set<CONFIG>&>(lhs);
275  return collide(obj.left(),rhs) || collide(obj.right(),rhs);
276  }
277  case shape_type::point :
278  switch(rhs.type()){
279  CASE(point,point);
280  CASE(point,sphere);
281  CASE(point,box);
282  default: return true;
283  }
284  case shape_type::sphere :
285  switch(rhs.type()){
286  CASE(sphere,sphere);
287  CASE(sphere,box);
288  default: return true;
289  }
290  case shape_type::box :
291  switch(rhs.type()){
292  CASE(box,box);
293  default: return true;
294  }
295  }
296  return true; // cannot reach here
297 }
298 #undef CASE
299 }
300 
301 template<typename CONFIG> bool collide( const shape<CONFIG>& lhs, const shape<CONFIG>& rhs)
302 {
303  return static_cast<std::int8_t>(lhs.type()) <= static_cast<std::int8_t>(rhs.type()) ?
304  collide_impl_(lhs,rhs):
305  collide_impl_(rhs,lhs);
306 }
307 
308 template<typename CONFIG> bool collide( const any_shape<CONFIG>& lhs, const any_shape<CONFIG>& rhs)
309 {
310  if( lhs.empty() || rhs.empty() ) return true;
311  else return collide(lhs.get(), rhs.get());
312 }
313 
314 template<typename CONFIG> bool collide( const any_shape<CONFIG>& lhs, const shape<CONFIG>& rhs)
315 {
316  if( lhs.empty() ) return true;
317  else return collide(lhs.get(), rhs);
318 }
319 
320 template<typename CONFIG> bool collide( const shape<CONFIG>& lhs, const any_shape<CONFIG>& rhs)
321 {
322  if( rhs.empty() ) return true;
323  else return collide(lhs, rhs.get());
324 }
325 
326 template<typename CONFIG> bool collide( const point<CONFIG>& lhs, const point<CONFIG>& rhs)
327 {
328  for( int i=0; i<CONFIG::D; ++i ) if( lhs.get_center()[i] != rhs.get_center()[i] ) return false;
329  return true;
330 }
331 
332 template<typename CONFIG> bool collide( const point<CONFIG>& lhs, const sphere<CONFIG>& rhs)
333 {
334  return normsq( lhs.get_center()-rhs.get_center() ) <= (rhs.get_radius()*rhs.get_radius());
335 }
336 
337 template<typename CONFIG> bool collide( const point<CONFIG>& lhs, const box<CONFIG>& rhs)
338 {
339  for( uint i=0; i<CONFIG::D; ++i )
340  if( lhs.get_center()[i] < rhs.get_min()[i] || rhs.get_max()[i] < lhs.get_center()[i] ) return false;
341  return true;
342 }
343 
344 template<typename CONFIG> bool collide( const sphere<CONFIG>& lhs, const sphere<CONFIG>& rhs)
345 {
346  return normsq( lhs.get_center() - rhs.get_center() ) <=
347  (lhs.get_radius()+rhs.get_radius())*(lhs.get_radius()+rhs.get_radius());
348 }
349 
350 namespace {
351 template<typename REAL>
352 REAL minimum_of_quadratic(REAL b, REAL c, REAL x0, REAL x1 )
353 {
354  // return the minimum of x^2+bx+c in [x0,x1]
355  REAL p0 = -0.5*b;
356  return std::max<REAL>( ( x0 <= p0 && p0 <= x1 )?
357  c+0.5*b*p0 :
358  std::min(x0*x0+b*x0, x1*x1+b*x1) + c, 0.0 );
359 }
360 }
361 template<typename CONFIG> bool collide( const sphere<CONFIG>& lhs, const box<CONFIG>& rhs)
362 {
363  auto a = lhs.get_center()[0];
364  auto dist = minimum_of_quadratic(-(a+a),a*a,rhs.get_min()[0],rhs.get_max()[0]);
365  for( uint i=1; i<CONFIG::D; ++i ){
366  auto a = lhs.get_center()[i];
367  dist += minimum_of_quadratic(-(a+a),a*a,rhs.get_min()[i],rhs.get_max()[i]);
368  }
369  return dist <= lhs.get_radius()*lhs.get_radius();
370 }
371 
372 template<typename CONFIG> bool collide( const box<CONFIG>& lhs, const box<CONFIG>& rhs)
373 {
374  for( uint i=0; i<CONFIG::D; ++i ) {
375  if( lhs.get_max()[i] < rhs.get_min()[i] || rhs.get_max()[i] < lhs.get_min()[i] ) return false;
376  }
377 
378  return true;
379 }
380 
381 template<typename CONFIG> box<CONFIG> any_shape<CONFIG>::bbox() const
382 {
383  if( content ) return content->bbox();
384  else {
385  box<CONFIG> bx;
386  for( uint i = 0; i<CONFIG::D; ++i ) {
387  bx.get_min()[i] = -std::numeric_limits<typename CONFIG::REAL>::infinity();
388  bx.get_max()[i] = std::numeric_limits<typename CONFIG::REAL>::infinity();
389  }
390  return bx;
391  }
392 }
393 
394 template<typename CONFIG> box<CONFIG> point<CONFIG>::bbox() const
395 {
396  return box<CONFIG>(center, center);
397 }
398 
399 template<typename CONFIG> box<CONFIG> sphere<CONFIG>::bbox() const
400 {
401  box<CONFIG> bx;
402  for( uint i=0; i<CONFIG::D; ++i ){
403  bx.get_min()[i] = center[i]-radius;
404  bx.get_max()[i] = center[i]+radius;
405  }
406  return bx;
407 }
408 
409 template<typename CONFIG>
411 {
412  return *this;
413 }
414 
415 template<typename CONFIG> box<CONFIG> or_set<CONFIG>::bbox() const
416 {
417  box<CONFIG> bx, lhs = lhs_.bbox(), rhs = rhs_.bbox();
418  for( uint i=0; i<CONFIG::D; ++i ){
419  bx.get_min()[i] = std::min(lhs.get_min()[i], rhs.get_min()[i]);
420  bx.get_max()[i] = std::min(lhs.get_max()[i], rhs.get_max()[i]);
421  }
422  return bx;
423 }
424 
425 template<typename CONFIG> ostream& operator<<( ostream& stream, const shape<CONFIG>& obj )
426 {
427  obj.serialize(stream);
428  return stream;
429 }
430 
431 template<typename CONFIG> istream& operator>>( istream& stream, shape<CONFIG>& obj )
432 {
433  obj.deserialize(stream);
434  return stream;
435 }
436 
437 template<typename CONFIG> or_set<CONFIG> operator|(any_shape<CONFIG> lhs, any_shape<CONFIG> rhs)
438 {
439  return or_set<CONFIG>(std::move(lhs), std::move(rhs));
440 }
441 
442 } // geometry
443 } // mui
444 
445 #endif
Definition: geometry.h:92
bool empty() const noexcept
Definition: geometry.h:105
friend ostream & operator<<(ostream &stream, const any_shape &obj)
Definition: geometry.h:114
any_shape(const any_shape &rhs)
Definition: geometry.h:95
void swap(any_shape &rhs) noexcept
Definition: geometry.h:106
const shape< CONFIG > & get() const
Definition: geometry.h:109
shape< CONFIG > & get()
Definition: geometry.h:108
any_shape & operator=(any_shape rhs)
Definition: geometry.h:99
friend istream & operator>>(istream &stream, any_shape &obj)
Definition: geometry.h:119
box< CONFIG > bbox() const
Definition: geometry.h:381
shape_type type() const noexcept
Definition: geometry.h:111
any_shape(any_shape &&) noexcept=default
Definition: geometry.h:188
void deserialize(istream &stream)
Definition: geometry.h:215
coordinate_type & get_max()
Definition: geometry.h:205
box(const coordinate_type &p1, const coordinate_type &p2)
Definition: geometry.h:193
coordinate_type get_min() const
Definition: geometry.h:202
shape_type type() const noexcept
Definition: geometry.h:208
coordinate_type & get_min()
Definition: geometry.h:203
box< CONFIG > bbox() const
Definition: geometry.h:410
shape< CONFIG > * clone() const
Definition: geometry.h:207
coordinate_type get_max() const
Definition: geometry.h:204
void serialize(ostream &stream) const
Definition: geometry.h:211
Definition: geometry.h:224
const any_shape< CONFIG > & left() const
Definition: geometry.h:231
shape_type type() const noexcept
Definition: geometry.h:237
shape< CONFIG > * clone() const
Definition: geometry.h:236
any_shape< CONFIG > & right()
Definition: geometry.h:234
any_shape< CONFIG > & left()
Definition: geometry.h:232
box< CONFIG > bbox() const
Definition: geometry.h:415
const any_shape< CONFIG > & right() const
Definition: geometry.h:233
void deserialize(istream &stream)
Definition: geometry.h:244
void serialize(ostream &stream) const
Definition: geometry.h:240
or_set(any_shape< CONFIG > obj1, any_shape< CONFIG > &obj2)
Definition: geometry.h:229
Definition: geometry.h:137
coordinate_type & get_center()
Definition: geometry.h:144
point(const coordinate_type &c__)
Definition: geometry.h:142
shape< CONFIG > * clone() const
Definition: geometry.h:147
box< CONFIG > bbox() const
Definition: geometry.h:394
void deserialize(istream &stream)
Definition: geometry.h:152
shape_type type() const noexcept
Definition: geometry.h:148
void serialize(ostream &stream) const
Definition: geometry.h:151
coordinate_type get_center() const
Definition: geometry.h:145
Definition: geometry.h:74
virtual shape_type type() const noexcept=0
virtual shape * clone() const =0
virtual void serialize(ostream &stream) const =0
shape(shape &&) noexcept=default
virtual box< CONFIG > bbox() const =0
virtual void deserialize(istream &stream)=0
Definition: geometry.h:158
box< CONFIG > bbox() const
Definition: geometry.h:399
coordinate_type get_center() const
Definition: geometry.h:166
shape_type type() const noexcept
Definition: geometry.h:171
REAL & get_radius()
Definition: geometry.h:167
coordinate_type & get_center()
Definition: geometry.h:165
void serialize(ostream &stream) const
Definition: geometry.h:174
void deserialize(istream &stream)
Definition: geometry.h:178
shape< CONFIG > * clone() const
Definition: geometry.h:170
sphere(const coordinate_type &c__, REAL r__)
Definition: geometry.h:163
REAL get_radius() const
Definition: geometry.h:168
Definition: stream.h:61
Definition: stream.h:67
#define CASE(LHS, RHS)
Definition: geometry.h:266
u u u u u u min
Definition: dim.h:289
ostream & operator<<(ostream &stream, const shape< CONFIG > &obj)
Definition: geometry.h:425
std::unique_ptr< shape< CONFIG > > shape_factory(shape_type)
Definition: geometry.h:252
shape_type
Definition: geometry.h:60
istream & operator>>(istream &stream, shape< CONFIG > &obj)
Definition: geometry.h:431
bool collide(const shape< CONFIG > &lhs, const shape< CONFIG > &rhs)
Definition: geometry.h:301
any_shape< CONFIG > get_universe_set()
Definition: geometry.h:134
or_set< CONFIG > operator|(any_shape< CONFIG > lhs, any_shape< CONFIG > rhs)
Definition: geometry.h:437
Definition: comm.h:54
SCALAR max(vexpr< E, SCALAR, D > const &u)
Definition: point.h:350
unsigned int uint
Definition: util.h:94
SCALAR normsq(vexpr< E, SCALAR, D > const &u)
Definition: point.h:380
SCALAR min(vexpr< E, SCALAR, D > const &u)
Definition: point.h:356