LoAdSG
SGIntegrator.h
1#ifndef SGINTEGRATOR_H
2#define SGINTEGRATOR_H
3
4#include <iostream>
5#include <algorithm>
6#include <vector>
7#include "curvedPoissonIntegrator.h"
8#include "../math_lib.h"
9#include <queue>
10#include <cmath>
11#include <string>
12
13typedef double (IntegratorPoissonCurved::*Curvedfunc)(D3vector& x);
14
15class SGPoint{
16private:
17 D3vector coords;//coordinates of the point
18 D3vector levels;//indicates the level of refinement
19 D3vector locs;//indicates the location
20 D3vector supp_sizes;//size of the support of the basis function along each dimension
21
22 D3vector limit1,limit2;
23
24public:
25 SGPoint(){
26
27 }
28
29 SGPoint(D3vector levels_,D3vector locs_,\
30 D3vector &limit1, D3vector &limit2):levels(levels_),locs(locs_){
31 this->limit1 = limit1;
32 this->limit2 = limit2;
33
34 //Assuming level starts from 0. Level 0 -> Boundary basis functions
35 for(int i=0;i<3;i++){
36 if(levels[i] == 0){
37 supp_sizes[i] = limit2[i]-limit1[i];
38 if(locs[i] == 0){
39 coords[i] = limit1[i];
40 }
41 else if(locs[i] == 2){
42 coords[i] = limit2[i];
43 }
44 }
45 else{
46 supp_sizes[i] = (limit2[i]-limit1[i])/pow(2,levels[i]-1);
47 coords[i] = limit1[i]+locs[i]*supp_sizes[i]*0.5;
48 }
49 }
50
51 }
52
53 SGPoint& operator=(SGPoint& point){
54 this->coords = point.coords;
55 this->levels = point.levels;
56 this->locs = point.locs;
57 this->supp_sizes = point.supp_sizes;
58
59 return *this;
60 }
61
62 void Print(){
63 std::cout<<coords[0]<<" "<<coords[1]<<" "<<coords[2]<<std::endl;
64 }
65
66 double volume(int dim);
67
68 D3vector getCoords(){
69 return coords;
70 }
71
72 D3vector getSizes(){
73 return supp_sizes;
74 }
75
76 D3vector getLevels(){
77 return levels;
78 }
79
80 D3vector getLocs(){
81 return locs;
82 }
83
84 void reset(D3vector levels_,D3vector locs_,D3vector &limit1, D3vector &limit2);
85};
86
87
88class SGIntegrator{
89private:
90 std::queue<SGPoint> refine_queue;
91 std::vector<SGPoint> refined_set;
92 double tol;//Refinement criteria
93 int dim;//dimension
94
95 //Limits of integration
96 D3vector limit1;
97 D3vector limit2;
98public:
99 SGIntegrator(double tol_, int dim_):tol(tol_),dim(dim_){
100
101 }
102
103 //Set the tolerance
104 void setTol(double &tol_){
105 this->tol = tol_;
106 }
107
108 //Check whether a given point lies on the boundary
109 bool isBoundaryPoint(SGPoint &p);
110
111 //Refine the grid by adding neighbours
112 void refine(SGPoint &p);
113
114 void decideMinMax(D3vector &min, D3vector &max, D3vector &levels);
115
116 //Find the contribution to the total integral from the given subspace of basis functions
117 double subspaceIntegral(IntegratorPoissonCurved& ipc, Curvedfunc funcToIntegrate, int level_x, int level_y, \
118 int level_z);
119
120 //Find the hierarchical surplus
121 double findHierarchicalSurplus(IntegratorPoissonCurved& ipc, SGPoint &p, Curvedfunc func);
122
123 //Perform the adaptive integration with the given integral limits
124 double integrate(IntegratorPoissonCurved& ipc, Curvedfunc funcToIntegrate,D3vector &limit1, D3vector &limit2);
125
126 //Perform the integration uising a classical smolyak grid
127 double smolyakIntegrate(IntegratorPoissonCurved& ipc, Curvedfunc funcToIntegrate, D3vector &limit1, D3vector &limit2, int max_level);
128
129};
130
131inline bool operator==(SGPoint point1, SGPoint point2){
132 return(point1.getCoords() == point2.getCoords() &&\
133 point1.getLevels() == point2.getLevels() &&\
134 point1.getLocs() == point2.getLocs());
135}
136
137//a utility function used in findHierarchicalSurplus
138int corn(int index){
139 if(index == 0){
140 return -1;
141 }
142 else{
143 return 1;
144 }
145}
146
147void SGPoint::reset(D3vector levels_,D3vector locs_,D3vector &limit1, D3vector &limit2){
148 this->levels = levels_;
149 this->locs = locs_;
150
151 this->limit1 = limit1;
152 this->limit2 = limit2;
153
154 //Assuming level starts from 0. Level 0 => Boundary basis functions
155 for(int i=0;i<3;i++){
156 if(levels[i] == 0){
157 supp_sizes[i] = limit2[i]-limit1[i];
158 if(locs[i] == 0){
159 coords[i] = limit1[i];
160 }
161 else if(locs[i] == 2){
162 coords[i] = limit2[i];
163 }
164 }
165 else{
166 supp_sizes[i] = (limit2[i]-limit1[i])/pow(2,levels[i]-1);
167 coords[i] = limit1[i]+locs[i]*supp_sizes[i]*0.5;
168 }
169 }
170
171}
172
173double SGPoint::volume(int dim){
174 double vol = 1.0;
175
176 for(int i=0;i<dim;i++){
177 vol *= 0.5*supp_sizes[i];
178 }
179 return vol;
180}
181
182bool SGIntegrator::isBoundaryPoint(SGPoint &p){
183 bool test = false;
184 D3vector levels = p.getLevels();
185 for(int i=0;i<this->dim;i++){
186 test = test || (levels[i] == 0);
187 }
188 return test;
189}
190
191void SGIntegrator::refine(SGPoint& current){
192 D3vector levels = current.getLevels();
193 D3vector locs = current.getLocs();
194
195 D3vector levels_temp = levels,locs_temp = locs;
196
197 /****Add all the neighbours(2*dim) to the refinement queue****/
198 for(int i=0;i<this->dim;i++){
199 //If it is a boundary point, add just one neighbour
200 if(levels[i] == 0){
201 levels_temp[i] = 1;
202 locs_temp[i] = 1;
203 current.reset(levels_temp,locs_temp,limit1,limit2);
204 refine_queue.push(current);
205
206 //Resetting the point to the its original location to prepare for refinement along next direction
207 levels_temp[i] = levels[i];
208 locs_temp[i] = locs[i];
209 }
210 //else add both neighbours
211 else{
212 //Refine
213 levels_temp[i]++;
214
215 //Right refine
216 locs_temp[i] = 2*locs_temp[i]+1;
217 current.reset(levels_temp,locs_temp,limit1,limit2);
218 refine_queue.push(current);
219
220 //Left refine
221 locs_temp[i] -= 2;
222 current.reset(levels_temp,locs_temp,limit1,limit2);
223 refine_queue.push(current);
224
225 //Resetting the point to the its original location to prepare for refinement along next direction
226 levels_temp[i] = levels[i];
227 locs_temp[i] = locs[i];
228 }
229 }
230
231
232}
233
234double SGIntegrator::findHierarchicalSurplus(IntegratorPoissonCurved& ipc, SGPoint &p, Curvedfunc func){
235
236 D3vector h = p.getSizes();
237 D3vector coords = p.getCoords();
238 D3vector levels = p.getLevels();
239
240 //surplus = f(coords)
241 double surplus = (ipc.*func)(coords);
242
243 //surplus -= 0.5*(..........)
244 for(int i=0;i<this->dim;i++){
245 if(levels[i] != 0){
246 coords[i] += 0.5*h[i];
247 surplus -= 0.5*(ipc.*func)(coords);
248
249 coords[i] -= h[i];
250 surplus -= 0.5*(ipc.*func)(coords);
251 }
252 coords = p.getCoords();
253 }
254
255 //surpplus += 0.25*(............)
256 int i1=0,i2=0;
257 int num_planes = ((this->dim)*(this->dim-1))/2;
258 for(int i=0;i<num_planes;i++){
259 i1 = i;
260 i2 = (i+1)%(this->dim);
261
262 if(levels[i1] != 0 && levels[i2] != 0){
263 coords[i1] += 0.5*h[i1];
264 coords[i2] += 0.5*h[i2];
265 surplus += 0.25*(ipc.*func)(coords);
266
267 coords[i2] -= h[i2];
268 surplus += 0.25*(ipc.*func)(coords);
269
270 coords[i1] -= h[i1];
271 surplus += 0.25*(ipc.*func)(coords);
272
273 coords[i2] += h[i2];
274 surplus += 0.25*(ipc.*func)(coords);
275 }
276
277 coords = p.getCoords();
278 }
279
280
281 //surplus -= 0.125*(.................)
282 if(this->dim == 3 && levels[0] != 0 && levels[1] != 0 && levels[2] != 0){
283 for(int i=0;i<2;i++){
284 for(int j=0;j<2;j++){
285 for(int k=0;k<2;k++){
286 coords = p.getCoords();
287 coords[0] += 0.5*corn(i)*h[0];
288 coords[1] += 0.5*corn(j)*h[1];
289 coords[2] += 0.5*corn(k)*h[2];
290
291 surplus -= 0.125*(ipc.*func)(coords);
292 }
293 }
294 }
295 }
296 //std::cout<<"Point is: "<<std::endl;
297 //p.Print();
298 //std::cout<<"Surplus is "<<surplus<<std::endl;
299
300 return surplus;
301
302}
303
304//Check levels and dimension of the problem and decide the locations of points to traverse for the subspace integral
305void SGIntegrator::decideMinMax(D3vector &min, D3vector &max, D3vector &levels){
306 for(int i=0;i<3;i++){
307 if(this->dim < i+1){
308 min[i] = max[i] = 0;
309 }
310 else{
311 if(levels[i] == 0){
312 min[i] = 0;
313 max[i] = 2;
314 }
315 else{
316 min[i] = 1;
317 max[i] = pow(2,levels[i])-1;
318 }
319
320 }
321 }
322}
323
324double SGIntegrator::subspaceIntegral(IntegratorPoissonCurved& ipc, Curvedfunc funcToIntegrate,int level_x,int level_y,\
325 int level_z){
326 SGPoint grid_point;
327 D3vector levels(level_x,level_y,level_z);
328 D3vector locs,boundary_coords;
329
330 double subspace_integral = 0.0;
331
332 D3vector max,min;
333 decideMinMax(min,max,levels);
334
335 for(int i = min[0]; i <= max[0] ;i += 2){
336 for(int j = min[1]; j <= max[1];j += 2){
337 for(int k = min[2]; k <= max[2];k += 2){
338 locs[0] = i; locs[1] = j; locs[2] = k;
339
340 grid_point.reset(levels,locs,limit1,limit2);
341
342 subspace_integral += findHierarchicalSurplus(ipc,grid_point,funcToIntegrate)*grid_point.volume(this->dim);
343 }
344 }
345 }
346 return subspace_integral;
347}
348
349double SGIntegrator::smolyakIntegrate(IntegratorPoissonCurved& ipc, Curvedfunc funcToIntegrate, D3vector &limit1, D3vector &limit2, int max_level){
350 double integral = 0.0;
351
352 //Initialize limits of integration
353 this->limit1 = limit1;
354 this->limit2 = limit2;
355
356 //check the dimension of the problem
357 bool dim_2 = (this->dim >= 2);
358 bool dim_3 = (this->dim >= 3);
359 int max_y,max_z;
360 for(int i=0;i<=max_level;i++){
361 if(dim_2)
362 max_y = max_level-i+this->dim-1;
363 else
364 max_y = 0;
365 for(int j=0;j<=max_y;j++){
366 if(dim_3)
367 max_z = max_level-i-j+this->dim-1;
368 else
369 max_z = 0;
370 for(int k=0;k<=max_z;k++){
371 //Increment the integral using basis functions of the subspace W(i,j,k)
372 integral += subspaceIntegral(ipc,funcToIntegrate,i,j,k);
373 }
374 }
375 }
376
377 return integral;
378}
379double SGIntegrator::integrate(IntegratorPoissonCurved& ipc, Curvedfunc funcToIntegrate,D3vector &limit1, D3vector &limit2){
380 double integral = 0.0;
381 double loc_integral = 1.0;
382 double surplus = 0.0;
383
384 //Initialize the limits of integration
385 this->limit1 = limit1;
386 this->limit2 = limit2;
387
388 //Create the first points along the corners
389 D3vector levels_0(0.0,0.0,0.0);
390 D3vector locs;
391 SGPoint current;
392
393 bool dim_2 = (this->dim >= 2);
394 bool dim_3 = (this->dim >= 3);
395 int max_y,max_z;
396 //Iterate through all the corners
397 for(int i = 0;i <= 2;i += 2){
398 max_y = dim_2 ? 2:0;
399
400 for(int j = 0;j <= max_y;j += 2){
401 max_z = dim_3 ? 2:0;
402
403 for(int k = 0;k <= max_z; k += 2){
404 locs[0] = i; locs[1] = j; locs[2] = k;
405 current.reset(levels_0,locs,limit1,limit2);
406 refine_queue.push(current);
407 }
408 }
409 }
410
411
412 while(!refine_queue.empty()){
413 current = refine_queue.front();
414 //current.Print();
415 //If the point hasn't been refined yet, find the local integral
416 if(std::find(refined_set.begin(),refined_set.end(),current) == refined_set.end()){
417 //local_integral = surplus*(h_x/2)*(h_y/2)*(h_z/2)
418 //current.Print();
419 surplus = findHierarchicalSurplus(ipc,current,funcToIntegrate);
420
421 loc_integral = surplus;
422 loc_integral = surplus*current.volume(this->dim);
423 integral += loc_integral;
424
425 //Pop the current point from the refinement queue & push it to the refined set
426 refine_queue.pop();
427 refined_set.push_back(current);
428
429 //Refine if hierarchical surplus is greater than tolerance
430 if(fabs(surplus) >= this->tol || current.getLevels() == levels_0){
431 refine(current);
432 }
433 }
434
435 //if it has been refined already, just pop
436 else{
437 refine_queue.pop();
438 }
439 }
440
441 return integral;
442}
443
444
445#endif // SGINTEGRATOR_H
Definition curvedPoissonIntegrator.h:19