diff --git a/.gitignore b/.gitignore index 882d4d6..77121f3 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ docs/_build/ .DS_Store .ruff_cache +.pytest_cache/ diff --git a/MANIFEST.in b/MANIFEST.in index 74ca7c6..854f30c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1 @@ -include evo/Data/*.txt -include evo/input/*.yaml +include evo/data/*.txt diff --git a/README.md b/README.md index d486c64..f737503 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,7 @@ Single pressure and decompression can be run for OH, COH, SOH, COHS and COHSN sy EVo can be set up using either melt volatile contents, or for a set amount of atomic volatile which is preferable for conducting experiments over a wide range of fO2 values. -### Prerequisites - -This programme requires Python 3 to run. - -Installation/Usage: -******************* +## Installation/Usage: To install locally, EVo must be downloaded from GitHub using @@ -33,16 +28,18 @@ From this point, EVo can either be imported into your python scripts as a regula `import evo` and run using -`evo.main(, , , folder=)` +`evo.run_evo(, , , folder=)` -Or EVo can be run directly from the terminal from inside the `evo` directory: +Or EVo can be run directly from the terminal: ``` -cd EVO/evo -python dgs.py input/chem.yaml input/env.yaml --output-options input/output.yaml +python evo input_files/chem.yaml input_files/env.yaml --output-options input_files/output.yaml ``` The model should run and produce an output file `outputs/dgs_output_*.csv`, and a set of graphs in an 'outputs' folder, if a decompression run has been selected. +The settings are controlled by a set of config files, found in the `input_files` folder. +You should edit these as described below to set up your decompression experiment. + ### Choosing run options in the env.yaml file The different run types, model parameters and input values are all set in the env.yaml file. Run types are toggled on or off using True/False, as are the various requirements. You will be warned in the terminal window if the run type you have chosen, and the input parameters selected, do not match. A summary of which parameters are required for which run type will also be given below. diff --git a/evo/input/chem.yaml b/input_files/chem.yaml similarity index 99% rename from evo/input/chem.yaml rename to input_files/chem.yaml index 3b30a1a..7d09310 100644 --- a/evo/input/chem.yaml +++ b/input_files/chem.yaml @@ -78,4 +78,4 @@ P2O5: 0.51 # K2O: 0 # P2O5: 0 # NIO: 0 -# CR2O3: 0 \ No newline at end of file +# CR2O3: 0 diff --git a/evo/input/env.yaml b/input_files/env.yaml similarity index 96% rename from evo/input/env.yaml rename to input_files/env.yaml index a2afe85..16e4d38 100644 --- a/evo/input/env.yaml +++ b/input_files/env.yaml @@ -32,11 +32,11 @@ LOSS_FRAC: 0.9999 DENSITY_MODEL: spera2000 # Relate fo2 to Fe2/Fe3 ratio; pick from kc1991 (Kress & Carmicheal 1991), r2013 (Righter et al., 2013)) FO2_MODEL: kc1991 -# Rock buffer definitions, options: frost1991; +# Rock buffer definitions, options: frost1991; FMQ_MODEL: frost1991 # select solubility laws from options. Some options do not include OH-, CO3, CH4 species. -# OH system models, pick from: burguisser2015 (H2O only); +# OH system models, pick from: burguisser2015 (H2O only); H2O_MODEL: burguisser2015 # H2 model, pick from: burguisser2015 (ONLY USE TO COMPARE TO DCOMPRESS; ERROR!); gaillard2003 H2_MODEL: gaillard2003 @@ -104,4 +104,4 @@ NITROGEN_SET: False NITROGEN_START: 0.0001 GRAPHITE_SATURATED: False -GRAPHITE_START: 0.0001 \ No newline at end of file +GRAPHITE_START: 0.0001 diff --git a/evo/input/output.yaml b/input_files/output.yaml similarity index 86% rename from evo/input/output.yaml rename to input_files/output.yaml index 00f1ba0..817360f 100644 --- a/evo/input/output.yaml +++ b/input_files/output.yaml @@ -5,4 +5,4 @@ Plt_gas_species_wt: False Plt_gas_species_mol: True Plt_gas_fraction: True -Plt_fo2_dFMQ: False \ No newline at end of file +Plt_fo2_dFMQ: False diff --git a/pyproject.toml b/pyproject.toml index 3f2d7ea..50c6490 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,13 @@ requires = ['setuptools>=40.8.0'] build-backend = 'setuptools.build_meta' [tool.setuptools] -packages = ["evo"] + + [tool.setuptools.packages.find] + where = ["src"] + include = ["evo*"] + + [tool.setuptools.package-data] + "evo" = ["data/*.txt"] [project] name = "EVo" @@ -14,6 +20,7 @@ license = {file = "LICENSE"} classifiers = ["License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Programming Language :: Python :: 3"] requires-python = ">=3.9" +scripts = { evo = "evo:main" } dependencies = ["numpy>=1.21.0", "scipy>=1.7.0", diff --git a/evo/__init__.py b/src/evo/__init__.py similarity index 63% rename from evo/__init__.py rename to src/evo/__init__.py index 38af8f4..a2bfe00 100644 --- a/evo/__init__.py +++ b/src/evo/__init__.py @@ -4,4 +4,6 @@ method. """ -from .dgs import main as main +from evo.dgs import run_evo as run_evo + +__all__ = ["run_evo"] diff --git a/src/evo/__main__.py b/src/evo/__main__.py new file mode 100644 index 0000000..0b9df21 --- /dev/null +++ b/src/evo/__main__.py @@ -0,0 +1,42 @@ +import argparse + +from evo.dgs import run_evo + + +def main(argv=None): + my_parser = argparse.ArgumentParser( + prog="dgs", description="Run EVo: a thermodynamic magma degassing model" + ) + + # Add the arguments + my_parser.add_argument("chem", metavar="chem.yaml", help="the magma chemistry file") + + my_parser.add_argument( + "env", metavar="env.yaml", help="the run environment settings file" + ) + + my_parser.add_argument( + "--output-options", + help="use selected output options from output.yaml file", + ) + + my_parser.add_argument( + "-o", "--output", help="the folder location to write the results to" + ) + + # Parse in files + args = my_parser.parse_args(argv) + + f_chem = args.chem # set chemical compositions file + f_env = args.env # set environment file + + if args.output_options: + f_out = args.output_options # set output file as an optional input + run_evo(f_chem, f_env, f_out, folder=args.output) + else: + f_out = None + run_evo(f_chem, f_env, f_out, folder=args.output) + + +if __name__ == "__main__": + main() diff --git a/evo/constants.py b/src/evo/constants.py similarity index 100% rename from evo/constants.py rename to src/evo/constants.py diff --git a/evo/conversions.py b/src/evo/conversions.py similarity index 100% rename from evo/conversions.py rename to src/evo/conversions.py diff --git a/evo/Data/CH4.txt b/src/evo/data/CH4.txt similarity index 100% rename from evo/Data/CH4.txt rename to src/evo/data/CH4.txt diff --git a/evo/Data/CO.txt b/src/evo/data/CO.txt similarity index 100% rename from evo/Data/CO.txt rename to src/evo/data/CO.txt diff --git a/evo/Data/CO2.txt b/src/evo/data/CO2.txt similarity index 100% rename from evo/Data/CO2.txt rename to src/evo/data/CO2.txt diff --git a/evo/Data/H2.txt b/src/evo/data/H2.txt similarity index 100% rename from evo/Data/H2.txt rename to src/evo/data/H2.txt diff --git a/evo/Data/H2O.txt b/src/evo/data/H2O.txt similarity index 100% rename from evo/Data/H2O.txt rename to src/evo/data/H2O.txt diff --git a/evo/Data/H2S.txt b/src/evo/data/H2S.txt similarity index 100% rename from evo/Data/H2S.txt rename to src/evo/data/H2S.txt diff --git a/evo/Data/N2.txt b/src/evo/data/N2.txt similarity index 100% rename from evo/Data/N2.txt rename to src/evo/data/N2.txt diff --git a/evo/Data/O2.txt b/src/evo/data/O2.txt similarity index 100% rename from evo/Data/O2.txt rename to src/evo/data/O2.txt diff --git a/evo/Data/OCS.txt b/src/evo/data/OCS.txt similarity index 100% rename from evo/Data/OCS.txt rename to src/evo/data/OCS.txt diff --git a/evo/Data/S2.txt b/src/evo/data/S2.txt similarity index 100% rename from evo/Data/S2.txt rename to src/evo/data/S2.txt diff --git a/evo/Data/SO2.txt b/src/evo/data/SO2.txt similarity index 100% rename from evo/Data/SO2.txt rename to src/evo/data/SO2.txt diff --git a/evo/density.py b/src/evo/density.py similarity index 100% rename from evo/density.py rename to src/evo/density.py diff --git a/evo/dgs.py b/src/evo/dgs.py similarity index 84% rename from evo/dgs.py rename to src/evo/dgs.py index 2aa6c81..99ca6d6 100644 --- a/evo/dgs.py +++ b/src/evo/dgs.py @@ -57,7 +57,6 @@ # ------------------------------------------------------------------------ # python main [ ensure these are on your system ] -import argparse import time from pathlib import Path @@ -75,7 +74,7 @@ # ------------------------------------------------------------------------ -def main(f_chem, f_env, f_out, folder="outputs"): +def run_evo(f_chem, f_env, f_out, folder="outputs"): """Main function for EVo. Call to run the model. @@ -212,43 +211,3 @@ def main(f_chem, f_env, f_out, folder="outputs"): writeout_figs(sys, melt, gas, out, sys.P_track) return df - - -if __name__ == "__main__": - # ------------------------------------------------------------------- - # SYSTEM SETUP ------------------------------------------------------ - # ------------------------------------------------------------------- - - # Create the parser - my_parser = argparse.ArgumentParser( - prog="dgs", description="Run EVo: a thermodynamic magma degassing model" - ) - - # Add the arguments - my_parser.add_argument("chem", metavar="chem.yaml", help="the magma chemistry file") - - my_parser.add_argument( - "env", metavar="env.yaml", help="the run environment settings file" - ) - - my_parser.add_argument( - "--output-options", - help="use selected output options from output.yaml file", - ) - - my_parser.add_argument( - "-o", "--output", help="the folder location to write the results to" - ) - - # Parse in files - args = my_parser.parse_args() - - f_chem = args.chem # set chemical compositions file - f_env = args.env # set environment file - - if args.output_options: - f_out = args.output_options # set output file as an optional input - main(f_chem, f_env, f_out, folder=args.output) - else: - f_out = None - main(f_chem, f_env, f_out, folder=args.output) diff --git a/evo/dgs_classes.py b/src/evo/dgs_classes.py similarity index 97% rename from evo/dgs_classes.py rename to src/evo/dgs_classes.py index 5af0f10..e79c0c6 100644 --- a/evo/dgs_classes.py +++ b/src/evo/dgs_classes.py @@ -1,11 +1,11 @@ # dgs_classes import copy +import importlib.resources import inspect import itertools import re import sys -from pathlib import Path import numpy as np @@ -812,7 +812,7 @@ def get_G(self, T): Calculates the GfF for a given temperature, to use in calculations of equilibrium constants. Reads in critical data for the species - from the Data folder, linearly interpolating between temperatures. + from the 'data' folder, linearly interpolating between temperatures. Parameters ---------- @@ -825,37 +825,37 @@ def get_G(self, T): Gibbs free energy of formation """ - # Open the file for data for the molecule - file_path = Path(__file__).parent / f"Data/{self.Mol}.txt" - - path = open(file_path) # Opens the file for data for the molecule - - Temp_ref = [] # To store temperatures which need to be interpolated - del_G_ref = [] # To store values of G which need to be interpolated - inter_count = 0 - - # iterate through file to find correct values according to T provided. - for aRow in path: - values = aRow.split("\t") - if not aRow.startswith("#"): # takes out descriptive headers - if T - float(values[0]) == 0: - # can find K with values in table, no interpolation needed - # adds name of mol. and delG. of form. to the del_G dictionary - self.delG = float(values[6]) - break - elif inter_count == 1: - # adds in the upper table values for interpolation - Temp_ref.append(float(values[0])) - del_G_ref.append(float(values[6])) - break - elif T - float(values[0]) <= 99: - Temp_ref.append(float(values[0])) - del_G_ref.append(float(values[6])) - inter_count += 1 + filename = f"{self.Mol}.txt" + + data_file = importlib.resources.files("evo") / "data" / filename + + with data_file.open("r", encoding="utf-8") as path: + Temp_ref = [] # To store temperatures for interpolation + del_G_ref = [] # To store values of G for interpolation + inter_count = 0 + + # Iterate through file to find correct values according to T provided. + for aRow in path: + values = aRow.split("\t") + if not aRow.startswith("#"): # Skips descriptive headers + if T - float(values[0]) == 0: + # Exact match found, no interpolation needed + self.delG = float(values[6]) + return self.delG + elif inter_count == 1: + # Adds in the upper table values for interpolation + Temp_ref.append(float(values[0])) + del_G_ref.append(float(values[6])) + break + elif T - float(values[0]) <= 99: + Temp_ref.append(float(values[0])) + del_G_ref.append(float(values[6])) + inter_count += 1 + + # Perform interpolation if needed if len(Temp_ref) == 2: - # interpolate between 2 and returns value for Gf. self.delG = np.interp(T, Temp_ref, del_G_ref) - path.close() + return self.delG diff --git a/evo/ferric.py b/src/evo/ferric.py similarity index 100% rename from evo/ferric.py rename to src/evo/ferric.py diff --git a/evo/fixed_weights.py b/src/evo/fixed_weights.py similarity index 100% rename from evo/fixed_weights.py rename to src/evo/fixed_weights.py diff --git a/evo/init_cons.py b/src/evo/init_cons.py similarity index 100% rename from evo/init_cons.py rename to src/evo/init_cons.py diff --git a/evo/messages.py b/src/evo/messages.py similarity index 100% rename from evo/messages.py rename to src/evo/messages.py diff --git a/evo/multirun.py b/src/evo/multirun.py similarity index 96% rename from evo/multirun.py rename to src/evo/multirun.py index d872499..dcf549d 100644 --- a/evo/multirun.py +++ b/src/evo/multirun.py @@ -5,7 +5,7 @@ import numpy as np import yaml -from evo.dgs import main +from evo.dgs import run_evo def amend_env(file, **kwargs): @@ -72,7 +72,7 @@ def multirun(**kwargs): onerun = {} # Runs EVo - main("chem.yaml", "multirun.yaml", None) + run_evo("chem.yaml", "multirun.yaml", None) # Copies the dgs_output file into a separate file ready to be run again. copyfile("Output/dgs_output.csv", f"Output/output_{run_name}.csv") diff --git a/evo/readin.py b/src/evo/readin.py similarity index 100% rename from evo/readin.py rename to src/evo/readin.py diff --git a/evo/sat_pressure.py b/src/evo/sat_pressure.py similarity index 100% rename from evo/sat_pressure.py rename to src/evo/sat_pressure.py diff --git a/evo/solubility_laws.py b/src/evo/solubility_laws.py similarity index 100% rename from evo/solubility_laws.py rename to src/evo/solubility_laws.py diff --git a/evo/solver.py b/src/evo/solver.py similarity index 100% rename from evo/solver.py rename to src/evo/solver.py diff --git a/evo/solvgas.py b/src/evo/solvgas.py similarity index 100% rename from evo/solvgas.py rename to src/evo/solvgas.py diff --git a/evo/writeout.py b/src/evo/writeout.py similarity index 100% rename from evo/writeout.py rename to src/evo/writeout.py diff --git a/testing_file.py b/testing_file.py new file mode 100644 index 0000000..b6ac79d --- /dev/null +++ b/testing_file.py @@ -0,0 +1,3 @@ +import evo + +evo.main("input_files/chem.yaml", "input_files/env.yaml", None, folder="testing_things") diff --git a/tests/integration/input_files/chem.yaml b/tests/integration/input_files/chem.yaml new file mode 100644 index 0000000..7d09310 --- /dev/null +++ b/tests/integration/input_files/chem.yaml @@ -0,0 +1,81 @@ +# Dry magma major element chemistry +# Standard chemistry is provided for basalt, phonolite and rhyolite. Please comment out (using # at the start of each line) data you DO NOT want to use, +# and/or provide your own chemistry data in the empty section at the bottom of the file. + +# ---------------------- +# BASALT +# ---------------------- + +SIO2: 47.95 +TIO2: 1.67 +AL2O3: 17.32 +FEO: 10.24 +MNO: 0.17 +MGO: 5.76 +CAO: 10.93 +NA2O: 3.45 +K2O: 1.99 +P2O5: 0.51 + +# # ---------------------- +# # PHONOLITE +# # ---------------------- + +# SIO2: 56.16 +# TIO2: 0.95 +# AL2O3: 20.03 +# FEO: 5.0 +# MNO: 0.23 +# MGO: 0.87 +# CAO: 2.65 +# NA2O: 8.51 +# K2O: 4.57 +# P2O5: 0.39 + +# # ---------------------- +# # RHYOLITE +# # ---------------------- + +# SIO2: 75.65 +# TIO2: 0.26 +# AL2O3: 12.97 +# FEO: 2.15 +# MNO: 0.08 +# MGO: 0.34 +# CAO: 2.26 +# NA2O: 4.34 +# K2O: 1.94 +# P2O5: 0.0 + +# # ---------------------- +# # SHERGOTTITE +# # ---------------------- + +# SIO2: 50.0 +# TIO2: 1.3 +# AL2O3: 10.0 +# FEO: 18.5 +# MNO: 0.3 +# MGO: 8.5 +# CAO: 8.5 +# NA2O: 1.6 +# K2O: 0.3 +# P2O5: 0.6 + +# # ---------------------- +# # USER-DEFINED - PLEASE PROVIDE OXIDE VALUES FOR YOUR MELT IN WT%. ELEMENTS CAN BE REMOVED IF DATA IS MISSING +# # ---------------------- + +# SIO2: 0 +# TIO2: 0 +# AL2O3: 0 +# FEO: 0 +# FE2O3: 0 +# MNO: 0 +# MGO: 0 +# CAO: 0 +# NA2O: 0 +# K2O: 0 +# P2O5: 0 +# NIO: 0 +# CR2O3: 0 diff --git a/tests/integration/test_coh.py b/tests/integration/test_coh.py index fed2c35..f93614f 100644 --- a/tests/integration/test_coh.py +++ b/tests/integration/test_coh.py @@ -3,8 +3,8 @@ def test_coh_default(tmp_path): - df = evo.main( - "evo/input/chem.yaml", + df = evo.run_evo( + "tests/integration/input_files/chem.yaml", "tests/integration/input_files/env_coh.yaml", None, folder=tmp_path, diff --git a/tests/integration/test_cohs.py b/tests/integration/test_cohs.py index 2813129..20ed05f 100644 --- a/tests/integration/test_cohs.py +++ b/tests/integration/test_cohs.py @@ -3,8 +3,8 @@ def test_cohs_default(tmp_path): - df = evo.main( - "evo/input/chem.yaml", + df = evo.run_evo( + "tests/integration/input_files/chem.yaml", "tests/integration/input_files/env_cohs.yaml", None, folder=tmp_path, diff --git a/tests/integration/test_cohsn.py b/tests/integration/test_cohsn.py index add8d36..75e3a70 100644 --- a/tests/integration/test_cohsn.py +++ b/tests/integration/test_cohsn.py @@ -3,8 +3,8 @@ def test_cohsn_default(tmp_path): - df = evo.main( - "evo/input/chem.yaml", + df = evo.run_evo( + "tests/integration/input_files/chem.yaml", "tests/integration/input_files/env_cohsn.yaml", None, folder=tmp_path, diff --git a/tests/integration/test_oh.py b/tests/integration/test_oh.py index df2d78b..b8fae15 100644 --- a/tests/integration/test_oh.py +++ b/tests/integration/test_oh.py @@ -3,8 +3,8 @@ def test_oh_default(tmp_path): - df = evo.main( - "evo/input/chem.yaml", + df = evo.run_evo( + "tests/integration/input_files/chem.yaml", "tests/integration/input_files/env_oh.yaml", None, folder=tmp_path, diff --git a/tests/integration/test_soh.py b/tests/integration/test_soh.py index e68038b..79fbffa 100644 --- a/tests/integration/test_soh.py +++ b/tests/integration/test_soh.py @@ -3,8 +3,8 @@ def test_soh_default(tmp_path): - df = evo.main( - "evo/input/chem.yaml", + df = evo.run_evo( + "tests/integration/input_files/chem.yaml", "tests/integration/input_files/env_soh.yaml", None, folder=tmp_path,