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

Last change on this file since 2398 was 2398, checked in by jderouillat, 22 months ago

Fix for recent GCC compiler

File size: 6.0 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
13double computePolygoneArea(Elt& a, const Coord &pole)
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  double area_a_gno=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_a_gno+=triarea(x0 * (1./norm(x0)),x1* (1./norm(x1)), x2* (1./norm(x2))) ;
58    }
59
60  vect_points.clear();
61  polyline.clear();
62  indices_a_gno.clear();
63  return area_a_gno ;
64}
65
66
67void cptEltGeom(Elt& elt, const Coord &pole)
68{
69  orient(elt.n, elt.vertex, elt.edge, elt.d, elt.x);
70  normals(elt, pole);
71  Coord gg;
72  elt.area = airbar(elt.n, elt.vertex, elt.edge, elt.d, pole, gg);
73  elt.x = gg;
74// overwrite area computation
75
76  elt.area =  computePolygoneArea(elt, pole) ;
77}
78
79
80void cptAllEltsGeom(Elt *elt, int N, const Coord &pole)
81{
82  for (int ne=0; ne<N; ne++)
83    cptEltGeom(elt[ne], pole);
84}
85
86/* for all elements of size-N-array `elt`,
87   make centre areaweighted average centres of super mesh elements */
88void update_baryc(Elt *elt, int N)
89{
90  for (int ne=0; ne<N; ne++)
91  {
92    Elt &e = elt[ne];
93    int ns = e.is.size();  // sous-elements
94    Coord *sx = new Coord[ns];
95    int i=0;
96    for (list<Polyg*>::iterator it = e.is.begin(); it != e.is.end(); i++, it++)
97    {
98      sx[i] = (*it)->x * (*it)->area;
99    }
100    e.x = barycentre(sx, ns);
101  }
102}
103
104
105Coord gradient_old(Elt& elt, Elt **neighElts)
106{
107  Coord grad = ORIGIN;
108  Coord *neighBaryc = new Coord[elt.n];
109  for (int j = 0; j < elt.n; j++)
110  {
111    int k = (j + 1) % elt.n;
112    neighBaryc[j] = neighElts[j]->x;
113    Coord edgeNormal = crossprod(neighElts[k]->x, neighElts[j]->x);
114
115    // use nomenclauture form paper
116    double f_i = elt.val;
117    double f_j = neighElts[j]->val;
118    double f_k = neighElts[k]->val;
119    grad = grad + edgeNormal * (0.5*(f_j + f_k) - f_i);
120  }
121  // area of the polygon whoes vertices are the barycentres the neighbours
122  grad = grad * (1./polygonarea(neighBaryc, elt.n));
123  delete[] neighBaryc;
124
125  return grad - elt.x * scalarprod(elt.x, grad);
126}
127
128
129
130Coord gradient(Elt& elt, Elt **neighElts)
131{
132   
133  Coord grad = ORIGIN;
134  Coord neighBaryc[3] ;
135
136  double f_i ;
137  double f_j ;
138  double f_k ;
139 
140  Coord edgeNormal ;
141  double area=0 ;
142  int k ;
143  int count=0 ;
144 
145  for (int j = 0; j < elt.n; j++)
146  {
147    f_i = elt.val;
148    k = (j + 1) % elt.n;
149    if (neighElts[j]==NULL || neighElts[k]==NULL) continue ;
150
151    // use nomenclauture form paper
152    f_j = neighElts[j]->val;
153    f_k = neighElts[k]->val;
154
155   
156   
157    neighBaryc[0] = elt.x;
158    neighBaryc[1] = neighElts[j]->x;
159    neighBaryc[2] = neighElts[k]->x;
160
161    edgeNormal = crossprod(neighElts[k]->x, neighElts[j]->x);
162    grad = grad + edgeNormal * (0.5*(f_k + f_j) - f_i);
163
164    edgeNormal = crossprod(neighElts[j]->x, elt.x);
165    grad = grad + edgeNormal * (0.5*(f_j + f_i) - f_i);
166
167    edgeNormal = crossprod(elt.x, neighElts[k]->x);
168    grad = grad + edgeNormal * (0.5*(f_i + f_k) - f_i);
169
170  // area of the polygon whoes vertices are the barycentres the neighbours
171
172    area+=polygonarea(neighBaryc, 3) ;
173    count++ ;
174
175  }
176  if (count>0) 
177  {
178    grad=grad*(1./area) ;
179    return grad - elt.x * scalarprod(elt.x, grad);
180  }
181  else return grad ;
182}
183
184
185
186
187void computeGradients(Elt **elts, int N)
188{
189 
190  for (int j = 0; j < N; j++)
191    elts[j]->val = 0;
192
193  Elt *neighbours[NMAX];
194  for (int j = 0; j < N; j++)
195  {
196    for (int i = 0; i < elts[j]->n; i++) 
197      if ( elts[j]->neighbour[i]== NOT_FOUND) neighbours[i]=NULL ; // no neighbour
198      else if (elts[elts[j]->neighbour[i]]->is.size() == 0) neighbours[i]=NULL ; // neighbour has none supermesh cell
199      else  neighbours[i] = elts[elts[j]->neighbour[i]];
200
201    for (int i = 0; i < elts[j]->n; i++)
202      if (neighbours[i]!=NULL) neighbours[i]->val = 0;
203     
204    for (int i = 0; i < elts[j]->n; i++)
205    {
206      if (neighbours[i]!=NULL)
207      {
208        elts[j]->neighId[i] = neighbours[i]->src_id;
209        /* for weight computation all values are always kept zero and only set to one when used .. */
210        neighbours[i]->val = 1;
211        elts[j]->gradNeigh[i] = gradient(*(elts[j]), neighbours);
212        /* .. and right after zeroed again */
213        neighbours[i]->val = 0;
214      }
215      else
216      {
217        elts[j]->neighId[i].rank = -1; // mark end
218        elts[j]->neighId[i].ind = -1; // mark end
219      }
220    }
221
222    for(int i = elts[j]->n ; i < NMAX; i++)
223    {
224      elts[j]->neighId[i].rank = -1; // mark end
225      elts[j]->neighId[i].ind = -1; // mark end
226    }
227    /* For the most naive algorithm the case where the element itself is one must also be considered.
228       Thomas says this can later be optimized out. */
229    elts[j]->val = 1;
230    elts[j]->grad = gradient(*(elts[j]), neighbours);
231    elts[j]->val = 0;
232  }
233}
234
235}
Note: See TracBrowser for help on using the repository browser.