Skip to content

Commit dc4a7e2

Browse files
authored
Added burn_cell test for primordial chem (#1064)
This PR will add the burn_cell test for primordial chemistry. The test is identical to the one used in other astrochem codes. It basically sets up a one-zone model of a collapsing primordial molecular cloud. We initialize the abundances of each chemical specie (H, H+, H2, D, HD, etc.) at some initial density. We then increase the density in steps of 0.1*freefall_time, and the output at each step is the number densities of all chemical species and the gas temperature. The model stops when the densities are > 3e-6 g/cm^3 or the number of steps > 1000, or the maximum time exceeds the given value.
1 parent 5bade97 commit dc4a7e2

8 files changed

Lines changed: 896 additions & 0 deletions

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
PRECISION = DOUBLE
2+
PROFILE = FALSE
3+
4+
# Set DEBUG to TRUE if debugging
5+
DEBUG = TRUE
6+
7+
DIM = 1
8+
9+
COMP = gnu
10+
11+
USE_MPI = FALSE
12+
USE_OMP = FALSE
13+
#set USE_CUDA to TRUE to compile and run on GPUs
14+
USE_CUDA = FALSE
15+
USE_REACT = TRUE
16+
17+
# Set USE_MICROPHYSICS_DEBUG to TRUE if debugging
18+
USE_MICROPHYSICS_DEBUG = TRUE
19+
20+
EBASE = main
21+
22+
USE_CXX_REACTIONS ?= TRUE
23+
24+
ifeq ($(USE_CXX_REACTIONS),TRUE)
25+
DEFINES += -DCXX_REACTIONS
26+
endif
27+
28+
# define the location of the CASTRO top directory
29+
MICROPHYSICS_HOME := ../..
30+
31+
# This sets the EOS directory in Castro/EOS -- note: gamma_law will not work,
32+
# you'll need to use gamma_law_general
33+
EOS_DIR := primordial_chem
34+
35+
# This sets the network directory in Castro/Networks
36+
NETWORK_DIR := primordial_chem
37+
38+
CONDUCTIVITY_DIR := stellar
39+
40+
INTEGRATOR_DIR = VODE
41+
42+
ifeq ($(USE_CUDA), TRUE)
43+
INTEGRATOR_DIR := VODE
44+
endif
45+
46+
EXTERN_SEARCH += .
47+
48+
Bpack := ./Make.package
49+
Blocs := .
50+
51+
include $(MICROPHYSICS_HOME)/unit_test/Make.unit_test
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
CEXE_sources += main.cpp
2+
CEXE_headers += burn_cell.H
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#Authors: Piyush Sharda & Benjamin Wibking (ANU, 2022)
2+
3+
# burn_cell_primordial_chem
4+
5+
`burn_cell_primordial_chem` integrates a primordial ISM chemistry network
6+
for a single set of initial conditions. The density, temperature, and composition
7+
are set in the inputs file, as well as the maximum time to integrate.
8+
9+
Upon completion, the new state is printed to the screen.
10+
11+
# key difference with other tests
12+
13+
For primordial chemistry, state.xn is always assumed to contain
14+
number densities. We work with number densities and not mass fractions
15+
because our equations are very stiff (stiffness ratios are as high as 1e31)
16+
because y/ydot (natural timescale for a species abundance to vary) can be
17+
very different (by factors ~ 1e30) for different species.
18+
However, state.rho still conatins the density in g/cm^3, and state.e
19+
still contains the specific internal energy in erg/g/K.
20+
21+
# continuous integration
22+
23+
The code is built with the `primordial_chem` network and run with `inputs_primordial_chem`.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@namespace: unit_test
2+
3+
run_prefix character "burn_cell_primordial_chem"
4+
5+
# floor values of temperature and density
6+
small_temp real 1.e1
7+
small_dens real 1.e-30
8+
9+
# the final time to integrate to
10+
tmax real 1.e20
11+
# tff_reduc reduces the calculated freefall time to accordingly increase the density during the single zone burn
12+
tff_reduc real 1.e-1
13+
14+
# first output time -- we will output in nsteps logarithmically spaced steps between [tfirst, tmax]
15+
tfirst real 0.0
16+
17+
# number of steps for the single zone burn
18+
nsteps integer 1000
19+
20+
# initial temperature
21+
temperature real 1e2
22+
23+
#list of species and their number densities used in the network (14 if including deuterium)
24+
primary_species_1 real 1.0d0
25+
primary_species_2 real 0.0d0
26+
primary_species_3 real 0.0d0
27+
primary_species_4 real 0.0d0
28+
primary_species_5 real 0.0d0
29+
primary_species_6 real 0.0d0
30+
primary_species_7 real 0.0d0
31+
primary_species_8 real 0.0d0
32+
primary_species_9 real 0.0d0
33+
primary_species_10 real 0.0d0
34+
primary_species_11 real 0.0d0
35+
primary_species_12 real 0.0d0
36+
primary_species_13 real 0.0d0
37+
primary_species_14 real 0.0d0
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
#include <extern_parameters.H>
2+
#include <eos.H>
3+
#include <network.H>
4+
#include <burner.H>
5+
#include <fstream>
6+
#include <iostream>
7+
8+
Real grav_constant = 6.674e-8;
9+
10+
void burn_cell_c()
11+
{
12+
13+
burn_t state;
14+
15+
Real numdens[NumSpec] = {-1.0};
16+
17+
for (int n = 1; n <= NumSpec; ++n) {
18+
switch (n) {
19+
20+
case 1:
21+
numdens[n-1] = primary_species_1;
22+
break;
23+
case 2:
24+
numdens[n-1] = primary_species_2;
25+
break;
26+
case 3:
27+
numdens[n-1] = primary_species_3;
28+
break;
29+
case 4:
30+
numdens[n-1] = primary_species_4;
31+
break;
32+
case 5:
33+
numdens[n-1] = primary_species_5;
34+
break;
35+
case 6:
36+
numdens[n-1] = primary_species_6;
37+
break;
38+
case 7:
39+
numdens[n-1] = primary_species_7;
40+
break;
41+
case 8:
42+
numdens[n-1] = primary_species_8;
43+
break;
44+
case 9:
45+
numdens[n-1] = primary_species_9;
46+
break;
47+
case 10:
48+
numdens[n-1] = primary_species_10;
49+
break;
50+
case 11:
51+
numdens[n-1] = primary_species_11;
52+
break;
53+
case 12:
54+
numdens[n-1] = primary_species_12;
55+
break;
56+
case 13:
57+
numdens[n-1] = primary_species_13;
58+
break;
59+
case 14:
60+
numdens[n-1] = primary_species_14;
61+
break;
62+
63+
}
64+
65+
}
66+
67+
// Echo initial conditions at burn and fill burn state input
68+
69+
std::cout << "Maximum Time (s): " << tmax << std::endl;
70+
std::cout << "State Temperature (K): " << temperature << std::endl;
71+
for (int n = 0; n < NumSpec; ++n) {
72+
std::cout << "Number Density input (" << short_spec_names_cxx[n] << "): " << numdens[n] << std::endl;
73+
}
74+
75+
state.T = temperature;
76+
77+
//find the density in g/cm^3
78+
Real rhotot = 0.0_rt;
79+
for (int n = 0; n < NumSpec; ++n) {
80+
state.xn[n] = numdens[n];
81+
rhotot += state.xn[n]*spmasses[n]; //spmasses contains the masses of all species, defined in EOS
82+
}
83+
84+
state.rho = rhotot;
85+
86+
// normalize -- just in case
87+
88+
Real mfracs[NumSpec] = {-1.0};
89+
Real msum = 0.0_rt;
90+
for (int n = 0; n < NumSpec; ++n) {
91+
mfracs[n] = state.xn[n]*spmasses[n]/rhotot;
92+
msum += mfracs[n];
93+
}
94+
95+
for (int n = 0; n < NumSpec; ++n) {
96+
mfracs[n] /= msum;
97+
//use the normalized mass fractions to obtain the corresponding number densities
98+
state.xn[n] = mfracs[n]*rhotot/spmasses[n];
99+
}
100+
101+
#ifdef DEBUG
102+
for (int n = 0; n < NumSpec; ++n) {
103+
std::cout << "Mass fractions (" << short_spec_names_cxx[n] << "): " << mfracs[n] << std::endl;
104+
std::cout << "Number Density conserved (" << short_spec_names_cxx[n] << "): " << state.xn[n] << std::endl;
105+
}
106+
#endif
107+
108+
109+
// call the EOS to set initial internal energy e
110+
eos(eos_input_rt, state);
111+
112+
// name of output file
113+
std::ofstream state_over_time("state_over_time.txt");
114+
115+
// save the initial state -- we'll use this to determine
116+
// how much things changed over the entire burn
117+
burn_t state_in = state;
118+
119+
// output the data in columns, one line per timestep
120+
state_over_time << std::setw(10) << "# Time";
121+
state_over_time << std::setw(15) << "Density";
122+
state_over_time << std::setw(15) << "Temperature";
123+
for(int x = 0; x < NumSpec; ++x){
124+
std::string element = short_spec_names_cxx[x];
125+
state_over_time << std::setw(15) << element;
126+
}
127+
state_over_time << std::endl;
128+
129+
Real t = 0.0;
130+
131+
state_over_time << std::setw(10) << t;
132+
state_over_time << std::setw(15) << state.rho;
133+
state_over_time << std::setw(15) << state.T;
134+
for (int x = 0; x < NumSpec; ++x){
135+
state_over_time << std::setw(15) << state.xn[x];
136+
}
137+
state_over_time << std::endl;
138+
139+
140+
// loop over steps, burn, and output the current state
141+
// the loop below is similar to that used in krome and pynucastro
142+
Real dd = rhotot;
143+
Real dd1 = 0.0_rt;
144+
145+
for (int n = 0; n < nsteps; n++){
146+
147+
dd1 = dd;
148+
149+
Real rhotmp = 0.0_rt;
150+
151+
for (int nn = 0; nn < NumSpec; ++nn) {
152+
rhotmp += state.xn[nn]*spmasses[nn];
153+
}
154+
155+
// find the freefall time
156+
Real tff = std::sqrt(M_PI*3.0 / (32.0*rhotmp*grav_constant));
157+
Real dt = tff_reduc * tff;
158+
// scale the density
159+
dd += dt*(dd/tff);
160+
161+
#ifdef DEBUG
162+
std::cout<<"step params "<<dd<<", "<<tff<<", "<<rhotmp<<std::endl;
163+
#endif
164+
165+
// stop the test if dt is very small
166+
if (dt < 10) {
167+
break; }
168+
169+
// stop the test if we have reached very high densities
170+
if (dd > 3e-6) {
171+
break; }
172+
173+
std::cout<<"step "<<n<<" done"<<std::endl;
174+
175+
// scale the number densities
176+
for (int nn = 0; nn < NumSpec; ++nn) {
177+
state.xn[nn] *= dd/dd1;
178+
}
179+
180+
// input the scaled density in burn state
181+
state.rho *= dd/dd1;
182+
183+
// do the actual integration
184+
burner(state, dt);
185+
186+
// ensure positivity and normalize
187+
Real inmfracs[NumSpec] = {-1.0};
188+
Real insum = 0.0_rt;
189+
for (int nn = 0; nn < NumSpec; ++nn) {
190+
state.xn[nn] = amrex::max(state.xn[nn], small_x);
191+
inmfracs[nn] = spmasses[nn]*state.xn[nn]/state.rho;
192+
insum += inmfracs[nn];
193+
}
194+
195+
for (int nn = 0; nn < NumSpec; ++nn) {
196+
inmfracs[nn] /= insum;
197+
//update the number densities with conserved mass fractions
198+
state.xn[nn] = inmfracs[nn]*state.rho/spmasses[nn];
199+
}
200+
201+
//update the number density of electrons due to charge conservation
202+
state.xn[0] = -state.xn[3] - state.xn[7] + state.xn[1] + state.xn[12] + state.xn[6] + state.xn[4] + state.xn[9] + 2.0*state.xn[11];
203+
204+
//reconserve mass fractions post charge conservation
205+
insum = 0;
206+
for (int nn = 0; nn < NumSpec; ++nn) {
207+
state.xn[nn] = amrex::max(state.xn[nn], small_x);
208+
inmfracs[nn] = spmasses[nn]*state.xn[nn]/state.rho;
209+
insum += inmfracs[nn];
210+
}
211+
212+
for (int nn = 0; nn < NumSpec; ++nn) {
213+
inmfracs[nn] /= insum;
214+
//update the number densities with conserved mass fractions
215+
state.xn[nn] = inmfracs[nn]*state.rho/spmasses[nn];
216+
}
217+
218+
// get the updated T
219+
eos(eos_input_re, state);
220+
221+
t += dt;
222+
223+
state_over_time << std::setw(10) << t;
224+
state_over_time << std::setw(15) << state.rho;
225+
state_over_time << std::setw(12) << state.T;
226+
for (int x = 0; x < NumSpec; ++x){
227+
state_over_time << std::setw(15) << state.xn[x];
228+
}
229+
state_over_time << std::endl;
230+
231+
232+
}
233+
state_over_time.close();
234+
235+
// output diagnostics to the terminal
236+
std::cout << "------------------------------------" << std::endl;
237+
std::cout << "successful? " << state.success << std::endl;
238+
239+
std::cout << "------------------------------------" << std::endl;
240+
std::cout << "T initial = " << state_in.T << std::endl;
241+
std::cout << "T final = " << state.T << std::endl;
242+
std::cout << "Eint initial = " << state_in.e << std::endl;
243+
std::cout << "Eint final = " << state.e << std::endl;
244+
std::cout << "rho initial = " << state_in.rho << std::endl;
245+
std::cout << "rho final = " << state.rho << std::endl;
246+
247+
std::cout << "------------------------------------" << std::endl;
248+
std::cout << "New number densities: " << std::endl;
249+
for (int n = 0; n < NumSpec; ++n) {
250+
std::cout << state.xn[n] << std::endl;
251+
}
252+
253+
}

0 commit comments

Comments
 (0)