source: XIOS2/trunk/extern/remap/src/meshutil.cpp @ 2500

Last change on this file since 2500 was 2500, checked in by ymipsl, 14 months ago

Modification in remaper to fix problems with non convex cells.

YM

File size: 6.3 KB
Line 
1#include <list>
2#include "elt.hpp"
3#include "polyg.hpp"
4#include "intersection_ym.hpp"
5#include "earcut.hpp"
6#include <vector>
7#include <array>
8
9namespace sphereRemap {
10
11using namespace std;
12
13void computePolygonGeometry(Elt& a, const Coord &pole, double& area, Coord& bary)
14{
15  using N = uint32_t;
16  using Point = array<double, 2>;
17  vector<Point> vect_points;
18  vector< vector<Point> > polyline;
19 
20  vector<Coord> dstPolygon ;
21  createGreatCirclePolygon(a, pole, dstPolygon) ;
22
23  int na=dstPolygon.size() ;
24  Coord *a_gno   = new Coord[na];
25 
26  Coord OC=barycentre(a.vertex,a.n) ;
27  Coord Oz=OC ;
28  Coord Ox=crossprod(Coord(0,0,1),Oz) ;
29// choose Ox not too small to avoid rounding error
30  if (norm(Ox)< 0.1) Ox=crossprod(Coord(0,1,0),Oz) ;
31  Ox=Ox*(1./norm(Ox)) ;
32  Coord Oy=crossprod(Oz,Ox) ;
33  double cos_alpha;
34
35  for(int n=0; n<na;n++)
36  {
37    cos_alpha=scalarprod(OC,dstPolygon[n]) ;
38    a_gno[n].x=scalarprod(dstPolygon[n],Ox)/cos_alpha ;
39    a_gno[n].y=scalarprod(dstPolygon[n],Oy)/cos_alpha ;
40    a_gno[n].z=scalarprod(dstPolygon[n],Oz)/cos_alpha ; // must be equal to 1
41
42    vect_points.push_back( array<double, 2>() );
43    vect_points[n][0] = a_gno[n].x;
44    vect_points[n][1] = a_gno[n].y;
45
46  }
47
48  polyline.push_back(vect_points);
49  vector<N> indices_a_gno = mapbox::earcut<N>(polyline);
50 
51  area=0 ;
52  for(int i=0;i<indices_a_gno.size()/3;++i)
53    {
54      Coord x0 = Ox * polyline[0][indices_a_gno[3*i]][0] + Oy* polyline[0][indices_a_gno[3*i]][1] + Oz ;
55      Coord x1 = Ox * polyline[0][indices_a_gno[3*i+1]][0] + Oy* polyline[0][indices_a_gno[3*i+1]][1] + Oz ;
56      Coord x2 = Ox * polyline[0][indices_a_gno[3*i+2]][0] + Oy* polyline[0][indices_a_gno[3*i+2]][1] + Oz ;
57      area+=triarea(x0 * (1./norm(x0)),x1* (1./norm(x1)), x2* (1./norm(x2))) ;
58    }
59
60
61  bary = exact_barycentre(dstPolygon.data(),na) ;
62 
63  // check signed area
64  double signedArea = 0 ;
65  for(int n=0; n<na;n++) signedArea+= a_gno[n].x*a_gno[(n+1)%na].y-a_gno[(n+1)%na].x*a_gno[n].y ;
66  if (signedArea<0) 
67  {
68    bary = bary * (-1.) ;
69    switchOrientation(a.n, a.vertex,a.edge,a.d) ;
70  }
71 
72  vect_points.clear();
73  polyline.clear();
74  indices_a_gno.clear();
75
76}
77
78
79void cptEltGeom(Elt& elt, const Coord &pole)
80{
81   orient(elt.n, elt.vertex, elt.edge, elt.d, elt.x);
82   normals(elt, pole);
83//  Coord gg;
84//  elt.area = airbar(elt.n, elt.vertex, elt.edge, elt.d, pole, gg);
85//  elt.x = gg;
86// overwrite area computation
87
88   computePolygonGeometry(elt, pole, elt.area, elt.x) ;
89   normals(elt, pole);
90
91}
92
93
94void cptAllEltsGeom(Elt *elt, int N, const Coord &pole)
95{
96  for (int ne=0; ne<N; ne++)
97    cptEltGeom(elt[ne], pole);
98}
99
100/* for all elements of size-N-array `elt`,
101   make centre areaweighted average centres of super mesh elements */
102void update_baryc(Elt *elt, int N)
103{
104  for (int ne=0; ne<N; ne++)
105  {
106    Elt &e = elt[ne];
107    int ns = e.is.size();  // sous-elements
108    Coord *sx = new Coord[ns];
109    int i=0;
110    for (list<Polyg*>::iterator it = e.is.begin(); it != e.is.end(); i++, it++)
111    {
112      sx[i] = (*it)->x * (*it)->area;
113    }
114    e.x = barycentre(sx, ns);
115  }
116}
117
118
119Coord gradient_old(Elt& elt, Elt **neighElts)
120{
121  Coord grad = ORIGIN;
122  Coord *neighBaryc = new Coord[elt.n];
123  for (int j = 0; j < elt.n; j++)
124  {
125    int k = (j + 1) % elt.n;
126    neighBaryc[j] = neighElts[j]->x;
127    Coord edgeNormal = crossprod(neighElts[k]->x, neighElts[j]->x);
128
129    // use nomenclauture form paper
130    double f_i = elt.val;
131    double f_j = neighElts[j]->val;
132    double f_k = neighElts[k]->val;
133    grad = grad + edgeNormal * (0.5*(f_j + f_k) - f_i);
134  }
135  // area of the polygon whoes vertices are the barycentres the neighbours
136  grad = grad * (1./polygonarea(neighBaryc, elt.n));
137  delete[] neighBaryc;
138
139  return grad - elt.x * scalarprod(elt.x, grad);
140}
141
142
143
144Coord gradient(Elt& elt, Elt **neighElts)
145{
146   
147  Coord grad = ORIGIN;
148  Coord neighBaryc[3] ;
149
150  double f_i ;
151  double f_j ;
152  double f_k ;
153 
154  Coord edgeNormal ;
155  double area=0 ;
156  int k ;
157  int count=0 ;
158 
159  for (int j = 0; j < elt.n; j++)
160  {
161    f_i = elt.val;
162    k = (j + 1) % elt.n;
163    if (neighElts[j]==NULL || neighElts[k]==NULL) continue ;
164
165    // use nomenclauture form paper
166    f_j = neighElts[j]->val;
167    f_k = neighElts[k]->val;
168
169   
170   
171    neighBaryc[0] = elt.x;
172    neighBaryc[1] = neighElts[j]->x;
173    neighBaryc[2] = neighElts[k]->x;
174
175    edgeNormal = crossprod(neighElts[k]->x, neighElts[j]->x);
176    grad = grad + edgeNormal * (0.5*(f_k + f_j) - f_i);
177
178    edgeNormal = crossprod(neighElts[j]->x, elt.x);
179    grad = grad + edgeNormal * (0.5*(f_j + f_i) - f_i);
180
181    edgeNormal = crossprod(elt.x, neighElts[k]->x);
182    grad = grad + edgeNormal * (0.5*(f_i + f_k) - f_i);
183
184  // area of the polygon whoes vertices are the barycentres the neighbours
185
186    area+=polygonarea(neighBaryc, 3) ;
187    count++ ;
188
189  }
190  if (count>0) 
191  {
192    grad=grad*(1./area) ;
193    return grad - elt.x * scalarprod(elt.x, grad);
194  }
195  else return grad ;
196}
197
198
199
200
201void computeGradients(Elt **elts, int N)
202{
203 
204  for (int j = 0; j < N; j++)
205    elts[j]->val = 0;
206
207  Elt *neighbours[NMAX];
208  for (int j = 0; j < N; j++)
209  {
210    for (int i = 0; i < elts[j]->n; i++) 
211      if ( elts[j]->neighbour[i]== NOT_FOUND) neighbours[i]=NULL ; // no neighbour
212      else if (elts[elts[j]->neighbour[i]]->is.size() == 0) neighbours[i]=NULL ; // neighbour has none supermesh cell
213      else  neighbours[i] = elts[elts[j]->neighbour[i]];
214
215    for (int i = 0; i < elts[j]->n; i++)
216      if (neighbours[i]!=NULL) neighbours[i]->val = 0;
217     
218    for (int i = 0; i < elts[j]->n; i++)
219    {
220      if (neighbours[i]!=NULL)
221      {
222        elts[j]->neighId[i] = neighbours[i]->src_id;
223        /* for weight computation all values are always kept zero and only set to one when used .. */
224        neighbours[i]->val = 1;
225        elts[j]->gradNeigh[i] = gradient(*(elts[j]), neighbours);
226        /* .. and right after zeroed again */
227        neighbours[i]->val = 0;
228      }
229      else
230      {
231        elts[j]->neighId[i].rank = -1; // mark end
232        elts[j]->neighId[i].ind = -1; // mark end
233      }
234    }
235
236    for(int i = elts[j]->n ; i < NMAX; i++)
237    {
238      elts[j]->neighId[i].rank = -1; // mark end
239      elts[j]->neighId[i].ind = -1; // mark end
240    }
241    /* For the most naive algorithm the case where the element itself is one must also be considered.
242       Thomas says this can later be optimized out. */
243    elts[j]->val = 1;
244    elts[j]->grad = gradient(*(elts[j]), neighbours);
245    elts[j]->val = 0;
246  }
247}
248
249}
Note: See TracBrowser for help on using the repository browser.