~ubuntu-branches/ubuntu/saucy/rheolef/saucy

« back to all changes in this revision

Viewing changes to nfem/plib/level_set.cc

  • Committer: Package Import Robot
  • Author(s): Pierre Saramito, Pierre Saramito, Sylvestre Ledru
  • Date: 2012-05-14 14:02:09 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120514140209-dzbdlidkotyflf9e
Tags: 6.1-1
[ Pierre Saramito ]
* New upstream release 6.1 (minor changes):
  - support arbitrarily polynomial order Pk
  - source code supports g++-4.7 (closes: #671996)

[ Sylvestre Ledru ]
* update of the watch file

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
///
 
2
/// This file is part of Rheolef.
 
3
///
 
4
/// Copyright (C) 2000-2009 Pierre Saramito <Pierre.Saramito@imag.fr>
 
5
///
 
6
/// Rheolef is free software; you can redistribute it and/or modify
 
7
/// it under the terms of the GNU General Public License as published by
 
8
/// the Free Software Foundation; either version 2 of the License, or
 
9
/// (at your option) any later version.
 
10
///
 
11
/// Rheolef is distributed in the hope that it will be useful,
 
12
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
/// GNU General Public License for more details.
 
15
///
 
16
/// You should have received a copy of the GNU General Public License
 
17
/// along with Rheolef; if not, write to the Free Software
 
18
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
/// 
 
20
/// =========================================================================
 
21
/// Banded level set routines 
 
22
///
 
23
/// Authors: Lara Aborm, Jocelyn Etienne, Pierre Saramito
 
24
///
 
25
#include "rheolef/level_set.h"
 
26
namespace rheolef {
 
27
 
 
28
// --------------------------------------------------------------------------------
 
29
// gestion de la numerotation locale
 
30
// --------------------------------------------------------------------------------
 
31
// TODO: move in reference_element
 
32
static
 
33
size_t
 
34
edge_t_iloc (size_t l, size_t m)
 
35
{
 
36
  static const int edge_t_iloc_table [3][3] = { 
 
37
                            {-1, 0, 2},
 
38
                            { 0,-1, 1},
 
39
                            { 2, 1,-1}};
 
40
  return size_t(edge_t_iloc_table [l][m]);
 
41
}
 
42
static
 
43
size_t
 
44
edge_T_iloc (size_t l, size_t m)
 
45
{
 
46
  static const int edge_T_iloc_table [4][4] = {
 
47
                            {-1, 0, 2, 3},
 
48
                            { 0,-1, 1, 4},
 
49
                            { 2, 1,-1, 5},
 
50
                            { 3, 4, 5,-1}};
 
51
  return size_t(edge_T_iloc_table [l][m]);
 
52
}
 
53
static
 
54
size_t
 
55
face_T_iloc (size_t l, size_t m, size_t n)
 
56
{
 
57
  static size_t face_T_iloc_table [4][4][4];
 
58
  bool static initialized = false;
 
59
  if (!initialized) {
 
60
    for (size_t i = 0; i < 4; i++) 
 
61
      for (size_t j = 0; j < 4; j++) 
 
62
        for (size_t k = 0; k < 4; k++) 
 
63
          face_T_iloc_table [i][j][k] = size_t(-1);
 
64
    reference_element hat_K (reference_element::T);
 
65
    for (size_t i_face = 0; i_face < hat_K.n_face(); i_face++) {
 
66
      size_t p[3];
 
67
      for (size_t k = 0; k < 3; k++) p[k] = hat_K.subgeo_local_vertex(2,i_face,k);
 
68
      face_T_iloc_table [p[0]][p[1]][p[2]] = i_face;
 
69
      face_T_iloc_table [p[0]][p[2]][p[1]] = i_face;
 
70
      face_T_iloc_table [p[1]][p[0]][p[2]] = i_face;
 
71
      face_T_iloc_table [p[1]][p[2]][p[0]] = i_face;
 
72
      face_T_iloc_table [p[2]][p[0]][p[1]] = i_face;
 
73
      face_T_iloc_table [p[2]][p[1]][p[0]] = i_face;
 
74
    }
 
75
  }
 
76
  return face_T_iloc_table [l][m][n];
 
77
}
 
78
// --------------------------------------------------------------------------------
 
79
// gestion de la precision
 
80
// --------------------------------------------------------------------------------
 
81
static Float level_set_epsilon = 100*std::numeric_limits<Float>::epsilon();
 
82
 
 
83
template <class T>
 
84
static
 
85
bool
 
86
is_zero (const T& x) {
 
87
  // TODO: control by level_set_option_type ?
 
88
  return fabs(x) <= level_set_epsilon;
 
89
}
 
90
template <class T>
 
91
static
 
92
bool
 
93
have_same_sign (const T& x, const T& y) {
 
94
  using namespace details;
 
95
  return !is_zero(x) && !is_zero(y) && x*y > 0;
 
96
}
 
97
template <class T>
 
98
static
 
99
bool
 
100
have_opposite_sign (const T& x, const T& y) {
 
101
  using namespace details;
 
102
  return !is_zero(x) && !is_zero(y) && x*y < 0;
 
103
}
 
104
// --------------------------------------------------------------------------------
 
105
// 2D: fonctions locales : sur un seul element triangle
 
106
// --------------------------------------------------------------------------------
 
107
// appele lors du 1er passage qui liste les elements de la bande cas de dimension 2
 
108
template <class T>
 
109
static
 
110
bool
 
111
belongs_to_band_t (const std::vector<T>& f) {
 
112
  using namespace details;
 
113
  if (have_same_sign(f[0],f[1]) && have_same_sign(f[0],f[2])) return false;
 
114
  // on rejette le triangle dans tous les sommets de meme signe :
 
115
  if (is_zero(f[0]) && is_zero(f[1]) && is_zero(f[2])) return false;
 
116
  // on rejette les triangles dont un sommet :
 
117
  if (is_zero(f[0]) && have_same_sign(f[1],f[2])) return false;
 
118
  if (is_zero(f[1]) && have_same_sign(f[0],f[2])) return false;
 
119
  if (is_zero(f[2]) && have_same_sign(f[0],f[1])) return false;
 
120
  return true;
 
121
}
 
122
// apellee lors du calcul des matrices M_K et A_K pour K dans la bande cas de dimension 2
 
123
template <class T>
 
124
static
 
125
size_t
 
126
isolated_vertex_t (const std::vector<T>& f)
 
127
{
 
128
  using namespace details;
 
129
  /* on retourne le sommet isole a chaque fois */
 
130
  if (have_same_sign    (f[0],f[1]) && have_opposite_sign(f[0],f[2]))  return 2;
 
131
  if (have_opposite_sign(f[0],f[1]) && have_same_sign    (f[0],f[2]))  return 1;
 
132
  if (have_opposite_sign(f[0],f[1]) && have_opposite_sign(f[0],f[2]))  return 0;
 
133
  if (is_zero(f[0])                 && have_opposite_sign(f[1],f[2]))  return 1; /* on peut retourner 2 de meme*/
 
134
 
 
135
  if (is_zero(f[1]) && have_opposite_sign(f[0],f[2]))  return 0; /* on peut retourner 2 */
 
136
  if (is_zero(f[2]) && have_opposite_sign(f[0],f[1]))  return 0; /* on peut retourner 1 */
 
137
  if (is_zero(f[0]) && is_zero(f[1]) && ! is_zero(f[2])) return 2;
 
138
  if (is_zero(f[0]) && is_zero(f[2]) && ! is_zero(f[1])) return 1;
 
139
  return 0; /* f1 == 0 et f2 == 0 et f0 != 0 */
 
140
}
 
141
template <class T>
 
142
static
 
143
void
 
144
subcompute_matrix_t (
 
145
    const std::vector<point_basic<T> >& x,
 
146
    const std::vector<T>&               f,
 
147
    std::vector<size_t>&                j,
 
148
    point_basic<T>&                     a,
 
149
    point_basic<T>&                     b,
 
150
    T&                                  S)
 
151
{
 
152
  using namespace details;
 
153
  j.resize (3);
 
154
  j[0] = isolated_vertex_t (f);
 
155
  j[1] = (j[0]+1) % 3;
 
156
  j[2] = (j[1]+1) % 3;
 
157
  // edge {j1,j2} has normal oriented as grad(f), in f>0 direction:
 
158
  if (! is_zero(f[j[0]]) && f[j[0]] < 0) std::swap (j[1], j[2]);
 
159
  T theta_1= f[j[1]]/(f[j[1]]-f[j[0]]);
 
160
  T theta_2= f[j[2]]/(f[j[2]]-f[j[0]]);
 
161
  // calcul des coordonnes díntersection
 
162
  a = theta_1*x[j[0]]+(1-theta_1)*x[j[1]];
 
163
  b = theta_2*x[j[0]]+(1-theta_2)*x[j[2]];
 
164
  S = sqrt(pow(a[0]-b[0],2)+pow(a[1]-b[1],2));
 
165
  if (is_zero(f[j[1]]) && is_zero(f[j[2]])) {
 
166
      S /= 2;
 
167
  }
 
168
}
 
169
// --------------------------------------------------------------------------------
 
170
// 3D: fonctions locales : sur un seul element tetraedre
 
171
// --------------------------------------------------------------------------------
 
172
 
 
173
class quadruplet {
 
174
public:
 
175
    quadruplet (size_t a=0, size_t b=0, size_t c=0, size_t d=0) {
 
176
        q[0]=a;
 
177
        q[1]=b;
 
178
        q[2]=c;
 
179
        q[3]=d;
 
180
    }
 
181
    size_t  operator[] (size_t i) const {
 
182
        return q[i%4];
 
183
    }
 
184
    size_t& operator[] (size_t i)       {
 
185
        return q[i%4];
 
186
    }
 
187
    friend std::ostream& operator<< (std::ostream& out, const quadruplet& q) {
 
188
        out << "((" << q[0] << "," << q[1] << "), (" << q[2] << "," << q[3] << "))";
 
189
        return out;
 
190
    }
 
191
protected:
 
192
    size_t q[4];
 
193
};
 
194
// appele lors du 1er passage qui liste les elements de la bande cas de dimension 3
 
195
template <class T>
 
196
static
 
197
bool
 
198
belongs_to_band_T (const std::vector<T>& f)
 
199
{
 
200
  using namespace details;
 
201
  if (have_same_sign(f[0],f[1]) && have_same_sign(f[0],f[2]) && have_same_sign(f[2],f[3])) return false;
 
202
  // cas ou 4 points s'annulent en dimension 3 est degenere
 
203
  if (is_zero(f[0]) && is_zero(f[1]) && is_zero(f[2]) && is_zero(f[3])) return false;
 
204
 
 
205
  if (is_zero(f[0]) && have_same_sign(f[1],f[2]) && have_same_sign(f[1],f[3])) return false;
 
206
  if (is_zero(f[1]) && have_same_sign(f[0],f[2]) && have_same_sign(f[0],f[3])) return false;
 
207
  if (is_zero(f[2]) && have_same_sign(f[0],f[1]) && have_same_sign(f[0],f[3])) return false;
 
208
  if (is_zero(f[3]) && have_same_sign(f[0],f[1]) && have_same_sign(f[0],f[2])) return false;
 
209
  // cas ou f s'annule sur 2 sommets et garde le meme signe sur les 2 autres sommets est exclu
 
210
  if (is_zero(f[0]) && is_zero(f[1]) && have_same_sign(f[2],f[3])) return false;
 
211
  if (is_zero(f[0]) && is_zero(f[2]) && have_same_sign(f[1],f[3])) return false;
 
212
  if (is_zero(f[0]) && is_zero(f[3]) && have_same_sign(f[1],f[2])) return false;
 
213
  if (is_zero(f[1]) && is_zero(f[2]) && have_same_sign(f[0],f[3])) return false;
 
214
  if (is_zero(f[1]) && is_zero(f[3]) && have_same_sign(f[0],f[2])) return false;
 
215
  if (is_zero(f[2]) && is_zero(f[3]) && have_same_sign(f[1],f[0])) return false;
 
216
  return true;
 
217
}
 
218
// apellee lors du calcul des matrices M_K et A_K pour T dans la bande cas de dimension 
 
219
template <class T>
 
220
bool
 
221
intersection_is_quadrilateral_T (const std::vector<T>& f, quadruplet& q)
 
222
{
 
223
  if (have_same_sign(f[0],f[1]) && have_opposite_sign(f[0],f[2]) && have_same_sign(f[2],f[3])) {
 
224
    if (f[0] > 0) q = quadruplet(0,1, 2,3);
 
225
    else          q = quadruplet(2,3, 0,1);
 
226
    return true;
 
227
  }
 
228
  if (have_opposite_sign(f[0],f[1]) && have_same_sign(f[0],f[2]) && have_opposite_sign(f[2],f[3])) {
 
229
    if (f[0] < 0) q = quadruplet(0,2, 1,3);
 
230
    else          q = quadruplet(1,3, 0,2);
 
231
    return true;
 
232
  }
 
233
  if (have_opposite_sign(f[0],f[1]) && have_opposite_sign(f[0],f[2]) && have_opposite_sign(f[2],f[3])) {
 
234
    if (f[0] > 0) q = quadruplet(0,3, 1,2);
 
235
    else          q = quadruplet(1,2, 0,3);
 
236
    return true;
 
237
  }
 
238
  return false;
 
239
}
 
240
// cas d'une intersection triangle:
 
241
template <class T>
 
242
static
 
243
size_t
 
244
isolated_vertex_T (const std::vector<T>& f)
 
245
{
 
246
  using namespace details;
 
247
  // cas ou l'intersection est un triangle
 
248
  if (have_opposite_sign(f[0],f[1]) && have_opposite_sign(f[0],f[2]) && have_same_sign    (f[2],f[3])) return 0;
 
249
  if (have_same_sign    (f[0],f[1]) && have_opposite_sign(f[0],f[2]) && have_opposite_sign(f[2],f[3])) return 2;
 
250
  if (have_same_sign    (f[0],f[1]) && have_same_sign    (f[0],f[2]) && have_opposite_sign(f[2],f[3])) return 3;
 
251
  // cas ou f s'annule sur un sommet et change de signe sur les 2 autres sommets
 
252
  if (have_opposite_sign(f[0],f[1]) && have_same_sign(f[0],f[2]) && have_same_sign(f[2],f[3])) return 1;
 
253
  if (is_zero(f[0]) && have_same_sign    (f[1],f[2]) && have_opposite_sign(f[1],f[3])) return 3;
 
254
  if (is_zero(f[0]) && have_opposite_sign(f[1],f[2]) && have_same_sign    (f[1],f[3])) return 2;
 
255
  if (is_zero(f[0]) && have_opposite_sign(f[1],f[2]) && have_opposite_sign(f[1],f[3])) return 1;
 
256
  if (is_zero(f[1]) && have_opposite_sign(f[0],f[2]) && have_same_sign    (f[0],f[3])) return 2;
 
257
  if (is_zero(f[1]) && have_same_sign    (f[0],f[2]) && have_opposite_sign(f[0],f[3])) return 3;
 
258
  if (is_zero(f[1]) && have_opposite_sign(f[0],f[2]) && have_opposite_sign(f[0],f[3])) return 0;
 
259
  if (is_zero(f[2]) && have_opposite_sign(f[0],f[1]) && have_same_sign    (f[0],f[3])) return 1;
 
260
  if (is_zero(f[2]) && have_same_sign    (f[0],f[1]) && have_opposite_sign(f[0],f[3])) return 3;
 
261
  if (is_zero(f[2]) && have_opposite_sign(f[0],f[1]) && have_opposite_sign(f[0],f[3])) return 0;
 
262
  if (is_zero(f[3]) && have_opposite_sign(f[0],f[1]) && have_same_sign    (f[0],f[2])) return 1;
 
263
  if (is_zero(f[3]) && have_same_sign    (f[0],f[1]) && have_opposite_sign(f[0],f[2])) return 2;
 
264
  if (is_zero(f[3]) && have_opposite_sign(f[0],f[1]) && have_opposite_sign(f[0],f[2])) return 0;
 
265
  // cas ou f s'annule en 2 sommets et change de signe sur les 2 autres sommets
 
266
  if (is_zero(f[0]) && is_zero(f[1]) && have_opposite_sign(f[2],f[3])) return 2; // ou 3
 
267
  if (is_zero(f[0]) && is_zero(f[2]) && have_opposite_sign(f[1],f[3])) return 1;
 
268
  if (is_zero(f[0]) && is_zero(f[3]) && have_opposite_sign(f[1],f[2])) return 1;
 
269
  if (is_zero(f[1]) && is_zero(f[2]) && have_opposite_sign(f[0],f[3])) return 0;
 
270
  if (is_zero(f[1]) && is_zero(f[3]) && have_opposite_sign(f[0],f[2])) return 0;
 
271
  if (is_zero(f[2]) && is_zero(f[3]) && have_opposite_sign(f[0],f[1])) return 0;
 
272
 
 
273
  // le triangle d'intersection est la face du tetradre ou f s'annule sur les 3 sommets
 
274
  if (is_zero(f[0]) && is_zero(f[1]) && is_zero(f[2]) && ! is_zero(f[3])) return 3;
 
275
  if (is_zero(f[0]) && is_zero(f[1]) && is_zero(f[3]) && ! is_zero(f[2])) return 2;
 
276
  if (is_zero(f[1]) && is_zero(f[2]) && is_zero(f[3]) && ! is_zero(f[0])) return 0;
 
277
  return 1;
 
278
}
 
279
template <class T>
 
280
static
 
281
void
 
282
subcompute_matrix_triangle_T (
 
283
  const std::vector<point_basic<T> >& x,
 
284
  const std::vector<T>&               f,
 
285
  std::vector<size_t>&                j,
 
286
  point_basic<T>&                     a,
 
287
  point_basic<T>&                     b,
 
288
  point_basic<T>&                     c,
 
289
  T&                                  aire)
 
290
{
 
291
  using namespace details;
 
292
  j.resize(4);
 
293
  j[0] = isolated_vertex_T (f);
 
294
  j[1] = (j[0]+1) % 4;
 
295
  j[2] = (j[1]+1) % 4;
 
296
  j[3] = (j[2]+1) % 4;
 
297
  // orient
 
298
  if (! is_zero(f[j[0]]) && ((f[j[0]] > 0 && j[0] % 2 == 0) || (f[j[0]] < 0 && j[0] % 2 == 1))) 
 
299
    std::swap (j[1], j[2]);
 
300
  T theta_1 = f[j[1]]/(f[j[1]]-f[j[0]]);
 
301
  T theta_2 = f[j[2]]/(f[j[2]]-f[j[0]]);
 
302
  T theta_3 = f[j[3]]/(f[j[3]]-f[j[0]]);
 
303
 
 
304
  /* calcul des coordonnees d'intersection */
 
305
  a = theta_1*x[j[0]]+(1-theta_1)*x[j[1]];
 
306
  b = theta_2*x[j[0]]+(1-theta_2)*x[j[2]];
 
307
  c = theta_3*x[j[0]]+(1-theta_3)*x[j[3]];
 
308
  aire = 0.5* norm (vect( b-a, c-a));
 
309
  if (is_zero(f[j[1]]) && is_zero(f[j[2]]) && is_zero(f[j[3]])) {
 
310
    aire /= 2;
 
311
  }
 
312
}
 
313
template <class T>
 
314
static
 
315
void
 
316
subcompute_matrix_quadrilateral_T (
 
317
    const std::vector<point_basic<T> >& x,
 
318
    const std::vector<T>&               f,
 
319
    const quadruplet&                   q,
 
320
    point_basic<T>&                     a,
 
321
    point_basic<T>&                     b,
 
322
    point_basic<T>&                     c,
 
323
    point_basic<T>&                     d,
 
324
    T&                                  aire_Q)
 
325
{
 
326
    // intersection:
 
327
    // a = segment {x(q0) x(q2)} inter {f=0}
 
328
    // b = segment {x(q1) x(q2)} inter {f=0}
 
329
    // d = segment {x(q1) x(q3)} inter {f=0}
 
330
    // c = segment {x(q0) x(q3)} inter {f=0}
 
331
    // quadrilatere abdc = triangle(abd) union triangle(adc)
 
332
    T theta_1 = f[q[2]]/(f[q[2]]-f[q[0]]);
 
333
    T theta_2 = f[q[2]]/(f[q[2]]-f[q[1]]);
 
334
    T theta_3 = f[q[3]]/(f[q[3]]-f[q[0]]);
 
335
    T theta_4 = f[q[3]]/(f[q[3]]-f[q[1]]);
 
336
    /* calcul des coordonnees d'intersection */
 
337
    a = theta_1*x[q[0]]+(1-theta_1)*x[q[2]];
 
338
    b = theta_2*x[q[1]]+(1-theta_2)*x[q[2]];
 
339
    c = theta_3*x[q[0]]+(1-theta_3)*x[q[3]];
 
340
    d = theta_4*x[q[1]]+(1-theta_4)*x[q[3]];
 
341
    aire_Q = 0.5*norm(vect(a-c,a-b)) + 0.5*norm(vect(d-c,d-b));
 
342
}
 
343
// --------------------------------------------------------------------------------
 
344
// level_set: compte the intersection mesh
 
345
// --------------------------------------------------------------------------------
 
346
typedef geo_element_auto<heap_allocator<geo_element::size_type> > element_type;
 
347
 
 
348
template <class T, class M>
 
349
void
 
350
gamma_list2array (
 
351
  const std::list<point_basic<T> >&            gamma_node_list,
 
352
  boost::array<std::list<std::pair<element_type,size_t> >, 
 
353
               reference_element::max_variant> gamma_side_list,
 
354
  const communicator&               comm,
 
355
  size_t                            d,
 
356
  array<point_basic<T>, M>&                     gamma_node,
 
357
  boost::array<array<element_type,M>,
 
358
               reference_element::max_variant>& gamma_side,
 
359
  array<size_t,M>&                              sid_ie2bnd_ie)
 
360
{
 
361
  typedef geo_element::size_type size_type;
 
362
  // 1) nodes:
 
363
  size_type nnod = gamma_node_list.size();
 
364
  distributor gamma_node_ownership (distributor::decide, comm, nnod);
 
365
  gamma_node.resize (gamma_node_ownership);
 
366
  typename array<point_basic<T>, M>::iterator node_iter = gamma_node.begin();
 
367
  for (typename std::list<point_basic<T> >::const_iterator
 
368
        iter = gamma_node_list.begin(),
 
369
        last = gamma_node_list.end();
 
370
        iter != last; iter++, node_iter++) {
 
371
    *node_iter = *iter;
 
372
  }
 
373
  // 2) sides:
 
374
  heap_allocator<size_type> alloc;
 
375
  size_type map_dim = d-1;
 
376
  size_type order = 1;
 
377
  size_type nsid = 0;
 
378
  for (size_type variant = reference_element::first_variant_by_dimension(map_dim);
 
379
                 variant < reference_element:: last_variant_by_dimension(map_dim); variant++) {
 
380
    size_type nsidv = gamma_side_list [variant].size();
 
381
    distributor gamma_sidv_ownership (distributor::decide, comm, nsidv);
 
382
    nsid += nsidv;
 
383
    element_type element_init (variant, order, alloc);
 
384
    gamma_side[variant].resize (gamma_sidv_ownership, element_init);
 
385
    typename array<element_type, M>::iterator side_iter = gamma_side[variant].begin();
 
386
    for (typename std::list<std::pair<element_type,size_type> >::const_iterator
 
387
          iter = gamma_side_list[variant].begin(),
 
388
          last = gamma_side_list[variant].end();
 
389
          iter != last; iter++, side_iter++) {
 
390
      *side_iter = (*iter).first;
 
391
    }
 
392
  }
 
393
  // 3) side2band correspondance
 
394
  distributor gamma_sid_ownership (distributor::decide, comm, nsid);
 
395
  const size_type undef      = std::numeric_limits<size_t>::max();
 
396
  sid_ie2bnd_ie.resize (gamma_sid_ownership, undef);
 
397
  typename array<size_type, M>::iterator idx_iter = sid_ie2bnd_ie.begin();
 
398
  for (size_type variant = reference_element::first_variant_by_dimension(map_dim);
 
399
                 variant < reference_element:: last_variant_by_dimension(map_dim); variant++) {
 
400
    for (typename std::list<std::pair<element_type,size_type> >::const_iterator
 
401
          iter = gamma_side_list[variant].begin(),
 
402
          last = gamma_side_list[variant].end();
 
403
          iter != last; iter++, idx_iter++) {
 
404
      *idx_iter = (*iter).second;
 
405
    }
 
406
  }
 
407
}
 
408
#ifdef TO_CLEAN
 
409
template <class T, class M>
 
410
void
 
411
gamma_dump (
 
412
  const array<point_basic<T>, M>&         gamma_node,
 
413
  const boost::array<array<element_type,M>, reference_element::max_variant>& gamma_side,
 
414
  size_t                                  d)
 
415
{
 
416
  using namespace std;
 
417
  typedef geo_element::size_type size_type;
 
418
  dout << "mesh" << endl
 
419
       << "4" << endl
 
420
       << "header" << endl
 
421
       << " dimension " << d << endl
 
422
       << " nodes  " << gamma_node.dis_size() << endl;
 
423
  if (d == 3) {
 
424
    if (gamma_side[reference_element::t].dis_size()!= 0) {
 
425
      dout << " triangles "   << gamma_side[reference_element::t].dis_size() << endl;
 
426
    }
 
427
    if (gamma_side[reference_element::q].dis_size()!= 0) {
 
428
      dout << " quadrangles " << gamma_side[reference_element::q].dis_size() << endl;
 
429
    }
 
430
  } else {
 
431
    dout << " edges " << gamma_side[reference_element::e].dis_size() << endl;
 
432
  }
 
433
  dout << "end header" << endl
 
434
       << endl
 
435
       << setprecision(7); // avoid non-regr test to depend upon mach prec
 
436
  gamma_node.put_values (dout, _point_put<T>(d));
 
437
  dout << endl;
 
438
  size_type map_dim = d-1;
 
439
  for (size_type variant = reference_element::first_variant_by_dimension(map_dim);
 
440
                 variant < reference_element:: last_variant_by_dimension(map_dim); variant++) {
 
441
    dout << gamma_side [variant];
 
442
  }
 
443
}
 
444
#endif // TO_CLEAN
 
445
struct to_solve {
 
446
  size_t variant, S_ige, k, dis_i;
 
447
  to_solve (size_t variant1, size_t S_ige1=0, size_t k1=0, size_t dis_i1=0) 
 
448
   : variant(variant1), S_ige(S_ige1), k(k1), dis_i(dis_i1) {}
 
449
};
 
450
template <class T, class M>
 
451
geo_basic<T,M>
 
452
level_set_internal (
 
453
    const field_basic<T,M>&      fh,
 
454
    const level_set_option_type& opt,
 
455
    std::vector<size_t>&         bnd_dom_ie_list,
 
456
    array<size_t,M>&             sid_ie2bnd_ie)
 
457
{
 
458
  using namespace std;
 
459
  using namespace details;
 
460
  typedef geo_element::size_type size_type;
 
461
  level_set_epsilon = opt.epsilon; // set global variable
 
462
  fh.dis_dof_update();
 
463
  const geo_basic<T,M>&   lambda = fh.get_geo();
 
464
  const space_basic<T,M>& Xh     = fh.get_space();
 
465
  check_macro(lambda.order() == 1,        "Only order=1 level set mesh supported");
 
466
  check_macro(fh.get_approx() == "P1", "Only P1 level set function supported");
 
467
  size_type order = 1;
 
468
  std::vector<size_type> dis_idof;
 
469
  std::vector<T>     f;
 
470
  size_type d = lambda.dimension();
 
471
  size_type map_dim = d-1;
 
472
  heap_allocator<size_type> alloc;
 
473
  boost::array<list<pair<element_type,size_type> >, 
 
474
               reference_element::max_variant> gamma_side_list;
 
475
  list<point_basic<T> >                        gamma_node_list;
 
476
  std::vector<size_type>       j(d+1);
 
477
  std::vector<point_basic<T> > x(d+1);
 
478
  const size_type not_marked = numeric_limits<size_t>::max();
 
479
  const size_type undef      = numeric_limits<size_t>::max();
 
480
 
 
481
  distributor                 node_ownership = lambda.sizes().node_ownership;
 
482
  size_type                   first_dis_inod = node_ownership.first_index();
 
483
  array<size_type>            marked_node (node_ownership, not_marked);
 
484
  array<size_type>            extern_node (node_ownership, not_marked);
 
485
  set<size_type>              ext_marked_node_idx;
 
486
  list<to_solve>              node_to_solve;
 
487
 
 
488
  distributor                 edge_ownership = lambda.sizes().ownership_by_dimension[1];
 
489
  size_type                   first_dis_iedg = edge_ownership.first_index();
 
490
  array<size_type>            marked_edge      (edge_ownership, not_marked);
 
491
  array<std::pair<size_type,point_basic<T> > > 
 
492
                              extern_edge      (edge_ownership, std::make_pair(not_marked,point_basic<T>()));
 
493
  set<size_type>              ext_marked_edge_idx;
 
494
  list<to_solve>              edge_to_solve;
 
495
 
 
496
  distributor                 face_ownership = lambda.sizes().ownership_by_dimension[2];
 
497
  size_type                   first_dis_ifac = face_ownership.first_index();
 
498
  array<size_type>            marked_face (face_ownership, not_marked);
 
499
 
 
500
  communicator comm = node_ownership.comm();
 
501
  size_type my_proc = comm.rank();
 
502
 
 
503
  bnd_dom_ie_list.resize(0);
 
504
 
 
505
  // ------------------------------------------------------------
 
506
  // 1) loop on lambda & build intersection sides
 
507
  // ------------------------------------------------------------
 
508
  for (size_type ie = 0, ne = lambda.size(), bnd_ie = 0; ie < ne; ie++) {
 
509
    // ---------------------------------------------------------
 
510
    // 1.1) fast check if there is an intersection:
 
511
    // ---------------------------------------------------------
 
512
    const geo_element& K = lambda [ie];
 
513
    Xh.dis_idof (K, dis_idof);
 
514
    f.resize (dis_idof.size());
 
515
    for (size_type loc_idof = 0, loc_ndof = dis_idof.size(); loc_idof < loc_ndof; loc_idof++) {
 
516
      f [loc_idof] = fh.dis_dof (dis_idof[loc_idof]);
 
517
    }
 
518
    bool do_intersect = false;
 
519
    switch (K.variant()) {
 
520
      case reference_element::t:
 
521
        do_intersect = belongs_to_band_t (f);
 
522
        break;
 
523
      case reference_element::T: {
 
524
        do_intersect = belongs_to_band_T (f);
 
525
        break;
 
526
      }
 
527
      default :
 
528
        error_macro("level set: element type `" << K.name() << "' not yet supported");
 
529
    }
 
530
    if (! do_intersect) continue;
 
531
    bnd_dom_ie_list.push_back (ie);
 
532
    // ---------------------------------------------------------
 
533
    // 1.2) compute the intersection
 
534
    // ---------------------------------------------------------
 
535
    x.resize   (dis_idof.size());
 
536
    for (size_type loc_idof = 0, loc_ndof = dis_idof.size(); loc_idof < loc_ndof; loc_idof++) {
 
537
      size_type loc_inod = loc_idof; // assume here that fh has an isoparametric approx
 
538
      size_type dis_inod = K [loc_inod];
 
539
      x [loc_idof] = lambda.dis_node(dis_inod);
 
540
    }
 
541
    element_type S (alloc);
 
542
    switch (K.variant()) {
 
543
      case reference_element::t: {
 
544
        // ---------------------------------------------------------
 
545
        // 1.2.a) triangle -> 1 edge
 
546
        // ---------------------------------------------------------
 
547
        point_basic<T> a, b;
 
548
        T length;
 
549
        subcompute_matrix_t (x, f, j, a, b, length);
 
550
        if (is_zero(f[j[1]]) && is_zero(f[j[2]])) {
 
551
          // ---------------------------------------------------------
 
552
          // 1.2.a.1) edge {j1,j2} is included in the bbox mesh
 
553
          // ---------------------------------------------------------
 
554
          for (size_type k = 0; k < 2; k++) {
 
555
            size_type dis_inod = K[j[k+1]];
 
556
            if (node_ownership.is_owned (dis_inod)) {
 
557
              size_type inod = dis_inod - first_dis_inod;
 
558
              if (marked_node [inod] == not_marked) {
 
559
                marked_node [inod] = gamma_node_list.size();
 
560
                gamma_node_list.push_back (lambda.node(inod));
 
561
              }
 
562
            } else {
 
563
              // dis_inod is owned by another partition jproc:
 
564
              // if there is another neighbour element K' from the same partition jproc
 
565
              //     then jproc will insert dis_inod in gamma
 
566
              //     so, there is nothing to do here
 
567
              // otherwise, dis_inod will be orphan in jproc and will be re-affected to my_proc
 
568
              extern_node.dis_entry (dis_inod) = my_proc;
 
569
            }
 
570
          }
 
571
          size_type loc_iedg = edge_t_iloc (j[1], j[2]);
 
572
          size_type dis_iedg = K.edge (loc_iedg);
 
573
          if (edge_ownership.is_owned (dis_iedg)) {
 
574
            size_type iedg = dis_iedg - first_dis_iedg;
 
575
            if (marked_edge [iedg] == not_marked) {
 
576
              S.reset(reference_element::e, order);
 
577
              marked_edge [iedg] = gamma_side_list [S.variant()].size();
 
578
              size_type S_ige = marked_edge [iedg];
 
579
              for (size_type k = 0; k < S.n_node(); k++) {
 
580
                size_type dis_inod = K[j[k+1]];
 
581
                if (node_ownership.is_owned (dis_inod)) {
 
582
                  size_type inod = dis_inod - first_dis_inod;
 
583
                  S[k] = marked_node [inod];
 
584
                } else {
 
585
                  S[k] = undef;
 
586
                  node_to_solve.push_back (to_solve (S.variant(), S_ige, k, dis_inod));
 
587
                  ext_marked_node_idx.insert (dis_inod);
 
588
                }
 
589
              }
 
590
              gamma_side_list [S.variant()].push_back (make_pair(S,bnd_ie));
 
591
            }
 
592
          } else {
 
593
            // intersection is an edge of lambda that is owned by another partition jproc
 
594
            // the neighbour element K' accross this e"dge belongs to the same partition jproc
 
595
            // and will insert dis_iedg in gamma
 
596
            // so, there is nothing to do here
 
597
          }
 
598
        } else {
 
599
          // ---------------------------------------------------------
 
600
          // 1.2.a.2) edge {j1,j2} is interior to the triangle
 
601
          // ---------------------------------------------------------
 
602
          S.reset(reference_element::e, order);
 
603
          size_type S_ige = gamma_side_list [S.variant()].size ();
 
604
          point_basic<T> xx[2] = {a,b};
 
605
          for (size_type k = 0; k < 2; k++) {
 
606
            if (! is_zero(f[j[k+1]]) && ! is_zero(f[j[0]])) {
 
607
              // xk is inside edge {j0,j[k+1]} of triangle K:
 
608
              size_type loc_iedg = edge_t_iloc (j[0], j[k+1]);
 
609
              size_type dis_iedg = K.edge (loc_iedg);
 
610
              if (edge_ownership.is_owned (dis_iedg)) {
 
611
                size_type iedg = dis_iedg - first_dis_iedg;
 
612
                if (marked_edge [iedg] == not_marked) {
 
613
                  marked_edge [iedg] = gamma_node_list.size();
 
614
                  gamma_node_list.push_back (xx[k]);
 
615
                }
 
616
                S[k] = marked_edge [iedg];
 
617
              } else {
 
618
                S[k] = undef;
 
619
                edge_to_solve.push_back (to_solve (S.variant(), S_ige, k, dis_iedg));
 
620
                ext_marked_edge_idx.insert (dis_iedg);
 
621
                extern_edge.dis_entry (dis_iedg) = std::make_pair (my_proc, xx[k]);
 
622
              }
 
623
            } else { // xk is at edge boundary: a node of the 2d mesh
 
624
              size_type dis_inod = (!is_zero(f[j[0]])) ? K[j[k+1]] : K[j[0]];
 
625
              if (node_ownership.is_owned (dis_inod)) {
 
626
                size_type inod = dis_inod - first_dis_inod;
 
627
                if (marked_node [inod] == not_marked) {
 
628
                  marked_node [inod] = gamma_node_list.size();
 
629
                  gamma_node_list.push_back (lambda.node(inod));
 
630
                }
 
631
                S[k] = marked_node [inod];
 
632
              } else {
 
633
                S[k] = undef;
 
634
                node_to_solve.push_back (to_solve (S.variant(), S_ige, k, dis_inod));
 
635
                ext_marked_node_idx.insert (dis_inod);
 
636
                extern_node.dis_entry (dis_inod) = my_proc;
 
637
              }
 
638
            }
 
639
          }
 
640
          // S[0] == S[1] when is_zero(f[j[0]]) but f[j[0]] != 0, i.e. precision pbs
 
641
          check_macro (S[0] != S[1] || S[0] == undef, "degenerate 2d intersection");
 
642
          gamma_side_list [S.variant()].push_back (make_pair(S,bnd_ie));
 
643
        }
 
644
        break;
 
645
      }
 
646
      case reference_element::T: {
 
647
        // ---------------------------------------------------------
 
648
        // 1.2.b) tetrahedron -> 1 triangle or 1 quadrangle
 
649
        // ---------------------------------------------------------
 
650
        quadruplet q;
 
651
        point_basic<T> a, b, c, d;
 
652
        T aire;
 
653
        if (!intersection_is_quadrilateral_T (f, q)) {
 
654
          subcompute_matrix_triangle_T (x, f, j, a, b, c, aire);
 
655
          if (is_zero(f[j[1]]) && is_zero(f[j[2]]) && is_zero(f[j[3]])) {
 
656
            // the full face {j1,j2,j3} is included in the surface mesh:
 
657
            for (size_type k = 0; k < 3; k++) {
 
658
              size_type dis_inod = K[j[k+1]];
 
659
              if (node_ownership.is_owned (dis_inod)) {
 
660
                size_type inod = dis_inod - first_dis_inod;
 
661
                if (marked_node [inod] == not_marked) {
 
662
                  marked_node [inod] = gamma_node_list.size();
 
663
                  gamma_node_list.push_back (lambda.node(inod));
 
664
                }
 
665
              } else {
 
666
                // dis_inod is owned by another partition jproc:
 
667
                // if there is another neighbour element K' from the same partition jproc
 
668
                //     then jproc will insert dis_inod in gamma
 
669
                //     so, there is nothing to do here
 
670
                // otherwise, dis_inod will be orphan in jproc and will be re-affected to my_proc
 
671
                extern_node.dis_entry (dis_inod) = my_proc;
 
672
              }
 
673
            }
 
674
            size_type loc_ifac = face_T_iloc (j[1], j[2], j[3]);
 
675
            size_type dis_ifac = K.face (loc_ifac);
 
676
            if (face_ownership.is_owned (dis_ifac)) {
 
677
              size_type ifac = dis_ifac - first_dis_ifac;
 
678
              if (marked_face [ifac] == not_marked) {
 
679
                S.reset(reference_element::t, order);
 
680
                marked_face [ifac] = gamma_side_list [S.variant()].size();
 
681
                size_type S_ige = marked_face [ifac];
 
682
                for (size_type k = 0; k < S.n_node(); k++) {
 
683
                  size_type dis_inod = K[j[k+1]];
 
684
                  if (node_ownership.is_owned (dis_inod)) {
 
685
                    size_type inod = dis_inod - first_dis_inod;
 
686
                    S[k] = marked_node [inod];
 
687
                  } else {
 
688
                    S[k] = undef;
 
689
                    node_to_solve.push_back (to_solve (S.variant(), S_ige, k, dis_inod));
 
690
                    ext_marked_node_idx.insert (dis_inod);
 
691
                  }
 
692
                }
 
693
                gamma_side_list [S.variant()].push_back (make_pair(S,bnd_ie));
 
694
              } else {
 
695
                // the side will be inserted by the neighbour of K in another partition
 
696
                // so, nothing to do
 
697
              }
 
698
            } else {
 
699
              // intersection is a face of lambda that is owned by another partition jproc
 
700
              // the neighbour element K' accross this face belongs to the same partition jproc
 
701
              // and will insert dis_ifac in gamma
 
702
              // so, there is nothing to do here
 
703
            }
 
704
          } else {
 
705
            // create the new face {j1,j2,j3} by intersections:
 
706
            S.reset(reference_element::t, order);
 
707
            size_type S_ige = gamma_side_list [S.variant()].size();
 
708
            point_basic<T> xx[3] = {a,b,c};
 
709
            for (size_type k = 0; k < 3; k++) {
 
710
              if (! is_zero(f[j[k+1]]) && ! is_zero(f[j[0]])) {
 
711
                // xk is inside edge {j0,j[k+1]} of triangle K:
 
712
                size_type loc_iedg = edge_T_iloc (j[0], j[k+1]);
 
713
                size_type dis_iedg = K.edge (loc_iedg);
 
714
                if (edge_ownership.is_owned (dis_iedg)) {
 
715
                  size_type iedg = dis_iedg - first_dis_iedg;
 
716
                  if (marked_edge [iedg] == not_marked) {
 
717
                    marked_edge [iedg] = gamma_node_list.size();
 
718
                    gamma_node_list.push_back (xx[k]);
 
719
                  }
 
720
                  S[k] = marked_edge [iedg];
 
721
                } else {
 
722
                  S[k] = undef;
 
723
                  edge_to_solve.push_back (to_solve (S.variant(), S_ige, k, dis_iedg));
 
724
                  ext_marked_edge_idx.insert (dis_iedg);
 
725
                  extern_edge.dis_entry (dis_iedg) = std::make_pair (my_proc, xx[k]);
 
726
                }
 
727
              } else { // xk is at edge boundary: a node of the 2d mesh
 
728
                size_type dis_inod = (!is_zero(f[j[0]])) ? K[j[k+1]] : K[j[0]];
 
729
                if (node_ownership.is_owned (dis_inod)) {
 
730
                  size_type inod = dis_inod - first_dis_inod;
 
731
                  if (marked_node [inod] == not_marked) {
 
732
                    marked_node [inod] = gamma_node_list.size();
 
733
                    gamma_node_list.push_back (lambda.node(inod));
 
734
                  }
 
735
                  S[k] = marked_node [inod];
 
736
                } else {
 
737
                  S[k] = undef;
 
738
                  node_to_solve.push_back (to_solve (S.variant(), S_ige, k, dis_inod));
 
739
                  ext_marked_node_idx.insert (dis_inod);
 
740
                  extern_node.dis_entry (dis_inod) = my_proc;
 
741
                }
 
742
              }
 
743
            }
 
744
            // S[0] == S[j] when is_zero(f[j[0]]) but f[j[0]] != 0, i.e. precision pbs
 
745
            check_macro ((S[0] != S[1] || S[0] == undef) &&
 
746
                         (S[1] != S[2] || S[1] == undef) &&
 
747
                         (S[2] != S[0] || S[2] == undef), "degenerate 3d intersection");
 
748
            gamma_side_list [S.variant()].push_back (make_pair(S,bnd_ie));
 
749
          }
 
750
        } else {
 
751
          // create the new quadri face by intersections:
 
752
          subcompute_matrix_quadrilateral_T (x, f, q, a, b, c, d, aire);
 
753
          S.reset (reference_element::q, order);
 
754
          size_type S_ige  = gamma_side_list[reference_element::q].size();
 
755
          size_type S1_ige = gamma_side_list[reference_element::t].size(); // or S1+S2=two 't'
 
756
          size_type S2_ige = S1_ige + 1;
 
757
          size_type iloc_S1[4] = {0, 1, 2, undef}; // the way to slip a q into 2 t
 
758
          size_type iloc_S2[4] = {0, undef, 1, 2};
 
759
          point_basic<T>  xx[4] = {a,b,d,c};
 
760
          size_type s[4] = {q[0],q[2],q[1],q[3]};
 
761
          for (size_type k = 0; k < 4; k++) {
 
762
            size_type k1 = (k+1) % 4;
 
763
            if (! is_zero(f[s[k]]) && ! is_zero(f[s[k1]])) {
 
764
              // xk is inside edge {j0,j[k+1]} of triangle K:
 
765
              size_type loc_iedg = edge_T_iloc (s[k], s[k1]);
 
766
              size_type dis_iedg = K.edge (loc_iedg);
 
767
              if (edge_ownership.is_owned (dis_iedg)) {
 
768
                size_type iedg = dis_iedg - first_dis_iedg;
 
769
                if (marked_edge [iedg] == not_marked) {
 
770
                  marked_edge [iedg] = gamma_node_list.size();
 
771
                  gamma_node_list.push_back (xx[k]);
 
772
                }
 
773
                S[k] = marked_edge [iedg]; 
 
774
              } else {
 
775
                S[k] = undef;
 
776
                if (!opt.split_to_triangle) {
 
777
                  edge_to_solve.push_back (to_solve (reference_element::q, S_ige, k, dis_iedg));
 
778
                } else {
 
779
                  if (iloc_S1[k] != undef) edge_to_solve.push_back (to_solve (reference_element::t, S1_ige, iloc_S1[k], dis_iedg));
 
780
                  if (iloc_S2[k] != undef) edge_to_solve.push_back (to_solve (reference_element::t, S2_ige, iloc_S2[k], dis_iedg));
 
781
                }
 
782
                ext_marked_edge_idx.insert (dis_iedg);
 
783
                extern_edge.dis_entry (dis_iedg) = std::make_pair (my_proc, xx[k]);
 
784
              }
 
785
            } else { // xk is at edge boundary: a node of the 2d mesh
 
786
              size_type dis_inod = is_zero(f[s[k]]) ? K[s[k]] : K[s[k1]];
 
787
              if (node_ownership.is_owned (dis_inod)) {
 
788
                size_type inod = dis_inod - first_dis_inod;
 
789
                if (marked_node [inod] == not_marked) {
 
790
                  marked_node [inod] = gamma_node_list.size();
 
791
                  gamma_node_list.push_back (lambda.node(inod));
 
792
                }
 
793
                S[k] = marked_node [inod];
 
794
              } else {
 
795
                S[k] = undef;
 
796
                if (!opt.split_to_triangle) {
 
797
                  node_to_solve.push_back (to_solve (reference_element::q, S_ige, k, dis_inod));
 
798
                } else {
 
799
                  if (iloc_S1[k] != undef) node_to_solve.push_back (to_solve (reference_element::t, S1_ige, iloc_S1[k], dis_inod));
 
800
                  if (iloc_S2[k] != undef) node_to_solve.push_back (to_solve (reference_element::t, S2_ige, iloc_S2[k], dis_inod));
 
801
                }
 
802
                ext_marked_node_idx.insert (dis_inod);
 
803
              }
 
804
            }
 
805
          }
 
806
          if (!opt.split_to_triangle) {
 
807
            check_macro ((S[0] != S[1] || S[0] == undef) &&
 
808
                         (S[1] != S[2] || S[1] == undef) &&
 
809
                         (S[2] != S[3] || S[2] == undef) &&
 
810
                         (S[3] != S[0] || S[3] == undef), "degenerate 3d intersection");
 
811
            // S[0] == S[j] when is_zero(f[j[0]]) but f[j[0]] != 0, i.e. precision pbs
 
812
            gamma_side_list [S.variant()].push_back (make_pair(S,bnd_ie));
 
813
          } else {
 
814
            // split quadri into 2 triangles
 
815
            // one K -> two (S1,S2) faces: table element2face may return a pair of size_t
 
816
            // but S1-> and S2->K only is required in form_element
 
817
            element_type S1 (alloc);
 
818
            S1.reset (reference_element::t, order);
 
819
            for (size_type k = 0; k < 4; k++) {
 
820
              if (iloc_S1[k] != undef) S1 [iloc_S1[k]] = S[k];
 
821
            }
 
822
            check_macro ((S1[0] != S1[1] || S1[0] == undef) &&
 
823
                         (S1[1] != S1[2] || S1[1] == undef) &&
 
824
                         (S1[2] != S1[0] || S1[2] == undef), "degenerate 3d intersection");
 
825
            gamma_side_list [S1.variant()].push_back (make_pair(S1,bnd_ie));
 
826
 
 
827
            element_type S2 (alloc);
 
828
            S2.reset (reference_element::t, order);
 
829
            for (size_type k = 0; k < 4; k++) {
 
830
              if (iloc_S2[k] != undef) S2 [iloc_S2[k]] = S[k];
 
831
            }
 
832
            check_macro ((S2[0] != S2[1] || S2[0] == undef) &&
 
833
                         (S2[1] != S2[2] || S2[1] == undef) &&
 
834
                         (S2[2] != S2[0] || S2[2] == undef), "degenerate 3d intersection");
 
835
            gamma_side_list [S2.variant()].push_back (make_pair(S2,bnd_ie));
 
836
          }
 
837
        } // if-else
 
838
        break;
 
839
      }
 
840
      default : {
 
841
        error_macro("level set intersection: element not yet implemented: " << K.name());
 
842
      }
 
843
    }
 
844
    bnd_ie++;
 
845
  }
 
846
  extern_node.dis_entry_assembly();
 
847
  extern_edge.dis_entry_assembly();
 
848
  // ------------------------------------------------------------
 
849
  // 2) solve orphan nodes, if any
 
850
  // ------------------------------------------------------------
 
851
  // 2.1.a) re-affect orphan node to another process where gamma use it
 
852
  distributor comm_ownership (comm.size(), comm, 1);
 
853
  array<index_set,M> orphan_node (comm_ownership, index_set());
 
854
  for (size_type inod = 0, nnod = node_ownership.size(); inod < nnod; inod++) {
 
855
    if (!(extern_node [inod] != not_marked && marked_node [inod] == not_marked)) continue;
 
856
    // inod is orphan in this proc: not used for gamma (but used for lambda)
 
857
    // re-affect it to a process that use it for gamma
 
858
    size_type iproc = extern_node[inod];
 
859
    size_type dis_inod = first_dis_inod + inod;
 
860
    index_set dis_inod_set;
 
861
    dis_inod_set.insert (dis_inod);
 
862
    orphan_node.dis_entry (iproc) += dis_inod_set;
 
863
  }
 
864
  orphan_node.dis_entry_assembly ();
 
865
 
 
866
  // 2.1.b) re-affect orphan edge to another process where gamma use it
 
867
  // there could be orphan edge in 2d if lambda is a part of a regular mesh:
 
868
  // => a boundary edge can belong to another proc. This is not yet handled
 
869
  array<index_set,M> orphan_edge (comm_ownership, index_set());
 
870
  for (size_type iedg = 0, nedg = edge_ownership.size(); iedg < nedg; iedg++) {
 
871
    if (!(extern_edge [iedg].first != not_marked && marked_edge [iedg] == not_marked)) continue;
 
872
    // iedg is orphan in this proc: not used for gamma (but used for lambda)
 
873
    // re-affect it to a process that use it for gamma
 
874
    size_type iproc = extern_edge[iedg].first;
 
875
    size_type dis_iedg = first_dis_iedg + iedg;
 
876
    index_set dis_iedg_set;
 
877
    dis_iedg_set.insert (dis_iedg);
 
878
    orphan_edge.dis_entry (iproc) += dis_iedg_set;
 
879
  }
 
880
  orphan_edge.dis_entry_assembly ();
 
881
  check_macro (orphan_edge[0].size() == 0, "unexpected orphan edges");
 
882
 
 
883
  // 2.2) count total nodes used by gamma
 
884
  size_type  orphan_gamma_nnod = orphan_node[0].size();
 
885
  size_type regular_gamma_nnod = gamma_node_list.size();
 
886
  size_type         gamma_nnod = regular_gamma_nnod + orphan_gamma_nnod;
 
887
  distributor gamma_node_ownership (distributor::decide, comm, gamma_nnod);
 
888
  // 2.3) shift marked_node & marked_edge from gamma_inod local count to gamma_dis_inod one
 
889
  size_type gamma_first_dis_inod = gamma_node_ownership.first_index();
 
890
  for (size_type inod = 0, nnod = node_ownership.size(); inod < nnod; inod++) {
 
891
    if (marked_node [inod] == not_marked) continue;
 
892
    marked_node [inod] += gamma_first_dis_inod;
 
893
  }
 
894
  for (size_type iedg = 0, nedg = edge_ownership.size(); iedg < nedg; iedg++) {
 
895
    if (marked_edge [iedg] == not_marked) continue;
 
896
    marked_edge [iedg] += gamma_first_dis_inod;
 
897
  }
 
898
  // 2.4) append orphan node to regular one in gamma_node_list and set marked_node
 
899
  for (index_set::const_iterator
 
900
        iter = orphan_node[0].begin(),
 
901
        last = orphan_node[0].end(); iter != last; ++iter) {
 
902
    size_type dis_inod = *iter;
 
903
    marked_node.dis_entry(dis_inod) = gamma_first_dis_inod + gamma_node_list.size();
 
904
    gamma_node_list.push_back (lambda.dis_node(dis_inod));
 
905
  }
 
906
  marked_node.dis_entry_assembly();
 
907
  marked_edge.dis_entry_assembly();
 
908
  // ------------------------------------------------------------
 
909
  // 3) convert lists to fixed size distributed arrays
 
910
  // ------------------------------------------------------------
 
911
  array<point_basic<T>, M>                                            gamma_node;
 
912
  boost::array<array<element_type,M>, reference_element::max_variant> gamma_side;
 
913
  gamma_list2array (gamma_node_list, gamma_side_list, comm, d, gamma_node, gamma_side, sid_ie2bnd_ie);
 
914
  // ------------------------------------------------------------
 
915
  // 4) replace inod to dis_inod in element lists
 
916
  // ------------------------------------------------------------
 
917
  for (size_type variant = reference_element::first_variant_by_dimension(map_dim);
 
918
                 variant < reference_element:: last_variant_by_dimension(map_dim); variant++) {
 
919
    for (size_type ige = 0, nge = gamma_side[variant].size(); ige < nge; ige++) {
 
920
      element_type& S = gamma_side[variant][ige];
 
921
      for (size_type loc_inod = 0, loc_nnod = S.n_node(); loc_inod < loc_nnod; loc_inod++) {
 
922
        if (S[loc_inod] == undef) continue; // external node, will be solved later
 
923
        S[loc_inod] += gamma_first_dis_inod;
 
924
      }
 
925
    }
 
926
  }
 
927
  // ----------------------------------------------------------------
 
928
  // 5) solve intersection that are located on external edges & nodes
 
929
  // ----------------------------------------------------------------
 
930
  marked_node.set_dis_indexes (ext_marked_node_idx);
 
931
  for (list<to_solve>::const_iterator iter = node_to_solve.begin(),
 
932
                                      last = node_to_solve.end(); iter != last; iter++) {
 
933
    const to_solve& x = *iter;
 
934
    element_type& S = gamma_side[x.variant][x.S_ige];
 
935
    check_macro (S[x.k] == undef, "external index already solved");
 
936
    size_type dis_inod = x.dis_i;
 
937
    size_type iproc = node_ownership.find_owner(dis_inod);
 
938
    size_type gamma_dis_inod = marked_node.dis_at (dis_inod);
 
939
    S[x.k] = gamma_dis_inod;
 
940
  }
 
941
 
 
942
  marked_edge.set_dis_indexes (ext_marked_edge_idx);
 
943
  for (list<to_solve>::const_iterator iter = edge_to_solve.begin(),
 
944
                                      last = edge_to_solve.end(); iter != last; iter++) {
 
945
    const to_solve& x = *iter;
 
946
    element_type& S = gamma_side[x.variant][x.S_ige];
 
947
    check_macro (S[x.k] == undef, "external index already solved");
 
948
    size_type dis_iedg = x.dis_i;
 
949
    size_type iproc = edge_ownership.find_owner(dis_iedg);
 
950
    size_type gamma_dis_inod = marked_edge.dis_at (dis_iedg);
 
951
    S[x.k] = gamma_dis_inod;
 
952
  }
 
953
  // ------------------------------------------------------------
 
954
  // 6) convert intersection to geo
 
955
  // ------------------------------------------------------------
 
956
  geo_basic<T,M> gamma (lambda, gamma_node, gamma_side);
 
957
  return gamma;
 
958
}
 
959
template <class T, class M>
 
960
geo_basic<T,M>
 
961
level_set (
 
962
    const field_basic<T,M>&      fh,
 
963
    const level_set_option_type& opt)
 
964
{
 
965
  typedef geo_element::size_type size_type;
 
966
  std::vector<size_type> bnd_dom_ie_list;
 
967
  array<size_type,M>     sid_ie2bnd_ie;
 
968
  return level_set_internal (fh, opt, bnd_dom_ie_list, sid_ie2bnd_ie);
 
969
}
 
970
// ----------------------------------------------------------------------------
 
971
// instanciation in library
 
972
// ----------------------------------------------------------------------------
 
973
#define _RHEOLEF_instanciation(T,M)                                                     \
 
974
template geo_basic<T,M> level_set_internal (                                            \
 
975
    const field_basic<T,M>&,                                                            \
 
976
    const level_set_option_type&,                                                       \
 
977
    std::vector<size_t>&,                                                               \
 
978
    array<size_t,M>&);                                                          \
 
979
template geo_basic<T,M> level_set (                                                     \
 
980
    const field_basic<T,M>&,                                                            \
 
981
    const level_set_option_type&);
 
982
 
 
983
_RHEOLEF_instanciation(Float,sequential)
 
984
#ifdef _RHEOLEF_HAVE_MPI
 
985
_RHEOLEF_instanciation(Float,distributed)
 
986
#endif // _RHEOLEF_HAVE_MPI
 
987
 
 
988
} // namespace