-
Notifications
You must be signed in to change notification settings - Fork 0
/
eos.c
307 lines (250 loc) · 11.1 KB
/
eos.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
305
306
307
#include "eos.h"
#include "util.h"
/* Prototypes for helper functions used in interface functions */
static PetscScalar GetCompositionalViscosityPrefactor(PetscScalar);
static PetscErrorCode LookupFilenameSet(const char*,const char*,char*,PetscBool*);
/* EOS interface functions (public API) */
PetscErrorCode EOSCheckType(EOS eos, EOSType type, PetscBool *same)
{
PetscErrorCode ierr;
PetscFunctionBeginUser;
ierr = PetscStrcmp(type, eos->type, same);CHKERRQ(ierr);
PetscFunctionReturn(0);
}
PetscErrorCode EOSCreate(EOS* p_eos, EOSType type)
{
PetscErrorCode ierr;
PetscBool flg;
EOS eos;
PetscFunctionBeginUser;
ierr = PetscMalloc1(1, p_eos);CHKERRQ(ierr);
eos = *p_eos;
eos->type = type;
eos->is_setup = PETSC_FALSE;
ierr = PetscStrcmp(type, SPIDER_EOS_LOOKUP, &flg);CHKERRQ(ierr);
if (flg) {
ierr = EOSCreate_Lookup(eos);CHKERRQ(ierr);
}
ierr = PetscStrcmp(type, SPIDER_EOS_COMPOSITE, &flg);CHKERRQ(ierr);
if (flg) {
ierr = EOSCreate_Composite(eos);CHKERRQ(ierr);
}
ierr = PetscStrcmp(type, SPIDER_EOS_ADAMSWILLIAMSON, &flg);CHKERRQ(ierr);
if (flg) {
ierr = EOSCreate_AdamsWilliamson(eos);CHKERRQ(ierr);
}
PetscFunctionReturn(0);
}
PetscErrorCode EOSEval(const EOS eos, PetscScalar P , PetscScalar S, EOSEvalData* eval)
{
PetscErrorCode ierr;
PetscFunctionBeginUser;
if (!eos->is_setup) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONGSTATE,"You must cannot evaluate the EOS before setting it up");
/* Implementation-specific logic */
if (!eos->eval) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONGSTATE,"Incomplete EOS object: no implementation for EOSEval has been provided");
ierr = (*(eos->eval))(eos,P,S,eval);CHKERRQ(ierr);
PetscFunctionReturn(0);
}
PetscErrorCode EOSDestroy(EOS *p_eos)
{
PetscErrorCode ierr;
PetscFunctionBeginUser;
if (p_eos) {
EOS eos = *p_eos;
ierr = (*eos->destroy)(eos);CHKERRQ(ierr);
if (eos->PHASE_BOUNDARY) {
ierr = Interp1dDestroy(&eos->phase_boundary);CHKERRQ(ierr);
}
ierr = PetscFree(*p_eos);CHKERRQ(ierr);
*p_eos = NULL;
}
PetscFunctionReturn(0);
}
PetscErrorCode EOSSetUpFromOptions(EOS eos, const char *prefix, const FundamentalConstants FC, const ScalingConstants SC)
{
PetscErrorCode ierr;
char buf[1024]; /* max size */
PetscFunctionBegin;
if (eos->setupfromoptions) {
ierr = (*eos->setupfromoptions)(eos, prefix, FC, SC);CHKERRQ(ierr);
}
/* conductivity (w/m/K) */
ierr = PetscSNPrintf(buf,sizeof(buf),"%s%s%s","-",prefix,"_cond");CHKERRQ(ierr);
eos->cond = 4.0;
ierr = PetscOptionsGetScalar(NULL,NULL,buf,&eos->cond,NULL);CHKERRQ(ierr);
eos->cond /= SC->COND;
/* viscosity-related, may eventually move into their own struct */
ierr = PetscSNPrintf(buf,sizeof(buf),"%s%s%s","-",prefix,"_log10visc");CHKERRQ(ierr);
eos->log10visc = 21.0; // note default is for solid only
ierr = PetscOptionsGetScalar(NULL,NULL,buf,&eos->log10visc,NULL);CHKERRQ(ierr);
eos->log10visc -= SC->LOG10VISC;
ierr = PetscSNPrintf(buf,sizeof(buf),"%s%s%s","-",prefix,"_activation_energy");CHKERRQ(ierr);
eos->activation_energy = 0.0;
ierr = PetscOptionsGetScalar(NULL,NULL,buf,&eos->activation_energy,NULL);CHKERRQ(ierr);
/* scalings for Ea and Va include the gas constant that appears in the
denominator of the Arrhenius viscosity law, so we then do not have
to pass FC->GAS to the viscosity functions */
eos->activation_energy /= SC->ENERGY * FC->GAS;
/* activation volume (m^3/mol) */
/* The numerical value in units of m^3/mol is the same as that in units of J/mol/Pa */
/* You can convince yourself of this by using the scalings for ENERGY and PRESSURE to
see that this is true */
ierr = PetscSNPrintf(buf,sizeof(buf),"%s%s%s","-",prefix,"_activation_volume");CHKERRQ(ierr);
eos->activation_volume = 0.0;
ierr = PetscOptionsGetScalar(NULL,NULL,buf,&eos->activation_volume,NULL);CHKERRQ(ierr);
/* as with activation energy, include gas constant in denominator */
eos->activation_volume *= SC->PRESSURE / (SC->ENERGY * FC->GAS);
ierr = PetscSNPrintf(buf,sizeof(buf),"%s%s%s","-",prefix,"_activation_volume_pressure_scale");CHKERRQ(ierr);
eos->activation_volume_pressure_scale = -1.0; /* negative is not set */
ierr = PetscOptionsGetScalar(NULL,NULL,buf,&eos->activation_volume_pressure_scale,NULL);CHKERRQ(ierr);
eos->activation_volume_pressure_scale /= SC->PRESSURE;
ierr = PetscSNPrintf(buf,sizeof(buf),"%s%s%s","-",prefix,"_visc_comp");CHKERRQ(ierr);
eos->visc_comp = -1.0; // negative is not set
ierr = PetscOptionsGetScalar(NULL,NULL,buf,&eos->visc_comp,NULL);CHKERRQ(ierr);
/* no scaling necessary since this is a ratio */
ierr = PetscSNPrintf(buf,sizeof(buf),"%s%s%s","-",prefix,"_visc_ref_temp");CHKERRQ(ierr);
eos->visc_ref_temp = -1.0; // negative is not set
ierr = PetscOptionsGetScalar(NULL,NULL,buf,&eos->visc_ref_temp,NULL);CHKERRQ(ierr);
eos->visc_ref_temp /= SC->TEMP;
ierr = PetscSNPrintf(buf,sizeof(buf),"%s%s%s","-",prefix,"_visc_ref_pressure");CHKERRQ(ierr);
eos->visc_ref_pressure = -1.0; // negative is not set
ierr = PetscOptionsGetScalar(NULL,NULL,buf,&eos->visc_ref_pressure,NULL);CHKERRQ(ierr);
eos->visc_ref_pressure /= SC->PRESSURE;
ierr = PetscSNPrintf(buf,sizeof(buf),"%s%s%s","-",prefix,"_visc_ref_comp");CHKERRQ(ierr);
eos->visc_ref_comp = -1.0; // negative is not set
ierr = PetscOptionsGetScalar(NULL,NULL,buf,&eos->visc_ref_comp,NULL);CHKERRQ(ierr);
/* no scaling necessary since this is a ratio */
/* phase boundary */
ierr = LookupFilenameSet( "_phase_boundary", prefix, eos->phase_boundary_filename, &eos->PHASE_BOUNDARY );CHKERRQ(ierr);
if( eos->PHASE_BOUNDARY ){
ierr = Interp1dCreateAndSet( eos->phase_boundary_filename, &eos->phase_boundary, SC->PRESSURE, SC->ENTROPY );CHKERRQ(ierr);
}
/* Mark as set up */
eos->is_setup = PETSC_TRUE;
PetscFunctionReturn(0);
}
PetscErrorCode EOSGetPhaseBoundary(EOS eos, PetscScalar P, PetscScalar *boundary, PetscScalar *dboundary)
{
PetscFunctionBeginUser;
SetInterp1dValue(eos->phase_boundary, P, boundary, dboundary); /* entropy S and derivative dS/dP */
PetscFunctionReturn(0);
}
PetscErrorCode EOSGetType(EOS eos, EOSType *type)
{
PetscFunctionBeginUser;
*type = eos->type;
PetscFunctionReturn(0);
}
PetscErrorCode EOSEvalSetViscosity(EOS eos, EOSEvalData *eval)
{
PetscScalar A, log10C, dP, dT;
PetscScalar fac1 = 1.0, fac2 = 1.0;
PetscFunctionBeginUser;
/* reference viscosity */
eval->log10visc = eos->log10visc; // i.e., log10(eta_0)
/* temperature and pressure contribution
A(T,P) = (E_a + V_a P) / RT - (E_a + V_a Pref)/ RTref
eta = eta_0 * exp(A)
log10(eta) = log10(eta0) + log10(exp(A))
log10(eta) = P->eos2_parameters.log10visc + A/ln(10) */
/* with Ps = activation_volume_pressure_scale:
V_a(P) = V_a exp (-P/Ps) */
A = 0.0;
/* pin viscosity profile to reference values */
if( (eos->visc_ref_pressure >= 0.0) || (eos->visc_ref_temp >= 0.0) ){
dT = ( eos->visc_ref_temp - eval->T ) / eos->visc_ref_temp;
if( eos->activation_volume_pressure_scale > 0.0 ){
fac1 = PetscExpReal( -eval->P / eos->activation_volume_pressure_scale );
fac2 = PetscExpReal( -eos->visc_ref_pressure / eos->activation_volume_pressure_scale );
}
/* else fac1 and fac2 retain unity scalings according to initialisation above */
dP = fac1 * eval->P - fac2 * eos->visc_ref_pressure * (eval->T / eos->visc_ref_temp );
}
/* do not pin viscosity profile */
else{
dT = 1.0;
dP = eval->P;
if( eos->activation_volume_pressure_scale > 0.0 ){
dP *= PetscExpReal( -eval->P / eos->activation_volume_pressure_scale );
}
}
if( eos->activation_energy > 0.0){
A += eos->activation_energy * dT;
}
if( eos->activation_volume > 0.0){
A += eos->activation_volume * dP;
}
/* division by R (gas constant) was already done during the scaling of parameters */
A *= 1.0 / eval->T;
eval->log10visc += A / PetscLogReal(10.0);
/* compositional (Mg/Si) contribution */
/* always pinned to some reference given by eos->visc_ref_comp */
if( eos->visc_comp > 0.0 ){
log10C = GetCompositionalViscosityPrefactor( eos->visc_comp );
log10C -= GetCompositionalViscosityPrefactor( eos->visc_ref_comp );
eval->log10visc += log10C;
}
/* add viscous lid */
/* add viscosity cutoff */
PetscFunctionReturn(0);
}
/* Helper Functions */
static PetscScalar GetCompositionalViscosityPrefactor( PetscScalar Mg_Si ){
/* These expressions were worked out by Rob Spaargaren as part
of his MSc thesis (2018) are are explained in Spaargaren et al. (2020) */
/* Mg_Si is molar mantle Mg/Si */
PetscScalar fac;
if (Mg_Si <= 1.0)
fac = 0.5185 * (1 - Mg_Si)/0.3; //
else if (Mg_Si <= 1.25)
/* Earth has Mg/Si = 1.08 */
fac = -1.4815 * (Mg_Si - 1)/0.25; // -1.4815 = log10(0.033)
else if (Mg_Si <= 1.5)
fac = -2 + (0.5185) * (1.5 - Mg_Si)/0.25; // 0.5185 = log10(0.033) - -2
else
/* Fp-rich composition (Ballmer et al. 2017) */
fac = -2;
return fac;
}
static PetscErrorCode LookupFilenameSet( const char* property, const char* prefix, char* lookup_filename, PetscBool *IS_SET )
{
PetscErrorCode ierr;
char buf1[1024]; /* max size */
char buf2[1024]; /* max size */
PetscBool set_rel_to_src,set;
PetscFunctionBeginUser;
/* Based on input options, determine which files to load. Options ending
with _rel_to_src indicate a path relative to the source code. In this
case we prepend a string, SPIDER_ROOT_DIR_STR, and /. The corresponding
option without this overrides. */
/* check for relative path name */
ierr = PetscSNPrintf(buf1,sizeof(buf1),"%s%s%s%s","-",prefix,property,"_filename_rel_to_src");CHKERRQ(ierr);
ierr = PetscOptionsGetString(NULL,NULL,buf1,lookup_filename,PETSC_MAX_PATH_LEN,&set_rel_to_src);CHKERRQ(ierr);
if (set_rel_to_src) {
ierr = MakeRelativeToSourcePathAbsolute(lookup_filename);CHKERRQ(ierr);
}
/* check for absolute path name */
ierr = PetscSNPrintf(buf2,sizeof(buf2),"%s%s%s%s","-",prefix,property,"_filename");CHKERRQ(ierr);
ierr = PetscOptionsGetString(NULL,NULL,buf2,lookup_filename,PETSC_MAX_PATH_LEN,&set);CHKERRQ(ierr);
/* if IS_SET is NULL, then we require a valid lookup_filename to be returned */
if( IS_SET==NULL ){
/* must return a valid lookup_filename */
if ( !set && !set_rel_to_src ){
SETERRQ2(PETSC_COMM_WORLD,PETSC_ERR_ARG_NULL,"Missing argument %s or %s",buf1,buf2);
}
}
/* if IS_SET is not NULL, then a valid lookup_filename is optional */
if( IS_SET!=NULL ){
if( set || set_rel_to_src ){
*IS_SET = PETSC_TRUE;
}
else{
*IS_SET = PETSC_FALSE;
}
}
/* absolute path name always overrides relative path name */
if (set && set_rel_to_src) {
ierr = PetscPrintf(PETSC_COMM_WORLD,"%s%s%s%s%s","Warning: ",buf1," ignored because ",buf2," provided\n");CHKERRQ(ierr);
}
PetscFunctionReturn(0);
}