Code Monkey home page Code Monkey logo

magrathea's Introduction

MAGRATHEA

Header

Excerpt from The Hitchhiker's Guide to the Galaxy, Page 634784, Section 5a, Entry: MAGRATHEA

Planet interior structure code for astronomers, planetary scientists, mice, and more.

What is this repository for?

A 1D planet structure code written in C++ which considers the case of fully differentiated interiors. The code integrates the hydrostatic equation in order to shoot for the correct planet radius given the mass in each layer. The code returns the pressure, temperature, density, phase, and radius at steps of enclosed mass. The code supports 4 layers: core, mantle, hydrosphere, and atmosphere. Each layer has a phase diagram with equations of state (EoS) chosen for each phase. The code was developed by Chenliang Huang, David R. Rice, and Jason H. Steffen at the Univerisity of Nevada, Las Vegas starting in 2017. See a list of works that use MAGRATHEA and instructions on how to cite. If you don't see something on this ReadMe check our publication in this repository: MAGRATHEA.pdf. A tutorial and practice projects/problems are found in Tutorial_Practice_Problems.pdf

We encourage the community to contribute to and use MAGRATHEA for their interior modeling needs.

Prerequisite

Install the GSL library(>= v2.0). Download the compressed package from the GNU ftp site. Extract the file and install the package following the instruction in the INSTALL file. For the simplest case,

sudo ./configure
sudo make
sudo make install

should configure, build, and install the GSL package. A few prerequisites, such as g++, make, make-guile, may need to be installed following the error messages throughout the process.

On Ubuntu systems, the GSL package can also be installed from the Ubuntu repository using sudo apt install libgsl27 libgsl-dev gsl-bin.

On Windows systems, we suggest using WSL and following the above isntructions.

If an error message like "error while loading shared libraries: libgsl.so.23: cannot open shared object file: No such file or directory" is reported when running the code, add export LD_LIBRARY_PATH=/usr/local/lib (directory of GSL library files) to the .bashrc file, or add setenv LD_LIBRARY_PATH /usr/local/lib to the .cshrc file.

When running many simulations with bulk input modes, OpenMP can be used to run individual planets in parallel, please contact us to get this set up in the code.

Quick Start

Installation:

  1. Open a terminal. Navigate to where you wish to install the directory.
  2. Clone the repository: git clone https://github.com/Huang-CL/Magrathea.git.
  3. If the gsl library is not installed globally (under /usr/local/ or equivalent), edit Makefile to include the actual path toward the gsl headers (e.g. ~/include or ~/gsl/include) and gsl library (e.g. ~/lib or ~/gsl/lib) following -I in CFLAGS and -L in LDFLAGS. The path of headers and libraries can be found using gsl-config --cflags and gsl-config --libs. If the gsl-config command is not found, gsl may not have been installed properly. Note: The path after -I should end with /include, not /include/gsl.
  4. Run make -B inside the code's directory. After the first compilation use make to compile the code.

Running a planet:

  1. Open run/mode0.cfg in a text editor.
  2. Line 12-14: set mass of the core, mantle, hydrosphere, and atmosphere in Earth-masses.
  3. Line 16-20: set surface temperature and any temperature discontinuities.
  4. Line 21: set output file name and path.
  5. In terminal, compile changed file with make.
  6. Run MAGRATHEA with ./planet run/mode0.cfg.

Capability and Output

MAGRATHEA uses a shooting to a fitting-point method with a Runge-Kutta-Fehlberg method with an adaptive step-size. The user's supplied mass fractions determine the enclosed mass at each layer's boundary. Within a layer the enclosed mass at which the phase changes is determined by P-T conditions. When a phase changes, the solver backs up to find the exact location of the phase change. The fitting point is at 20% the mass of the planet. The solver integrates until the inner and outer branch of integration agree at the fitting point with a relative error less than 10-4.

Input Modes

There are 7 modes with different functionality described below. These modes can be used with the 7 config (.cfg) files in the run directory. The code is then ran with ./planet run/mode_.cfg.

mode0.cfg

The basic capability: calculate the structure of a planet given the mass of each layer.

The config file requires defining the mass in the planet's core, mantle, hydrosphere, and atmosphere in the unit of Earth-mass. Additionally the mode requires four temperatures, first the "surface temperature" in Kelvin which is the temperature at the top of the planet, where enclosed mass is equal to total mass. Then three temperatures which will be used for discontinuities in temperature at layer boundaries. The first being temp_jump_1, the size of temperature discontinuity between the atmosphere and hydrosphere, and the last being temp_jump_3, the size of temperature discontinuity between the core and the mantle. Setting these jumps to 0 will ensure layers in thermodynamic equilibrium. These parameters will be used in the fitting_method() function in src/main.cpp.

The function also requires a guess for the density in each layer from ave_rho and the surface pressure from P_surface located in the #Global Run Options section of the config file. Default surface pressure is 100 mbar. Lastly, the phase diagrams are chosen. This is detailed further in the Phase Diagram section below.

The planet structure will be output as an ASCII file with pressure (GPa), interior mass (Earth mass), density (g cm-3), temperature (K), and phase of composition as a function of radius (Earth radius).

mode1.cfg

Running the code with this input file will use the getmass() function which assumes an isothermal planet. This function runs much quicker than the full solver. User provides in the config file the mass of the core, mantle, and hydrospehre in Earth-masses. No atmosphere layer is available in this solver. Outputs interior conditions to a file as in mode 0.

mode2.cfg

The fastest solver available using the twolayer() function. Using this input file will find radii for an array of planet masses each with only two layers using an isothermal inside-out shooting method. Built to quickly make mass-radius curves with a constant mass ratio between the layers.

The config file requires defining a layer_index where =0 is a planet with only mantle and hydrosphere (no core), =1 is only core and hydrosphere, and =2 is core and mantle. The file also requires defining mass_fraction which is the mass fraction of the inner layer. An array of masses in Earth-masses is defined by min_mass, max_mass, and step_mass. Planets will be solved from min_mass to max_mass in steps of step_mass. Returns radii for each mass in the terminal.

mode3.cfg

This mode is for bulk inputs of planets using the solvers from mode 0 or mode 1. Requires a space separated file, where each row of the table lists the total mass in Earth-masses and fraction of mass in each layer for a planet.

Example input file:

Mass  fCore  fMantle  fWater
2     0.2    0.4      0.4
1.5   0.5    0.39     0.1

Any remaining mass (1-fCore-fMantle-fWater) will be put into the atmosphere. Example input files can also be found in the input directory.

In the config file, the user sets the path to the input file and the path to where the output file should be created. The full solver from mode 0 can be used by setting solver=1 and the temperature-free solver can be used with solver=2 (solver=1 is recommended). For solver=1, the surface temperature and temperature jumps are defined in the same way as mode 0. These parameters will be used in the multiplanet() function from src/compfind.cpp.

MAGRATHEA will generate an output file with mass of core, mantle, water, and atmosphere and the radius of the core, mantle, water, and planet for each line in the input file. If the solution crosses the part of the phase diagram that the code has not been fully implemented, "Dummy EOS used" is added to the end of the row. If the solver cannot find the solution that meets the required accuracy with the given number of iteration, "Solution did not converge" is added. "No solution found" is also possible in the output if the solver failed to find a solution.

mode4.cfg

This mode is our composition finder which finds the mass fraction of an unkown layer for a planet of given mass and radius. Requires a space separated file, where each row of the table lists a planet's total mass in Earth-masses and radius in Earth-radii.

Example input file:

M (Earth-masses) 	R (Earth-radii)
1.06658             1.09393
1.02955             1.04153

Example input files can also be found in the input directory.

In the config file, the user sets the path to the input file and the path to where the output file should be created. Then they set which layer to find, find_layer and which two layers to set in constant partial mass ratio, layer_outer and layer_inner. The indexes are 1 for core, 2 for mantle, 3 for water/hydrosphere, and 4 for atmosphere. The index of layer_inner must be less than that of layer_outer.

The partial mass ratio (PMR%) is given by the percentage ratio of the outer mass fraction to the total non-unkown mass fraction. In other words, OMF/(IMF+OMF)*100 where OMF is the outer mass fraction and IMF is the inner mass fraction. The user can then make an array of PMRs to loop over from PMR_min to PMR_max with a step of PMR_step these parameters must be between 0 and 100 and truncated to the tenths place. If PMR_min is equal to PMR_max the composition finder will find the unkown mass fraction for just one PMR for each mass and radius. Lastly, the user must define R_error which is error tolerance in simulated radius to target radius.

The surface temperature and temperature jumps are defined in the same way as mode 0. The above parameters will be used in the compfinder() function from src/compfind.cpp.

MAGRATHEA will use the full solver from mode 0 and for each mass and target radius in the input file and will first find the radius of a planet with no unkown mass and the rest of the mass distributed according to the PMR. A secant method is then used to find the unkown mass which is needed to match the planet radius. If a negative mass is needed an error is printed in the output file. An output file with mass of core, mantle, water, and atmosphere and the radius of the core, mantle, water, and planet and the target radius for each line in the input file and for each PMR. If the target radius is not matched within the error tolerance in 30 interations the finder moves to the next PMR or next line in the input file.

mode5,6,7.cfg

These modes allow for changing an EoS in the model temporarily during a run (changing an EoS pernamently or adding an EoS discussed below). These modes can be used to measure how the uncertainty in a measurement affects a planet's radius. Mode 5 changes an EoS and uses the twolayer function. Mode 6 and Mode 7 iteratively change an EoS from an input file with the twolayer (Mode 2) and fullmodel (Mode 0) respectively.

For the moment, we save documenting how to create an input file for these modes for a later date. Examples of input files that change the EoSs are included in the input directory.

Build your own planet model

MAGRATHEA is built for model flexibility with transparent storage structures for equations of state (EoS). We make it easy for users to build a reproduceable model and cite the material measurements that have gone into the model.

The built-in EoSs for various planet building materials and phases are listed in the file EOSlist.h. The detailed definition of each one can be found in EOSlist.cpp.

Adding new equations of state

The code takes a new EoS in the format of (0) 3rd order Birch-Murnaghan, (1) 4th order Birch-Murnaghan, (2) Vinet, (3) Holzapfel, (4) Keane, (6) Ideal Gas, (7) Density-Pressure input table or Pressure-Temperature-Density-dT/dP_S input table from file for interpolation, (8-12) same as 0-4 in combination with RTPress.

New phases should be listed into the file EOSlist.h, defined in EOSlist.cpp, and deleted in main.cpp.

Examples:

// Epsilon Iron (hcp), Smith et al. 2018, Nature Astronomy. (Gruneisen determined from fitting Fig. 3b)
// DEFAULT
double Fe_hcp_array[][2] = {{0,2}, {1,mFe/8.43}, {2,177.7}, {3,5.64}, {5,mFe}, {7,322}, {8,2.09}, {9,1.01}, {10,0.0500}, {14,1}, {15,26}};
EOS *Fe_hcp = new EOS("Fe hcp (Smith)", Fe_hcp_array, sizeof(Fe_hcp_array)/2/sizeof(Fe_hcp_array[0][0]));

// Post-Perovskite, MgSiO3, Sakai, Dekura, & Hirao, 2016, Scientific Reports
// DEFAULT
double Si_PPv_Sakai_array[][2] = {{0,4}, {1,24.73}, {2,203}, {3,5.35}, {5,mMg+mSi+3*mO}, {7,848}, {8,1.47}, {9,2.7}, {10,0.93}, {14,5}};
EOS *Si_PPv_Sakai = new EOS("Si PPv (Sakai)", Si_PPv_Sakai_array, sizeof(Si_PPv_Sakai_array)/2/sizeof(Si_PPv_Sakai_array[0][0]));

Analytical EoS are defined by an array with as many parameters as needed from the table below. For example, the Epsilon Iron EoS above has a bulk modulus of 177.7 GPa.

Index Variable Unit Comment
0 EOS formula type Index in parentheses above
1 V0 cm^3 mol^-1$ Molar volume at reference point
2 K0 GPa Bulk modulus
3 K0' Pressure derivative of the bulk modulus. Default 4
4 K0'' GPa^-1 Second pressure derivative
5 m_mol g mol^-1 Molar mass
6 P0 GPa The minimum pressure, corresponding to V0. Default 0
7 Theta0 K Fitting parameter of Einstein or Debye temperature. Default 1
8 gamma_0 Fitting parameter of Gruneisen parameter
9 beta Fitting parameter of Gruneisen parameter
10 gamma_inf Fitting parameter of Gruneisen parameter. Default 2/3
11 gamma_0' Volume derivative of the Gruneisen parameter
12 e0 10^-6$ K^-1 Electronic contribution to Helmholtz free energy. Default 0
13 g Electronic analogue of the Gruneisen parameter
14 n Number of atoms in the chemical formula. Default 1
15 Z Atomic number (number of electron)
16 T0 K Reference temperature for the thermal pressure. Default 300
17 alpha0 10^-6 K^-1 The zeroth order coefficient of thermal expansion at a reference pressure P0
18 alpha1 10^-6 K^-2 The first order coefficient of thermal expansion at a reference pressure P0
19 xi Power law index in the coefficient of thermal expansion. Default 0
20 c_p0 10^7 erg g^-1 K^-1 Specific heat capacity at constant pressure
21 c_p1 10^7 erg g^-1 K^-2 Coefficient for specific heat capacity
22 c_p2 10^7 erg g^-1 K Coefficient for specific heat capacity
23 Debye approx Positive number for Debye, otherwise Einstein
24 thermal type See Paper

Tabulated EoS can be read from files in the tabulated directory. A table can either have 2 or 4 columns. If 2, the user defines the density at each pressure and the code will assume the material is isothermal and interpolate the density from pressure alone. The table must monotonically increase in pressure. If 4 columns are provided, they must be pressure, temperature, density, and the adiabatic gradient (dT/dP_S). The code will linearly interpolate the density from both the temperature and pressure. The table must be rectangular in pressure and temperature with each temperature listed for a pressure before moving to the next pressure, and both must be increasing.

Phase Diagrams

To pick desired materials/phases in each layer, change the corresponding return values of find_phase_water_default, find_phase_Fe_default, find_phase_Si_default, or find_phase_gas_default in phase.cpp using conditionals to set the desired pressure and temperature where the material/phase will exist.

Example:

// 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.
	   return Fe_liquid;
 else
	   return Fe_hcp;             // use hcp Iron for all regions.
}

A number of predefined phase diagrams are available to test out which can be defined in the config files for the modes which will take changeable phase diagrams.

Layer Name to call Details
Core "Fe_default" hcp and Liquid iron
  "Fe_fccbcc" Includes low pressure fcc and bcc iron
Mantle "Si_default" Upper Mantle: Fo, Wds, Rwd, and liquid ; Lower Mantle: Brg, PPv
  "Si_simple" Brg, PPv, and liquid
  "PREM" PREM tabulated mantle
Hydrosphere "water_default" H2O Water/Ice boundaries primarily form Dunaeva et al. 2010
  "water_tabulated" AQUA Haldemann et al. 2020 Tabulated Ice, Liquid, Vapor, Supercritical
Atmosphere "gas_default" Ideal Gas: Isothermal for P<100 bar. Adiabatic ideal gas for P > 100 bar
  "HHe_tabulated" H/He Gas: Isothermal ideal for P<100 bar, P>100 bar: tabulated real gas, Chabrier & Debras 2021 Y=0.275

Adding new phase diagrams

Saving a phase diagram for repeated use and comparison with others is often helpful. There is a number of places where a new phase diagram needs to be added. First, define the new find_phase_X_Y in phase.h then create the function using conidtionals which return an EoS in phase.cpp folowing the example of other find_phase functions. Then later in phase.cpp pass the function into a phase diagram (PhaseDgm) and the layer to which it belongs. Give the PhaseDgm a new name (we suggest to continue to interate on our format) and add this new PhaseDgm near the end of phase.h. Lastly in main.cpp the parser must find the user defined string in the config file and pass it to the vector of phase diagrams in the //Set Phase Diagrams section. Write a new conditional for the correct layer and set the correct position in the vector to your new PhaseDgm.

Useful unit conversions

The input parameters required to create an EOS in the program are typically in cgs units. However, the EoS measurement/calculation article may list their result in different units. Thus, the following unit conversions maybe helpful.

In the equations below, m is the number of formula units per unit cell. For example, cubic ice-VII (space group Pn3m) has two water molecules per unit cell, so m=2. n is the number atoms per molecule formula. For example, MgSiO3 has 5 atoms in a molecule, so n=5.

  • 1 Å3/cell = 10-24NA/m cm3/mol = 0.6022/m cm3/mol.
  • 1 Å3/atom = 10-24nNA cm3/mol = 0.6022n cm3/mol.
  • 1 eV/atom = 1.602×10-12nNA erg/mol = 9.649×1011n erg/mol.
  • 1 GPa = 1010µbar = 0.01 Mbar.

Functions to obtain the calculated planetary parameters

The functions in the table below can be used to obtain the calculated planetary parameters after a successful solving of planetary structure.

Function Output unit Comment
double totalM() g return the total mass of a planet
double totalR() cm return the total radius of a planet
int getLayer_from_r(double r) Input radius in the RE, return the layer index l (from 0, count from bottom), rb(l)<=r*R⊕<rb(l+1)
int getLayer_from_m(double m) Input mass in the ME, return the layer index l (from 0, count from bottom), M(l)<=m*M⊕<M(l+1)
double getP(int l) µbar return the pressure at layer l
double getM(int l) g return the pressure at layer l
double getR(int l) cm return the radius at layer l
double getrho(int l) g/ cm3 return the ensity at layer l
double getT(int l) K return the temperature at layer l
int getsize() return the total number of layers
vector<double> getRs() R⊕ Return the radii of core, mantle, and water layer, and the total radius in the unit of earth radii.
vector<double> getTs() K Return the temperatures at the outer side of each component interfaces as well as planet surface

Example code:

vector<double> Tgap = {0, 0, 0, 300};
vector<double> Mcomp =  {1.0,0.5,0.1,0.00001}; 
planet=fitting_method(Comp, Mcomp, Tgap, ave_rho, P_surface, false);
if (planet)
{
  int l = planet->getLayer_from_r(1);
  cout<<"layer:"<<l<<" P="<<planet->getP(l)<<"microbar R="<<planet->getR(l)/RE<<"REarth  rho="<<planet->getrho(l)<<"g/cm^3"<<endl;
  l = planet->getLayer_from_m(1);
  cout<<"layer:"<<l<<" P="<<planet->getP(l)<<"microbar M="<<planet->getM(l)/ME<<"MEarth  rho="<<planet->getrho(l)<<"g/cm^3"<<endl;
  vector<double> Rs = planet->getRs();
  vector<double> Ts = planet->getTs();
  for (int i=0; i<4; i++)
    cout<<planet->getLayer_from_r(Rs[i])<<' '<<Rs[i]<<"REarth "<<Ts[i]<<'K'<<endl;
}

Example output:

layer:605 P=1.21568e+11microbar R=0.998631REarth  rho=1.95656g/cm^3
layer:547 P=1.5147e+12microbar M=0.999971MEarth  rho=11.8156g/cm^3
547 0.726926REarth 630.97K
602 0.978419REarth 460.504K
682 1.07939REarth 300K
752 1.12843REarth 300K

Print EoS into a table

The code can print the pressure-density relation of a built-in EoS into an ASCII table by using the printEOS function of the EoS object. This can be a simple way to double check the EoS is set up correctly. The table covers the pressure range from 0.1 GPa (or P0 if it is larger) to 2000 GPa at the temperature T0 (default 300 K) of the EoS. The output table file is located at ./tabulated/phasename.txt.

Examples/Plots

Within the directories input and result are example input files and output files which are described in each directory's markdown (.md) file.

Python plotting scripts are included in the directory plot. Scripts are written for Python 3.6. Scripts may require matplotlib, numpy, astropy, python-ternary, regex, cmasher, and scipy.

3D Representations of Planets

Magrathea outputs can be imaged in the 3D open-source software Blender. Instructions and code are in https://github.com/DavidRRice/Blender-Magrathea.

Don't Panic (FAQ)

Who do I talk to?

Find our emails on our websites:

Chenliang Huang, Shanghai Astronomical Observatory website

David R. Rice, ARCO, Open University of Israel website

Where is the EoS/functionality I want?

Open an issue with details of what you need.

What if I need to model a planet, but I'm currently being tortured by Vogon poetry?

We are open to collaborations! Emails found on websites above.

Where do I find other codes for exoplanet modeling?

MAGRATHEA and many other useful exoplanet-related codes are archived on NASA's Exoplanet Modeling and Analysis Center.

Where does the name MAGRATHEA come from?

Magrathea is a fictional planet in Douglas Adams's The Hitchiker's Guide to the Galaxy:

"for all the richest and most successful merchants life inevitably became rather dull and niggly, and they began to imagine that this was therefore the fault of the worlds they'd settled on... And thus were created the conditions for a staggering new form of specialist industry: custom-made luxury planet building. The home of this industry was the planet Magrathea, where hyperspatial engineers sucked matter through white holes in space to form it into dream planets- gold planets, platinum planets, soft rubber planets with lots of earthquakes- all lovingly made to meet the exacting standards that the Galaxy's richest men naturally came to expect.

But so successful was this venture that Magrathea itself soon became the richest planet of all time and the rest of the Galaxy was reduced to abject poverty. And so the system broke down, the Empire collapsed, and a long sullen silence settled over a billion worlds...

Magrathea itself disappeared and its memory soon passed into the obscurity of legend. In these enlightened days of course, no one believes a word of it."


MAGRATHEA is or has been supported by the Nevada Center for Astrophysics, the University of Nevada, Las Vegas's Physics & Astronomy Department and Star & Planet Formation Group, the Astrophysics Research Center of the Open University of Israel, and the University of Arizona's Lunar and Planetary Laboratory

We want to thank the many users and supporters of this code. We greatly appreciate the contributions, discussions, and support of Allona Vazan, Michael Lozovsky, Ashkan Salamat, and Piyush Puranik

magrathea's People

Contributors

davidrrice avatar huang-cl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

magrathea's Issues

Where exactly the code reads EOS from a file?

Hi,

My goal now is to replace the EOS table with a one I have. In the meanwhile:

  1. I created a file named "Test_Si.txt" in "tabulated" folder (temporal test EOS file)
  2. in the file "EOSlist.h" I added " , *Si_QEOS"
  3. in the file "EOSlist.ccp" I added a line "EOS *Si_QEOS = new EOS("Si (test)", "./tabulated/Test_Si.txt");"
  4. in the file "phase.ccp" under "EOS* find_Si_phase(double P, double T)" I added "return Si_QEOS"

It worked: compiles and runs.

Now, as a next step I try to find the exact place there the code reads P and Rho from this "Test_Si.txt" file. I want to place there a breakpoint. As the format of the EOS file I'll use differs from yours, I what to modify/correct the reading procedure to my needs.

Adding Entropy instead of dT/dP

The program runs with my new EOS, but there is one more issue: temperature profile.

Now it runs with " dTdP_QEOS( P, T)= 2.*T / (7.*P); " (a copy from dTdP_gas). This approximation is not very good for our case.

In a paper you write: "In addition, either a temperature gradient, dT/dP, as a function of pressure and temperature or an entropy function dependent on density and temperature can be used to set up the temperature solver in a phase."

So, if I understand correctly, I can provide S(T,rho) function instead of dTdP_QEOS, right? How do I do it?

I get isothermal profile, instaed of adiabatic

Hello again.
I gave up on polynomial method. There are too much trouble with this approximation. Mostly the problem is unexpected behavior on edges of different regions.
No instead I read directly from a table. I created global variables, arrays named: T_QEOS, P_QEOS , rho_QEOS, U_QEOS, S_QEOS
QEOS_tableTPrhoUS.txt
And I load them in the begging of the run.

In EOSlist.cpp I have:

double Si_QEOS_array[][2] = {{0,5}, {1, 27.36}, {5, mSi+2*mO} };
EOS *Si_QEOS = new EOS("Rock-H20-mix (QEOS)", Si_QEOS_array, sizeof(Si_QEOS_array)/2/sizeof(Si_QEOS_array[0][0]));


...
double S_Mix(double rho, double T){
 return S_Si_QEOS(rho,T);
}
double S_Si_QEOS(double rho, double T){
... reading from table, few interpolations
    S= (something)// in erg/(gram*K)
    S= S/(3.0*8.31446261815324e7 ); // 3 molecules, gas constant
}

In EOS.cpp I have:


double EOS::density(double P, double T, double rho_guess)
if(eqntype == 5){
		return  Rho_QEOS(double T, double P);
}
...
}
double Rho_QEOS(double T, double P) {
...reading from table, few interpolations
rho= (something) 
}

In main.cpp:

Si_QEOS->modify_extern_entropy(S_Mix);

(I hope I didn't forget to write something important)

Now for some reason, the results are wrong: the profile is almost completely isothermal. So there is some bug in what I'm doing.
I try to find where can be a trouble.
How does the program "know" to be adiabatic?

Here I plot s as a function of P and T. This line was calculated then I take P and T from Magrathea output and calculate s for each point in Matlab (calculating via interpolation in table). It seems like the T is increasing very very slowly, but more important: s isn't constant. What can be the problem?
Do you have a way to output the value of s in each layer?

Adding temperature dependent tabulated EOS

What I'm trying to do is to add to the program a new feature: to read from temperature dependent EOS, that I have as a table.
The format of my table is as follows:

T rho P
11.605 2.51188643150958e-13 4.28547303990553e-16
11.605 3.16227766016838e-13 4.28547303990553e-16
11.605 3.98107170553497e-13 4.28547303990553e-16
11.605 5.01187233627271e-13 4.28547303990553e-16
11.605 6.30957344480194e-13 4.28547303990553e-16
...
14.6098294038713 2.51188643150958e-13 5.45304484892599e-16
14.6098294038713 3.16227766016838e-13 5.45304484892599e-16
14.6098294038713 3.98107170553497e-13 5.45304484892599e-16
14.6098294038713 5.01187233627271e-13 5.45304484892599e-16
14.6098294038713 6.30957344480194e-13 5.45304484892599e-16
...
...
581627.784624449 2.51188643150958e-13 6.96820850132487e-10
581627.784624449 3.16227766016838e-13 7.45909582615774e-10
581627.784624449 3.98107170553497e-13 9.38469438957118e-10
581627.784624449 5.01187233627271e-13 1.18077741816094e-09
581627.784624449 6.30957344480194e-13 1.48568922527515e-09
...
1160500 79.4328234724281 340332.523678576
1160500 100 474344.468455402


In that way for every pair (T,rho) in a table I get one P.

My idea is pretty simple: Now the code is able to read EOS of (rho,P). The only thing I have to add is a function that will read T and create a table of (rho,P) for every layer (as the planet is not isothermic). I call may EOS (of rock) "QEOS".
The function reads QEOS_full.txt (a file with T, rho. P) and creates a file for a given temperature T:

void QEOS_build(double T, const int size) {
	// "size" is the length of the entire table. 

	double P_line = 0.0, T_line = 0.0, rho_line = 0.0, tmp = 0.0, Tlow = 0.0, Thigh = 0.0, T0 = 0.0;
	double P_table[size], T_table[size], rho_table[size];
	double rhohigh[size], rholow[size], Phigh[size], Plow[size], rhoiterp[size], Piterp[size]; //Note that not entire array is used. 
	

	FILE* fp = fopen("tabulated/QEOS_full.txt", "r");
	int j, i, blocksize, jbrake;

	if (!fp) {
		perror("fopen");
		return;
	}

	char line[512];

	if (!fgets(line, sizeof line, fp) || !strstr(line, "T rho P")) {
		fprintf(stderr, "Invalid or missing header.\n");
		return;
	}
	j = 0;


	while (fgets(line, sizeof line, fp)) {
		if (3 == sscanf(line, "%lf%lf%lf", &T_line, &rho_line, &P_line)) {
			T_table[j] = T_line;
			rho_table[j] = rho_line;
			P_table[j] = P_line;
			j = j + 1;

		}
	}



	fclose(fp);
	T0 = T_table[0];

	for (j = 0; j < size; j++) {
		tmp = T_table[j];
		if (tmp > T0) {
			break;
		}

	}	// j breaks so [0--j] is one block size

	blocksize = j;


	for (j = 0; j < size; j++) {
		tmp = T_table[j];
		if (tmp > T) {
			break;
		}

	} //Find T in table that is larger than given T

	Tlow = T_table[j - 1];
	Thigh = T_table[j];
	jbrake = j; // a place there two blocks meet



	i = 0;
	for (j = jbrake; j <= blocksize + jbrake - 1; j++) {
		Phigh[i] = P_table[j];
		rhohigh[i] = rho_table[j];
		i++;

	}

	i = 0;
	for (j = jbrake - blocksize ; j <= jbrake; j++) {
		Plow[i] = P_table[j];
		rholow[i] = rho_table[j];
		i++;

	}
	for (j = 0; j < blocksize ; j++) { //intepulation between two blocks
		Piterp[j] = Plow[j] + (Phigh[j] - Plow[j])  / (Thigh - Tlow) * (T - Tlow); //Not useful in my case
		rhoiterp[j] = rholow[j] + (rhohigh[j] - rholow[j]) / (Thigh - Tlow) * (T - Tlow); 

	}


	
	ofstream myfile; //save as new EOS table:

	myfile.open("tabulated/QEOS.txt");
	
	
	myfile << "rho (g/cm^-3)	P (GPa); T="<<T<<"\n";
	for (j = 0; j < blocksize; j++) {
		myfile << std::scientific << std::setprecision(10) <<rhoiterp[j]<< " " ;
		myfile<< std::scientific << std::setprecision(6) << Piterp[j];
		if(j < blocksize - 1) myfile << "\n";
		
		
	}

	myfile.close();

	 
}

This function is not extremely well written from the point of c++, but it does the work of creating a table for a given T.

Now, the only thing left is to integrate this table into the program. So I added it to the end of the file phase.cpp, there I repalced the line "return Si_Pv;" with two lines: "QEOS_build(T, 7497); " and "return Si_QEOS;".
The file EOSlist.cpp was modified: I added "EOS *Si_QEOS = new EOS("Si (QEOS)", "./tabulated/QEOS.txt");" and added the new EOS to the list.

now.... for some reason this doen't work. Maybe it's my clumsy wring style in C, but for some reason the code seem to fail to read my EOS.

My guess is a different format of P-rho relations, but also it might be some wrong place to add my new function.

QEOS_full.txt
QEOS.txt

Adding new EOS fucntion

Hello again!

I decided to "start over", as reading from a table in each iteration took too much time. And I got some strange bugs in the code, with density jumps. So instead of reading form a table, I found numerical fits for my function. The function is approximately piecewise polynomial. So no interpolation, just put in a formula from now.
Namely, my function looks like:


double QEOS(double T, double rho) {
    double P;
    double p00,p10,p01,p20,p02,p11,p12,p21,p30,p03;
    T= T*8.61697e-8; // form K to Kev
    T=log10(T); //to Log scale
    rho=log10(rho);// (assuming cgs) to Log scale
    
    if (rho<=0.4 && T<4.2){ //region 1
        p00=-8.773;
        p10=4.017;
        p01=0;
        p20=0.4632;
        p11=0;
        p02=0;
        p30=0.02391;
        p21=0;
        p12=0;
        p03 = 0;}
 // ....(missing part)....
   if (T>-3 && rho<=0.4) {//region 4
            p00 =      -1.364;
            p10 =       0.9002;
            p01 =      0.9935;
            p20 =      -0.2522;
            p11 =      0.05099;
            p02 =      -0.003507;
            p30 =      -0.03374;
            p21 =      0.009997;
            p12 =      -0.0004553;
            p03 =      0;
    }
    P= p00 + p10*T + p01*rho + p20*T*T + p11*T*rho + p02*rho*rho +p21*T*T *rho  +   p12*T*rho*rho + p30*T*T*T+ 03*rho*rho*rho;
    P= pow(10.0,P); // in 10^4 megabars
    P= P* 1e16; // back to cgs (dynes * cm^-2)
	return P;
}

The EOS itself has phase separation and different regimes. This EOS is supposed to be used for mantle only (rock).
Fist of all: the table was in log10 scale, pentapascals and KeV, so I made a conversion. The ** input of the function is in Kelvin and gr*cm^-3, the output is dynes * cm^-2**. Are the units correct?

Second, and more important:
I will use the latest version of your code. What are the changes I need to to to force the code use my EOS for the mantle?
So far, if I understand:

  1. add the code of QEOS itself to EOS.cpp, just after the end of "double EOS::Press(double rho, double T)" function.
  2. add a line "double QEOS(double T, double rho);" in EOS.h, line 159
  3. add double Si_QEOS_array[][2] = {{0,5}, {1, 40}, {5, mSi}};
    EOS *Si_QEOS = new EOS("Si (QEOS)", Si_QEOS_array, sizeof(Si_QEOS_array)/2/sizeof(Si_QEOS_array[0][0]));
    to EOSList.cpp
  4. In phase.cpp, in function EOS* find_Si_phase(double P, double T) I replace both EOS'es with "return QEOS;"

so far, so good?
I get an error "src/phase.cpp:386:11: error: cannot convert ‘double ()(double, double)’ to ‘EOS’ in return", so I missed some step.

Am I doing it right? If not, what should I do?

Thanks a lot.

changing of EOS gives negative density?

Hi guys,

I added a new function to the code:
double P_mixEOS(double T, double rho0, double Xr, double Pguess , double epsilon, double DeltaRho)
the input arguments are: T (K), rho (cgs), rock mass fraction ( [0-1]) and three numerical arguments: guess of P (Gpa) and two small numerical factors (not very important for this question). The output is P (Gpa).
The function calculates pressure P for a given pair of (T and Rho) and a given rock mass fraction (I assume EOS of rock/ice mixture).
Th code assumes positive inputs, and can't run with negative values.
In EOS.cpp in a function double EOS::Press(double rho, double T) I added:
case 5:
P= P_mixEOS(T,rho, 0.5, 1.5, 0.001, 1.0e-3 );
return P;

In phase.cpp, in a function EOS* find_Si_phase(double P, double T) I changes that in any case the there is only one option:
return Si_QEOS;
In EOSlist.cpp I have:
double Si_QEOS_array[][2] = {{0,5}, {1, 100}, {5, mSi+2*mO}};
EOS *Si_QEOS = new EOS("Si (QEOS)", Si_QEOS_array, sizeof(Si_QEOS_array)/2/sizeof(Si_QEOS_array[0][0]));

EOS.h was updated with new functions.

The program is able to run my function for 441 times, and then it stuck.
It runs into some very unexpected input of T=1200, rho=-848289 , that can't be a result of any previous iteration.
actually my log says the the output of the last run of the function was P = 46.4413 , for (T=1200 , rho= 3.01599).
My conclusion is that the program uses the output of EOS::Press(double rho, double T) somewhere and in some point made something weird.
What can be a problem and how to correct it?

Did anyone managed to install and run this code?

Hi,
I'm trying few days to go over the instructions and install this code.
I tried using windows' buiIt-in Ubuntu, I tried on remote server. installed cygwin with gsl; nothing works!

On the remote uni server I get " ... is not in the sudoers file. This incident will be reported."
On Cygwin I get "-bash: sudo: command not found"
On windows "Ubuntu" terminal I get:
"g++ -o src/phase.o -c src/phase.cpp -std=c++0x -O3 -Wall
In file included from src/EOS.h:4:0,
from src/phase.h:4,
from src/phase.cpp:1:
src/define.h:13:10: fatal error: gsl/gsl_odeiv2.h: No such file or directory
#include <gsl/gsl_odeiv2.h>
^~~~~~~~~~~~~~~~~~
compilation terminated.
Makefile:20: recipe for target 'src/phase.o' failed
make: *** [src/phase.o] Error 1

"

Did anyone managed with it? Any solution?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.