PLUTO
ctu_step.c
Go to the documentation of this file.
1 /* ///////////////////////////////////////////////////////////////////// */
2 /*!
3  \file
4  \brief Advance equations using Corner Transport Upwind (CTU).
5 
6  Implement the dimensionally unsplit, Corner Transport Upwind method
7  (CTU) of Colella. It consists of
8 
9  <b> A predictor step </b>:
10  -# start from cell center values of \c V and compute time-centered
11  interface states using either HANCOCK or CHARACTERISTIC_TRACING:
12  \f[
13  V^{n+\HALF}_{i,\pm} = V^n_{i,\pm} + \pd{V}{t}\frac{\Delta t}{2}
14  \f]
15  Store the resulting states by converting \f$ V_\pm \f$ in \f$ U_\pm \f$
16  (= \c UP, \c UM).
17  Normal (n) and trasnverse (t) indexes for this step should span
18  \f$ n \in [n_{\rm beg} - 1, n_{\rm end} + 1] \f$,
19  \f$ t \in [t_{\rm beg} - 1, t_{\rm end} + 1] \f$
20  for cell-centered schemes and
21  \f$ n \in [n_{\rm beg} - 2, n_{\rm end} + 2] \f$,
22  \f$ t \in [t_{\rm beg} - 2, t_{\rm end} + 2] \f$ for staggered MHD.
23  -# Solve Riemann problems between \f$ V_{i,+}\f$ and \f$ V_{i+1,-}\f$
24  and store the flux difference in RHS.
25  -# Compute cell and time-centered values UH = U + dt/2*RHS with index
26  range \f$ n \in [n_{\rm beg}, n_{\rm end}]\f$,
27  \f$ t \in [t_{\rm beg}, t_{\rm end}]\f$ for cell-centered schemes
28  and \f$ n \in [n_{\rm beg}-1, n_{\rm end}+1]\f$,
29  \f$ t \in [t_{\rm beg}-1, t_{\rm end}+1]\f$ for staggered MHD.
30 
31  <b> A corrector step </b>:
32  -# correct left and right states \c UP and \c UM computed in the previous
33  step by adding the transverse RHS contribution, e.g.
34  \f$ U^{n+\HALF}_{i\pm} += ({\cal RHS}^n_y + {\cal RHS}^n_z)\Delta t/2 \f$.
35  This step should cover \f$ [n_{\rm beg}-1, n_{\rm end} + 1]\f$,
36  \f$ [t_{\rm beg}, t_{\rm end}]\f$ for cell-centered MHD and
37  \f$ [n_{\rm beg}-2, n_{\rm end} + 2]\f$, \f$
38  [t_{\rm beg}-1, tend+1]\f$ for staggered MHD.
39 
40  -# Solve a normal Riemann problem with left and right states
41  \c UP and \c UM, get RHS and evolve to final stage,
42  \f$ U^{n+1} = U^n + \Delta t^n {\cal RHS}^{n+\HALF} \f$
43 
44 
45  This integrator performs an integration in the ghost boundary zones,
46  in order to recover appropriate information to build the transverse
47  predictors.
48 
49  \note If explicit parabolic flux have to be included, the predictor
50  step is modified by computing the RHS from 1st order states at t^n.
51  This allows to obtain space and time centered states in one
52  row of boundary zones required during the following corrector step.
53 
54  \b References
55  - "The Piecewise Parabolic Method for Multidimensional
56  Relativistic Fluid Dynamics" \n
57  Mignone, A.; Plewa, T.; Bodo, G. ApJS (2005), 160..199M
58  - "An unsplit Godunov method for ideal MHD via constrained transport" \n
59  Gardiner & Stone, JCP (2005), 205, 509
60  - "A second-order unsplit Godunov scheme for cell-centered MHD:
61  the CTU-GLM scheme" \n
62  Mignone & Tzeferacos JCP (2010), 229, 2117
63 
64  \authors A. Mignone (mignone@ph.unito.it)\n
65  P. Tzeferacos (petros.tzeferacos@ph.unito.it)
66  \date June 24, 2015
67 */
68 /* ///////////////////////////////////////////////////////////////////// */
69 #include"pluto.h"
70 
71 #ifdef STAGGERED_MHD
72  #if TIME_STEPPING == CHARACTERISTIC_TRACING
73  #define CTU_MHD_SOURCE YES
74  #elif TIME_STEPPING == HANCOCK && PRIMITIVE_HANCOCK == YES
75  #define CTU_MHD_SOURCE YES
76  #else
77  #define CTU_MHD_SOURCE NO
78  #endif
79 #else
80  #define CTU_MHD_SOURCE NO
81 #endif
82 
83 #if CTU_MHD_SOURCE == YES
84  static void CTU_CT_Source (double **, double **, double **,
85  double *, int, int, Grid *);
86 #endif
87 /* ********************************************************************* */
88 int AdvanceStep (const Data *d, Riemann_Solver *Riemann,
89  Time_Step *Dts, Grid *grid)
90 /*!
91  * Advance equations using the corner transport upwind method
92  * (CTU)
93  *
94  * \param [in,out] d pointer to Data structure
95  * \param [in] Riemann pointer to a Riemann solver function
96  * \param [in,out] Dts pointer to time step structure
97  * \param [in] grid pointer to array of Grid structures
98  *
99  *********************************************************************** */
100 {
101  int i, j,k, nv, *in;
102  int errp, errm;
103  double dt2, inv_dtp, *inv_dl;
104  Index indx;
105  static unsigned char *flagm, *flagp;
106  static Data_Arr UM[DIMENSIONS], UP[DIMENSIONS];
107 
108  static Data_Arr dU, UH, Bs0;
109  static State_1D state;
110  static double **dtdV, **dcoeff, ***T;
111  double *dtdV2, **rhs;
112  RBox *box = GetRBox(DOM, CENTER);
113 
114 /* -----------------------------------------------------------------
115  Check algorithm compatibilities
116  ----------------------------------------------------------------- */
117 
118  #if !(GEOMETRY == CARTESIAN || GEOMETRY == CYLINDRICAL)
119  print1 ("! AdvanceStep(): ");
120  print1 ("CTU only works in Cartesian or cylindrical coordinates\n");
121  QUIT_PLUTO(1);
122  #endif
123 
124 /* --------------------------------------------------------
125  Allocate static memory areas
126  --------------------------------------------------------- */
127 
128  if (dU == NULL){
129 
130  dtdV = ARRAY_2D(DIMENSIONS,NMAX_POINT, double);
131 
132  MakeState (&state);
133 
134  flagp = ARRAY_1D(NMAX_POINT, unsigned char);
135  flagm = ARRAY_1D(NMAX_POINT, unsigned char);
136 
137  UH = ARRAY_4D(NX3_TOT, NX2_TOT, NX1_TOT, NVAR, double);
138  dU = ARRAY_4D(NX3_TOT, NX2_TOT, NX1_TOT, NVAR, double);
139  #ifdef STAGGERED_MHD
140  Bs0 = ARRAY_4D(DIMENSIONS, NX3_TOT, NX2_TOT, NX1_TOT, double);
141  #endif
142 
143  /* ---------------------------------------------------------
144  corner-coupled multidimensional arrays are stored into
145  memory following the same conventions adopted when
146  sweeping along the coordinate directions, i.e.,
147 
148  (z,y,x)->(z,x,y)->(y,x,z).
149 
150  This allows 1-D arrays to conveniently point at the
151  fastest running indexes of the respective multi-D ones.
152  --------------------------------------------------------- */
153 
154  UM[IDIR] = ARRAY_4D(NX3_TOT, NX2_TOT, NX1_TOT, NVAR, double);
155  UP[IDIR] = ARRAY_4D(NX3_TOT, NX2_TOT, NX1_TOT, NVAR, double);
156 
157  UM[JDIR] = ARRAY_4D(NX3_TOT, NX1_TOT, NX2_TOT, NVAR, double);
158  UP[JDIR] = ARRAY_4D(NX3_TOT, NX1_TOT, NX2_TOT, NVAR, double);
159 
160  #if DIMENSIONS == 3
161  UM[KDIR] = ARRAY_4D(NX2_TOT, NX1_TOT, NX3_TOT, NVAR, double);
162  UP[KDIR] = ARRAY_4D(NX2_TOT, NX1_TOT, NX3_TOT, NVAR, double);
163  #endif
164 
165  #if (PARABOLIC_FLUX & EXPLICIT)
166  dcoeff = ARRAY_2D(NMAX_POINT, NVAR, double);
167  #endif
168  #if THERMAL_CONDUCTION == EXPLICIT
169  T = ARRAY_3D(NX3_TOT, NX2_TOT, NX1_TOT, double);
170  #endif
171  }
172 
173 /* -- save pointers -- */
174 
175  rhs = state.rhs;
176 /* memset (dU[0][0][0], 0.0, NX3_TOT*NX2_TOT*NX1_TOT*NVAR*sizeof(double)); */
177 
178  #ifdef FARGO
179  FARGO_SubtractVelocity (d,grid);
180  #endif
181 
182 /* -------------------------------------------------------
183  Set boundary conditions and flag shocked regions for
184  shock flattening or energy/entropy selective update.
185  ------------------------------------------------------- */
186 
187  g_intStage = 1;
188  Boundary (d, ALL_DIR, grid);
189  #if (SHOCK_FLATTENING == MULTID) || (ENTROPY_SWITCH)
190  FlagShock (d, grid);
191  #endif
192 
193  dt2 = 0.5*g_dt;
194  D_EXPAND(
195  ITOT_LOOP(i) dtdV[IDIR][i] = dt2/grid[IDIR].dV[i]; ,
196  JTOT_LOOP(j) dtdV[JDIR][j] = dt2/grid[JDIR].dV[j]; ,
197  KTOT_LOOP(k) dtdV[KDIR][k] = dt2/grid[KDIR].dV[k];
198  )
199 
201  TOT_LOOP(k,j,i) T[k][j][i] = d->Vc[PRS][k][j][i]/d->Vc[RHO][k][j][i];
202  #endif
203 
204 /* ------------------------------------------------
205  Compute current arrays
206  ------------------------------------------------ */
207 
208  #if (RESISTIVITY == EXPLICIT) && (defined STAGGERED_MHD)
209  GetCurrent (d, -1, grid);
210  #endif
211 
212 /* ----------------------------------------------------
213  Convert primitive to conservative and reset arrays
214  ---------------------------------------------------- */
215 
216  KTOT_LOOP(k) JTOT_LOOP(j){
217  ITOT_LOOP(i){
218  VAR_LOOP(nv) state.v[i][nv] = d->Vc[nv][k][j][i];
219  }
220  PrimToCons(state.v, d->Uc[k][j], 0, NX1_TOT-1);
221  }
222 
223  #ifdef STAGGERED_MHD
224  nv = NX1_TOT*sizeof(double);
225  KTOT_LOOP(k) JTOT_LOOP(j){
226  D_EXPAND(memcpy(Bs0[BX1s][k][j], d->Vs[BX1s][k][j], nv); ,
227  memcpy(Bs0[BX2s][k][j], d->Vs[BX2s][k][j], nv); ,
228  memcpy(Bs0[BX3s][k][j], d->Vs[BX3s][k][j], nv);)
229  }
230  #endif
231 
232 /* ----------------------------------------------------
233  1. Compute Normal predictors and
234  solve normal Riemann problems.
235  Store computations in UP, UM, RHS (X,Y,Z)
236  ---------------------------------------------------- */
237 
238  for (g_dir = 0; g_dir < DIMENSIONS; g_dir++){
239 
240  SetIndexes (&indx, grid);
241  ResetState (d, &state, grid);
242  #if (RESISTIVITY == EXPLICIT) && !(defined STAGGERED_MHD)
243  GetCurrent(d, g_dir, grid);
244  #endif
245  TRANSVERSE_LOOP(indx,in,i,j,k){
246 
247  g_i = i; g_j = j; g_k = k;
248 
249  /* ---------------------------------------------
250  save computational time by having state.up
251  and state.um pointing at the fastest
252  running indexes of UP and UM.
253  Also, during the x-sweep we initialize Uc
254  and dU by changing the memory address of
255  state.u and state.rhs.
256  --------------------------------------------- */
257 
258  state.up = UP[g_dir][*(indx.pt2)][*(indx.pt1)]; state.uL = state.up;
259  state.um = UM[g_dir][*(indx.pt2)][*(indx.pt1)]; state.uR = state.um + 1;
260 
261  /* ---- get a 1-D array of primitive quantities ---- */
262 
263  for (*in = 0; (*in) < indx.ntot; (*in)++) {
264  VAR_LOOP(nv) state.v[*in][nv] = d->Vc[nv][k][j][i];
265  state.flag[*in] = d->flag[k][j][i];
266  #ifdef STAGGERED_MHD
267  state.bn[*in] = d->Vs[g_dir][k][j][i];
268  #endif
269  }
270 
271  CheckNaN (state.v, 0, indx.ntot - 1, 0);
272 
273 #if !(PARABOLIC_FLUX & EXPLICIT) /* adopt this formulation when there're no
274  explicit diffusion flux terms */
275  States (&state, indx.beg - 1, indx.end + 1, grid);
276  Riemann (&state, indx.beg - 1, indx.end, Dts->cmax, grid);
277  #ifdef STAGGERED_MHD
278  CT_StoreEMF (&state, indx.beg - 1, indx.end, grid);
279  #endif
280  RightHandSide (&state, Dts, indx.beg, indx.end, dt2, grid);
281 
282  #if CTU_MHD_SOURCE == YES
283  CTU_CT_Source (state.v, state.up, state.um,
284  dtdV[g_dir], indx.beg - 1, indx.end + 1, grid);
285  #endif
286 
287  /* ------------------------------------------------------------------
288  At this point we have at disposal the normal predictors U^_\pm.
289  To save memory, we compute corner coupled states by first
290  subtracting the normal contribution and then by adding the total
291  time increment. For example, in the x-direction, we do
292 
293  U^{n+1/2}_\pm = U^_\pm - RX + (RX + RY + RZ)
294 
295  where the first subtraction is done here while dU = (RX + RY + RZ) is
296  the total time increment which will be added later (step 2 below).
297  In a 2-D domain dU contains the following (X,Y,Z) contributions:
298 
299  0 X 0 0 X 0
300  +--------+ +--------+
301  | | | |
302  0| X |0 --> Y| XY |Y
303  | | | |
304  +--------+ +--------+
305  0 X 0 0 X 0
306 
307  (X sweep) (Y sweep)
308 
309  Also, evolve cell center values by dt/2.
310  For staggered mhd, this step should be carried also in one rows of
311  boundary zones in order to provide the cell and time centered
312  e.m.f.
313  ------------------------------------------------------------------ */
314 
315  if (g_dir == IDIR){
316 
317  for (nv = NVAR; nv--; ) {
318  state.rhs[indx.beg - 1][nv] = 0.0;
319  state.rhs[indx.end + 1][nv] = 0.0;
320  }
321 
322  for ((*in) = indx.beg-1; (*in) <= indx.end+1; (*in)++) {
323  for (nv = NVAR; nv--; ){
324  dU[k][j][i][nv] = state.rhs[*in][nv];
325  UH[k][j][i][nv] = d->Uc[k][j][i][nv] + state.rhs[*in][nv];
326  state.up[*in][nv] -= state.rhs[*in][nv];
327  state.um[*in][nv] -= state.rhs[*in][nv];
328  }}
329  }else{
330  for ((*in) = indx.beg; (*in) <= indx.end; (*in)++) {
331  for (nv = NVAR; nv--; ){
332  dU[k][j][i][nv] += state.rhs[*in][nv];
333  UH[k][j][i][nv] += state.rhs[*in][nv];
334  state.up[*in][nv] -= state.rhs[*in][nv];
335  state.um[*in][nv] -= state.rhs[*in][nv];
336  }}
337  }
338 
339 #else
340 
341  /* -------------------------------------------------------------
342  When parabolic terms have to be included explicitly, we use
343  a slightly different formulation where the transverse
344  predictors are computed using 1st order states.
345  This still yields a second-order accurate scheme but allow
346  to compute the solution at the half time step in one rows
347  of ghost zones, which is essential to update the parabolic
348  terms using midpoint rule:
349 
350  U^{n+1} = U^n - RHS(hyp, n+1/2) - RHS(par, n+1/2)
351 
352 
353  Since RHS(par) has a stencil 3-point wide.
354  Corner coupled states are modified to account for parabolic
355  terms in the following way:
356 
357  U^{n+1/2}_\pm = U^_\pm - RX,h + (RX,h + RY,h + RZ,h)
358  + (RX,p + RY,p + RZ,p)
359  -------------------------------------------------------------- */
360 
361  for ((*in) = 0; (*in) < indx.ntot; (*in)++) {
362  for (nv = NVAR; nv--; ) {
363  state.vp[*in][nv] = state.vm[*in][nv] = state.vh[*in][nv] = state.v[*in][nv];
364  }}
365  #ifdef STAGGERED_MHD
366  for (*in = 0; (*in) < indx.ntot-1; (*in)++) {
367  state.vR[*in][BXn] = state.vL[*in][BXn] = state.bn[*in];
368  }
369  #endif
370  PrimToCons(state.vm, state.um, 0, indx.ntot-1);
371  PrimToCons(state.vp, state.up, 0, indx.ntot-1);
372 
373  Riemann (&state, indx.beg-1, indx.end, Dts->cmax, grid);
374  #ifdef STAGGERED_MHD
375  CT_StoreEMF (&state, indx.beg-1, indx.end, grid);
376  #endif
377 
378  /* -----------------------------------------------------------
379  compute rhs using the hyperbolic fluxes only
380  ----------------------------------------------------------- */
381 
382  #if (VISCOSITY == EXPLICIT)
383  for ((*in) = 0; (*in) < indx.ntot; (*in)++) for (nv = NVAR; nv--; )
384  state.par_src[*in][nv] = 0.0;
385  #endif
386  RightHandSide (&state, Dts, indx.beg, indx.end, dt2, grid);
387  ParabolicFlux (d->Vc, d->J, T, &state, dcoeff, indx.beg-1, indx.end, grid);
388 
389  /* ----------------------------------------------------------------
390  compute LR states and subtract normal (hyperbolic)
391  rhs contribution.
392  NOTE: states are computed from IBEG - 1 (= indx.beg) up to
393  IEND + 1 (= indx.end) since EMF has already been evaluated
394  and stored using 1st order states above.
395  NOTE: States should be called after ParabolicFlux since some
396  terms (e.g. thermal conduction) may depend on left and
397  right normal states.
398  ---------------------------------------------------------------- */
399 
400  States (&state, indx.beg, indx.end, grid);
401  #if CTU_MHD_SOURCE == YES
402  CTU_CT_Source (state.v, state.up, state.um,
403  dtdV[g_dir], indx.beg, indx.end, grid);
404  #endif
405 
406  for ((*in) = indx.beg; (*in) <= indx.end; (*in)++) {
407  for (nv = NVAR; nv--; ){
408  state.up[*in][nv] -= state.rhs[*in][nv];
409  state.um[*in][nv] -= state.rhs[*in][nv];
410  }}
411 
412  /* -----------------------------------------------------------
413  re-compute the full rhs using the total (hyp+par) rhs
414  ----------------------------------------------------------- */
415 
416  RightHandSide (&state, Dts, indx.beg, indx.end, dt2, grid);
417 
418  if (g_dir == IDIR){
419  for ((*in) = indx.beg; (*in) <= indx.end; (*in)++) {
420  for (nv = NVAR; nv--; ){
421  dU[k][j][i][nv] = state.rhs[*in][nv];
422  UH[k][j][i][nv] = d->Uc[k][j][i][nv] + state.rhs[*in][nv];
423  }}
424  }else{
425  for ((*in) = indx.beg; (*in) <= indx.end; (*in)++) {
426  for (nv = NVAR; nv--; ){
427  dU[k][j][i][nv] += state.rhs[*in][nv];
428  UH[k][j][i][nv] += state.rhs[*in][nv];
429  }}
430  }
431 #endif
432  } /* -- end loop on transverse directions -- */
433 
434  } /* -- end loop on dimensions -- */
435 
436 /* -------------------------------------------------------
437  2a. Advance staggered magnetic fields by dt/2
438  ------------------------------------------------------- */
439 
440  #ifdef STAGGERED_MHD
441  CT_Update (d, d->Vs, 0.5*g_dt, grid);
442  CT_AverageMagneticField (d->Vs, UH, grid);
443  #endif
444 
445 /* ----------------------------------------------------------
446  2b. Convert cell and time centered values to primitive.
447  UH is transformed from conservative to primitive
448  variables for efficiency purposes.
449  ---------------------------------------------------------- */
450 
451  g_dir = IDIR;
452  SetIndexes (&indx, grid);
453  TRANSVERSE_LOOP(indx,in,i,j,k){
454  g_i = i; g_j = j; g_k = k;
455  errp = ConsToPrim(UH[k][j], state.v, indx.beg, indx.end, d->flag[k][j]);
456  for ((*in) = indx.beg; (*in) <= indx.end; (*in)++) {
457  VAR_LOOP(nv) d->Vc[nv][k][j][i] = state.v[*in][nv];
458  }
459  #if THERMAL_CONDUCTION == EXPLICIT
460  for ((*in) = indx.beg; (*in) <= indx.end; (*in)++){
461  T[k][j][i] = d->Vc[PRS][k][j][i]/d->Vc[RHO][k][j][i];
462  }
463  #endif
464  }
465  #if (RESISTIVITY == EXPLICIT) && (defined STAGGERED_MHD)
466  GetCurrent (d, -1, grid);
467  #endif
468 
469 /* ----------------------------------------------------
470  3. Final conservative update
471  ---------------------------------------------------- */
472 
473  g_intStage = 2;
474  for (g_dir = 0; g_dir < DIMENSIONS; g_dir++){
475 
476  SetIndexes (&indx, grid);
477  ResetState (d, &state, grid);
478  #if (RESISTIVITY == EXPLICIT) && !(defined STAGGERED_MHD)
479  GetCurrent(d, g_dir, grid);
480  #endif
481  TRANSVERSE_LOOP(indx,in,i,j,k){
482 
483  g_i = i; g_j = j; g_k = k;
484 
485  /* ---------------------------------------------------------
486  Convert conservative corner-coupled states to primitive
487  --------------------------------------------------------- */
488 
489  state.up = UP[g_dir][*(indx.pt2)][*(indx.pt1)]; state.uL = state.up;
490  state.um = UM[g_dir][*(indx.pt2)][*(indx.pt1)]; state.uR = state.um + 1;
491 
492  for ((*in) = indx.beg-1; (*in) <= indx.end+1; (*in)++){
493  for (nv = NVAR; nv--; ){
494  state.up[*in][nv] += dU[k][j][i][nv];
495  state.um[*in][nv] += dU[k][j][i][nv];
496  }
497  flagp[*in] = flagm[*in] = d->flag[k][j][i];
498  }
499 
500  /* -------------------------------------------------------
501  compute time centered, cell centered state.
502  Useful for source terms like gravity,
503  curvilinear terms and Powell's 8wave
504  ------------------------------------------------------- */
505 
506  for ((*in) = indx.beg-1; (*in) <= indx.end+1; (*in)++) {
507  NVAR_LOOP(nv) state.vh[*in][nv] = d->Vc[nv][k][j][i];
508  state.flag[*in] = d->flag[k][j][i];
509  }
510 
511  #ifdef STAGGERED_MHD
512  for ((*in) = indx.beg - 2; (*in) <= indx.end + 1; (*in)++){
513  state.uL[*in][BXn] = state.uR[*in][BXn] = d->Vs[BXs + g_dir][k][j][i];
514  state.bn[*in] = state.uL[*in][BXn];
515  }
516  #endif
517 
518  errm = ConsToPrim (state.um, state.vm, indx.beg - 1, indx.end + 1, flagm);
519  errp = ConsToPrim (state.up, state.vp, indx.beg - 1, indx.end + 1, flagp);
520 /*
521  if (errm || errp){
522  WARNING(print ("! Corner coupled states not physical: reverting to 1st order\n");)
523  for (in = indx.beg - 1; in <= indx.end + 1; in++){
524  if ( (flagm[*in] & FLAG_CONS2PRIM_FAIL)
525  || (flagm[in] & FLAG_CONS2PRIM_FAIL) ) {
526  for (nv = 0; nv < NVAR; nv++) {
527  state.v[in][nv] = d->Vc[nv][*k][*j][*i];
528  }
529  PrimToCons(state.v, state.u, in, in);
530  for (nv = 0; nv < NVAR; nv++) {
531  state.vm[in][nv] = state.vp[in][nv] = state.vh[in][nv] = state.v[in][nv];
532  state.um[in][nv] = state.up[in][nv] = state.uh[in][nv] = state.u[in][nv];
533  }
534  }
535  }
536  }
537 */
538 
539  /* ------------------------------------------
540  compute flux & righ-hand-side
541  ------------------------------------------ */
542 
543  Riemann (&state, indx.beg - 1, indx.end, Dts->cmax, grid);
544  #ifdef STAGGERED_MHD
545  CT_StoreEMF (&state, indx.beg - 1, indx.end, grid);
546  #endif
547  #if (PARABOLIC_FLUX & EXPLICIT)
548 
549  /* --------------------------------------------------------
550  since integration in the transverse directions extends
551  one point below and one point above the computational
552  box (when using CT), we avoid computing parabolic
553  operators in one row of boundary zones below and above
554  since the 3-point wide stencil may not be available.
555  -------------------------------------------------------- */
556 
557  errp = 1;
558  #ifdef STAGGERED_MHD
559  D_EXPAND( ,
560  errp = (*(indx.pt1) < indx.t1_end) && (*(indx.pt1) > indx.t1_beg); ,
561  errp = errp && (*(indx.pt2) < indx.t2_end) && (*(indx.pt2) > indx.t2_beg);)
562  #endif
563  if (errp) {
564  ParabolicFlux (d->Vc, d->J, T, &state, dcoeff, indx.beg - 1, indx.end, grid);
565  inv_dl = GetInverse_dl(grid);
566  for ((*in) = indx.beg; (*in) <= indx.end; (*in)++) {
567  inv_dtp = 0.0;
568  #if VISCOSITY == EXPLICIT
569  inv_dtp = MAX(inv_dtp, dcoeff[*in][MX1]);
570  #endif
571  #if RESISTIVITY == EXPLICIT
572  EXPAND(inv_dtp = MAX(inv_dtp, dcoeff[*in][BX1]); ,
573  inv_dtp = MAX(inv_dtp, dcoeff[*in][BX2]); ,
574  inv_dtp = MAX(inv_dtp, dcoeff[*in][BX3]);)
575  #endif
577  inv_dtp = MAX(inv_dtp, dcoeff[*in][ENG]);
578  #endif
579  inv_dtp *= inv_dl[*in]*inv_dl[*in];
580 
581  Dts->inv_dtp = MAX(Dts->inv_dtp, inv_dtp);
582  }
583  }
584  #endif
585  #if UPDATE_VECTOR_POTENTIAL == YES
586  VectorPotentialUpdate (d, NULL, &state, grid);
587  #endif
588  #ifdef SHEARINGBOX
589  SB_SaveFluxes(&state, grid);
590  #endif
591 
592  RightHandSide (&state, Dts, indx.beg, indx.end, g_dt, grid);
593 
594  for ((*in) = indx.beg; (*in) <= indx.end; (*in)++) {
595  NVAR_LOOP(nv) d->Uc[k][j][i][nv] += state.rhs[*in][nv];
596  }
597  }
598  }
599 
600  #ifdef SHEARINGBOX
601  SB_CorrectFluxes(d->Uc, g_time+0.5*g_dt, g_dt, grid);
602  #endif
603 
604  #ifdef STAGGERED_MHD
605  CT_Update (d, Bs0, g_dt, grid);
606  CT_AverageMagneticField (d->Vs, d->Uc, grid);
607  #endif
608 
609 /* ----------------------------------------------
610  convert to primitive
611  ---------------------------------------------- */
612 
613  #ifdef FARGO
614  FARGO_ShiftSolution (d->Uc, d->Vs, grid);
615  #endif
616 
617  ConsToPrim3D(d->Uc, d->Vc, d->flag, box);
618 
619  #ifdef FARGO
620  FARGO_AddVelocity (d,grid);
621  #endif
622 
623  return(0); /* -- step has been achieved, return success -- */
624 }
625 
626 #if CTU_MHD_SOURCE == YES
627 /* ********************************************************************* */
628 void CTU_CT_Source (double **v, double **up, double **um,
629  double *dtdV, int beg, int end, Grid *grid)
630 /*!
631  * Add source terms to conservative left and right states obtained from
632  * the primitive form of the equations. The source terms are:
633  *
634  * - m += dt/2 * B * dbx/dx
635  * - Bt += dt/2 * vt * dbx/dx (t = transverse component)
636  * - E += dt/2 * v*B * dbx/dx
637  *
638  * These terms are NOT accounted for when the primitive form of the
639  * equations is used (see Gardiner & Stone JCP (2005), Crockett et al.
640  * JCP(2005)). This is true for both the Charactheristic Tracing AND the
641  * primitive Hancock scheme when the constrained transport is used, since
642  * the resulting system is 7x7. To better understand this, you can
643  * consider the stationary solution rho = p = 1, v = 0 and Bx = x,
644  * By = -y. If these terms were not included the code would generate
645  * spurious velocities.
646  *
647  *********************************************************************** */
648 {
649  int i;
650  double scrh, *dx, *A;
651  static double *db;
652 
653  if (db == NULL) db = ARRAY_1D(NMAX_POINT, double);
654 
655 /* ----------------------------------------
656  comput db/dx
657  ---------------------------------------- */
658 
659  #if GEOMETRY == CARTESIAN
660  for (i = beg; i <= end; i++){
661  db[i] = dtdV[i]*(up[i][BXn] - um[i][BXn]);
662  }
663  #elif GEOMETRY == CYLINDRICAL
664  if (g_dir == IDIR){
665  A = grid[IDIR].A;
666  for (i = beg; i <= end; i++){
667  db[i] = dtdV[i]*(up[i][BXn]*A[i] - um[i][BXn]*A[i - 1]);
668  }
669  }else{
670  for (i = beg; i <= end; i++){
671  db[i] = dtdV[i]*(up[i][BXn] - um[i][BXn]);
672  }
673  }
674  #else
675  print1 (" ! CTU-MHD does not work in this geometry\n");
676  QUIT_PLUTO(1);
677  #endif
678 
679 /* --------------------------------------------
680  Add source terms
681  -------------------------------------------- */
682 
683  for (i = beg; i <= end; i++){
684  EXPAND( up[i][MX1] += v[i][BX1]*db[i];
685  um[i][MX1] += v[i][BX1]*db[i]; ,
686  up[i][MX2] += v[i][BX2]*db[i];
687  um[i][MX2] += v[i][BX2]*db[i]; ,
688  up[i][MX3] += v[i][BX3]*db[i];
689  um[i][MX3] += v[i][BX3]*db[i]; )
690 
691  EXPAND( ; ,
692  up[i][BXt] += v[i][VXt]*db[i];
693  um[i][BXt] += v[i][VXt]*db[i]; ,
694  up[i][BXb] += v[i][VXb]*db[i];
695  um[i][BXb] += v[i][VXb]*db[i];)
696 
697  #if HAVE_ENERGY
698  scrh = EXPAND( v[i][VX1]*v[i][BX1] ,
699  + v[i][VX2]*v[i][BX2] ,
700  + v[i][VX3]*v[i][BX3]);
701  up[i][ENG] += scrh*db[i];
702  um[i][ENG] += scrh*db[i];
703  #endif
704  }
705 
706 }
707 #endif
#define MX3
Definition: mod_defs.h:22
void Boundary(const Data *d, int idim, Grid *grid)
Definition: boundary.c:36
#define MAX(a, b)
Definition: macros.h:101
tuple T
Definition: Sph_disk.py:33
void CT_StoreEMF(const State_1D *state, int beg, int end, Grid *grid)
Definition: ct_emf.c:35
double ** v
Cell-centered primitive varables at the base time level, v[i] = .
Definition: structs.h:134
double **** Vs
The main four-index data array used for face-centered staggered magnetic fields.
Definition: structs.h:43
void ResetState(const Data *, State_1D *, Grid *)
Definition: set_indexes.c:163
int AdvanceStep(const Data *d, Riemann_Solver *Riemann, Time_Step *Dts, Grid *grid)
Definition: ctu_step.c:88
#define MX1
Definition: mod_defs.h:20
double ** vh
Primitive state at n+1/2 (only for one step method)
Definition: structs.h:162
double **** Data_Arr
Definition: pluto.h:492
double **** J
Electric current defined as curl(B).
Definition: structs.h:54
#define VX2
Definition: mod_defs.h:29
void GetCurrent(const Data *d, int dir, Grid *grid)
Definition: res_functions.c:97
RBox * GetRBox(int, int)
Definition: rbox.c:232
int ntot
Definition: structs.h:318
#define CENTER
Definition: pluto.h:200
void print1(const char *fmt,...)
Definition: amrPluto.cpp:511
void Riemann_Solver(const State_1D *, int, int, double *, Grid *)
Definition: pluto.h:489
double ** rhs
Conservative right hand side.
Definition: structs.h:163
int t2_end
Definition: structs.h:320
void States(const State_1D *, int, int, Grid *)
Definition: plm_states.c:430
#define RHO
Definition: mod_defs.h:19
tuple scrh
Definition: configure.py:200
int t1_end
Definition: structs.h:319
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
#define KTOT_LOOP(k)
Definition: macros.h:40
static void CTU_CT_Source(double **, double **, double **, double *, int, int, Grid *)
Definition: ctu_step.c:628
double g_dt
The current integration time step.
Definition: globals.h:118
double * GetInverse_dl(const Grid *)
Definition: set_geometry.c:205
void SB_CorrectFluxes(Data_Arr U, double t, double dt, Grid *grid)
Definition: sb_flux.c:105
double * dV
Cell volume.
Definition: structs.h:86
#define DOM
Computational domain (interior)
Definition: pluto.h:152
#define BX3s
Definition: ct.h:29
void CT_Update(const Data *d, Data_Arr Bs, double dt, Grid *grid)
Definition: ct.c:29
void FARGO_ShiftSolution(Data_Arr U, Data_Arr Us, Grid *grid)
Definition: fargo.c:42
double ** vR
Primitive variables to the right of the interface, .
Definition: structs.h:139
#define ARRAY_3D(nx, ny, nz, type)
Definition: prototypes.h:172
double * cmax
Maximum signal velocity for hyperbolic eqns.
Definition: structs.h:214
void FARGO_AddVelocity(const Data *, Grid *)
#define VX1
Definition: mod_defs.h:28
#define KDIR
Definition: pluto.h:195
unsigned char *** flag
Pointer to a 3D array setting useful integration flags that are retrieved during integration.
Definition: structs.h:55
int t2_beg
Definition: structs.h:320
void ConsToPrim3D(Data_Arr U, Data_Arr V, unsigned char ***flag, RBox *box)
Definition: mappers3D.c:16
int VXb
Definition: globals.h:73
void MakeState(State_1D *)
Definition: tools.c:51
double inv_dtp
Inverse of diffusion (parabolic) time step .
Definition: structs.h:217
int BXn
Definition: globals.h:75
double ** vp
prim vars at i+1/2 edge, vp[i] = vL(i+1/2)
Definition: structs.h:142
int t1_beg
Definition: structs.h:319
int g_i
x1 grid index when sweeping along the x2 or x3 direction.
Definition: globals.h:82
int CheckNaN(double **, int, int, int)
Definition: tools.c:19
void FARGO_SubtractVelocity(const Data *, Grid *)
#define THERMAL_CONDUCTION
Definition: pluto.h:365
#define VAR_LOOP(n)
Definition: macros.h:226
#define TOT_LOOP(k, j, i)
Definition: macros.h:44
int * pt1
Definition: structs.h:319
#define IDIR
Definition: pluto.h:193
int g_dir
Specifies the current sweep or direction of integration.
Definition: globals.h:86
#define NVAR_LOOP(n)
Definition: pluto.h:618
int ConsToPrim(double **ucons, double **uprim, int ibeg, int iend, unsigned char *flag)
Definition: mappers.c:89
int g_j
x2 grid index when sweeping along the x1 or x3 direction.
Definition: globals.h:83
Definition: structs.h:78
#define BXs
Definition: ct.h:33
long int NX3_TOT
Total number of zones in the X3 direction (boundaries included) for the local processor.
Definition: globals.h:59
int * pt2
Definition: structs.h:320
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 VXt
Definition: globals.h:73
unsigned char * flag
Definition: structs.h:168
int k
Definition: analysis.c:2
#define BX1s
Definition: ct.h:27
void SetIndexes(Index *indx, Grid *grid)
Definition: set_indexes.c:49
void RightHandSide(const State_1D *state, Time_Step *Dts, int beg, int end, double dt, Grid *grid)
Definition: rhs.c:88
int g_k
x3 grid index when sweeping along the x1 or x2 direction.
Definition: globals.h:84
double ** vm
prim vars at i-1/2 edge, vm[i] = vR(i-1/2)
Definition: structs.h:141
double ** uR
same as vR, in conservative vars
Definition: structs.h:145
int beg
Definition: structs.h:318
#define BX3
Definition: mod_defs.h:27
PLUTO main header file.
#define ARRAY_1D(nx, type)
Definition: prototypes.h:170
#define ITOT_LOOP(i)
Definition: macros.h:38
D_EXPAND(tot/[n]=(double) grid[IDIR].np_int_glob;, tot/[n]=(double) grid[JDIR].np_int_glob;, tot/[n]=(double) grid[KDIR].np_int_glob;)
Definition: analysis.c:27
Definition: structs.h:30
long int NMAX_POINT
Maximum number of points among the three directions, boundaries excluded.
Definition: globals.h:62
#define JTOT_LOOP(j)
Definition: macros.h:39
void PrimToCons(double **uprim, double **ucons, int ibeg, int iend)
Definition: mappers.c:26
int i
Definition: analysis.c:2
double g_time
The current integration time.
Definition: globals.h:117
double * bn
Face magentic field, bn = bx(i+1/2)
Definition: structs.h:165
Definition: structs.h:317
double **** Uc
The main four-index data array used for cell-centered conservative variables.
Definition: structs.h:37
void SB_SaveFluxes(State_1D *state, Grid *grid)
Definition: sb_flux.c:57
#define BX1
Definition: mod_defs.h:25
double ** um
same as vm, in conservative vars
Definition: structs.h:146
#define VX3
Definition: mod_defs.h:30
void ParabolicFlux(Data_Arr V, Data_Arr J, double ***T, const State_1D *state, double **dcoeff, int beg, int end, Grid *grid)
double ** vL
Primitive variables to the left of the interface, .
Definition: structs.h:136
#define BX2s
Definition: ct.h:28
double ** up
same as vp, in conservative vars
Definition: structs.h:147
#define ARRAY_2D(nx, ny, type)
Definition: prototypes.h:171
#define BX2
Definition: mod_defs.h:26
void FlagShock(const Data *, Grid *)
void VectorPotentialUpdate(const Data *d, const void *vp, const State_1D *state, const Grid *grid)
#define JDIR
Definition: pluto.h:194
int BXt
Definition: globals.h:75
int end
Definition: structs.h:318
#define NVAR
Definition: pluto.h:609
Definition: structs.h:346
int BXb
Definition: globals.h:75
#define QUIT_PLUTO(e_code)
Definition: macros.h:125
#define EXPLICIT
Definition: pluto.h:67
#define TRANSVERSE_LOOP(indx, ip, i, j, k)
Definition: macros.h:54
long int NX1_TOT
Total number of zones in the X1 direction (boundaries included) for the local processor.
Definition: globals.h:55
double * A
Right interface area, A[i] = .
Definition: structs.h:87
#define DIMENSIONS
Definition: definitions_01.h:2
#define HAVE_ENERGY
Definition: pluto.h:395
double ** uL
same as vL, in conservative vars
Definition: structs.h:144
void CT_AverageMagneticField(double ****bf, double ****UU, Grid *grid)
#define ALL_DIR
Definition: pluto.h:196