From 77e4cefd2cc88234f1b94c25caa14f9173a9de17 Mon Sep 17 00:00:00 2001
From: titusquah <46580668+titusquah@users.noreply.github.com>
Date: Fri, 12 Jun 2020 08:34:43 -0600
Subject: [PATCH] Included package data in data/csvs and data/xmls. Note this
only works for sdists. If bdist is needed, research "manifest.in" python
setup files.
---
.idea/dictionaries/Titus.xml | 5 +
.idea/workspace.xml | 114 ++---
data/xmls/twophase.xml | 2 +-
docs/Examples/1_getting_started.ipynb | 95 +++--
reeps.py | 572 --------------------------
setup.py | 18 +-
tests/__init__.py | 0
tests/test_multi_reeps.py | 32 +-
tests/test_reeps.py | 124 +++++-
9 files changed, 259 insertions(+), 703 deletions(-)
delete mode 100644 reeps.py
delete mode 100644 tests/__init__.py
diff --git a/.idea/dictionaries/Titus.xml b/.idea/dictionaries/Titus.xml
index 618a4d8..43b55a4 100644
--- a/.idea/dictionaries/Titus.xml
+++ b/.idea/dictionaries/Titus.xml
@@ -1,6 +1,7 @@
+ cantera
coeffs
conc
csvs
@@ -12,11 +13,15 @@
ftol
kmol
lmse
+ matplotlib
maxiter
+ molality
ndarray
pred
+ quah
reeps
scipy
+ seaborn
slsqp
thermo
xmls
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index afc0287..d476773 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,10 +4,13 @@
-
-
+
+
+
+
+
@@ -18,10 +21,16 @@
+
+
+
+
+
@@ -33,12 +42,13 @@
+
-
+
-
-
+
+
@@ -50,7 +60,7 @@
-
+
@@ -59,7 +69,7 @@
-
+
@@ -67,29 +77,32 @@
-
+
-
+
-
+
-
+
+
+
+
-
-
+
+
-
+
@@ -135,11 +148,11 @@
+
+
+
-
-
-
-
+
@@ -260,9 +273,10 @@
-
-
+
+
+
@@ -272,11 +286,11 @@
-
+
-
+
@@ -285,57 +299,63 @@
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
+
-
+
+
+
+
+
-
+
-
+
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
+
-
-
+
+
diff --git a/data/xmls/twophase.xml b/data/xmls/twophase.xml
index 337bd4a..c10d135 100644
--- a/data/xmls/twophase.xml
+++ b/data/xmls/twophase.xml
@@ -50,7 +50,7 @@
298.14999999999998
- -4704699.156668724
+ -4704703.645715787
1117.965
0.0
diff --git a/docs/Examples/1_getting_started.ipynb b/docs/Examples/1_getting_started.ipynb
index f04f220..b533e52 100644
--- a/docs/Examples/1_getting_started.ipynb
+++ b/docs/Examples/1_getting_started.ipynb
@@ -37,18 +37,16 @@
"metadata": {},
"outputs": [],
"source": [
- "import sys # Navigating to reeps.py since not a package yet\n",
- "sys.path.append('../../')\n",
"from reeps import REEPS\n",
- "searcher_parameters = {'exp_csv_filename': '../../data/csvs/exp_data.csv',\n",
+ "searcher_parameters = {'exp_csv_filename': '../../data/csvs/Nd_exp_data.csv',\n",
" 'phases_xml_filename': '../../data/xmls/twophase.xml',\n",
" 'opt_dict': {'Nd(H(A)2)3(org)': {'h0': -4.7e6}},\n",
" 'phase_names': ['HCl_electrolyte', 'PC88A_liquid'],\n",
" 'aq_solvent_name': 'H2O(L)',\n",
" 'extractant_name': '(HA)2(org)',\n",
" 'diluant_name': 'dodecane',\n",
- " 'complex_name': 'Nd(H(A)2)3(org)',\n",
- " 'rare_earth_ion_name': 'Nd+++',\n",
+ " 'complex_names': ['Nd(H(A)2)3(org)'],\n",
+ " 'rare_earth_ion_names': ['Nd+++'],\n",
" 'aq_solvent_rho': 1000.0,\n",
" 'extractant_rho': 960.0,\n",
" 'diluant_rho': 750.0}\n",
@@ -74,7 +72,7 @@
"metadata": {},
"source": [
"exp_csv_filename is the file name for the csv containing experimental data.
\n",
- "Let us explore the format of this file with pandas"
+ "Let us get the pandas dataframe created by REEPS."
]
},
{
@@ -103,77 +101,77 @@
" \n",
" \n",
" | \n",
- " HI(m) | \n",
- " REeq(m) | \n",
- " D(m) | \n",
- " ZI(m) | \n",
- " Zeq | \n",
- " Heq | \n",
- " REI | \n",
+ " h_i | \n",
+ " h_eq | \n",
+ " z_i | \n",
+ " z_eq | \n",
+ " Nd_aq_i | \n",
+ " Nd_aq_eq | \n",
+ " Nd_d_eq | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 0.01 | \n",
- " 0.0239 | \n",
- " 1.0921 | \n",
+ " 0.088304 | \n",
" 1 | \n",
" 0.921696 | \n",
- " 0.088304 | \n",
" 0.050001 | \n",
+ " 0.0239 | \n",
+ " 1.0921 | \n",
"
\n",
" \n",
" 1 | \n",
" 0.01 | \n",
- " 0.0683 | \n",
- " 0.4641 | \n",
+ " 0.105094 | \n",
" 1 | \n",
" 0.904906 | \n",
- " 0.105094 | \n",
" 0.099998 | \n",
+ " 0.0683 | \n",
+ " 0.4641 | \n",
"
\n",
" \n",
" 2 | \n",
" 0.01 | \n",
- " 0.1170 | \n",
- " 0.2821 | \n",
+ " 0.109017 | \n",
" 1 | \n",
" 0.900983 | \n",
- " 0.109017 | \n",
" 0.150006 | \n",
+ " 0.1170 | \n",
+ " 0.2821 | \n",
"
\n",
" \n",
" 3 | \n",
" 0.01 | \n",
- " 0.1680 | \n",
- " 0.1905 | \n",
+ " 0.106012 | \n",
" 1 | \n",
" 0.903988 | \n",
- " 0.106012 | \n",
" 0.200004 | \n",
+ " 0.1680 | \n",
+ " 0.1905 | \n",
"
\n",
" \n",
" 4 | \n",
" 0.01 | \n",
- " 0.2637 | \n",
- " 0.1377 | \n",
+ " 0.118934 | \n",
" 1 | \n",
" 0.891066 | \n",
- " 0.118934 | \n",
" 0.300011 | \n",
+ " 0.2637 | \n",
+ " 0.1377 | \n",
"
\n",
" \n",
"\n",
""
],
"text/plain": [
- " HI(m) REeq(m) D(m) ZI(m) Zeq Heq REI\n",
- "0 0.01 0.0239 1.0921 1 0.921696 0.088304 0.050001\n",
- "1 0.01 0.0683 0.4641 1 0.904906 0.105094 0.099998\n",
- "2 0.01 0.1170 0.2821 1 0.900983 0.109017 0.150006\n",
- "3 0.01 0.1680 0.1905 1 0.903988 0.106012 0.200004\n",
- "4 0.01 0.2637 0.1377 1 0.891066 0.118934 0.300011"
+ " h_i h_eq z_i z_eq Nd_aq_i Nd_aq_eq Nd_d_eq\n",
+ "0 0.01 0.088304 1 0.921696 0.050001 0.0239 1.0921\n",
+ "1 0.01 0.105094 1 0.904906 0.099998 0.0683 0.4641\n",
+ "2 0.01 0.109017 1 0.900983 0.150006 0.1170 0.2821\n",
+ "3 0.01 0.106012 1 0.903988 0.200004 0.1680 0.1905\n",
+ "4 0.01 0.118934 1 0.891066 0.300011 0.2637 0.1377"
]
},
"execution_count": 2,
@@ -182,9 +180,7 @@
}
],
"source": [
- "import pandas as pd\n",
- "exp_df = pd.read_csv(searcher_parameters['exp_csv_filename'])\n",
- "exp_df"
+ "searcher.get_exp_df()"
]
},
{
@@ -193,22 +189,23 @@
"source": [
"The rows are for experiments, and the columns are for the measured quantaties.
\n",
"REEPS is looking for the ordering of these columns so it is important your experimental file has this ordering. Column names do not matter.
\n",
- "Below is a table explaining the meaning of the column headers"
+ "Below is a table explaining the meaning of the column headers and the needed column order.
\n",
+ "If you have more than one rare earth element, append the data to the end in the same order (aq_i, aq_eq, d_eq)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "| Column | Meaning |\n",
- "|---------|-----------------------------------------------------------------------------------------|\n",
- "| HI(m) | Initial Concentration of H+ ions (mol/L) |\n",
- "| REeq(m) | Equilibrium concentration of Rare Earth ions (mol/L) |\n",
- "| D(m) | Equilibrium Ratio between amount of rare earth elements in organic to amount in aqueous |\n",
- "| ZI(m) | Initial concentration of extractant (mol/L) |\n",
- "| Zeq | Equilibrium concentration of extractant (mol/L) |\n",
- "| Heq | Equilibrium concentration of H+ ions (mol/L) |\n",
- "| REI | Initial concentration of rare earth ions (mol/L) |"
+ "| Order | Column | Meaning |\n",
+ "|-------|------------|--------------------------------------------------------------------|\n",
+ "| 0 | h_i | Initial Concentration of H+ ions (mol/L) |\n",
+ "| 1 | h_eq | Equilibrium concentration of H+ ions (mol/L) |\n",
+ "| 2 | z_i | Initial concentration of extractant (mol/L) |\n",
+ "| 3 | z_eq | Equilibrium concentration of extractant (mol/L) |\n",
+ "| 4 | \\{RE\\}\\_aq_i | Initial concentration of RE ions (mol/L) |\n",
+ "| 5 | \\{RE\\}\\_aq_eq | Equilibrium concentration of RE ions in aqueous phase (mol/L) |\n",
+ "| 6 | \\{RE\\}\\_d_eq | Equilibrium Ratio between amount of RE atoms in organic to aqueous |"
]
},
{
@@ -238,7 +235,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "[, ]\n"
+ "[, ]\n"
]
}
],
@@ -464,7 +461,7 @@
"outputs": [
{
"data": {
- "image/png": "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\n",
+ "image/png": "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\n",
"text/plain": [
""
]
diff --git a/reeps.py b/reeps.py
deleted file mode 100644
index 16029a6..0000000
--- a/reeps.py
+++ /dev/null
@@ -1,572 +0,0 @@
-from datetime import datetime
-import cantera as ct
-import pandas as pd
-import numpy as np
-from scipy.optimize import minimize
-# noinspection PyPep8Naming
-import xml.etree.ElementTree as ET
-import seaborn as sns
-import matplotlib.pyplot as plt
-import shutil
-import copy
-from inspect import signature
-import os
-
-sns.set()
-sns.set(font_scale=1.6)
-
-class REEPS:
- """REEPS (Rare earth extraction parameter searcher)
- Takes in experimental data
- Returns parameters for GEM
- Only good for 1 rare earth and 1 extractant
- :param exp_csv_filename: (str) csv file name with experimental data
- :param phases_xml_filename: (str) xml file with parameters for equilibrium calc
- :param opt_dict: (dict) optimize info {species:{thermo_prop:guess}
- :param phase_names: (list) names of phases in xml file
- :param aq_solvent_name: (str) name of aqueous solvent in xml file
- :param extractant_name: (str) name of extractant in xml file
- :param diluant_name: (str) name of diluant in xml file
- :param complex_name: (str) name of complex in xml file
- :param rare_earth_ion_name: (str) name of rare earth ion in xml file
- :param aq_solvent_rho: (float) density of solvent (g/L)
- :param extractant_rho: (float) density of extractant (g/L)
- :param diluant_rho: (float) density of diluant (g/L)
- If no density is given, molar volume/molecular weight is used from xml
- :param objective_function: (function) function to compute objective
- By default, the objective function is log mean squared error
- of distribution ratio np.log10(re_org/re_aq)
- Function needs to take inputs:
- objective_function(predicted_dict, measured_df, **kwargs)
- **kwargs is optional
- Below is the guide for referencing predicted values
- | To access | Use |
- |------------------------------------- |--------------------------|
- | predicted rare earth eq conc in aq | predicted_dict['re_aq'] |
- | predicted rare earth eq conc in org | predicted_dict['re_org'] |
- | predicted hydrogen ion conc in aq | predicted_dict['h'] |
- | predicted extractant conc in org | predicted_dict['z'] |
- | predicted rare earth distribution ratio | predicted_dict['re_d'] |
- For measured values, use the column names in the experimental data file
- :param optimizer: (function) function to perform optimization
- By default, the optimizer is scipy's optimize function with
- default_kwargs= {"method": 'SLSQP',
- "bounds": [(1e-1, 1e1)*len(x_guess)],
- "constraints": (),
- "options": {'disp': True, 'maxiter': 1000, 'ftol': 1e-6}}
- Function needs to take inputs:
- optimizer(objective_function, x_guess, **kwargs)
- **kwargs is optional
- :param temp_xml_file_path: (str) path to temporary xml file
- default is local temp folder
- """
-
- def __init__(self,
- exp_csv_filename,
- phases_xml_filename,
- opt_dict,
- phase_names,
- aq_solvent_name,
- extractant_name,
- diluant_name,
- complex_name,
- rare_earth_ion_name,
- aq_solvent_rho=None,
- extractant_rho=None,
- diluant_rho=None,
- objective_function='Log-MSE',
- optimizer='SLSQP',
- temp_xml_file_path=None
- ):
- self._built_in_obj_list = ['Log-MSE']
- self._built_in_opt_list = ['SLSQP']
- self._exp_csv_filename = exp_csv_filename
- self._phases_xml_filename = phases_xml_filename
- self._opt_dict = opt_dict
- self._phase_names = phase_names
- self._aq_solvent_name = aq_solvent_name
- self._extractant_name = extractant_name
- self._diluant_name = diluant_name
- self._complex_name = complex_name
- self._rare_earth_ion_name = rare_earth_ion_name
- self._aq_solvent_rho = aq_solvent_rho
- self._extractant_rho = extractant_rho
- self._diluant_rho = diluant_rho
- self._objective_function = None
- self.set_objective_function(objective_function)
- self._optimizer = None
- self.set_optimizer(optimizer)
- if temp_xml_file_path is None:
- temp_xml_file_path = '{0}\\temp.xml'.format(os.getenv('TEMP'))
- self._temp_xml_file_path = temp_xml_file_path
- shutil.copyfile(phases_xml_filename, self._temp_xml_file_path)
- self._phases = ct.import_phases(phases_xml_filename, phase_names)
- self._exp_df = pd.read_csv(self._exp_csv_filename)
-
- self._in_moles = None
-
- self._aq_ind = None
- self._org_ind = None
-
- self.set_in_moles(feed_vol=1)
- self._predicted_dict = None
- self.update_predicted_dict()
-
- @staticmethod
- def log_mean_squared_error(predicted_dict, meas_df):
- meas = meas_df.values[:, 2]
- pred = predicted_dict['re_org'] / predicted_dict['re_aq']
- log_pred = np.log10(pred)
- log_meas = np.log10(meas)
- obj = np.sum((log_pred - log_meas) ** 2)
- return obj
-
- @staticmethod
- def slsqp_optimizer(objective, x_guess):
- optimizer_kwargs = {"method": 'SLSQP',
- "bounds": [(1e-1, 1e1)] * len(x_guess),
- "constraints": (),
- "options": {'disp': True, 'maxiter': 1000, 'ftol': 1e-6}}
- res = minimize(objective, x_guess, **optimizer_kwargs)
- est_parameters = res.x
- return est_parameters
-
- def get_exp_csv_filename(self) -> str:
- return self._exp_csv_filename
-
- def set_exp_csv_filename(self, exp_csv_filename):
- self._exp_csv_filename = exp_csv_filename
- self._exp_df = pd.read_csv(self._exp_csv_filename)
- self.update_predicted_dict()
- return None
-
- def get_phases(self) -> list:
- return self._phases
-
- def set_phases(self, phases_xml_filename, phase_names):
- """Change xml and phase names
- Also runs set_in_mole to set initial moles to 1 g/L"""
- self._phases_xml_filename = phases_xml_filename
- self._phase_names = phase_names
- shutil.copyfile(phases_xml_filename, self._temp_xml_file_path)
- self._phases = ct.import_phases(phases_xml_filename, phase_names)
- self.set_in_moles(feed_vol=1)
- self.update_predicted_dict()
- return None
-
- def get_opt_dict(self) -> dict:
- return self._opt_dict
-
- def set_opt_dict(self, opt_dict):
- self._opt_dict = opt_dict
- return None
-
- def get_aq_solvent_name(self) -> str:
- return self._aq_solvent_name
-
- def set_aq_solvent_name(self, aq_solvent_name):
- self._aq_solvent_name = aq_solvent_name
- return None
-
- def get_extractant_name(self) -> str:
- return self._extractant_name
-
- def set_extractant_name(self, extractant_name):
- self._extractant_name = extractant_name
- return None
-
- def get_diluant_name(self) -> str:
- return self._diluant_name
-
- def set_diluant_name(self, diluant_name):
- self._diluant_name = diluant_name
- return None
-
- def get_complex_name(self) -> str:
- return self._complex_name
-
- def set_complex_name(self, complex_name):
- self._complex_name = complex_name
- return None
-
- def get_rare_earth_ion_name(self) -> str:
- return self._rare_earth_ion_name
-
- def set_rare_earth_ion_name(self, rare_earth_ion_name):
- self._rare_earth_ion_name = rare_earth_ion_name
- return None
-
- def get_aq_solvent_rho(self) -> str:
- return self._aq_solvent_rho
-
- def set_aq_solvent_rho(self, aq_solvent_rho):
- self._aq_solvent_rho = aq_solvent_rho
- return None
-
- def get_extractant_rho(self) -> str:
- return self._extractant_rho
-
- def set_extractant_rho(self, extractant_rho):
- self._extractant_rho = extractant_rho
- return None
-
- def get_diluant_rho(self) -> str:
- return self._diluant_rho
-
- def set_diluant_rho(self, diluant_rho):
- self._diluant_rho = diluant_rho
- return None
-
- def set_in_moles(self, feed_vol):
- """Function that initializes mole fractions
- :param feed_vol: (float) feed volume of mixture (g/L)"""
- phases_copy = self._phases.copy()
- exp_df = self._exp_df.copy()
- solvent_name = self._aq_solvent_name
- extractant_name = self._extractant_name
- diluant_name = self._diluant_name
- solvent_rho = self._aq_solvent_rho
- extractant_rho = self._extractant_rho
- diluant_rho = self._diluant_rho
- re_name = self._rare_earth_ion_name
-
- mixed = ct.Mixture(phases_copy)
- aq_ind = None
- solvent_ind = None
- for ind, phase in enumerate(phases_copy):
- if solvent_name in phase.species_names:
- aq_ind = ind
- solvent_ind = phase.species_names.index(solvent_name)
- if aq_ind is None:
- raise Exception('Solvent "{0}" not found \
- in xml file'.format(solvent_name))
-
- if aq_ind == 0:
- org_ind = 1
- else:
- org_ind = 0
- self._aq_ind = aq_ind
- self._org_ind = org_ind
- extractant_ind = phases_copy[org_ind].species_names.index(
- extractant_name)
- diluant_ind = phases_copy[org_ind].species_names.index(diluant_name)
-
- re_ind = phases_copy[aq_ind].species_names.index(re_name)
- re_charge = phases_copy[aq_ind].species(re_ind).charge
-
- mix_aq = mixed.phase(aq_ind)
- mix_org = mixed.phase(org_ind)
- solvent_mw = mix_aq.molecular_weights[solvent_ind] # g/mol
- extractant_mw = mix_org.molecular_weights[extractant_ind]
- diluant_mw = mix_org.molecular_weights[diluant_ind]
- if solvent_rho is None:
- solvent_rho = mix_aq(aq_ind).partial_molar_volumes[
- solvent_ind] / solvent_mw * 1e6 # g/L
- self._aq_solvent_rho = solvent_rho
- if extractant_rho is None:
- extractant_rho = mix_org(org_ind).partial_molar_volumes[
- extractant_ind] / extractant_mw * 1e6
- self._extractant_rho = extractant_rho
- if diluant_rho is None:
- diluant_rho = mix_org(org_ind).partial_molar_volumes[
- extractant_ind] / extractant_mw * 1e6
- self._diluant_rho = diluant_rho
-
- in_moles_data = []
- aq_phase_solvent_moles = feed_vol * solvent_rho / solvent_mw
- for row in exp_df.values:
- h_plus_moles = feed_vol * row[0]
- hydroxide_ions = 0
- rare_earth_moles = feed_vol * row[6]
- chlorine_moles = re_charge * rare_earth_moles + h_plus_moles
- extractant_moles = feed_vol * row[3]
- extractant_vol = extractant_moles * extractant_mw / extractant_rho
- diluant_vol = feed_vol - extractant_vol
- diluant_moles = diluant_vol * diluant_rho / diluant_mw
- complex_moles = 0
-
- species_moles = [aq_phase_solvent_moles,
- h_plus_moles,
- hydroxide_ions,
- chlorine_moles,
- rare_earth_moles,
- extractant_moles,
- diluant_moles,
- complex_moles,
- ]
- in_moles_data.append(species_moles)
- self._in_moles = pd.DataFrame(in_moles_data, columns=mixed.species_names)
- self.update_predicted_dict()
- return None
-
- def get_in_moles(self) -> pd.DataFrame:
- return self._in_moles
-
- def set_objective_function(self, objective_function):
- """Set objective function. see class docstring for instructions"""
- if not callable(objective_function) \
- and objective_function not in self._built_in_obj_list:
- raise Exception(
- "objective_function must be a function "
- "or in this strings list: {0}".format(self._built_in_obj_list))
- if callable(objective_function):
- if len(signature(objective_function).parameters) < 2:
- raise Exception(
- "objective_function must be a function "
- "with at least 3 arguments:"
- " f(predicted_dict, experimental_df,**kwargs)")
- if objective_function == 'Log-MSE':
- objective_function = self.log_mean_squared_error
- self._objective_function = objective_function
- return None
-
- def get_objective_function(self):
- return self._objective_function
-
- def set_optimizer(self, optimizer):
- if not callable(optimizer) \
- and optimizer not in self._built_in_opt_list:
- raise Exception(
- "optimizer must be a function "
- "or in this strings list: {0}".format(self._built_in_opt_list))
- if callable(optimizer):
- if len(signature(optimizer).parameters) < 2:
- raise Exception(
- "optimizer must be a function "
- "with at least 2 arguments: "
- "f(objective_func,x_guess,**kwargs)")
- if optimizer == 'SLSQP':
- optimizer = self.slsqp_optimizer
- self._optimizer = optimizer
- return None
-
- def get_optimizer(self):
- return self._optimizer
-
- def update_predicted_dict(self, phases_xml_filename=None):
- if phases_xml_filename is None:
- phases_xml_filename = self._phases_xml_filename
- phase_names = self._phase_names
- aq_ind = self._aq_ind
- org_ind = self._org_ind
- complex_name = self._complex_name
- extractant_name = self._extractant_name
- rare_earth_ion_name = self._rare_earth_ion_name
- in_moles = self._in_moles
-
- phases_copy = ct.import_phases(phases_xml_filename, phase_names)
- mix = ct.Mixture(phases_copy)
- predicted_dict = {"re_aq": [],
- "re_org": [],
- "h": [],
- "z": []
- }
-
- for row in in_moles.values:
- mix.species_moles = row
- mix.equilibrate('TP', log_level=0)
- re_org = mix.species_moles[mix.species_index(
- org_ind, complex_name)]
- re_aq = mix.species_moles[mix.species_index(
- aq_ind, rare_earth_ion_name)]
- hydrogen_ions = mix.species_moles[mix.species_index(aq_ind, 'H+')]
- extractant = mix.species_moles[mix.species_index(
- org_ind, extractant_name)]
- predicted_dict['re_aq'].append(re_aq)
- predicted_dict['re_org'].append(re_org)
- predicted_dict['h'].append(hydrogen_ions)
- predicted_dict['z'].append(extractant)
- predicted_dict['re_aq'] = np.array(predicted_dict['re_aq'])
- predicted_dict['re_org'] = np.array(predicted_dict['re_org'])
- predicted_dict['h'] = np.array(predicted_dict['h'])
- predicted_dict['z'] = np.array(predicted_dict['z'])
-
- self._predicted_dict = predicted_dict
- return None
-
- def get_predicted_dict(self):
- return self._predicted_dict
-
- def _internal_objective(self, x, kwargs=None):
- """default Log mean squared error between measured and predicted data
- :param x: (list) thermo properties varied to minimize LMSE
- :param kwargs: (list) arguments for objective_function
- """
- temp_xml_file_path = self._temp_xml_file_path
- exp_df = self._exp_df
- objective_function = self._objective_function
- opt_dict = copy.deepcopy(self._opt_dict)
- i = 0
- for species_name in opt_dict.keys():
- for _ in opt_dict[species_name].keys():
- i += 1
- x = np.array(x)
-
- if len(x.shape) == 1:
- xs = np.array([x])
- vectorized_x = False
- else:
- vectorized_x = True
- xs = x
- objective_values = []
- for x in xs:
- i = 0
- for species_name in opt_dict.keys():
- for thermo_prop in opt_dict[species_name].keys():
- opt_dict[species_name][thermo_prop] *= x[i]
- i += 1
- self.update_xml(opt_dict, temp_xml_file_path)
-
- self.update_predicted_dict(temp_xml_file_path)
- predicted_dict = self.get_predicted_dict()
-
- if kwargs is None:
- # noinspection PyCallingNonCallable
- obj = objective_function(predicted_dict, exp_df)
- else:
- # noinspection PyCallingNonCallable
- obj = objective_function(predicted_dict, exp_df, **kwargs)
- objective_values.append(obj)
- if vectorized_x:
- objective_values = np.array(objective_values)
- else:
- objective_values = objective_values[0]
- return objective_values
-
- def fit(self, objective_function=None, optimizer=None, objective_kwargs=None, optimizer_kwargs=None) -> dict:
- """Fits experimental to modeled data by minimizing objective function
- Returns estimated complex enthalpy in J/mol
- :param objective_function: (function) function to compute objective
- :param optimizer: (function) function to perform optimization
- :param optimizer_kwargs: (dict) arguments for optimizer
- :param objective_kwargs: (dict) arguments for objective function
- """
- if objective_function is not None:
- self.set_objective_function(objective_function)
- if optimizer is not None:
- self.set_optimizer(optimizer)
-
- def objective(x):
- return self._internal_objective(x, objective_kwargs)
-
- optimizer = self._optimizer
- opt_dict = copy.deepcopy(self._opt_dict)
- i = 0
- for species_name in opt_dict.keys():
- for _ in opt_dict[species_name].keys():
- i += 1
- x_guess = np.ones(i)
-
- if optimizer_kwargs is None:
- # noinspection PyCallingNonCallable
- est_parameters = optimizer(objective, x_guess)
- else:
- # noinspection PyCallingNonCallable
- est_parameters = optimizer(objective, x_guess, **optimizer_kwargs)
-
- i = 0
- for species_name in opt_dict.keys():
- for thermo_prop in opt_dict[species_name].keys():
- opt_dict[species_name][thermo_prop] *= est_parameters[i]
- i += 1
- self.update_predicted_dict()
- return opt_dict
-
- def update_xml(self,
- info_dict,
- phases_xml_filename=None):
- """updates xml file with info_dict
- :param info_dict: (dict) info in {species_names:{thermo_prop:val}}
- :param phases_xml_filename: (str) xml filename if editing other xml
- """
- if phases_xml_filename is None:
- phases_xml_filename = self._phases_xml_filename
-
- tree = ET.parse(phases_xml_filename)
- root = tree.getroot()
- # Update xml file
- for species_name in info_dict.keys():
- for thermo_prop in info_dict[species_name].keys():
- for species in root.iter('species'):
- if species.attrib['name'] == species_name:
- for changed_prop in species.iter(thermo_prop):
- changed_prop.text = str(
- info_dict[species_name][thermo_prop])
- now = datetime.now()
- changed_prop.set('updated',
- 'Updated at {0}:{1} {2}-{3}-{4}'
- .format(now.hour, now.minute,
- now.month, now.day,
- now.year))
-
- tree.write(phases_xml_filename)
- if phases_xml_filename == self._phases_xml_filename:
- self.set_phases(self._phases_xml_filename, self._phase_names)
- return None
-
- # noinspection PyUnusedLocal
- def parity_plot(self, species='re_aq', save_path=None, print_r_squared=False):
- """Parity plot between measured and predicted rare earth composition"""
- phases_copy = self._phases.copy()
- mix = ct.Mixture(phases_copy)
- aq_ind = self._aq_ind
- exp_df = self._exp_df
- in_moles = self._in_moles
- rare_earth_ion_name = self._rare_earth_ion_name
- pred = []
- for row in in_moles.values:
- mix.species_moles = row
- mix.equilibrate('TP', log_level=0)
- re_aq = mix.species_moles[mix.species_index(
- aq_ind, rare_earth_ion_name)]
- pred.append(re_aq)
- pred = np.array(pred)
- meas = exp_df.values[:, 1]
- min_data = np.min([pred, meas])
- max_data = np.max([pred, meas])
- min_max_data = np.array([min_data, max_data])
- fig, ax = plt.subplots()
- re_element = ''
- n_plus = 0
- for char in self._rare_earth_ion_name:
- if char.isalpha():
- re_element = '{0}{1}'.format(re_element, char)
- else:
- n_plus += 1
- re_ion_name = '$%s^{%d+}$' % (re_element, n_plus)
- p1 = sns.scatterplot(meas, pred, color="r",
- label="{0} eq. conc. (mol/L)".format(re_ion_name),
- legend=False)
- p2 = sns.lineplot(min_max_data, min_max_data, color="b", label="")
- if print_r_squared:
- p1.text(min_max_data[0], min_max_data[1]*0.9, '$R^2$={0:.2f}'.format(self.r_squared()))
- plt.legend(loc='lower right')
- else:
- plt.legend()
- ax.set(xlabel='Measured', ylabel='Predicted')
- plt.show()
- if save_path is not None:
- plt.savefig(save_path, bbox_inches='tight')
- return None
-
- def r_squared(self):
- """r-squared value comparing measured and predicted rare earth composition"""
- phases_copy = self._phases.copy()
- mix = ct.Mixture(phases_copy)
- aq_ind = self._aq_ind
- exp_df = self._exp_df
- in_moles = self._in_moles
- rare_earth_ion_name = self._rare_earth_ion_name
- pred = []
- for row in in_moles.values:
- mix.species_moles = row
- mix.equilibrate('TP', log_level=0)
- re_aq = mix.species_moles[mix.species_index(
- aq_ind, rare_earth_ion_name)]
- pred.append(re_aq)
- predicted_y = np.array(pred)
- actual_y = exp_df.values[:, 1]
- num = sum((actual_y - predicted_y) ** 2)
- den = sum((actual_y - np.mean(actual_y)) ** 2)
- r_2 = (1 - num / den)
- return r_2
diff --git a/setup.py b/setup.py
index a6b5090..4de9d9d 100644
--- a/setup.py
+++ b/setup.py
@@ -2,11 +2,23 @@ from setuptools import setup
setup(
name='reeps',
- version='1.0.0',
- packages=['tests'],
+ version='0.0.0',
+ packages=['reeps'],
+ package_data={
+ 'csvs': ['data/csvs/*.csv'],
+ 'xmls': ['data/xmls/*.xml']
+ },
+ include_package_data=True,
+ zip_safe=False,
url='',
license='',
author='Titus Quah',
author_email='',
- description='Rare earth element parameter searcher'
+ description='Rare earth element parameter searcher',
+ install_requires=['cantera==2.4.0',
+ 'pandas==1.0.3',
+ 'numpy==1.15.4',
+ 'scipy==1.4.1',
+ 'seaborn==0.10.1',
+ 'matplotlib==3.1.3']
)
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/test_multi_reeps.py b/tests/test_multi_reeps.py
index 88765ac..e84c7d4 100644
--- a/tests/test_multi_reeps.py
+++ b/tests/test_multi_reeps.py
@@ -1,33 +1,15 @@
import json
import numpy as np
-import pyswarms as ps
import sys
sys.path.append('../')
-from reeps import REEPS1
+from reeps import REEPS
with open('multi_ree_settings.txt') as file:
testing_params = json.load(file)
-beaker = REEPS1(**testing_params)
-
-
-# def new_obj(predicted_dict, meas_df, epsilon):
-# meas_cols = list(meas_df)
-# pred_keys = list(predicted_dict.keys())
-# meas = meas_df[meas_cols[2]]
-# pred = (predicted_dict['re_org'] + epsilon) / (predicted_dict['re_aq'] + epsilon)
-# log_pred = np.log10(pred)
-# log_meas = np.log10(meas)
-# obj = np.sum((log_pred - log_meas) ** 2)
-# return obj
-# #
-# #
-# # def new_obj(ping):
-# # print(ping)
-# beaker.set_objective_function(new_obj)
-# objective_kwargs = {"epsilon": 1e-14}
-# beaker.set
-# noinspection PyUnusedLocal
+beaker = REEPS(**testing_params)
+
+
def optimizer(func, x_guess):
lb = np.array([1e-1])
ub = np.array([1e1])
@@ -48,6 +30,6 @@ minimizer_kwargs = {"method": 'SLSQP',
est_enthalpy = beaker.fit()
print(est_enthalpy)
-# beaker.update_xml(est_enthalpy)
-# beaker.parity_plot()
-# print(beaker.r_squared())
+beaker.update_xml(est_enthalpy)
+# beaker.parity_plot('Nd_d_eq', print_r_squared=True)
+print(beaker.r_squared())
diff --git a/tests/test_reeps.py b/tests/test_reeps.py
index da361cd..93ae2c0 100644
--- a/tests/test_reeps.py
+++ b/tests/test_reeps.py
@@ -1,14 +1,14 @@
import json
+from unittest import TestCase
+
import numpy as np
import pyswarms as ps
-import sys
-sys.path.append('../')
-from reeps import REEPS
+from reeps import REEPS1
with open('one_ree_settings.txt') as file:
testing_params = json.load(file)
-beaker = REEPS(**testing_params)
+beaker = REEPS1(**testing_params)
# def new_obj(predicted_dict, meas_df, epsilon):
@@ -48,6 +48,118 @@ minimizer_kwargs = {"method": 'SLSQP',
est_enthalpy = beaker.fit()
print(est_enthalpy)
-# beaker.update_xml(est_enthalpy)
+
+beaker.update_xml(est_enthalpy)
# beaker.parity_plot()
-# print(beaker.r_squared())
+print(beaker.r_squared())
+# class TestREEPS1(TestCase):
+# def test_slsqp_optimizer(self):
+# self.fail()
+#
+# def test_log_mean_squared_error(self):
+# self.fail()
+#
+# def test_get_exp_df(self):
+# self.fail()
+#
+# def test_set_exp_df(self):
+# self.fail()
+#
+# def test_get_phases(self):
+# self.fail()
+#
+# def test_set_phases(self):
+# self.fail()
+#
+# def test_get_opt_dict(self):
+# self.fail()
+#
+# def test_set_opt_dict(self):
+# self.fail()
+#
+# def test_get_aq_solvent_name(self):
+# self.fail()
+#
+# def test_set_aq_solvent_name(self):
+# self.fail()
+#
+# def test_get_extractant_name(self):
+# self.fail()
+#
+# def test_set_extractant_name(self):
+# self.fail()
+#
+# def test_get_diluant_name(self):
+# self.fail()
+#
+# def test_set_diluant_name(self):
+# self.fail()
+#
+# def test_get_complex_names(self):
+# self.fail()
+#
+# def test_set_complex_names(self):
+# self.fail()
+#
+# def test_get_rare_earth_ion_names(self):
+# self.fail()
+#
+# def test_set_rare_earth_ion_names(self):
+# self.fail()
+#
+# def test_get_aq_solvent_rho(self):
+# self.fail()
+#
+# def test_set_aq_solvent_rho(self):
+# self.fail()
+#
+# def test_get_extractant_rho(self):
+# self.fail()
+#
+# def test_set_extractant_rho(self):
+# self.fail()
+#
+# def test_get_diluant_rho(self):
+# self.fail()
+#
+# def test_set_diluant_rho(self):
+# self.fail()
+#
+# def test_set_in_moles(self):
+# self.fail()
+#
+# def test_get_in_moles(self):
+# self.fail()
+#
+# def test_set_objective_function(self):
+# self.fail()
+#
+# def test_get_objective_function(self):
+# self.fail()
+#
+# def test_set_optimizer(self):
+# self.fail()
+#
+# def test_get_optimizer(self):
+# self.fail()
+#
+# def test_update_predicted_dict(self):
+# self.fail()
+#
+# def test_get_predicted_dict(self):
+# self.fail()
+#
+# def test__internal_objective(self):
+# self.fail()
+#
+# def test_fit(self):
+# self.fail()
+#
+# def test_update_xml(self):
+# self.fail()
+#
+# def test_parity_plot(self):
+# self.fail()
+#
+# def test_r_squared(self):
+# self.fail()