source: XIOS3/trunk/extern/remap/src/meshutil.cpp @ 2471

Last change on this file since 2471 was 2471, checked in by jderouillat, 16 months ago

Fixes for new MAC environment. AND On clients that do not initialize MPI themselves, do not monitor XIOS initialization with timers (requires that MPI_init has already been done)

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