Program Listing for File phase.cpp
↰ Return to documentation for file (src/phase.cpp)
#include "phase.h"
//Conditionals for Phase Diagrams in each layer begin LINE 249
PhaseDgm::PhaseDgm(string Comp_name, EOS* (*f)(double, double), int k, EOS** phase_name, double *start_pressure)
{
Comp_type = Comp_name;
phase_lowP = f;
n = k;
if(k > 0)
phase_list = new EOS*[k];
if(k > 1)
start_P = new double[k-1]; // In GPa
for(int i=0; i<n; i++)
{
phase_list[i] = phase_name[i];
if(i != n-1)
start_P[i] = start_pressure[i];
}
}
PhaseDgm::PhaseDgm(const PhaseDgm &a)
{
Comp_type = a.Comp_type;
n = a.n;
if(n > 0)
phase_list = new EOS*[n];
if(n > 1)
start_P = new double[n-1]; // In GPa
for(int i=0; i<n; i++)
{
phase_list[i] = a.phase_list[i];
if(i != n-1)
start_P[i] = a.start_P[i];
}
phase_lowP = a.phase_lowP;
}
PhaseDgm::~PhaseDgm()
{
if(n>0)
delete[] phase_list;
if(n>1)
delete[] start_P;
}
void PhaseDgm::set_phase_highP(int k, double *start_pressure, EOS** phase_name)
// start pressure is an array with dimension k-1. The first phase will replace the one with the same name in the phase diagram.
{
if(n > 1)
delete[] start_P;
if(n > 0)
delete[] phase_list;
n = k;
phase_list = new EOS*[k];
if(k > 1)
start_P = new double[k-1];
for(int i=0; i<n; i++)
{
phase_list[i] = phase_name[i];
if(i != n-1)
start_P[i] = start_pressure[i];
}
}
EOS* PhaseDgm::find_phase(double P, double T)
// Pressure in microbar
{
if (P <= 0 || T <= 0)
{
return NULL;
}
EOS* phase_matched;
string first_token, s;
if(n == 0)
return phase_lowP(P,T);
else if(n == 1)
{
phase_matched = phase_lowP(P,T);
s = phase_matched->getEOS();
first_token = s.substr(0,s.find(" ("));
if(first_token == phase_list[0]->getEOS())
return phase_list[0];
else
return phase_matched;
}
else
{
int i = n-2;
while(P < start_P[i]*1E10 && i > 0)
i--;
if(P >= start_P[i]*1E10)
return phase_list[i+1];
else
{
phase_matched = phase_lowP(P,T);
s = phase_matched->getEOS();
first_token = s.substr(0,s.find(" ("));
if(first_token == phase_list[0]->getEOS())
return phase_list[0];
else
return phase_matched;
}
}
}
double checkphase(double P, void *params)
{
struct phase_params *p = (struct phase_params *) params;
PhaseDgm* cmpn = p->cmpn;
double Pu=p->Pu, Pl=p->Pl;
if (P < Pl || P > Pu)
{
cout<<"Pressure "<<P/1E10<<" is outside the bound between "<<Pl<<" and "<<Pu<<" when solving the pressure of phase boundary for component "<<cmpn->getname()<<" from phase "<<p->Phase->getEOS()<<endl;
return numeric_limits<double>::quiet_NaN();
}
double Tt;
if (P == Pu) // In case the output Tt is very close but not exact Tu or Tl.
Tt = p->Tu;
else if (P == Pl)
Tt = p->Tl;
else
Tt = (p->Tl*(Pu-P)+p->Tu*(P-Pl))/(Pu-Pl); // Linear interpolate temperature at P
if (cmpn->find_phase(P, Tt) == p->Phase)
return 1.;
else
return -1.;
}
EOS* PhaseDgm::find_phase_boundary(double Pl, double Pu, double Tl, double Tu, bool inward, double &Po, double &To, double &rhoo, double &Pn, double &Tn, double &rhon)
// Used when integrate adiabatic profile across the phase boundary. Given the pressure in cgs, integration direction, the lower and upper pressure and temperature limit (at previous and next integral step depends on the integration direction). Return the pressure, temperature, density at old (o) phase boundary and new (n) phase boundary.
{
EOS* new_phase;
double P1, P2;
int iter = 0, max_iter = 100;
int status;
const gsl_root_fsolver_type *TPL = gsl_root_fsolver_bisection;
gsl_root_fsolver *s = gsl_root_fsolver_alloc (TPL);
gsl_function F;
EOS* old_phase;
if (inward)
old_phase = find_phase (Pl, Tl);
else
old_phase = find_phase (Pu, Tu);
struct phase_params params = {Pl, Pu, Tl, Tu, old_phase, this};
F.function = &checkphase;
F.params = ¶ms;
status = gsl_root_fsolver_set (s, &F, Pl, Pu);
if (status == GSL_EINVAL)
{
cout<<"Error: The phase transition boundary is not between the lower pressure bound "<<Pl<<" and upper pressure bound "<<Pu<<", low temperature "<<Tl<<" and high temperature "<<Tu<<" when find the phase boundary of component "<<Comp_type<<" from phase "<<old_phase->getEOS()<<" to new phase ";
if (inward)
new_phase = find_phase (Pu, Tu);
else
new_phase = find_phase (Pl, Tl);
gsl_root_fsolver_free (s);
Po = numeric_limits<double>::quiet_NaN();
To = numeric_limits<double>::quiet_NaN();
rhoo = numeric_limits<double>::quiet_NaN();
Pn = numeric_limits<double>::quiet_NaN();
Tn = numeric_limits<double>::quiet_NaN();
rhon = numeric_limits<double>::quiet_NaN();
return NULL;
}
else if (status != GSL_SUCCESS)
{
cout<<"Error: Failed to set up the phase boundary of component "<<Comp_type<<" from phase "<<old_phase->getEOS()<<endl;
gsl_root_fsolver_free (s);
Po = numeric_limits<double>::quiet_NaN();
To = numeric_limits<double>::quiet_NaN();
rhoo = numeric_limits<double>::quiet_NaN();
Pn = numeric_limits<double>::quiet_NaN();
Tn = numeric_limits<double>::quiet_NaN();
rhon = numeric_limits<double>::quiet_NaN();
return NULL;
}
do
{
iter++;
status = gsl_root_fsolver_iterate (s);
P1 = gsl_root_fsolver_x_lower (s);
P2 = gsl_root_fsolver_x_upper (s);
status = gsl_root_test_interval (P1, P2, 1E-10, 1E-12);
}
while (status == GSL_CONTINUE && iter < max_iter);
if (status == GSL_CONTINUE)
{
cout<<"Error: Can't find the pressure of the phase boundary from "<<find_phase (Pl, Tl) -> getEOS()<<" and "<<find_phase (Pu, Tu) -> getEOS()<<" at pressure "<<Pl/1E10<<" GPa within maximum interation "<<max_iter<<endl;
gsl_root_fsolver_free (s);
Po = numeric_limits<double>::quiet_NaN();
To = numeric_limits<double>::quiet_NaN();
rhoo = numeric_limits<double>::quiet_NaN();
Pn = numeric_limits<double>::quiet_NaN();
Tn = numeric_limits<double>::quiet_NaN();
rhon = numeric_limits<double>::quiet_NaN();
return NULL;
}
if (inward)
{
Pn = P2;
Po = P1;
}
else
{
Pn = P1;
Po = P2;
}
Tn = (Tl*(Pu-Pn)+Tu*(Pn-Pl))/(Pu-Pl); // Linear interpolate temperature at P
To = (Tl*(Pu-Po)+Tu*(Po-Pl))/(Pu-Pl); // Linear interpolate temperature at P
new_phase = find_phase (Pn, Tn);
rhon = new_phase->density (Pn, Tn, rhoo);
rhoo = find_phase (Po, To) -> density(Po, To, rhoo);
gsl_root_fsolver_free (s);
return new_phase;
}
// Phase curve function in Dunaeva et al. 2010, input P in GPa, return T
double dunaeva_phase_curve(double P, double a, double b, double c, double d, double e)
{
P *= 1E4; // convert P from GPa to bar
if (P <= 0)
{
cout<<"Error: P = "<<P<<" bar. Dunaeva phase curve can't handle negative pressure."<<endl;
return numeric_limits<double>::quiet_NaN();
}
return a + b*P + c*log(P) + d/P + e*sqrt(P);
}
// ========== Phase Diagrams for Core ================
// ---------------------------------
// Fe Default: hcp and Liquid iron
EOS* find_phase_Fe_default(double P, double T)
{
if (P <= 0 || T <= 0)
{
return NULL;
}
P /= 1E10; // convert microbar to GPa
// Default Core
if( T > 12.8*P + 2424 && T > 13.7*P + 2328) // melting curve from Dorogokupets et al. 2017, Scientific Reports. fcc and hcp Fe melting curve.
{
if(P<80 || T>10000)
return Fe_liquid2;
else
return Fe_liquid;
}
else
return Fe_hcp; // use hcp Iron for all regions.
}
// ---------------------------------
// Fe_fccbcc: Includes low pressure fcc and bcc iron
EOS* find_phase_Fe_fccbcc(double P, double T)
{
if (P <= 0 || T <= 0)
{
return NULL;
}
P /= 1E10; // convert microbar to GPa
if(T>575+18.7*P+0.213*pow(P,2)-0.000817*pow(P,3) && P<98.5) // Anzellini et al. 2013
{
if(T<1991*pow((((P-5.2)/27.39)+1),1/2.38) && P<98.5)
if(T<-41.1*P+1120)
return Fe_bcc;
else
return Fe_fcc;
else
return Fe_liquid;
}
else
{
if(T<3712*pow((((P-98.5)/161.2)+1),1/1.72))
if(T<-61.2*P+1266) // Dorogokupets et al. 2017
return Fe_bcc;
else
return Fe_hcp;
else
return Fe_liquid;
}
}
// ========== Phase Diagrams for Mantle ================
// ---------------------------------
// Si Default: Upper Mantle: Fo, Wds, Rwd, and liquid ; Lower Mantle: Brg, PPv
EOS* find_phase_Si_default(double P, double T)
{
if (P <= 0 || T <= 0)
{
return NULL;
}
P /= 1E10; // convert microbar to GPa
if(P > 112.5 + 7E-3*T) // Phase transfer curve from Ono & Oganov 2005, Earth Planet. Sci. Lett. 236, 914
return Si_PPv_Sakai;
else if (T > 1830*pow(1+P/4.6, 0.33)) // Melting curve from Belonoshko et al. 2005 Eq. 2
return Si_Liquid_Wolf;
else if (P > 24.3+(-2.12E-4*T)+(-3.49E-7*pow(T, 2))) // Dorogokupets et al. 2015
return Si_Pv;
else if (P > 8.69+6.05E-3*T)
return Rwd;
else if (P > 9.45+2.76E-3*T)
return Wds;
else
return Fo;
}
// ---------------------------------
// Si Simplified: Brg, PPv, and liquid
EOS* find_phase_Si_simple(double P, double T)
{
if (P <= 0 || T <= 0)
{
return NULL;
}
P /= 1E10; // convert microbar to GPa
if(P > 112.5 + 7E-3*T) // Phase transfer curve from Ono & Oganov 2005, Earth Planet. Sci. Lett. 236, 914
return Si_PPv_Sakai;
else if (T > 1830*pow(1+P/4.6, 0.33)) // Melting curve from Belonoshko et al. 2005 Eq. 2
return Si_Liquid_Wolf;
else
return Si_Pv;
}
// ---------------------------------
// PREM tabulated mantle
EOS* find_phase_PREM(double P, double T)
{
if (P <= 0 || T <= 0)
{
return NULL;
}
P /= 1E10; // convert microbar to GPa
if(P > 3500)
return Si_Seager;
else if(P > 23.83)
return Si_BM2fit;
else
return Si_PREM;
}
//-----------------------------------
// Carbon Mantle
EOS* find_phase_C_simple(double P, double T)
{
if (P <= 0 || T <= 0)
return NULL;
P /= 1E10; // convert microbar to GPa
if (P>=970.679+(-1.52854E-2*T)+(-5.72152E-7*pow(T,2))) // Transition from Benedict et al (2018)
return BC8;
else if (P>=1.949+(T+273)/400) // Transition from Kennedy and Kennedy (1976)
return Diam;
else
return Graph;
}
//-----------------------------------
// Silicon Carbide Mantle
EOS* find_phase_SiC(double P, double T)
{
if (P <= 0 || T <= 0)
{
return NULL;
}
P /= 1E10; // convert microbar to GPa
double transition_pressure = 69.0 - 0.001 * (T - 300.0);
if (P < transition_pressure)
return SiC_B3_Vinet; // Low pressure zinc blende structure (Vinet EOS)
else
return SiC_B1_Vinet; // High pressure rock salt structure (Vinet EOS)
}
// ========== Phase Diagrams for Hydrosphere ================
// ---------------------------------
// H2O Water/Ice/Gas boundaries
EOS* find_phase_water_default(double P, double T)
// input P in cgs
{
P /= 1E10; // convert microbar to GPa
if (P <= 0 || T <= 0)
{
return NULL;
}
//Below supercritical point, Liquid/Vapor/Ice Ih
if(P<0.022064)
{
if(P<0.022064*exp((647.096/T)*(-7.85951783*(1-T/647.096)+1.84408259*pow(1-T/647.096,1.5)-11.7866497*pow(1-T/647.096,3)+22.6807411*pow(1-T/647.096,6)))||T>647.096) //Vapor Line Wagner & PruB 22
{
if(T<1000) //use simplified EOS above 1000 K, IAPWS below
return Water_Vap_IAPWS; //IAPWS-R6-95
else
return vdW_H2O; //Van Der Walls Gas
}
else if(T<-32.26706488*pow(P,3)-143.6159774*pow(P,2)-74.97759097*P+273.1683519) //Ice Ih melt line, SeaFreeze fitted polynomial
return IceIh_SF;
else if(T>490)
return Water_IAPWS;
else
return Water_SF;
}
// Ice Ih, III, Water Triple Point (includes Ice II region) SeaFreeze
else if( P < 0.207592 )
{
if(T > -32.26706488*pow(P,3)-143.6159774*pow(P,2)-74.97759097*P+273.1683519) //Ice Ih melt line, SeaFreeze fitted polynomial
{
if(T<490)
return Water_SF;
else if(T>1000)
return vdW_H2O;
else
return Water_Vap_IAPWS;
}
else if(P < 3.986300903e-09*pow(T,3)-1.789026292e-06*pow(T,2)+0.0009677787797*T+0.02631882383) // Ih to II transition, SeaFreeze fitted polynomial
return IceIh_SF;
else
return IceII_SF;
}
// III, V, Water Triple Point, (Includes Ice II reigon) SeaFreeze
else if( P < 0.350109 )
{
if(T > 99.49717929*pow(P,3)-158.5333434*pow(P,2)+100.0993404*P+236.281993) //Ice III Melt line, SeaFreeze fitted polynomial
{
if(T>1280) //Use Brown <1280 K and Mazevet >1280K, there will be a density decrease if transitioning from Brown -> Mazevet
return Water_sc_Mazevet;
else
return Water_Brown;
}
else if(P > 3.986300903e-09*pow(T,3)-1.789026292e-06*pow(T,2)+0.0009677787797*T+0.02631882383 && T<10.6802119*pow(P,3)-60.79880497*pow(P,2)+108.5464607*P+218.0347735) //IceII region, SeaFreeze fitted polynomial
return IceII_SF;
else if(P < 1.153769845e-08*pow(T,3)-7.956399761e-06*pow(T,2)-0.001642755909*T+0.1140942871) //Small remaining IceIh region, SeaFreeze
return IceIh_SF;
else
return IceIII_SF;
}
// V, VI, Water Triple Point SeaFreeze
else if(P < 0.634399)
{
if(T > 47.24417282*pow(P,3)-120.4230091*pow(P,2)+143.9050041*P+218.5209061) //Ice V Melt line, SeaFreeze fitted polynomial
{
if(T>1280)
return Water_sc_Mazevet; //there will be a density decrease if transitioning from Brown -> Mazevet
else
return Water_Brown;
}
else if(T<8.754511801*pow(P,3)-42.36539788*pow(P,2)-114.2410848*P+294.9938885 && T<10.6802119*pow(P,3)-60.79880497*pow(P,2)+108.5464607*P+218.0347735) //IceII region, SeaFreeze fitted polynomial
return IceII_SF;
else if(P< 2.669414392e-08*pow(T,3)-1.786325179e-05*pow(T,2)+0.003113786951*T+0.2759414249) //Small remaining IceIII, SeaFreeze
return IceIII_SF;
else
return IceV_SF;
}
// Water, Ice VI, Ice VII Triple Point, SeaFreeze
else if(P < 2.216)
{
if(T>5.711742978*pow(P,3)-39.67340784*pow(P,2)+125.6893825*P+208.5585936 || T>355) //Ice VI Melt line, SeaFreeze fitted polynomial
{
if(T>1280)
return Water_sc_Mazevet;
else
return Water_Brown;
}
else if(P< -3.607661344e-08*pow(T,3)+1.032010899e-05*pow(T,2)-0.002592049235*T+1.070211316 && T<8.754511801*pow(P,3)-42.36539788*pow(P,2)-114.2410848*P+294.9938885) //Remaining IceII region
return IceII_SF;
else if(P< -1.970275298e-08*pow(T,3)-1.858690183e-06*pow(T,2)+0.003737731993*T+0.1540994852) //Remaining IceV region
return IceV_SF;
else if(T>-1.4699e5+6.10791e-6*P*1e9+8.1529e3*log(P*1e9)-8.8439e-1*sqrt(P*1e9)) // IceVI-VII transition AQUA
return IceVI_SF;
else
return IceVII_Bezacier;
}
// Ice VII, X, Water Triple Point. Region of possible transitional Ice VII' reported in Grande not used in default
else if(P < 30.9)
{
if(P<2.17+1.253*(pow(T/355,3.0)-1) || T>1023) // Ice VII Melting curve Datchi et al. 2000 Phys. Rev. B 61, 6535
{
if(T>1280)
return Water_sc_Mazevet;
else
return Water_Brown;
}
else
{
if(T<700) //Avoid extrpolating Bezacier to high temperatures where dT/dP_S is too high
return IceVII_Bezacier;
else
return IceVII_Fei;
}
}
// Phase diagram becomes more uncertain over 30.9 GPa
else if (P<700)
{ // use Ice X if T<2250 and P<700 otherwise supercritical similiar to AQUA
if(P<pow(10.0, exp(1.7818*pow(T/1634.6, 0.2408) + 0.8310*pow(T/1634.6, -1.0) - 0.1444*pow(T/1634.6, -3.0)) - 1.0)/1e9 || T>2250) // Ice X Melting curve AQUA
return Water_sc_Mazevet;
else
return IceX;
}
else
return Water_sc_Mazevet;
}
// ---------------------------------
// H2O Water/Ice boundaries primarily from Dunaeva et al. 2010
//Simplified phase diagram with major phases as used in Huang et al. 22
EOS* find_phase_water_legacy(double P, double T)
// input P in cgs
{
P /= 1E10; // convert microbar to GPa
double Tt1, Tt2;
if (P <= 0 || T <= 0)
{
return NULL;
}
if( P < 0.208566 ) // liquid water or Ice Ih (Dunaeva et al. 2010)
{
Tt1 = dunaeva_phase_curve(P, 273.0159, -0.0132, -0.1577, 0, 0.1516);
if (!gsl_finite(Tt1))
{
cout<<"Error: Can't find the phase of H2O at P="<<P<<" GPa and T="<<T<<" K."<<endl;
return NULL;
}
if(T > Tt1)
return Water;
else
return IceIh;
}
else if( P < 0.6324 ) // liquid water or Ice II, III, V
{
Tt1 = dunaeva_phase_curve(P, 10.277, 0.0265, 50.1624, 0.5868, -4.3288);
Tt2 = dunaeva_phase_curve(P, 5.0321, -0.0004, 30.9482, 1.0018, 0);
if (!gsl_finite(Tt1) || !gsl_finite(Tt2))
{
cout<<"Error: Can't find the phase of H2O at P="<<P<<" GPa and T="<<T<<" K."<<endl;
return NULL;
}
if( (P < 0.3501 && T > Tt1) || (P >= 0.3501 && T > Tt2))
return Water;
else
{
return Ice_Dummy;
}
}
else if(P < 2.216) // liquid water or Ice VI, VII
{
Tt1 = dunaeva_phase_curve(P, 4.2804, -0.0013, 21.8756, 1.0018, 1.0785);
Tt2 = dunaeva_phase_curve(P, -47.8507, 0, -389.006, 0.9932, 28.8539);
if (!gsl_finite(Tt1) || !gsl_finite(Tt2))
{
cout<<"Error: Can't find the phase of H2O at P="<<P<<" GPa and T="<<T<<" K."<<endl;
return NULL;
}
if(T > Tt1)
return Water;
else if(T > Tt2)
return IceVI_Bezacier;
else
return IceVII_Bezacier;
}
else if(P < 5.10) // liquid water or Ice VII.
{
if(T>1200) // A dummy melting curve to avoid ice VII EOS extrapolated to temperature too high.
return Water_sc_Mazevet;
else
return IceVII_Bezacier;
}
else if(P < 30.9) // liquid water or Ice VII'.
{
if(T>1200) // A dummy melting curve to avoid Ice VII EOS extrapolated to temperature too high.
return Water_sc_Mazevet;
else
//return IceVIIp; //Region of possible transitional Ice VII' reported in Grande not used in default
return IceVII_Bezacier;
}
else if (P<700) // Phase diagram becomes more uncertain over 30.9 GPa
{ // use Ice X if T<2250 and P<700 otherwise supercritical similiar to AQUA
if(T<2250)
return IceX;
else
return Water_sc_Mazevet;
}
else
return Water_sc_Mazevet;
}
// ---------------------------------
// AQUA Haldemann et al. 2020 Tabulated Ice, Liquid, Vapor, Supercritical
EOS* find_phase_water_tabulated(double P, double T)
{
if (P <= 0 || T <= 0)
{
return NULL;
}
P /= 1E10; // convert microbar to GPa
return H2O_AQUA;
}
// ========== Phase Diagram for Atmosphere ================
// ---------------------------------
// Ideal Gas: Isothermal for P<100 bar, the radiative/convective boundary (Nixon & Madhusudhan 2021). Adiabatic ideal gas for P > 100 bar
EOS* find_phase_gas_default(double P, double T)
{
if (P <= 0 || T <= 0)
{
return NULL;
}
else if (P < 1E8)
return Gas_iso;
else
//return vdW_H2;
return Gas;
}
// ---------------------------------
// H/He Gas: Isothermal ideal for P<100 bar, P>100 bar: tabulated real gas, Chabrier & Debras 2021 Y=0.275
EOS* find_phase_HHe_tabulated(double P, double T)
{
if (P <= 0 || T <= 0)
{
return NULL;
}
else if (P < 1E8)
return Gas_iso;
else
return Gas_hhe;
}
PhaseDgm core("core", find_phase_Fe_default); //Phase Diagrams for Core
PhaseDgm core1("core1", find_phase_Fe_fccbcc);
PhaseDgm mant("mantle", find_phase_Si_default); //Phase Diagrams for Mantle
PhaseDgm mant1("mantle1", find_phase_Si_simple);
PhaseDgm mant2("mantle2", find_phase_PREM);
PhaseDgm mant3("mantle3", find_phase_C_simple); //Phase Diagram for Carbon Mantle
PhaseDgm mant4("mantle4", find_phase_SiC); //Phase Diagram for Carbide Mantle
PhaseDgm water("water", find_phase_water_default); //Phase Diagrams for Hydrosphere
PhaseDgm water1("water1", find_phase_water_tabulated);
PhaseDgm water2("water2", find_phase_water_legacy);
PhaseDgm atm("atm", find_phase_gas_default); //Phase Diagrams for Atmosphere
PhaseDgm atm1("atm1", find_phase_HHe_tabulated);
EOS* find_phase(double m, double MC, double MM, double MW, double MG, double P, double T, bool inward)
// given the accumulated mass (in g), P (in cgs) and T, return the corresponding phase
{
if (inward)
{
if(m < MC*ME) // iron core
return core.find_phase(P,T);
else if(m < (MM+MC)*ME) // silicon mantle
return mant.find_phase(P,T);
else if(m < (MM+MC+MW)*ME) // hydrosphere
return water.find_phase(P,T);
else // return the outermost existing layer
{
if(MG > 1E-18)
return atm.find_phase(P,T);
else if(MW > 1E-18)
return water.find_phase(P,T);
else if(MM > 1E-18)
return mant.find_phase(P,T);
else
return core.find_phase(P,T);
}
}
else
{
if(m <= MC*ME) // iron core
return core.find_phase(P,T);
else if(m <= (MM+MC)*ME) // silicon mantle
return mant.find_phase(P,T);
else if(m <= (MM+MC+MW)*ME) // hydrosphere
return water.find_phase(P,T);
else // return the outermost existing layer
{
if(MG > 1E-18)
return atm.find_phase(P,T);
else if(MW > 1E-18)
return water.find_phase(P,T);
else if(MM > 1E-18)
return mant.find_phase(P,T);
else
return core.find_phase(P,T);
}
}
}
EOS* find_phase(double m, vector<PhaseDgm> &Comp, vector<double> M, double P, double T, bool inward)
{
if (Comp.size() != M.size())
{
cout<<"Error. The length of input vectors doesn't match."<<endl;
exit(1);
}
double mass_layers = 0;
int n_comp = Comp.size();
for (int i=0; i<n_comp; i++)
{
if (M[i]*ME<1)
continue;
mass_layers += M[i];
if (inward)
{
if (m < mass_layers*ME)
return Comp[i].find_phase(P, T);
}
else
if (m <= mass_layers*ME)
return Comp[i].find_phase(P, T);
}
// if nothing matched, return the outermost existing layer
return Comp.back().find_phase(P, T);
}