Multiscale Universal Interface  2.0
A Concurrent Framework for Coupling Heterogeneous Solvers
bin.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 BIN_H
49 #define BIN_H
50 
51 #include "../geometry/geometry.h"
52 #include "../config.h"
53 
54 namespace mui {
55 
56 namespace {
57 template<typename INT>
58 struct count_iterator : std::iterator<std::random_access_iterator_tag,INT,INT,INT,INT&>{
59  INT cur_;
60  count_iterator() {}
61  count_iterator(const count_iterator&) = default;
62  count_iterator( INT cur ): cur_(cur) {}
63 
64  count_iterator& operator++(){
65  ++cur_;
66  return *this;
67  }
68  count_iterator& operator--(){
69  --cur_;
70  return *this;
71  }
72  count_iterator operator++(int){
73  count_iterator ret = *this;
74  operator++();
75  return ret;
76  }
77  count_iterator operator--(int){
78  count_iterator ret = *this;
79  operator--();
80  return ret;
81  }
82  count_iterator operator+(INT n) const { return count_iterator(cur_+n); }
83  count_iterator& operator+=(INT n) { cur_ +=n; return *this; }
84  count_iterator operator-(INT n) const { return count_iterator(cur_-n); }
85  count_iterator& operator-(INT n) { cur_ -= n; return *this; }
86  INT operator-(count_iterator&rhs) const { return cur_-rhs.cur_; }
87 
88  INT& operator*() { return cur_; }
89  const INT& operator*() const { return cur_; }
90 
91  bool operator!=( count_iterator rhs ) const {
92  return cur_ != rhs.cur_;
93  }
94  bool operator==( count_iterator rhs ) const {
95  return !operator!=(rhs);
96  }
97 };
98 
99 template<typename INT>
100 count_iterator<INT> operator+(INT n, count_iterator<INT> rhs) { return count_iterator<INT>(rhs.cur_+n); }
101 template<int depth> struct set_map_{
102  static void apply( int offset, int lda[], int lh[][2],
103  const std::vector<std::size_t>& displs, std::vector<std::size_t>& map ) {
104  for( int i=lh[depth][0]; i<lh[depth][1]; ++i )
105  set_map_<depth-1>::apply( offset+i*lda[depth], lda, lh, displs, map );
106  }
107 };
108 template<> struct set_map_<0>{
109  static void apply( int offset, int[] , int lh[][2],
110  const std::vector<std::size_t>& displs, std::vector<std::size_t>& map ) {
111  typedef count_iterator<std::size_t> iter;
112  map.insert(map.end(), iter(displs[offset+lh[0][0]]), iter(displs[offset+lh[0][1]]));
113  }
114 };
115 }
116 
117 template<typename T, typename CONFIG>
118 struct bin_range;
119 
120 template<typename T,typename CONFIG>
121 struct bin_iterator : std::iterator<std::forward_iterator_tag,std::pair<typename CONFIG::point_type,T> > {
122  using P = std::pair<typename CONFIG::point_type,T>;
123  static const int D = CONFIG::D;
124  bin_iterator( const bin_range<T,CONFIG>& range_ );
125  explicit bin_iterator( const bin_range<T,CONFIG>& range_, int) : range(range_) { invalidate(); }
126  bin_iterator( const bin_iterator& ) = default;
127  bin_iterator& operator=( const bin_iterator& ) = default;
128 
129  inline bin_iterator& operator++();
130  inline bin_iterator operator++( int ){
131  bin_iterator other = *this;
132  this->operator++();
133  return other;
134  }
135 
136  inline void invalidate();
137  inline void validate();
138  inline bool operator!=( const bin_iterator& rhs ) const { return index != rhs.index; }
139  inline bool operator==( const bin_iterator& rhs ) const { return !(this->operator!=(rhs)); }
140 
141  inline const P& operator*() const;
142  inline const P* operator->() const;
143 
145  int count[D-1];
146  std::size_t high;
147  std::size_t index;
148 };
149 
150 template<typename T, typename CONFIG>
151 struct bin_range {
152  using P = std::pair<typename CONFIG::point_type,T>;
153  static const int D = CONFIG::D;
155  iterator begin() const { return iterator(*this); }
156  iterator end() const { return iterator(*this,0); }
157 
158  bin_range( int lda_[], int lh_[][2], const std::vector<std::size_t>& d_, const std::vector<P>& v_ )
159  : displs(d_), value(v_) {
160  for( int i=0; i<D; ++i ){
161  lda[i] = lda_[i];
162  lh[i][0] = lh_[i][0];
163  lh[i][1] = lh_[i][1];
164  }
165  }
166  bin_range(const bin_range&) = default;
167  bin_range& operator=(const bin_range&) = default;
168 
169  int lda[D];
170  int lh[D][2];
171  const std::vector<std::size_t>& displs;
172  const std::vector<P>& value;
173 };
174 
175 template<typename T, typename CONFIG>
177 {
178  for( int i=0; i<D-1; ++i ) count[i] = range.lh[i+1][0];
179  validate();
180 }
181 template<typename T, typename CONFIG>
183 {
184  if( ++index == high ){
185  int i=0;
186  for( ; i<D-2; ++i ){
187  if( ++count[i] != range.lh[i+1][1] ) goto VALIDATE;
188  count[i] = range.lh[i+1][0];
189  }
190  ++count[i];
191  VALIDATE:
192  validate();
193  }
194  return *this;
195 }
196 template<typename T, typename CONFIG>
198 {
199  std::size_t offset = 0;
200  for( int i=0; i<D-1; ++i ) offset += range.lda[i+1]*(range.lh[i+1][1]-1);
201  index = high = range.displs[offset+range.lh[0][1]];
202 }
203 template<typename T, typename CONFIG>
205 {
206  if( count[D-2] == range.lh[D-1][1] ) return;
207  std::size_t offset = 0;
208  for( int i=0; i<D-1; ++i ) offset += range.lda[i+1]*count[i];
209  index = range.displs[offset+range.lh[0][0]];
210  high = range.displs[offset+range.lh[0][1]];
211 }
212 
213 template<typename T, typename CONFIG>
214 inline const typename bin_iterator<T,CONFIG>::P& bin_iterator<T,CONFIG>::operator*() const { return range.value[index]; }
215 template<typename T, typename CONFIG>
216 inline const typename bin_iterator<T,CONFIG>::P* bin_iterator<T,CONFIG>::operator->() const { return std::addressof(range.value[index]); }
217 
218 
219 template<typename CONFIG>
220 struct bin_t {
221 private:
222  using point_type = typename CONFIG::point_type;
223  static const int D = CONFIG::D;
224  static const bool QUIET = CONFIG::QUIET;
225 
226  std::vector<std::size_t> displs;
227  // sorted[displs[i]] is the first element of the i-th bin
228 
229  point_type min, max;
230  std::size_t n[CONFIG::D];
231  typename CONFIG::REAL h;
232  using REAL = typename CONFIG::REAL;
233 public:
234  template<typename T>
235  bin_t( std::vector<std::pair<point_type,T> >& val ){
236  if( val.empty() ){
237  displs.resize(2,0);
238  h = 1.0;
239  return;
240  }
241 
242  // calculate h & n
243  min = max = val[0].first;
244  for( std::size_t i=1; i<val.size(); ++i ){
245  point_type p = val[i].first;
246  for( std::size_t i=0; i<D; ++i ) {
247  min[i] = std::min(min[i],p[i]);
248  max[i] = std::max(max[i],p[i]);
249  }
250  }
251 
252  size_t zero_count=0;
253  REAL vol = std::abs(max[0]-min[0]);
254  if(almost_equal(vol, static_cast<REAL>(0))) { // check if first dimension is zero size, if so set to 1
255  vol = 1.0;
256  zero_count++;
257  }
258 
259  REAL vol_multi = vol;
260  for( int i=1; i<D; ++i ){
261  vol_multi = max[i]-min[i];
262  if(almost_equal(vol_multi, static_cast<REAL>(0))) { // check if other dimensions are zero size, if so set them to 1
263  vol_multi = static_cast<REAL>(1);
264  zero_count++;
265  }
266  vol *= vol_multi;
267  }
268 
269  if (zero_count == D) // if each dimension was actually zero (rather than just a subset) then set vol to zero
270  vol = static_cast<REAL>(0);
271 
272  h = std::pow(static_cast<REAL>(6)*vol/static_cast<REAL>(val.size()),1.0/D); // about 6 points per bin
273 
274  if(almost_equal(h, static_cast<REAL>(0))){ // if h is still zero (only in the case of all dimensions being zero) then warn the user as this may be a problem
275  h = static_cast<REAL>(1); // in this special case set h to 1 arbitrarily so bins work numerically
276  if(val.size() > 1 && !QUIET)
277  std::cout << "MUI Warning [bin.h]: Bin support size fixed to 1.0, check interface dimensionality or problem decomposition." << std::endl;
278  }
279 
280  std::size_t nn=1;
281  for( int i=0; i<D; ++i ) {
282  n[i] = static_cast<size_t>(std::ceil((max[i]-min[i])/h));
283  n[i] = static_cast<size_t>(std::max( n[i], std::size_t(1) ));
284  nn *= n[i];
285  }
286 
287  // make index
288  std::vector<std::size_t> index(val.size()+1,0);
289  std::vector<std::size_t> counts(nn,0);
290  for( std::size_t i=0; i<val.size(); ++i ) {
291  index[i] = get_index_(val[i].first);
292  ++counts[index[i]];
293  }
294  displs.resize(nn+1,0); // add 1 for sentinel
295  std::partial_sum(counts.begin(),counts.end(), displs.begin()+1);
296 
297  counts = displs;
298  std::vector<std::pair<point_type,T> > v(val.size());
299  for( std::size_t i=0; i<val.size(); ++i ) v[counts[index[i]]++] = val[i];
300  v.swap(val);
301  }
302 
303  std::vector<std::size_t> query( const geometry::box<CONFIG>& bx ) const {
304  std::vector<std::size_t> map;
305  int lda[D];
306  int lh[D][2];
307  if( initialize_query_(bx,lda,lh) ) return map;
308  map.reserve(lda[D-1]*12);
309  set_map_<D-1>::apply( 0, lda, lh, displs, map );
310  return map;
311  }
312 
313  template<typename T>
314  bin_range<T,CONFIG> query2( const geometry::box<CONFIG>& bx, const std::vector<std::pair<point_type,T> >& v ) const {
315  int lda[D];
316  int lh[D][2];
317  initialize_query_(bx,lda,lh);
318  return bin_range<T,CONFIG>{lda,lh,displs,v};
319  }
320 
321  REAL domain_size() {
322  REAL dim_size = norm(max-min);
323  // Special case if domain only contains a single point
324  if(dim_size == 0) dim_size = 1.0;
325  return dim_size;
326  }
327 
328 private:
329  bool initialize_query_( const geometry::box<CONFIG>& bx, int lda[], int lh[][2] ) const {
330  bool broken = false;
331  lda[0] = 1;
332  for( int i=1; i<CONFIG::D; ++i ) lda[i] = lda[i-1]*n[i-1];
333  for( int i=0; i<CONFIG::D; ++i ) {
334  lh[i][0] = static_cast<int>(std::max(std::floor((bx.get_min()[i]-min[i])/h),typename CONFIG::REAL(0)));
335  lh[i][1] = static_cast<int>(std::min(std::ceil((bx.get_max()[i]-min[i])/h),typename CONFIG::REAL(n[i])));
336  if( lh[i][0] >= lh[i][1] ){
337  lh[i][0] = lh[i][1];
338  broken = true;
339  }
340  }
341  return broken;
342  }
343 
344  inline std::size_t get_index_( const point_type& pt ) const {
345  std::size_t m = 1, ret=0;
346  for( int i=0; i<D; ++i ) {
347  std::size_t d = static_cast<size_t>((std::floor((pt[i]-min[i])/h)));
348  d = static_cast<size_t>(std::min(d,n[i]-1)); // the values may change here if (max[i]-min[i])/h is equal to a integer value.
349  ret += m*d;
350  m *= n[i];
351  }
352  return ret;
353  }
354 };
355 
356 }
357 #endif
INT cur_
Definition: bin.h:59
Definition: geometry.h:188
coordinate_type get_min() const
Definition: geometry.h:202
coordinate_type get_max() const
Definition: geometry.h:204
u u u u u u min
Definition: dim.h:289
u u m
Definition: dim.h:281
Definition: comm.h:54
bool almost_equal(T x, T y)
Definition: util.h:128
vexpr_sub< E1, E2, SCALAR, D > operator-(vexpr< E1, SCALAR, D > const &u, vexpr< E2, SCALAR, D > const &v)
Definition: point.h:290
vexpr_add< E1, E2, SCALAR, D > operator+(vexpr< E1, SCALAR, D > const &u, vexpr< E2, SCALAR, D > const &v)
Definition: point.h:285
vexpr_mul< E1, E2, SCALAR, D > operator*(vexpr< E1, SCALAR, D > const &u, vexpr< E2, SCALAR, D > const &v)
Definition: point.h:300
SCALAR max(vexpr< E, SCALAR, D > const &u)
Definition: point.h:350
vexpr_apply1< E, OP, SCALAR, D > apply(vexpr< E, SCALAR, D > const &u, OP const &op)
Definition: point.h:392
SCALAR norm(vexpr< E, SCALAR, D > const &u)
Definition: point.h:386
Definition: bin.h:121
const P & operator*() const
Definition: bin.h:214
bool operator==(const bin_iterator &rhs) const
Definition: bin.h:139
bin_iterator(const bin_range< T, CONFIG > &range_, int)
Definition: bin.h:125
bin_iterator operator++(int)
Definition: bin.h:130
const bin_range< T, CONFIG > & range
Definition: bin.h:144
const P * operator->() const
Definition: bin.h:216
bin_iterator & operator=(const bin_iterator &)=default
std::pair< typename CONFIG::point_type, T > P
Definition: bin.h:122
std::size_t index
Definition: bin.h:147
int count[D-1]
Definition: bin.h:145
void invalidate()
Definition: bin.h:197
bool operator!=(const bin_iterator &rhs) const
Definition: bin.h:138
bin_iterator & operator++()
Definition: bin.h:182
std::size_t high
Definition: bin.h:146
static const int D
Definition: bin.h:123
bin_iterator(const bin_range< T, CONFIG > &range_)
Definition: bin.h:176
void validate()
Definition: bin.h:204
bin_iterator(const bin_iterator &)=default
Definition: bin.h:151
const std::vector< std::size_t > & displs
Definition: bin.h:171
int lh[D][2]
Definition: bin.h:170
bin_range(const bin_range &)=default
int lda[D]
Definition: bin.h:169
static const int D
Definition: bin.h:153
iterator begin() const
Definition: bin.h:155
bin_range(int lda_[], int lh_[][2], const std::vector< std::size_t > &d_, const std::vector< P > &v_)
Definition: bin.h:158
iterator end() const
Definition: bin.h:156
const std::vector< P > & value
Definition: bin.h:172
bin_range & operator=(const bin_range &)=default
bin_iterator< T, CONFIG > iterator
Definition: bin.h:154
std::pair< typename CONFIG::point_type, T > P
Definition: bin.h:152
Definition: bin.h:220
REAL domain_size()
Definition: bin.h:321
bin_t(std::vector< std::pair< point_type, T > > &val)
Definition: bin.h:235
std::vector< std::size_t > query(const geometry::box< CONFIG > &bx) const
Definition: bin.h:303
bin_range< T, CONFIG > query2(const geometry::box< CONFIG > &bx, const std::vector< std::pair< point_type, T > > &v) const
Definition: bin.h:314