PLUTO
init.c
Go to the documentation of this file.
1 /* ///////////////////////////////////////////////////////////////////// */
2 /*!
3  \file
4  \brief Accretion disk in 3D spherical coordinates.
5 
6  Setup a magnetized disk in 3D spherical coordinates \f$(r,\theta,\phi\f$).
7  The disk model is taken form [Flo11],[Mig12] and it consists of an initial
8  equilibrium in a point mass gravity \f$ 1/r^2\f$ with equilibrium profiles
9  given by
10  \f[
11  \rho = \frac{1}{R^{3/2}}\exp\left[\frac{\sin(\theta) - 1}{c_0^2}\right]
12  \,,\qquad
13  p = c_s^2\rho\
14  ,,\qquad
15  v_\phi = \frac{1}{\sqrt{r}}\left(1 - \frac{5}{2\sin\theta}c_0^2\right)
16  \f]
17  where \f$R = r\sin\theta\f$ is the cylindrical radius while
18  \f$c_0 = H/R\f$ and \f$c_s = H/R^{3/2}\f$ is the sound speed.
19  Here \c H is the scale height and it is proportional to the cylindrical
20  radius.
21  The constant of proportionality is the ratio \f$ H/R \f$ defined by the
22  input parameter <tt>g_inputParam[H_R]</tt>.
23  With the current setting, one rotation period of the inner orbit (\c r=1)
24  is \f$\Delta T = 2\pi\f$.
25 
26  Differently from [Flo11], a polodial magnetic field is used here, with
27  vector potential prescribed as follows:
28  \f[
29  A_\phi = A_0\frac{\sin(2\pi R) - R\cos(2\pi R)}{R}
30  \exp\left[-\left(\frac{z}{H}\right)^4\right]
31  \exp\left[-\left(\frac{R-6}{2}\right)^4\right]
32  \f]
33  where \c A0 is a constant chosen to prescribe a given plasma beta.
34  The exponential terms on the right hand side confine the magnetic field
35  in the midplane around \c R=6.
36  We also make the vector potential vanish identically for \f$ z/H > 2.5\f$
37  or \f$ R < 2.5\f$.
38 
39  The boundary conditions are all set to \c userdef:
40 
41  - at the inner radial boundary, zero-gradient is imposed except for
42  the azimuthal velocity (which is fixed the equilibrium value) and the
43  radial velocity which is zero if velocity is directed inside the domain
44  or copied otherwise (this is referred to as the "diode" b.c.)
45  - at the outer radial boundary we impose zero-gradient except for the
46  azimuthal velocity (fixed to equil. value) and radial velocity
47  which is reflected.
48  - at the vertical (theta) boundaries, ghost zones are filled with
49  the initial equilibrium solution.
50 
51  For the sake of simplicity only a quarter of a disk is considered.
52  This test problems can be run normally or using the FARGO module,
53  giving a saving factor of (roughly) 5.
54  The figure below was produced by running the current setup at twice the
55  resolution and for 90 orbits using FARGO.
56 
57  \image html mhd_spherical_disk.02.png "Density map of the disk after 90 innter orbits at twice the resolution."
58  \authors A. Mignone (mignone@ph.unito.it)\n
59  \date Aug 16, 2012
60 
61  \b References
62  - [Flo11]: "Turbulence and Steady Flows in 3D Global Stratified
63  MHD Simulations of Accretion Disks", Flock et al., ApJ (2011), 735:122
64  - [Mig12]: "A Conservative orbital advection scheme for simulations of
65  magnetized shear flows with the PLUTO code",
66  Mignone et al, A&A (2012) 545, A152
67 */
68 /* ///////////////////////////////////////////////////////////////////// */
69 #include "pluto.h"
70 
71 /* ********************************************************************* */
72 void Init (double *us, double x1, double x2, double x3)
73 /*
74  *
75  *********************************************************************** */
76 {
77  static int first_call = 1;
78  double rnd, s, c, R, r, z;
79  double H, c0, cs, Bphi;
80 
81  g_gamma = 1.0001;
82  r = x1;
83  s = sin(x2);
84  c = cos(x2);
85 
86  R = r*s; /* Cylindrical radius */
87  z = r*c;
88  c0 = g_inputParam[H_R];
89  cs = c0/sqrt(R);
90  H = g_inputParam[H_R]*R;
91 
92  us[RHO] = exp((s-1.0)/(c0*c0))/(R*sqrt(R));
93  us[iVR] = 0.0;
94  us[iVTH] = 1.e-4*cs*cos(8.0*x3)*exp(-2.0*z*z/(H*H)); /* Perturbation */
95  us[iVPHI] = 1.0/sqrt(r)*(1.0 - 2.5*c0*c0/s);
96  us[PRS] = cs*cs*us[RHO];
97 
98  #if PHYSICS == MHD
99  us[BX1] = us[BX2] = us[BX3] = 0.0;
100  us[AX1] = us[AX2] = us[AX3] = 0.0;
101 
102  us[AX3] = (sin(2.0*CONST_PI*R) - R*cos(2.0*CONST_PI*R))/R;
103  us[AX3] *= 3.5e-4*exp(-pow(z/H,4.0))*exp(-pow((R-6.0)/2.0,4.0));
104  if (fabs(z/H) > 2.5 || R < 2.5) us[AX3] = 0.0;
105  #endif
106  g_smallPressure = 1.e-9;
107 }
108 /* ********************************************************************* */
109 void Analysis (const Data *d, Grid *grid)
110 /*
111  *
112  *
113  *********************************************************************** */
114 {
115  int i,j,k,nv;
116  static int first_call = 1;
117  double v[NVAR];
118  double *r, *th, *dVr, *dVth, *dVphi, vol;
119  double pm, kin;
120  double pmtot, Tmtot;
121  static double voltot;
122  FILE *fp;
123 
124  r = grid[IDIR].x;
125  th = grid[JDIR].x;
126  dVr = grid[IDIR].dV; dVth = grid[JDIR].dV; dVphi = grid[KDIR].dV;
127 
128 /* ---------------------------------------------------------
129  compute total volume once at the beginning
130  --------------------------------------------------------- */
131 
132  if (first_call){
133  voltot = 0.0;
134  DOM_LOOP(k,j,i) voltot += dVr[i]*dVth[j]*dVphi[k];
135  #ifdef PARALLEL
136  MPI_Allreduce (&voltot, &kin, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
137  MPI_Barrier (MPI_COMM_WORLD);
138  voltot = kin;
139  #endif
140  }
141 
142 /* --------------------------------------------------------
143  compute volume averages
144  -------------------------------------------------------- */
145 
146  pmtot = Tmtot = 0.0;
147  DOM_LOOP(k,j,i){
148  vol = dVr[i]*dVth[j]*dVphi[k]/voltot;
149 
150  for (nv = NVAR; nv--; ) v[nv] = d->Vc[nv][k][j][i];
151 
152  #if PHYSICS == MHD
153  pm = 0.5*(v[BX1]*v[BX1] + v[BX2]*v[BX2] + v[BX3]*v[BX3]);
154  pmtot += pm*vol;
155  Tmtot += v[BX1]*v[BX3]*vol;
156  #endif
157  }
158 
159  #ifdef PARALLEL
160  MPI_Allreduce (&pmtot, &vol, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
161  pmtot = vol;
162 
163  MPI_Allreduce (&Tmtot, &vol, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
164  Tmtot = vol;
165 
166  MPI_Barrier (MPI_COMM_WORLD);
167  #endif
168 
169 /* -----------------------------------------------------
170  Write "averages.dat" to disk.
171  The file is created as new if this is the very
172  initial time step. Data is appended otherwise.
173  Processor #0 does the actual writing.
174  ----------------------------------------------------- */
175 
176  if (prank == 0){
177  static double tpos = -1.0;
178  if (g_stepNumber == 0){
179  fp = fopen("averages.dat","w");
180  fprintf (fp,"#%s %12s %12s %12s\n",
181  " t","dt","<B^2>/2","<Tm>");
182  }else{
183  if (tpos < 0.0){ /* obtain time coordinate of to last entry */
184  char sline[512];
185  fp = fopen("averages.dat","r");
186  while (fgets(sline, 512, fp)) {}
187  sscanf(sline, "%lf\n",&tpos);
188  fclose(fp);
189  }
190  fp = fopen("averages.dat","a");
191  }
192  if (g_time > tpos){
193  fprintf (fp, "%12.6e %12.6e %12.6e %12.6e\n",
194  g_time, g_dt, pmtot, Tmtot);
195  }
196  fclose(fp);
197  }
198  first_call = 0;
199 }
200 /* ********************************************************************* */
201 void UserDefBoundary (const Data *d, RBox *box, int side, Grid *grid)
202 /*
203  *
204  *
205  *
206  *********************************************************************** */
207 {
208  int i, j, k, nv;
209  double c0, cs, qx, qy, qz, s, v[256];
210  double *r, *th, *phi;
211 
212  r = grid[IDIR].xgc;
213  th = grid[JDIR].xgc;
214  phi = grid[KDIR].xgc;
215  c0 = g_inputParam[H_R];
216 
217  if (side == 0) { /* -- check solution inside domain -- */
218  }
219 
220  if (side == X1_BEG){ /* -- X1_BEG boundary -- */
221  if (box->vpos == CENTER){
222  BOX_LOOP(box,k,j,i){
223  for (nv = 0; nv < NVAR; nv++) d->Vc[nv][k][j][i]= d->Vc[nv][k][j][IBEG];
224  s = sin(th[j]);
225  d->Vc[iVPHI][k][j][i] = 1.0/sqrt(r[i])*(1.0 - 2.5*c0*c0/s);
226  if (d->Vc[iVR][k][j][i] > 0.0) d->Vc[iVR][k][j][i] = 0.0;
227  }
228  }else if (box->vpos == X2FACE){
229  #ifdef STAGGERED_MHD
230  BOX_LOOP(box,k,j,i) d->Vs[BX2s][k][j][i] = d->Vs[BX2s][k][j][IBEG];
231  #endif
232  }else if (box->vpos == X3FACE){
233  #ifdef STAGGERED_MHD
234  BOX_LOOP(box,k,j,i) d->Vs[BX3s][k][j][i] = d->Vs[BX3s][k][j][IBEG];
235  #endif
236  }
237  }
238 
239  if (side == X1_END){ /* -- X1_END boundary -- */
240  if (box->vpos == CENTER){
241  BOX_LOOP(box, k, j, i){
242  for (nv = 0; nv < NVAR; nv++) d->Vc[nv][k][j][i]= d->Vc[nv][k][j][IEND];
243  s = sin(th[j]);
244  d->Vc[iVPHI][k][j][i] = 1.0/sqrt(r[i])*(1.0 - 2.5*c0*c0/s);
245  d->Vc[iVR][k][j][i] = -d->Vc[iVR][k][j][2*IEND - i + 1];
246  }
247  }else if (box->vpos == X2FACE){
248  #ifdef STAGGERED_MHD
249  BOX_LOOP(box,k,j,i) d->Vs[BX2s][k][j][i] = d->Vs[BX2s][k][j][IEND];
250  #endif
251  }else if (box->vpos == X3FACE){
252  #ifdef STAGGERED_MHD
253  BOX_LOOP(box,k,j,i) d->Vs[BX3s][k][j][i] = d->Vs[BX3s][k][j][IEND];
254  #endif
255  }
256  }
257 
258  if (side == X2_BEG){ /* -- X2_BEG boundary -- */
259  if (box->vpos == CENTER){
260  BOX_LOOP(box, k, j, i){
261  Init (v, r[i], th[j], phi[k]);
262  cs = c0/sqrt(r[i]*sin(th[j]));
263  v[iVTH] = 0.0;
264  v[PRS] = v[RHO]*cs*cs;
265  for (nv = 0; nv < NVAR; nv++) d->Vc[nv][k][j][i]= v[nv];
266  }
267  }else if (box->vpos == X1FACE){
268  #ifdef STAGGERED_MHD
269  BOX_LOOP(box, k, j, i) d->Vs[BX1s][k][j][i] = 0.0;
270  #endif
271  }else if (box->vpos == X3FACE){
272  #ifdef STAGGERED_MHD
273  BOX_LOOP(box, k, j, i) d->Vs[BX3s][k][j][i] = 0.0;
274  #endif
275  }
276 
277  }
278 
279  if (side == X2_END){ /* -- X2_END boundary -- */
280  if (box->vpos == CENTER){
281  BOX_LOOP(box, k, j, i){
282  Init (v, r[i], th[j], phi[k]);
283  cs = c0/sqrt(r[i]*sin(th[j]));
284  v[iVTH] = 0.0;
285  v[PRS] = v[RHO]*cs*cs;
286  for (nv = 0; nv < NVAR; nv++) d->Vc[nv][k][j][i]= v[nv];
287  }
288  }else if (box->vpos == X1FACE){
289  #ifdef STAGGERED_MHD
290  BOX_LOOP(box, k, j, i) d->Vs[BX1s][k][j][i] = 0.0;
291  #endif
292  }else if (box->vpos == X3FACE){
293  #ifdef STAGGERED_MHD
294  BOX_LOOP(box, k, j, i) d->Vs[BX3s][k][j][i] = 0.0;
295  #endif
296  }
297  }
298 }
299 
300 #if (BODY_FORCE & VECTOR)
301 /* ************************************************************************ */
302 void BodyForceVector(double *v, double *g, double x1, double x2, double x3)
303 /*
304  *
305  *
306  *
307  *************************************************************************** */
308 {
309  g[IDIR] = -1.0/(x1*x1);
310  g[JDIR] = 0.0;
311  g[KDIR] = 0.0;
312 }
313 #endif
314 
315 #if (BODY_FORCE & POTENTIAL)
316 /* ************************************************************************ */
317 double BodyForcePotential(double x1, double x2, double x3)
318 /*
319  *
320  *
321  *
322  *************************************************************************** */
323 {
324  return 0.0;
325 }
326 #endif
#define X1_BEG
Boundary region at X1 beg.
Definition: pluto.h:146
double **** Vs
The main four-index data array used for face-centered staggered magnetic fields.
Definition: structs.h:43
double g_gamma
Definition: globals.h:112
void UserDefBoundary(const Data *d, RBox *box, int side, Grid *grid)
Definition: init.c:98
DOM_LOOP(k, j, i)
Definition: analysis.c:22
#define CENTER
Definition: pluto.h:200
int vpos
Location of the variable inside the cell.
Definition: structs.h:359
#define RHO
Definition: mod_defs.h:19
#define X3FACE
Definition: pluto.h:203
#define BOX_LOOP(B, k, j, i)
Definition: macros.h:70
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
#define iVPHI
Definition: mod_defs.h:67
double * dV
Cell volume.
Definition: structs.h:86
#define AX2
Definition: mod_defs.h:86
#define BX3s
Definition: ct.h:29
double g_smallPressure
Small value for pressure fix.
Definition: globals.h:110
#define X1_END
Boundary region at X1 end.
Definition: pluto.h:147
int prank
Processor rank.
Definition: globals.h:33
#define KDIR
Definition: pluto.h:195
#define X1FACE
Definition: pluto.h:201
long int g_stepNumber
Gives the current integration step number.
Definition: globals.h:97
#define iVR
Definition: mod_defs.h:65
#define IDIR
Definition: pluto.h:193
#define X2_END
Boundary region at X2 end.
Definition: pluto.h:149
Definition: structs.h:78
#define AX3
Definition: mod_defs.h:87
double g_inputParam[32]
Array containing the user-defined parameters.
Definition: globals.h:131
#define PHYSICS
Definition: definitions_01.h:1
int j
Definition: analysis.c:2
#define iVTH
Definition: mod_defs.h:66
long int IEND
Upper grid index of the computational domain in the the X1 direction for the local processor...
Definition: globals.h:37
int k
Definition: analysis.c:2
#define BX1s
Definition: ct.h:27
double * x
Definition: structs.h:80
double * xgc
Cell volumetric centroid (!= x when geometry != CARTESIAN).
Definition: structs.h:84
tuple c
Definition: menu.py:375
#define H_R
#define MHD
Definition: pluto.h:111
#define s
#define BX3
Definition: mod_defs.h:27
PLUTO main header file.
Definition: structs.h:30
int i
Definition: analysis.c:2
double g_time
The current integration time.
Definition: globals.h:117
double BodyForcePotential(double x, double y, double z)
Definition: init.c:479
#define AX1
Definition: mod_defs.h:85
FILE * fp
Definition: analysis.c:7
#define BX1
Definition: mod_defs.h:25
#define CONST_PI
.
Definition: pluto.h:269
#define BX2s
Definition: ct.h:28
#define X2_BEG
Boundary region at X2 beg.
Definition: pluto.h:148
#define BX2
Definition: mod_defs.h:26
#define JDIR
Definition: pluto.h:194
#define NVAR
Definition: pluto.h:609
Definition: structs.h:346
#define X2FACE
Definition: pluto.h:202
long int IBEG
Lower grid index of the computational domain in the the X1 direction for the local processor...
Definition: globals.h:35
void Analysis(const Data *d, Grid *grid)
Definition: init.c:66
void Init(double *v, double x1, double x2, double x3)
Definition: init.c:17
void BodyForceVector(double *v, double *g, double x, double y, double z)
Definition: init.c:441