CG  Version 25
bodyForcingMacros.h
Go to the documentation of this file.
1 // ---------------------------------------------------------------------------------------------------------------------------
2 //
3 // bodyForcingMacros.h:
4 // This file defines macros used for body forces (bodyForcing.bC) and boundary forces (defineVariableBoundaryValues.bC)
5 //
6 // ---------------------------------------------------------------------------------------------------------------------------
7 
8 
9 // =================================================================
10 // Macro to compute the grid point coordinates.
11 // =================================================================
12 #beginMacro getGridCoordinates(xv)
14  {
15  for( int axis=0; axis<numberOfDimensions; axis++ )
16  xv[axis]=XC(iv,axis);
17  }
18  else
19  {
20  for( int axis=0; axis<numberOfDimensions; axis++ )
21  xv[axis]=vertexLocal(i1,i2,i3,axis);
22  }
23 #endMacro
24 
25 // ============================================================================================
26 // This macro computes the directions in which the region box is longest.
27 // ============================================================================================
28 #beginMacro getWidestBoxDirectionsMacro(dir1,dir2)
29  if( numberOfDimensions==2 )
30  {
31  // dir1 = the longest axes of the box (in 2D)
32  // xb-xa > yb-ya : assume the boundary is horizontal, else vertical
33  dir1 = xWidth > yWidth ? 0 : 1;
34  }
35  else
36  {
37  // Find the two directions (dir1,dir2) that define the two longest axes of the box
38  //
39  if( xWidth < min(yWidth,zWidth) )
40  {
41  dir1=1; dir2=2;
42  }
43  else if( yWidth < min(xWidth,zWidth) )
44  {
45  dir1=0; dir2=2;
46  }
47  else
48  {
49  dir1=0; dir2=1;
50  }
51  }
52 #endMacro
53 
54 // ===================================================================================
55 // Macro: Add a body force or boundary force (i.e. assign the RHS to a BC):
56 //
57 // This macro will add a body/boundary force over the appropriate region.
58 //
59 // Parameters:
60 // TYPE : body or boundary to indicate whether this is a body forcing or BC forcing
61 // I1,I2,I3 : apply forcing over this indicies.
62 //
63 // Implied Parameters:
64 // regionType : a string (e.g. "box") denoting the region.
65 // bodyForce : a BodyForce object that contains info on the region.
66 // NOTE:
67 // This macro expects the perl variable $statements to hold the statements that assign
68 // the body/boundary force at a single point
69 // ===================================================================================
70 
71 #beginMacro addBodyForceMacro(TYPE,I1,I2,I3)
72 
73  const int addBodyForce=0, addBoundaryForce=1;
74  #If #TYPE eq "body"
75  const int forcingType=addBodyForce;
76  #Elif #TYPE eq "boundary"
77  const int forcingType=addBoundaryForce;
78  #Else
79  OV_ABORT("addBodyForceMacro: UNKNOWN argument =TYPE");
80  #End
81 
82  real profileFactor=1.; // The forcing is multiplied by this factor (changed below for parabolic, ...)
83 
84  if( regionType=="box" )
85  {
86  // -- drag is applied over a box (square in 2D) --
87 
88  const real *boxBounds = bodyForce.dbase.get<real[6] >("boxBounds");
89 
90  #define xab(side,axis) boxBounds[(side)+2*(axis)]
91  const real & xa = xab(0,0), &xb = xab(1,0);
92  const real & ya = xab(0,1), &yb = xab(1,1);
93  const real & za = xab(0,2), &zb = xab(1,2);
94 
95  const aString & profileType = bodyForce.dbase.get<aString>("profileType");
96 
97  // if( debug() & 4 )
98  // printF("computeBodyForce: profileType=%s, box bounds = [%e,%e]x[%e,%e][%e,%e]\n",(const char*)profileType,xa,xb,ya,yb,za,zb);
99 
100 
101  if( profileType=="uniform" )
102  {
103  // --- uniform profile ---
104  FOR_3D(i1,i2,i3,I1,I2,I3)
105  {
106  // Get the grid coordinates xv[axis]:
107  getGridCoordinates(xv);
108 
109  // Turn on the drag if we are inside the box
110  if( xv[0]>=xa && xv[0]<=xb && xv[1]>=ya && xv[1]<=yb && xv[2]>=za && xv[2]<=zb )
111  {
112  #peval $statements
113  }
114 
115  } // end FOR_3D
116  }
117  else if( profileType=="parabolic" )
118  {
119  // -- Parabolic profile --
120 
121  // Near each edge of the region the parabolic profile looks like:
122  // u(x) = U(x)*( 1 - (1-d(x)/W)^2 ), for d(x) < W
123  // u(x) = U(x) , for d(x) > W
124  // where d(x) is the distance from the point x to the box that defines the region,
125  // and W=parabolicProfileDepth is the width of the parabolic profile.
126 
127  const real & parabolicProfileDepth = bodyForce.dbase.get<real>("parabolicProfileDepth");
128  const real xWidth=xb-xa, yWidth=yb-ya, zWidth=zb-za;
129 
130  // For now we assume the boundary is parallel to the longest axis (2D) axes (3D) of the box.
131  int dir1, dir2;
132  getWidestBoxDirectionsMacro(dir1,dir2);
133 
134  FOR_3D(i1,i2,i3,I1,I2,I3)
135  {
136  // Get the grid coordinates xv[axis]:
137  getGridCoordinates(xv);
138 
139  real dist;
140  #If #TYPE eq "body"
141  // Body force (volume): compute minimum distance to any side of the box:
142  dist = min( xv[0]-xab(0,0), xab(1,0)-xv[0], xv[1]-xab(0,1), xab(1,1)-xv[1] );
143  if( numberOfDimensions==3 )
144  dist=min( dist, xv[2]-xab(0,2), xab(1,2)-xv[2] );
145  #Elif #TYPE eq "boundary"
146  // Boundary: compute the minimum distance to the box edges (ignore box faces in the normal direction to the boundary):
147  dist = min( xv[dir1]-xab(0,dir1), xab(1,dir1)-xv[dir1] );
148  if( numberOfDimensions==3 )
149  dist=min( dist, xv[dir2]-xab(0,dir2), xab(1,dir2)-xv[dir2] );
150  #Else
151  OV_ABORT("addBodyForceMacro: UNKNOWN argument =TYPE");
152  #End
153 
154  // printF("parabolic: (i1,i2)=(%i,%i) x=(%g,%g) dist=%g \n",i1,i2,xv[0],xv[1],dist);
155 
156  if( dist>=0. )
157  {
158  dist /= parabolicProfileDepth;
159  if( dist<1. )
160  {
161  // 1 - (1-d)^2 = 2*d-d^2 = d*(2-d)
162  profileFactor = dist*(2.-dist);
163  }
164  else
165  {
166  profileFactor=1.;
167  }
168  // printF(" : profileFactor=%g \n",profileFactor);
169 
170  #peval $statements
171  }
172 
173  } // end FOR_3D
174  }
175  else if( profileType=="tanh" )
176  {
177  // -- Tanh profile:
178  // The one-dimensional tanh profile is of the form:
179  // u = U(x) *[ .5*( tanh( b*(x-xa) ) - tanh( b*(x-xb) ) ) ]
180  //
181 
182  const real & b = bodyForce.dbase.get<real>("tanhProfileExponent");
183  const real xWidth=xb-xa, yWidth=yb-ya, zWidth=zb-za;
184 
185  // For now we assume the boundary is parallel to the longest axis (2D) axes (3D) of the box.
186  int dir1, dir2;
187  getWidestBoxDirectionsMacro(dir1,dir2);
188 
189  FOR_3D(i1,i2,i3,I1,I2,I3)
190  {
191  // Get the grid coordinates xv[axis]:
192  getGridCoordinates(xv);
193 
194  // --> we could have a cutoff if we are far away from the transition zone, to avoid
195  // evaluating the tanh's.
196 
197  #If #TYPE eq "body"
198  // Body force force:
199  profileFactor = .5*( tanh( b*(xv[0]-xab(0,0)) ) - tanh( b*(xv[0]-xab(1,0)) ) );
200  profileFactor *= .5*( tanh( b*(xv[1]-xab(0,1)) ) - tanh( b*(xv[1]-xab(1,1)) ) );
201  if( numberOfDimensions==3 )
202  profileFactor *= .5*( tanh( b*(xv[2]-xab(0,2)) ) - tanh( b*(xv[2]-xab(1,2)) ) );
203  #Elif #TYPE eq "boundary"
204  // Boundary force:
205  profileFactor = .5*( tanh( b*(xv[dir1]-xab(0,dir1)) ) - tanh( b*(xv[dir1]-xab(1,dir1)) ) );
206  if( numberOfDimensions==3 )
207  profileFactor *= .5*( tanh( b*(xv[dir2]-xab(0,dir2)) ) - tanh( b*(xv[dir2]-xab(1,dir2)) ) );
208  #Else
209  OV_ABORT("addBodyForceMacro: UNKNOWN argument =TYPE");
210  #End
211 
212  #peval $statements
213 
214 
215  } // end FOR_3D
216  }
217  else
218  {
219  printF("addBodyForceMacro: ERROR: unknown profileType=%s\n",(const char*)profileType);
220  OV_ABORT("ERROR");
221  }
222 
223 
224  }
225  else if( regionType=="ellipse" )
226  {
227  // -- drag is applied over an ellipse --
228  // [(x-xe)/ae]^2 + [(y-ye)/be]^2 + [(z-ze)/ce]^2 = 1
229 
230  const real *ellipse = bodyForce.dbase.get<real[6] >("ellipse");
231 
232  const real ae = ellipse[0];
233  const real be = ellipse[1];
234  const real ce = ellipse[2];
235  const real xe = ellipse[3];
236  const real ye = ellipse[4];
237  const real ze = ellipse[5];
238 
239 
240  FOR_3D(i1,i2,i3,I1,I2,I3)
241  {
242  // Get the grid coordinates xv[axis]:
243  getGridCoordinates(xv);
244 
245  real rad;
246  if( numberOfDimensions==2 )
247  {
248  real xa = (xv[0]-xe)/ae;
249  real ya = (xv[1]-ye)/be;
250  rad = xa*xa+ya*ya;
251  }
252  else
253  {
254  real xa = (xv[0]-xe)/ae;
255  real ya = (xv[1]-ye)/be;
256  real za = (xv[2]-ze)/ce;
257  rad = xa*xa+ya*ya+za*za;
258  }
259 
260 
261  // // amp = 1 inside the circle and 0 outside
262  // // -- here is a smooth transition from 0 to damp at "radius" rad0
263  // real amp = .5*damp*(tanh( -beta*(rad-rad0) )+1.);
264  // fg(i1,i2,i3,uc) = -amp*ug(i1,i2,i3,uc);
265  // fg(i1,i2,i3,vc) = -amp*ug(i1,i2,i3,vc);
266 
267  // here we turn on the drag as a step function at rad=rad0
268  if( rad < 1. )
269  {
270  #peval $statements
271  }
272 
273  } // end FOR_3D
274  }
275  else if( regionType=="maskFromGridFunction" )
276  {
277  // ---- The region is defined by a grid function that holds a mask ----
278 
279  if( !parameters.dbase.has_key("bodyForceMaskGridFunction") )
280  {
281  printF("ERROR: regionType==`maskFromGridFunction' but the grid function does not exist!\n");
282  OV_ABORT("ERROR");
283  }
284 
285  // printF("Setting a body force for regionType==maskFromGridFunction for grid=%i\n",grid);
286 
287  realCompositeGridFunction *maskPointer =
288  parameters.dbase.get<realCompositeGridFunction*>("bodyForceMaskGridFunction");
289  assert( maskPointer!=NULL );
290  realCompositeGridFunction & bodyForceMask = *maskPointer;
291 
292  realArray & bfMask = bodyForceMask[grid];
293  OV_GET_SERIAL_ARRAY(real,bfMask,bfMaskLocal);
294 
295  getIndex( mg.dimension(),I1,I2,I3 ); // all points including ghost points.
296  // restrict bounds to local processor, include ghost
297  bool ok = ParallelUtility::getLocalArrayBounds(bfMask,bfMaskLocal,I1,I2,I3,1);
298 
299  if( ok )
300  {
301 
302  profileFactor=1.;
303  FOR_3D(i1,i2,i3,I1,I2,I3)
304  {
305  if( bfMaskLocal(i1,i2,i3)<=0. ) // signed distance
306  {
307  #peval $statements
308  }
309 
310  }
311  }
312 
313 
314  }
315  else
316  {
317  printF("computeBodyForcing:ERROR: unexpected regionType=%s\n",(const char*)regionType);
318  OV_ABORT("ERROR: finish me...");
319  }
320 
321 #endMacro
322 
323 // =====================================================================================
324 // Save info about the body force region and profile in the bodyForce object.
325 // =====================================================================================
326 #beginMacro saveBodyForceRegionInfoMacro(bodyForce,regionPar)
327 {
328  // Here is the region type ("box", "ellipse", ... ) chosen by the user
329  const aString & regionType = regionPar.dbase.get<aString>("regionType");
330 
331  // Save the region type:
332  if( !bodyForce.dbase.has_key("regionType") )
333  bodyForce.dbase.put<aString>("regionType"); // region type
334  bodyForce.dbase.get<aString>("regionType")=regionType;
335 
336  if( !bodyForce.dbase.has_key("linesToPlot") )
337  bodyForce.dbase.put<int[3]>("linesToPlot");
338  int *linesToPlot = bodyForce.dbase.get<int[3]>("linesToPlot");
339  int *lines = regionPar.dbase.get<int[3] >("linesToPlot");
340  for( int i=0; i<3; i++ )
341  linesToPlot[i]=lines[i];
342 
343  if( regionType=="box" )
344  {
345  bodyForce.dbase.put<real[6] >("boxBounds");
346  real *boxBounds = bodyForce.dbase.get<real[6]>("boxBounds");
347  const real *bpar = regionPar.dbase.get<real[6]>("boxBounds");
348  for( int i=0; i<6; i++ )
349  boxBounds[i]=bpar[i];
350  }
351  else if( regionType=="ellipse" )
352  {
353  bodyForce.dbase.put<real[6] >("ellipse");
354  real *ellipse = bodyForce.dbase.get<real[6]>("ellipse");
355  const real *epar = regionPar.dbase.get<real[6]>("ellipse");
356  for( int i=0; i<6; i++ )
357  ellipse[i]=epar[i];
358  }
359  else if( regionType=="maskFromGridFunction" )
360  {
361  // region defined from a mask in a grid function
362  }
363  else
364  {
365  printF("defineVariableBoundaryValues:ERROR: unexpected regionType=%s\n",(const char*)regionType);
366  OV_ABORT("ERROR: finish me...");
367  }
368 
369  // Save the profile type
370  const aString & profileType = regionPar.dbase.get<aString>("profileType");
371  bodyForce.dbase.put<aString>("profileType");
372  bodyForce.dbase.get<aString>("profileType")=profileType;
373  if( profileType=="parabolic" )
374  {
375  bodyForce.dbase.put<real>("parabolicProfileDepth");
376  bodyForce.dbase.get<real>("parabolicProfileDepth")=regionPar.dbase.get<real>("parabolicProfileDepth");
377  }
378  else if( profileType=="tanh" )
379  {
380  bodyForce.dbase.put<real>("tanhProfileExponent");
381  bodyForce.dbase.get<real>("tanhProfileExponent")=regionPar.dbase.get<real>("tanhProfileExponent");
382  }
383 }
384 #endMacro