-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcooling_planet.c
304 lines (279 loc) · 10 KB
/
cooling_planet.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#ifndef NOCOOLING
/*
* Cooling code originally written by James Wadsley, McMaster
* University for GASOLINE.
*
* Updated for ChaNGa by Isaac Backus, University of Washington
*/
/*
* Cooling functions for a planetary disk where the cooling time is
* proportional to the orbital time.
*
* ALGORITHM:
*
* Integrating over a time step (see CoolIntegrateEnergyCode) gives:
* E(t+dt) = exp(-dt/tcool) (E(t) - PdV*tcool) + PdV*tcool
* where:
* tcool = beta/omega
* beta is a dimensionless cooling time (see CoolAddParams) and omega is the
* approximate Keplerian angular velocity, calculated as:
* omega = sqrt(G*M/R**3)
* where M is the total mass of all star particles and R is the distance to
* the center of mass of star particles.
*
* NOTES:
*
* The convention is that Cool...() functions are public and cl..()
* functions are private (which could be enforced if we move this to
* C++). The COOL class will contain data which is constant across
* all processors, and will be contained in a Charm++ NodeGroup.
* The clDerivsData structure will contain data that changes from
* particle to particle.
*
* By convention, all cooling is done in CGS. The header file defines macros
* which convert between code and CGS units [cooling_planet.h]. For example,
* to convert energy into CGS, do :
* E = CoolCodeEnergyToErgPerGm(cl, E);
* Conversion factors are stored in a COOL struct (see clInitConstants)
*
* For a list of parameters to set, see CoolAddParams in cooling_planet.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <string.h>
#include "cooling.h"
/**
* @brief CoolInit initializes a COOL data structure for storing
* cooling constants and parameters
* @return a blank COOL data structure with nTableRead = 0
*/
COOL *CoolInit( )
{
COOL *cl;
cl = (COOL *) malloc(sizeof(COOL));
assert(cl!=NULL);
/* Internal Tables read from Files */
cl->nTableRead = 0;
return cl;
}
/**
* Per thread initialization of cooling data.
* @param cl Initialized COOL structure.
*/
clDerivsData *CoolDerivsInit(COOL *cl)
{
clDerivsData *Data;
assert(cl != NULL);
Data = malloc(sizeof(clDerivsData));
assert(Data != NULL);
return Data;
}
///Frees memory and deletes cl
void CoolFinalize(COOL *cl )
{
free(cl);
}
/**
* Deallocate memory for per-thread data.
*/
void CoolDerivsFinalize(clDerivsData *clData)
{
free(clData);
}
/**
* @brief clInitConstants sets physical constants and parameters
* for cooling
* @param cl a COOL data structure (see CoolInit)
* @param CoolParam an initialized COOLPARAM structure (see CoolAddParams)
*/
void clInitConstants(COOL *cl, double dGmPerCcUnit,
double dComovingGmPerCcUnit, double dErgPerGmUnit,
double dSecUnit, double dKpcUnit, COOLPARAM CoolParam)
{
assert(cl!=NULL);
/* Units */
cl->dGmPerCcUnit = dGmPerCcUnit;
cl->dComovingGmPerCcUnit = dComovingGmPerCcUnit;
cl->dErgPerGmUnit = dErgPerGmUnit;
cl->dSecUnit = dSecUnit;
cl->dErgPerGmPerSecUnit = cl->dErgPerGmUnit / cl->dSecUnit;
cl->diErgPerGmUnit = 1./dErgPerGmUnit;
cl->dKpcUnit = dKpcUnit;
/* config parameters */
cl->Y_Total = CoolParam.Y_Total;
cl->Tmin = CoolParam.dCoolingTmin;
cl->Tmax = CoolParam.dCoolingTmax;
cl->beta = CoolParam.dBetaCooling;
}
/**
* @brief Calculates thermal energy from temperature and Y (deg. freedom/3)
* @param Y_Total (deg. freedom)/3
* @param T Temperature
* @return Thermal (internal) energy per mass (CGS)
*/
double clThermalEnergy( double Y_Total, double T ) {
return Y_Total*CL_Eerg_gm_degK3_2*T;
}
/**
* @brief Calculates temperature from internal energy and Y (deg.freedom/3)
* @param Y_Total (deg. freedom)/3
* @param E Internal energy per mass (CGS units)
* @return Temperature
*/
double clTemperature( double Y_Total, double E ) {
return E/(Y_Total*CL_Eerg_gm_degK3_2);
}
/* Module Interface routines */
/**
* @brief CoolAddParams Parses parameters and adds them to the COOLPARAM
* struct
* @param CoolParam A COOLPARAM struct
* @param prm The param struct
*
* The available parameters to be set are:
* dBetaCooling : Effective cooling time = t_cool * omega. Also
* equal to 2*pi*(t_cool/T_orbit)
* dY_Total : (degrees of freedom)/3 for the gas
* dCoolingTmin : Minimum allowed temperature (in Kelvin)
* dCoolingTmax : Maximum allowed temperature (in Kelvin)
*/
void CoolAddParams( COOLPARAM *CoolParam, PRM prm ) {
CoolParam->dBetaCooling = 1.0;
prmAddParam(prm, "dBetaCooling", paramDouble, &CoolParam->dBetaCooling,
sizeof(double), "betacool",
"<Effective cooling time (tCool*omega)> = 1");
CoolParam->Y_Total = 2;
prmAddParam(prm,"dY_Total",paramDouble,&CoolParam->Y_Total,
sizeof(double),"Y_Total",
"<Y_Total> = 2");
CoolParam->dCoolingTmin = 0;
prmAddParam(prm,"dCoolingTmin",paramDouble,&CoolParam->dCoolingTmin,
sizeof(double),"ctmin",
"<Minimum Temperature for Cooling> = 0K");
CoolParam->dCoolingTmax = 1e9;
prmAddParam(prm,"dCoolingTmax",paramDouble,&CoolParam->dCoolingTmax,
sizeof(double),"ctmax",
"<Maximum Temperature for Cooling> = 1e9K");
}
/* Placeholder functions which just need to be defined to make
* Sph.C and the compiler happy */
void CoolTableReadInfo( COOLPARAM *CoolParam, int cntTable, int *nTableColumns,
char *suffix )
{
*nTableColumns = 0;
}
void CoolTableRead( COOL *Cool, int nData, void *vData) {}
void CoolInitRatesTable( COOL *cl, COOLPARAM CoolParam ) {}
double CoolEdotInstantCode(COOL *cl, COOLPARTICLE *cp, double ECode,
double rhoCode, double ZMetal, double *posCode ) {}
/* Initialization Routines */
/**
* @brief Initializes data and sets defaults for a cooling particle
* @param cp a COOLPARTICLE structure (see cooling_planet.h)
*/
void CoolDefaultParticleData( COOLPARTICLE *cp )
{
cp->Y_Total = 2;
}
/**
* @brief Initializes data for a cooling particle, given a COOL struct
* @param cl a COOL struct which has been initialized with constants defined
* @param cp a cooling particle COOLPARTICLE struct
* @param E Pointer to the particle's internal energy
*
* Initializes data for a cooling particle, given a COOL struct.
* Sets Y_total and E in the cooling particle
*/
void CoolInitEnergyAndParticleData( COOL *cl, COOLPARTICLE *cp, double *E,
double dDensity, double dTemp, double fMetal)
{
cp->Y_Total = cl->Y_Total;
*E = clThermalEnergy(cp->Y_Total,dTemp)*cl->diErgPerGmUnit;
}
///A hold over from cosmology. Sets the time which is available to all threads
void CoolSetTime( COOL *cl, double dTime, double z ) {
cl->z = z;
cl->dTime = dTime;
}
/**
* @brief CoolSetStarCM saves the center of mass of the star(s) to the COOL
* struct cl
* @param cl COOL struct, which stores cooling data/info
* @param dCenterOfMass Array(length 4) which contains the star(s) center of
* mass as the first 3 entries and the total star mass as the final entry
*/
void CoolSetStarCM(COOL *cl, double dCenterOfMass[4]) {
int i;
for(i=0; i<4; ++i) {
cl->dStarCenterOfMass[i] = dCenterOfMass[i];
}
}
///Calculates the temperature of a COOLPARTICLE given its energy (in Code units)
double CoolCodeEnergyToTemperature( COOL *Cool, COOLPARTICLE *cp, double E,
double fMetal) {
return clTemperature(cp->Y_Total, E*Cool->dErgPerGmUnit);
}
/**
* Updates a particle's internal energy based on cooling and PdV work.
* Cooling is done according to the equation:
* Edot = -E/tcool + PdV
* where PdV is the PdV work per time done on the particle and tcool
* is given by:
* tcool = beta/omega
* beta is a dimensionless cooling set by the runtime parameter dBetaCooling
* and omega is the approximate keplerian orbital angular velocity
* Solving the cooling equation over a time interval from 0 to t gives:
* E(t) = exp(-t/tcool) (E0 - PdV*tcool) + PdV*tcool
*
* The Energy (Ecode) is updated
*
* @brief CoolIntegrateEnergyCode Integrates a particle's internal energy
* due to cooling and PdV work
* @param cl The COOL structure containing constants/params for the simulation
* @param clData [unused]
* @param cp Cooling particle
* @param ECode Particle internal energy in Code units
* @param PdVCode PdV work per time in code units
* @param rhoCode [unused]
* @param ZMetal [Unused]
* @param posCode particle position in code units
* @param tStep Time step to integrate over, in seconds
*/
void CoolIntegrateEnergyCode(COOL *cl, clDerivsData *clData, COOLPARTICLE *cp,
double *ECode, double PdVCode, double rhoCode,
double ZMetal, double *posCode, double tStep )
{
double radius = 0;
double omega, tcool, PdV, T, dECGS;
/* This is used as a switch to disable cooling before a certain time*/
if (tStep <= 0) return;
/* Calculate the radius (in simulation units)
* Defined as the distance to the center of mass of all the star
* particles */
int i=0;
for(i=0; i<3; ++i) {
radius += pow(posCode[i] - cl->dStarCenterOfMass[i], 2);
}
radius = sqrt(radius);
/* Calculate approximate keplerian angular velocity */
omega = sqrt(cl->dStarCenterOfMass[3] / pow(radius,3));
/* Calculate cooling time (in seconds)*/
tcool = cl->dSecUnit * cl->beta/omega;
/* Convert the particle's internal energy to CGS */
dECGS = CoolCodeEnergyToErgPerGm( cl, *ECode );
/* Convert PdV work to CGS */
PdV = CoolCodeWorkToErgPerGmPerSec(cl, PdVCode);
/* Integrate energy */
dECGS = exp(-tStep/tcool) * (dECGS - PdV*tcool) + PdV*tcool;
/* apply minimum temperature cutoff */
T = clTemperature(cp->Y_Total, dECGS);
if (T < cl->Tmin) {
T = cl->Tmin;
dECGS = clThermalEnergy(cp->Y_Total, T);
}
/*Convert energy back to simulation units */
*ECode = CoolErgPerGmToCodeEnergy(cl, dECGS);
}
#endif /* NOCOOLING */