PLUTO
sts.c
Go to the documentation of this file.
1 /* ///////////////////////////////////////////////////////////////////// */
2 /*!
3  \file
4  \brief Super Time Stepping driver for integration of diffusion terms.
5 
6  Take one step in the solution of the diffusion equation
7  \f$ dU/dt = R(\partial^2U) \f$ where R is a nonlinear right hand side
8  involving second derivatives.
9  The super step is taken to be equal to the current time step
10  ::g_dt and the number of substeps Nsts is given by solving the following
11  nonlinear equation:
12  \f[
13  \frac{\Delta t}{\Delta t_{\rm par}}
14  =
15  \frac{N}{2\sqrt{\nu}}\frac{(1+\sqrt{\nu})^{2N} - (1-\sqrt{\nu})^{2N}}
16  {(1+\sqrt{\nu})^{2N} + (1-\sqrt{\nu})^{2N}}
17  \f]
18  where \f$\nu\f$ is set by the macro ::STS_NU (default equal to 0.01).
19  The previous relation is given by Eq. [2.10] of Alexiades et al. with the
20  explicit parabolic time step \f$\Delta t_{\rm par}\f$ being computed from
21  \f[
22  \frac{2}{N_d} \max\left[ \frac{\eta_x}{\Delta x^2}
23  + \frac{\eta_y}{\Delta y^2}
24  + \frac{\eta_z}{\Delta z^2} \right]
25  \Delta t_{\rm par} = C_p < \frac{1}{N_d}
26  \f]
27  where \f$C_p\f$ is the parabolic Courant number, \f$ N_d \f$ is the number
28  of spatial dimensions and the maximum of the square
29  bracket is computed during the call to ::ParabolicRHS.
30 
31  This function is called in an operator-split way before/after advection has
32  been carried out.
33 
34  \b References
35  - Alexiades, V., Amiez, A., \& Gremaud E.-A. 1996,
36  Com. Num. Meth. Eng., 12, 31
37 
38  \authors A. Mignone (mignone@ph.unito.it)\n
39  T. Matsakos
40  \date Aug 27, 2015
41 */
42 /* ///////////////////////////////////////////////////////////////////// */
43 #include "pluto.h"
44 
45 #ifndef STS_NU
46  #define STS_NU 0.01 /**< Sets the nu parameter used in STS. */
47 #endif
48 
49 #define STS_MAX_STEPS 1024
50 
51 static void STS_ComputeSubSteps(double, double tau[], int);
52 static double STS_FindRoot(double, double, double);
53 static double STS_CorrectTimeStep(int, double);
54 /* ********************************************************************* */
55 void STS (const Data *d, Time_Step *Dts, Grid *grid)
56 /*!
57  * Solve diffusion equation(s) using Super-Time-Stepping.
58  *
59  * \param [in,out] d pointer to Data structure
60  * \param [in,out] Dts pointer to Time_Step structure
61  * \param [in] grid pointer to an array of Grid structures
62  *
63  *********************************************************************** */
64 {
65  int i, j, k, nv, n, m;
66  double N, ts[STS_MAX_STEPS];
67  double dt_par, tau, tsave, inv_dtp;
68  static Data_Arr rhs;
69  RBox *box = GetRBox(DOM, CENTER);
70 
71  if (rhs == NULL) rhs = ARRAY_4D(NX3_TOT, NX2_TOT, NX1_TOT, NVAR, double);
72 
73 /* -------------------------------------------------------------
74  Compute the conservative vector in order to start the cycle.
75  This step will be useless if the data structure
76  contains Vc as well as Uc (for future improvements).
77  ------------------------------------------------------------- */
78 
79  PrimToCons3D(d->Vc, d->Uc, box);
80  tsave = g_time;
81 
82 /* ------------------------------------------------------------
83  Main STS Loop starts here
84  ------------------------------------------------------------ */
85 
86  m = 0;
87  n = STS_MAX_STEPS;
88  while (m < n){
89 
90  g_intStage = m + 1;
91  Boundary(d, ALL_DIR, grid);
92  inv_dtp = ParabolicRHS(d, rhs, 1.0, grid);
93 
94  /* --------------------------------------------------------------
95  At the first step (m=0) compute (explicit) parabolic time
96  step. Restriction on explicit time step should be
97 
98  [2*eta_x/dx^2 + 2*eta_y/dy^2 + 2*eta_z/dz^2]*dt < 1
99 
100  which in PLUTO is normally written as
101 
102  [2/dtp_x + 2/dtp_y + 2/dtp_z]*dt/Ndim = 1/Ndim = cfl_par
103 
104  where Ndim is the number of spatial dimensions.
105  -------------------------------------------------------------- */
106 
107  if (m == 0){
108  Dts->inv_dtp = inv_dtp/(double)DIMENSIONS;
109  #ifdef PARALLEL
110  MPI_Allreduce (&Dts->inv_dtp, &tau, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
111  Dts->inv_dtp = tau;
112  #endif
113  Dts->inv_dtp = MAX(Dts->inv_dtp, 1.e-18);
114  dt_par = Dts->cfl_par/(2.0*Dts->inv_dtp); /* explicit parabolic
115  time step */
116  /* -------------------------------------------
117  Compute the number of steps needed to fit
118  the supertimestep with the advection one.
119  ------------------------------------------- */
120 
121  N = STS_FindRoot(1.0, dt_par, g_dt);
122  N = floor(N+1.0);
123  n = (int)N;
124 
125  Dts->Nsts = n;
126  if (n > STS_MAX_STEPS){
127  print1 ("! STS: the number of substeps (%d) is > %d\n",n, STS_MAX_STEPS);
128  QUIT_PLUTO(1);
129  }
130 
131  /* ------------------------------------------
132  Adjust explicit timestep to make Nsts an
133  integer number and compute the substeps.
134  ------------------------------------------ */
135 
136  if (Dts->Nsts > 1){
137  dt_par = STS_CorrectTimeStep(Dts->Nsts, g_dt);
138  STS_ComputeSubSteps(dt_par, ts, Dts->Nsts);
139  }
140 
141  if (Dts->Nsts == 1) ts[0] = g_dt;
142 
143  } /* end if m == 0 */
144 
145  tau = ts[n-m-1];
146 
147  /* -----------------------------------------------
148  Update cell-centered conservative variables
149  ----------------------------------------------- */
150 
151  DOM_LOOP (k,j,i){
152  #if VISCOSITY == SUPER_TIME_STEPPING
153  EXPAND(d->Uc[k][j][i][MX1] += tau*rhs[k][j][i][MX1]; ,
154  d->Uc[k][j][i][MX2] += tau*rhs[k][j][i][MX2]; ,
155  d->Uc[k][j][i][MX3] += tau*rhs[k][j][i][MX3];)
156  #endif
157  #if (RESISTIVITY == SUPER_TIME_STEPPING)
158  EXPAND(d->Uc[k][j][i][BX1] += tau*rhs[k][j][i][BX1]; ,
159  d->Uc[k][j][i][BX2] += tau*rhs[k][j][i][BX2]; ,
160  d->Uc[k][j][i][BX3] += tau*rhs[k][j][i][BX3];)
161  #endif
162  #if HAVE_ENERGY
163  #if (THERMAL_CONDUCTION == SUPER_TIME_STEPPING) || \
164  (RESISTIVITY == SUPER_TIME_STEPPING) || \
165  (VISCOSITY == SUPER_TIME_STEPPING)
166  d->Uc[k][j][i][ENG] += tau*rhs[k][j][i][ENG];
167  #endif
168  #endif
169  }
170  #if (defined STAGGERED_MHD) && (RESISTIVITY == SUPER_TIME_STEPPING)
171 
172  /* -----------------------------------------------
173  Update staggered magnetic field variables
174  ----------------------------------------------- */
175 
176 /* This piece of code should be used for simple Cartesian 2D
177  configurations with constant resistivity.
178  It shows that the stability limit of the resistive part of the
179  induction equation is larger if the right hand side is written
180  as Laplacian(B) rather than curl(J)
181 
182 double ***Bx, ***By, ***Bz, Jz, dx, dy, dt;
183 static double ***Ez, ***Rx, ***Ry;
184 if (Ez == NULL) {
185  Ez = ARRAY_3D(NX3_TOT, NX2_TOT, NX1_TOT, double);
186  Rx = ARRAY_3D(NX3_TOT, NX2_TOT, NX1_TOT, double);
187  Ry = ARRAY_3D(NX3_TOT, NX2_TOT, NX1_TOT, double);
188 }
189 Bx = d->Vs[BX1s];
190 By = d->Vs[BX2s];
191 dx = grid[IDIR].dx[IBEG];
192 dy = grid[JDIR].dx[JBEG];
193 
194 dt = tau;
195 k=0;
196 for (j = 1; j < NX2_TOT-1; j++) for (i = 1; i < NX1_TOT-1; i++){
197  Jz = (By[k][j][i+1] - By[k][j][i])/dx - (Bx[k][j+1][i] - Bx[k][j][i])/dy;
198  Ez[k][j][i] = Jz*g_inputParam[ETAZ];
199  Rx[k][j][i] = (Bx[k][j][i+1] - 2.0*Bx[k][j][i] + Bx[k][j][i-1])/(dx*dx)
200  + (Bx[k][j+1][i] - 2.0*Bx[k][j][i] + Bx[k][j-1][i])/(dy*dy);
201 
202  Ry[k][j][i] = (By[k][j][i+1] - 2.0*By[k][j][i] + By[k][j][i-1])/(dx*dx)
203  + (By[k][j+1][i] - 2.0*By[k][j][i] + By[k][j-1][i])/(dy*dy);
204 }
205 
206 JDOM_LOOP(j) for (i = IBEG-1; i <= IEND; i++){
207 // Bx[k][j][i] += - dt/dy*(Ez[k][j][i] - Ez[k][j-1][i]);
208  Bx[k][j][i] += dt*g_inputParam[ETAZ]*Rx[k][j][i];
209 }
210 
211 for (j = JBEG-1; j <= JEND; j++) IDOM_LOOP(i){
212 // By[k][j][i] += dt/dx*(Ez[k][j][i] - Ez[k][j][i-1]);
213  By[k][j][i] += dt*g_inputParam[ETAZ]*Ry[k][j][i];
214 }
215 */
216  CT_Update (d, d->Vs, tau, grid);
217  CT_AverageMagneticField (d->Vs, d->Uc, grid);
218  #endif
219 
220  /* --------------------------------------------------
221  Unflag zone tagged with the ENTROPY_SWITCH since
222  only total energy can be evolved using STS
223  -------------------------------------------------- */
224 
225  #if ENTROPY_SWITCH
226  TOT_LOOP(k,j,i) d->flag[k][j][i] &= ~FLAG_ENTROPY;
227  #endif
228 
229  /* ----------------------------------------------
230  convert conservative variables to primitive
231  for next iteration. Increment loop index.
232  ---------------------------------------------- */
233 
234  ConsToPrim3D(d->Uc, d->Vc, d->flag, box);
235  g_time += ts[n-m-1];
236  m++;
237  }
238  g_time = tsave; /* restore initial time step */
239 }
240 
241 /* ********************************************************************* */
242 void STS_ComputeSubSteps(double dtex, double tau[], int ssorder)
243 /*
244  *
245  *********************************************************************** */
246 {
247  int i;
248  double S=0.0;
249 
250  for (i = 0; i < ssorder; i++) {
251  tau[i] = dtex / ((-1.0 + STS_NU)*cos(((2.0*i+1.0)*CONST_PI)/(2.0*ssorder))
252  + 1.0 + STS_NU);
253  S += tau[i];
254  }
255 }
256 
257 /* ********************************************************************* */
258 double STS_FindRoot(double x0, double dtr, double dta)
259 /*
260  *
261  *********************************************************************** */
262 {
263  double a,b,c;
264  double Ns, Ns1;
265  int n;
266 
267  n = 0;
268 
269  Ns = x0+1.0;
270  Ns1 = x0;
271 
272  while(fabs(Ns-Ns1) >= 1.0e-5){
273  Ns = Ns1;
274  a = (1.0-sqrt(STS_NU))/(1.0+sqrt(STS_NU));
275  b = pow(a,2.0*Ns);
276  c = (1.0-b)/(1.0+b);
277  Ns1 = Ns + (dta - dtr*Ns/(2.0*sqrt(STS_NU))*c)
278  /(dtr/(2.0*sqrt(STS_NU))*(c-2.0*Ns*b*log(a)*(1.0+c)/(1.0+b)));
279  n += 1;
280  if (n == 128){
281  print1 ("! STS_FindRoot: max number of iterations exceeded");
282  QUIT_PLUTO(1);
283  }
284  }
285  return(Ns);
286 }
287 
288 /* ********************************************************************* */
289 double STS_CorrectTimeStep(int n0, double dta)
290 /*
291  *
292  *********************************************************************** */
293 {
294  double a,b,c;
295  double dtr;
296 
297  a = (1.0-sqrt(STS_NU))/(1.0+sqrt(STS_NU));
298  b = pow(a,2.0*n0);
299  c = (1.0-b)/(1.0+b);
300 
301  dtr = dta*2.0*sqrt(STS_NU)/(n0*c);
302  return(dtr);
303 }
304 #undef STS_MAX_STEPS
#define MX3
Definition: mod_defs.h:22
void Boundary(const Data *d, int idim, Grid *grid)
Definition: boundary.c:36
static double a
Definition: init.c:135
#define MAX(a, b)
Definition: macros.h:101
double **** Vs
The main four-index data array used for face-centered staggered magnetic fields.
Definition: structs.h:43
#define MX1
Definition: mod_defs.h:20
double **** Data_Arr
Definition: pluto.h:492
DOM_LOOP(k, j, i)
Definition: analysis.c:22
static int n
Definition: analysis.c:3
RBox * GetRBox(int, int)
Definition: rbox.c:232
#define CENTER
Definition: pluto.h:200
void print1(const char *fmt,...)
Definition: amrPluto.cpp:511
void PrimToCons3D(Data_Arr V, Data_Arr U, RBox *box)
Definition: mappers3D.c:86
long int NX2_TOT
Total number of zones in the X2 direction (boundaries included) for the local processor.
Definition: globals.h:57
int g_intStage
Gives the current integration stage of the time stepping method (predictor = 0, 1st corrector = 1...
Definition: globals.h:98
double **** Vc
The main four-index data array used for cell-centered primitive variables.
Definition: structs.h:31
double g_dt
The current integration time step.
Definition: globals.h:118
double ParabolicRHS(const Data *d, Data_Arr dU, double dt, Grid *grid)
Definition: parabolic_rhs.c:50
#define DOM
Computational domain (interior)
Definition: pluto.h:152
void CT_Update(const Data *d, Data_Arr Bs, double dt, Grid *grid)
Definition: ct.c:29
static void STS_ComputeSubSteps(double, double tau[], int)
Definition: sts.c:242
unsigned char *** flag
Pointer to a 3D array setting useful integration flags that are retrieved during integration.
Definition: structs.h:55
void ConsToPrim3D(Data_Arr U, Data_Arr V, unsigned char ***flag, RBox *box)
Definition: mappers3D.c:16
double inv_dtp
Inverse of diffusion (parabolic) time step .
Definition: structs.h:217
void STS(const Data *d, Time_Step *Dts, Grid *grid)
Definition: sts.c:55
static double STS_CorrectTimeStep(int, double)
Definition: sts.c:289
#define TOT_LOOP(k, j, i)
Definition: macros.h:44
#define FLAG_ENTROPY
Update pressure using entropy equation.
Definition: pluto.h:182
double cfl_par
Courant number for diffusion (STS only).
Definition: structs.h:221
Definition: structs.h:78
#define STS_NU
Sets the nu parameter used in STS.
Definition: sts.c:46
long int NX3_TOT
Total number of zones in the X3 direction (boundaries included) for the local processor.
Definition: globals.h:59
int j
Definition: analysis.c:2
#define MX2
Definition: mod_defs.h:21
#define ARRAY_4D(nx, ny, nz, nv, type)
Definition: prototypes.h:173
int k
Definition: analysis.c:2
tuple c
Definition: menu.py:375
#define BX3
Definition: mod_defs.h:27
PLUTO main header file.
static double STS_FindRoot(double, double, double)
Definition: sts.c:258
Definition: structs.h:30
#define STS_MAX_STEPS
Definition: sts.c:49
int i
Definition: analysis.c:2
double g_time
The current integration time.
Definition: globals.h:117
double **** Uc
The main four-index data array used for cell-centered conservative variables.
Definition: structs.h:37
#define BX1
Definition: mod_defs.h:25
#define CONST_PI
.
Definition: pluto.h:269
int Nsts
Maximum number of substeps used in STS.
Definition: structs.h:223
#define BX2
Definition: mod_defs.h:26
#define NVAR
Definition: pluto.h:609
Definition: structs.h:346
#define QUIT_PLUTO(e_code)
Definition: macros.h:125
long int NX1_TOT
Total number of zones in the X1 direction (boundaries included) for the local processor.
Definition: globals.h:55
#define DIMENSIONS
Definition: definitions_01.h:2
void CT_AverageMagneticField(double ****bf, double ****UU, Grid *grid)
#define ALL_DIR
Definition: pluto.h:196