\n"
+ ],
+ "text/plain": [
+ "\u001b[1;32mDownloaded \u001b[0m\n",
+ "\u001b[1;4;32mhttps://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/experimental_data_references.json\u001b[0m\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
"source": [
- "db=core.Database(configs.Database(adm_parameters_urls=configs.E_ADM_2_REMOTE,adm_parameters=configs.E_ADM_2_LOCAL)) #To make sure the parameters are up to date\n",
- "db.download_adm_parameters(verbose=False)\n",
- "db.download_feed_database()\n",
- "db.download_studies_database()"
+ "db = core.Database(\n",
+ " configs.Database(\n",
+ " feed_db=EXAMPLES_DIR / \"feed_db.tsv\",\n",
+ " studies_local={\n",
+ " \"metagenomics_studies\": EXAMPLES_DIR / \"Studies\" / \"metagenomics_studies.tsv\",\n",
+ " \"experimental_data_db\": EXAMPLES_DIR / \"Studies\" / \"experimental_data_references.json\",\n",
+ " },\n",
+ " )\n",
+ ")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "As an example, we want to compare gas production between three microbiomes explored in Ding et al. The data for this study is added to the database before (see Parameter Tuning notebook). First lets load the model parameters.The address to the parameter files are in E_ADM_2_LOCAL variable in the configs module and they are in json format. You can either load the files one by one or use a helper function like below:"
+ "As an example, we compare gas production between three microbiomes explored in Ding et al. The model requirements are loaded from the consolidated `reference_data/models.json` file."
]
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
- "params=utils.load_multiple_json_files(configs.E_ADM_2_LOCAL)"
+ "params = SimpleNamespace(**utils.load_model_json(MODEL_DB, \"e_adm\"))\n"
]
},
{
@@ -320,7 +560,7 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
@@ -336,7 +576,7 @@
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
@@ -347,7 +587,7 @@
},
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
@@ -365,7 +605,7 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
@@ -377,7 +617,7 @@
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
@@ -392,8 +632,8 @@
" inlet_conditions=params.inlet_conditions,\n",
" species=params.species,\n",
" reactions=params.reactions,\n",
- " build_stoichiometric_matrix=adm.build_e_adm_2_stoichiometric_matrix,\n",
- " ode_system=adm.e_adm_2_ode_sys,\n",
+ " build_stoichiometric_matrix=adm.build_e_adm_stoichiometric_matrix,\n",
+ " ode_system=adm.e_adm_ode_sys,\n",
" feed=feed,\n",
" control_state={'S_H_ion':10**(-6.5)},\n",
" )\n",
@@ -418,7 +658,7 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": null,
"metadata": {},
"outputs": [
{
@@ -437,7 +677,7 @@
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -453,7 +693,7 @@
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -462,7 +702,7 @@
},
{
"cell_type": "code",
- "execution_count": 16,
+ "execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -471,7 +711,7 @@
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": null,
"metadata": {},
"outputs": [
{
@@ -551,7 +791,7 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -562,7 +802,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "ADTInstall",
+ "display_name": "adtoolbox",
"language": "python",
"name": "python3"
},
@@ -576,7 +816,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.10.6"
+ "version": "3.14.0"
}
},
"nbformat": 4,
diff --git a/Examples/parameter_tuning.ipynb b/Examples/parameter_tuning.ipynb
index f854cad..5cc2fa2 100644
--- a/Examples/parameter_tuning.ipynb
+++ b/Examples/parameter_tuning.ipynb
@@ -48,14 +48,24 @@
"metadata": {},
"outputs": [],
"source": [
- "from adtoolbox import core,configs\n",
+ "from pathlib import Path\n",
+ "from types import SimpleNamespace\n",
+ "from adtoolbox import core, configs, utils\n",
"import pandas as pd\n",
"import numpy as np\n",
"from sklearn import manifold\n",
"import scipy.spatial.distance as distance\n",
"from scipy.stats import spearmanr\n",
"from threading import Thread\n",
- "import plotly.express as px"
+ "import plotly.express as px\n",
+ "\n",
+ "NOTEBOOK_DIR = Path.cwd()\n",
+ "REPO_DIR = NOTEBOOK_DIR.parent if NOTEBOOK_DIR.name == \"Examples\" else NOTEBOOK_DIR\n",
+ "EXAMPLES_DIR = REPO_DIR / \"Examples\"\n",
+ "MODEL_DB = REPO_DIR / \"reference_data\" / \"models.json\"\n",
+ "DATABASE_DIR = Path(\"/Users/parsaghadermarzi/Desktop/Academics/Projects/Database/ADToolbox\")\n",
+ "if not DATABASE_DIR.exists():\n",
+ " DATABASE_DIR = REPO_DIR / \"reference_data\"\n"
]
},
{
@@ -89,7 +99,16 @@
"metadata": {},
"outputs": [],
"source": [
- "db=core.Database(config=configs.Database())"
+ "db = core.Database(\n",
+ " config=configs.Database(\n",
+ " database_dir=DATABASE_DIR,\n",
+ " feed_db=EXAMPLES_DIR / \"feed_db.tsv\",\n",
+ " studies_local={\n",
+ " \"metagenomics_studies\": EXAMPLES_DIR / \"Studies\" / \"metagenomics_studies.tsv\",\n",
+ " \"experimental_data_db\": EXAMPLES_DIR / \"Studies\" / \"experimental_data_references.json\",\n",
+ " },\n",
+ " )\n",
+ ")\n"
]
},
{
@@ -144,7 +163,7 @@
"metadata": {},
"outputs": [],
"source": [
- "seed_db=core.SeedDB(configs.Database())"
+ "seed_db = core.SeedDB(configs.Database(database_dir=DATABASE_DIR))"
]
},
{
@@ -484,17 +503,8 @@
"metadata": {},
"outputs": [],
"source": [
- "from adtoolbox import utils\n",
- "local_params=dict(\n",
- " model_parameters=\"./Database/ADM_Parameters/Modified_ADM_Model_Parameters.json\",\n",
- " base_parameters=\"./Database/ADM_Parameters/Modified_ADM_Base_Parameters.json\",\n",
- " initial_conditions=\"./Database/ADM_Parameters/Modified_ADM_Initial_Conditions.json\",\n",
- " inlet_conditions=\"./Database/ADM_Parameters/Modified_ADM_Inlet_Conditions.json\",\n",
- " species=\"./Database/ADM_Parameters/Modified_ADM_Species.json\",\n",
- " reactions=\"./Database/ADM_Parameters/Modified_ADM_Reactions.json\",\n",
- ")\n",
- "params=utils.load_multiple_json_files(local_params) #just a helper function to load multiple json files.\n",
- "initial_conditions=params.initial_conditions"
+ "params = SimpleNamespace(**utils.load_model_json(MODEL_DB, \"e_adm\"))\n",
+ "initial_conditions = params.initial_conditions\n"
]
},
{
@@ -799,7 +809,7 @@
"metadata": {},
"outputs": [],
"source": [
- "cellulose=SeedDB(config=configs.Database()).instantiate_metabs(\"cpd11746\")"
+ "cellulose = SeedDB(config=configs.Database(database_dir=DATABASE_DIR)).instantiate_metabs(\"cpd11746\")"
]
},
{
@@ -1317,28 +1327,23 @@
"metadata": {},
"outputs": [],
"source": [
- "local_params=dict(\n",
- " model_parameters=\"./Database/ADM_Parameters/Modified_ADM_Model_Parameters.json\",\n",
- " base_parameters=\"./Database/ADM_Parameters/Modified_ADM_Base_Parameters.json\",\n",
- " initial_conditions=\"./Database/ADM_Parameters/Modified_ADM_Initial_Conditions.json\",\n",
- " inlet_conditions=\"./Database/ADM_Parameters/Modified_ADM_Inlet_Conditions.json\",\n",
- " species=\"./Database/ADM_Parameters/Modified_ADM_Species.json\",\n",
- " reactions=\"./Database/ADM_Parameters/Modified_ADM_Reactions.json\",\n",
+ "params = SimpleNamespace(**utils.load_model_json(MODEL_DB, \"e_adm\"))\n",
+ "\n",
+ "base_model = adm.Model(\n",
+ " model_parameters=params.model_parameters,\n",
+ " base_parameters=params.base_parameters,\n",
+ " initial_conditions=params.initial_conditions,\n",
+ " inlet_conditions=params.inlet_conditions,\n",
+ " species=params.species,\n",
+ " reactions=params.reactions,\n",
+ " feed=feed,\n",
+ " build_stoichiometric_matrix=adm.build_e_adm_stoichiometric_matrix,\n",
+ " ode_system=adm.e_adm_ode_sys,\n",
+ " control_state={\"S_H_ion\": 10 ** (-6.5)},\n",
+ " simulation_time=30,\n",
")\n",
- "params=utils.load_multiple_json_files(local_params)\n",
"\n",
- "base_model=adm.Model(model_parameters=params.model_parameters,\n",
- " base_parameters=params.base_parameters,\n",
- " initial_conditions=params.initial_conditions,\n",
- " inlet_conditions=params.inlet_conditions,\n",
- " species=params.species,\n",
- " reactions=params.reactions,\n",
- " feed=feed,\n",
- " build_stoichiometric_matrix=adm.build_e_adm_2_stoichiometric_matrix,\n",
- " ode_system=adm.e_adm_2_ode_sys,\n",
- " simulation_time=30) \n",
- " \n",
- "base_model.update_parameters(base_parameters={\"q_in\":0,\"V_liq\":0.0001,\"V_gas\":0.00007},model_parameters={\"k_p\":0})"
+ "base_model.update_parameters(base_parameters={\"q_in\": 0, \"V_liq\": 0.0001, \"V_gas\": 0.00007}, model_parameters={\"k_p\": 0})\n"
]
},
{
@@ -3666,8 +3671,7 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
- },
- "orig_nbformat": 4
+ }
},
"nbformat": 4,
"nbformat_minor": 2
diff --git a/Examples/pipeline.ipynb b/Examples/pipeline.ipynb
index c34900f..dcd10e8 100644
--- a/Examples/pipeline.ipynb
+++ b/Examples/pipeline.ipynb
@@ -145,17 +145,23 @@
"source": [
"import os\n",
"import pathlib\n",
- "from adtoolbox import core,configs,utils\n",
+ "from adtoolbox import core, configs, utils\n",
"import pandas as pd\n",
- "db=core.Database(config=configs.Database())\n",
+ "\n",
+ "WORK_DIR = pathlib.Path.cwd() / \"adtoolbox_pipeline_work\"\n",
+ "DATABASE_DIR = pathlib.Path(\"/Users/parsaghadermarzi/Desktop/Academics/Projects/Database/ADToolbox\")\n",
+ "if not DATABASE_DIR.exists():\n",
+ " DATABASE_DIR = WORK_DIR / \"database\"\n",
+ "\n",
+ "db = core.Database(config=configs.Database(database_dir=DATABASE_DIR))\n",
"#db.download_qiime_classifier_db() # downloads the qiime classifier if not already installed (only needs to download once)\n",
"metadata=pd.read_table(\"/Users/parsaghadermarzi/Desktop/Academics/Projects/Anaerobic_Digestion_Modeling/16s_study/wastewater_16s.csv\",delimiter=\",\")\n",
"accessions=metadata[\"Run\"].to_list()\n",
- "metag_class=core.Metagenomics(configs.Metagenomics())\n",
+ "metag_class=core.Metagenomics(configs.Metagenomics(database_dir=DATABASE_DIR))\n",
"alignment_to_gtdb={}\n",
- "base=pathlib.Path(os.path.join(core.Main_Dir,\"sra_wastewater\")) # base directory\n",
+ "base=pathlib.Path(os.path.join(WORK_DIR,\"sra_wastewater\")) # base directory\n",
"for i in accessions:\n",
- " mg_config=configs.Metagenomics(top_repseq_dir=str(base/i/\"seqs\"/i/\"dna-sequences.fasta\"),\n",
+ " mg_config=configs.Metagenomics(database_dir=DATABASE_DIR, top_repseq_dir=str(base/i/\"seqs\"/i/\"dna-sequences.fasta\"),\n",
" vsearch_similarity=0.90,\n",
" align_to_gtdb_outputs_dir=str(base/i/\"seqs\"/i))\n",
" \n",
@@ -174,7 +180,7 @@
"genome_ids=set()\n",
"for sample in alignment_to_gtdb:\n",
" genome_ids.update(tuple(alignment_to_gtdb[sample].values()))\n",
- "mg_config=configs.Metagenomics(genomes_base_dir=os.path.join(core.Main_Dir,\"genomes\"))\n",
+ "mg_config=configs.Metagenomics(database_dir=DATABASE_DIR, genomes_base_dir=os.path.join(WORK_DIR,\"genomes\"))\n",
"mg=core.Metagenomics(mg_config)\n",
"genome_address=mg.extract_genome_info(save=False)"
]
@@ -76693,11 +76699,11 @@
}
],
"source": [
- "mg.config.genomes_json_info=os.path.join(core.Main_Dir,\"sra_wastewater\",\"genome_address.json\")\n",
+ "mg.config.genomes_json_info=os.path.join(WORK_DIR,\"sra_wastewater\",\"genome_address.json\")\n",
"genome_address=mg.extract_genome_info(save=False)\n",
"genome_address={k:v for k,v in genome_address.items() if k in genome_ids}\n",
- "mg=core.Metagenomics(configs.Metagenomics(genome_alignment_output=os.path.join(core.Main_Dir,\"genomes\")\n",
- " ,genomes_base_dir=os.path.join(core.Main_Dir,\"genomes\")))\n",
+ "mg=core.Metagenomics(configs.Metagenomics(database_dir=DATABASE_DIR, genome_alignment_output=os.path.join(WORK_DIR,\"genomes\")\n",
+ " ,genomes_base_dir=os.path.join(WORK_DIR,\"genomes\")))\n",
"for i in enumerate(genome_address):\n",
" os.system(mg.align_genome_to_protein_db(genome_address[i[1]],i[1],container=\"None\")[0])\n"
]
@@ -76708,7 +76714,7 @@
"metadata": {},
"outputs": [],
"source": [
- "base=pathlib.Path(os.path.join(core.Main_Dir))"
+ "base=pathlib.Path(os.path.join(WORK_DIR))"
]
},
{
@@ -80776,7 +80782,7 @@
"outputs": [],
"source": [
"normalized_cods={}\n",
- "samples=pathlib.Path(os.path.join(core.Main_Dir,\"sra_wastewater\"))\n",
+ "samples=pathlib.Path(os.path.join(WORK_DIR,\"sra_wastewater\"))\n",
"for i in samples.iterdir():\n",
" sample_basedir=i/\"seqs\"/i.name\n",
" if \"SRR\" in i.name:\n",
@@ -85021,8 +85027,7 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
- },
- "orig_nbformat": 4
+ }
},
"nbformat": 4,
"nbformat_minor": 2
diff --git a/Examples/toy_model.json b/Examples/toy_model.json
new file mode 100644
index 0000000..eba10b2
--- /dev/null
+++ b/Examples/toy_model.json
@@ -0,0 +1,51 @@
+{
+"metabolites":[
+{
+"id":"A",
+"name":"A",
+"compartment":"Model"
+},
+{
+"id":"B",
+"name":"B",
+"compartment":"Model"
+},
+{
+"id":"C",
+"name":"C",
+"compartment":"Model"
+}
+],
+"reactions":[
+{
+"id":"r1",
+"name":"r1",
+"metabolites":{
+"A":-1.0,
+"B":-1.0,
+"C":1.0
+},
+"lower_bound":0.0,
+"upper_bound":1000.0,
+"gene_reaction_rule":""
+},
+{
+"id":"r2",
+"name":"r2",
+"metabolites":{
+"A":-1.0,
+"B":1.0,
+"C":-1.0
+},
+"lower_bound":0.0,
+"upper_bound":1000.0,
+"gene_reaction_rule":""
+}
+],
+"genes":[],
+"id":"ADM",
+"compartments":{
+"Model":""
+},
+"version":"1"
+}
\ No newline at end of file
diff --git a/adtoolbox/.DS_Store b/adtoolbox/.DS_Store
index a471cfc..a753771 100644
Binary files a/adtoolbox/.DS_Store and b/adtoolbox/.DS_Store differ
diff --git a/adtoolbox/__init__.py b/adtoolbox/__init__.py
index 177514e..5c53136 100644
--- a/adtoolbox/__init__.py
+++ b/adtoolbox/__init__.py
@@ -1,39 +1,11 @@
-import json
import os
-import rich
-from rich.prompt import Prompt
import sys
"""Project Setup for ADToolBox."""
__version__ = "1.0.0"
-__all__=["adm","configs","__main__","cli","core","optimize","pipeline","utils","Main_Dir","PKG_DATA"]
+__all__=["adm","configs","__main__","cli","core","optimize","pipeline","utils","PKG_DATA"]
sys.path.append(os.path.join(os.path.dirname(__file__)))
PKG_DATA=os.path.join(os.path.dirname(os.path.realpath(__file__)),"pkg_data")
-
-if not os.path.exists(os.path.join(PKG_DATA,"ADToolbox_Configs.json")):
- with open(os.path.join(PKG_DATA,"ADToolbox_Configs.json"),"w") as f:
- json.dump({"Base_Dir":""},f)
-
-with open(os.path.join(PKG_DATA,"ADToolbox_Configs.json"),"r") as f:
- conf = json.load(f)
- Main_Dir=conf["Base_Dir"]
-if Main_Dir and os.path.exists(Main_Dir):
- pass
-elif Main_Dir and not os.path.exists(Main_Dir):
- Main_Dir=input(f"Base directory is not configured properly.\nPlease input the correct path for the base directory:")
- if not os.path.exists(Main_Dir):
- os.makedirs(Main_Dir)
- rich.print(f"[green]Base directory is set to {Main_Dir}")
-else:
- Main_Dir=Prompt.ask("No Base Directory Found: \nWhere do you want to store your ADToolBox Data?")
-
-if not os.path.exists(Main_Dir):
- os.mkdir(Main_Dir)
- rich.print(f"\nDirectory did not exist. Created directory: {Main_Dir}")
-
-with open(os.path.join(os.path.dirname(os.path.realpath(__file__)),"pkg_data","ADToolbox_Configs.json"),"w") as f:
- conf["Base_Dir"]=Main_Dir
- json.dump(conf,f)
diff --git a/adtoolbox/__main__.py b/adtoolbox/__main__.py
index 669be75..71b440f 100644
--- a/adtoolbox/__main__.py
+++ b/adtoolbox/__main__.py
@@ -1,7 +1,4 @@
-import sys
-import os
-from cli import main as main
-import adtoolbox
+from .cli import main
if __name__ == '__main__':
- main()
\ No newline at end of file
+ main()
diff --git a/adtoolbox/adm.py b/adtoolbox/adm.py
index 37be67e..b8368d7 100644
--- a/adtoolbox/adm.py
+++ b/adtoolbox/adm.py
@@ -16,7 +16,7 @@
import pandas as pd
import dash_bootstrap_components as dbc
import utils
-from adtoolbox import Main_Dir,PKG_DATA
+from adtoolbox import PKG_DATA
import dash_escher
import configs
import time
@@ -35,13 +35,24 @@
si=30,
xi=50,
tss=80)
-RT = SeedDB(config=configs.Database())
-
class _Fake_Sol:
def __init__(self, y,t):
self.y = y
self.t=t
+
+def _require_model_parameters(model_parameters: dict, required: list[str], model_name: str) -> None:
+ missing = sorted(set(required) - set(model_parameters))
+ if missing:
+ raise ValueError(
+ f"{model_name} model_parameters is missing required keys: {', '.join(missing)}"
+ )
+
+
+def _monod_limitation(concentration: float, half_saturation: float, eps: float = 10**-9) -> float:
+ return concentration / (half_saturation + concentration + eps)
+
+
class Model:
"""Any kinetic model could be an instance of this class.
@@ -899,14 +910,14 @@ def adm1_ode_sys(t: float, c: np.ndarray, model:Model)-> np.ndarray:
return dCdt[:, 0]
-def build_e_adm_2_stoichiometric_matrix(base_parameters: dict,
- model_parameters: dict,
- reactions: list,
- species: list,
- feed:Feed,
- nitrogen_limited:bool=False)->np.ndarray:
+def build_e_adm_stoichiometric_matrix(base_parameters: dict,
+ model_parameters: dict,
+ reactions: list,
+ species: list,
+ feed:Feed,
+ nitrogen_limited:bool=False)->np.ndarray:
"""
- This function builds the stoichiometric matrix for e-ADM2 Model.
+ This function builds the stoichiometric matrix for the e-ADM model.
Model Parameters (dict): a dictionary which contains model parameters
base_parameters (dict): a dictionary which contains base paramters
@@ -918,6 +929,15 @@ def build_e_adm_2_stoichiometric_matrix(base_parameters: dict,
Returns:
np.ndarray: Returns an matrix of stochiometic values.
"""
+ _require_model_parameters(
+ model_parameters,
+ [
+ 'Y_su', 'Y_aa', 'Y_fa', 'Y_ac_et', 'Y_ac_lac', 'Y_pro_et',
+ 'Y_pro_lac', 'Y_bu_et', 'Y_bu_lac', 'Y_va', 'Y_cap', 'Y_bu',
+ 'Y_Me_ac', 'Y_Me_CO2', 'Y_ac_et_ox', 'Y_pro_lac_ox',
+ ],
+ "e-ADM",
+ )
S = np.zeros((len(species), len(reactions)))
S[list(map(species.index, ["TSS", "X_ch", "X_pr", "X_li", "X_I"])),
reactions.index('TSS_Disintegration')] = [-1,feed.ch_tss, feed.prot_tss, feed.lip_tss, feed.xi_tss]
@@ -1025,7 +1045,7 @@ def build_e_adm_2_stoichiometric_matrix(base_parameters: dict,
Y_ac_lac]
Y_pro_et=0 if nitrogen_limited else model_parameters['Y_pro_et']
- Y_pro_lac=0 if nitrogen_limited else model_parameters['Y_pro_et']
+ Y_pro_lac=0 if nitrogen_limited else model_parameters['Y_pro_lac']
f_IC_pro_et = -(-model_parameters['C_pro'] +
model_parameters['f_et_pro']*model_parameters['C_et'] +
@@ -1104,20 +1124,22 @@ def build_e_adm_2_stoichiometric_matrix(base_parameters: dict,
(1 - Y_cap),
Y_cap]
- Y_cap=0 if nitrogen_limited else model_parameters['Y_bu']
+ Y_bu=0 if nitrogen_limited else model_parameters['Y_bu']
S[list(map(species.index, ["S_bu", "S_ac", "X_VFA_deg"])),
reactions.index('Uptake of butyrate')] = [-1,
- (1 - Y_cap),
- Y_cap]
+ (1 - Y_bu),
+ Y_bu]
Y_Me_ac=0 if nitrogen_limited else model_parameters["Y_Me_ac"]
- f_IC_Me_ach2 =0
+ f_IC_Me_ach2 = -(model_parameters['f_ac_h2']*model_parameters['C_ac'] +
+ (1 - Y_Me_ac)*model_parameters['C_ch4'] +
+ Y_Me_ac*model_parameters['C_bac'])
S[list(map(species.index, ["S_gas_h2", "S_ac", "S_ch4", "X_Me_ac", 'S_IC', 'S_IN'])),
reactions.index('Methanogenessis from acetate and h2')] = [-1,
model_parameters['f_ac_h2'],
- (1 +model_parameters['f_ac_h2']- Y_Me_ac),
+ (1 - Y_Me_ac),
Y_Me_ac,
f_IC_Me_ach2,
-Y_Me_ac *model_parameters['N_bac']
@@ -1208,362 +1230,18 @@ def build_e_adm_2_stoichiometric_matrix(base_parameters: dict,
reactions.index('Acid Base Equilibrium (In)')] = [-1, 1] # I don't think this is right، should look at the reaction in ADM1
S[list(map(species.index, ["S_h2", "S_gas_h2"])),
- reactions.index('Gas Transfer H2')] = [-base_parameters['V_liq']/base_parameters['V_gas'], 1]
+ reactions.index('Gas Transfer H2')] = [-1, base_parameters['V_liq']/base_parameters['V_gas']]
S[list(map(species.index, ["S_ch4", "S_gas_ch4"])),
- reactions.index('Gas Transfer CH4')] = [-base_parameters['V_liq']/base_parameters['V_gas'], 1]
+ reactions.index('Gas Transfer CH4')] = [-1, base_parameters['V_liq']/base_parameters['V_gas']]
S[list(map(species.index, ["S_co2", "S_gas_co2"])),
- reactions.index('Gas Transfer CO2')] = [-base_parameters['V_liq']/base_parameters['V_gas'], 1]
+ reactions.index('Gas Transfer CO2')] = [-1, base_parameters['V_liq']/base_parameters['V_gas']]
return S
-def build_e_adm_stoiciometric_matrix(base_parameters: dict,
- model_parameters: dict,
- reactions: list,
- species: list,
- feed:Feed,
- nitrogen_limited:bool=False)->np.ndarray:
- """
- This function builds the stoichiometric matrix for the e_ADM Model.
-
- Model Parameters (dict): a dictionary which contains model parameters
- base_parameters (dict): a dictionary which contains base paramters
- Initial Conditions (dict): a dictionary containing inlet conditions for all species
- Inlet Conditions (dict): a dictionary containing inlet conditions for all species
- reactions (list): a list containing all of the reaction names
- species (list): a list containing all species
-
- Returns:
- np.ndarray: Returns an matrix of stochiometic values.
- """
- S = np.zeros((len(species), len(reactions)))
- S[list(map(species.index, ["TSS", "X_ch", "X_pr", "X_li", "X_I"])),
- reactions.index('TSS_Disintegration')] = [-1,feed.ch_tss, feed.prot_tss, feed.lip_tss,feed.xi_tss]
- S[list(map(species.index, ["TDS", "X_ch", "X_pr", "X_li", "S_I"])), reactions.index('TDS_Disintegration')] = [-1,
- feed.ch_tds, feed.prot_tds, feed.lip_tds, feed.si_tds]
- S[list(map(species.index, ["X_ch", "S_su"])),reactions.index('Hydrolysis carbohydrates')] = [-1, 1]
- S[list(map(species.index, ["X_pr", "S_aa"])),reactions.index('Hydrolysis proteins')] = [-1, 1]
- S[list(map(species.index, ["X_li", "S_fa"])),reactions.index('Hydrolysis lipids')] = [-1, 1]
-
- f_IC_su_et=-(-model_parameters['C_su']+
- (1-model_parameters['Y_su_et']) * model_parameters['C_et']+
- (1-model_parameters['Y_su_et']) * model_parameters['C_bac']
- )
-
- f_IC_su_lac=-(-model_parameters['C_su']+
- (1-model_parameters['Y_su_lac']) * model_parameters['C_lac']+
- (1-model_parameters['Y_su_lac']) * model_parameters['C_bac']
- )
-
- f_IC_su_ac=-(-model_parameters['C_su']+
- (1-model_parameters['Y_su_ac']) * model_parameters['C_ac']+
- (1-model_parameters['Y_su_ac']) * model_parameters['C_bac']
- )
- f_IC_su_pro=-(-model_parameters['C_su']+
- (1-model_parameters['Y_su_pro']) * model_parameters['C_pro']+
- (1-model_parameters['Y_su_pro']) * model_parameters['C_bac']
- )
-
- S[list(map(species.index, ["S_su","S_et","S_IN","S_IC","X_su"])),
- reactions.index('Su_to_et')] = [-1,
- (1-model_parameters['Y_su_et']),
- -model_parameters['N_bac']* model_parameters['Y_su_et'],
- f_IC_su_et,
- model_parameters['Y_su_et']]
-
- S[list(map(species.index, ["S_su","S_lac","S_IN","S_IC","X_su"])),
- reactions.index('Su_to_lac')] = [-1,
- (1-model_parameters['Y_su_lac']),
- -model_parameters['N_bac']* model_parameters['Y_su_lac'],
- f_IC_su_lac,
- model_parameters['Y_su_lac']]
-
- S[list(map(species.index, ["S_su","S_ac","S_IN","S_IC","X_su"])),
- reactions.index('Su_to_ac')] = [-1,
- (1-model_parameters['Y_su_ac']),
- -model_parameters['N_bac']* model_parameters['Y_su_ac'],
- f_IC_su_ac,
- model_parameters['Y_su_ac']]
-
- S[list(map(species.index, ["S_su","S_pro","S_IN","S_IC","X_su"])),
- reactions.index('Su_to_pro')] = [-1,
- (1-model_parameters['Y_su_pro']),
- -model_parameters['N_bac']* model_parameters['Y_su_pro'],
- f_IC_su_pro,
- model_parameters['Y_su_pro']]
-
- f_IC_aa_lac=-(-model_parameters['C_aa']+
- (1-model_parameters['Y_aa_lac']) * model_parameters['C_lac']+
- (1-model_parameters['Y_aa_lac']) * model_parameters['C_bac']
- )
-
- f_IC_aa_ac=-(-model_parameters['C_aa']+
- (1-model_parameters['Y_aa_ac']) * model_parameters['C_ac']+
- (1-model_parameters['Y_aa_ac']) * model_parameters['C_bac']
- )
-
- f_IC_aa_pro=-(-model_parameters['C_aa']+
- (1-model_parameters['Y_aa_pro']) * model_parameters['C_pro']+
- (1-model_parameters['Y_aa_pro']) * model_parameters['C_bac']
- )
-
-
- S[list(map(species.index, ["S_aa","S_lac","S_IN", "S_IC", "X_aa"])),
- reactions.index('aas_to_lac')] = [-1,
- (1-model_parameters['Y_aa_lac']),
- model_parameters['N_aa']- model_parameters['Y_aa_lac'] * model_parameters['N_bac'],
- f_IC_aa_lac,
- model_parameters['Y_aa_lac']]
-
- S[list(map(species.index, ["S_aa","S_pro","S_IN", "S_IC", "X_aa"])),
- reactions.index('aas_to_pro')] = [-1,
- (1-model_parameters['Y_aa_pro']),
- model_parameters['N_aa']- model_parameters['Y_aa_pro'] * model_parameters['N_bac'],
- f_IC_aa_pro,
- model_parameters['Y_aa_pro']]
-
-
- S[list(map(species.index, ["S_aa","S_ac","S_IN", "S_IC", "X_aa"])),
- reactions.index('aas_to_ac')] = [-1,
- (1-model_parameters['Y_aa_ac']),
- model_parameters['N_aa']- model_parameters['Y_aa_ac'] * model_parameters['N_bac'],
- f_IC_aa_ac,
- model_parameters['Y_aa_ac']]
-
- Y_fa=0 if nitrogen_limited else model_parameters['Y_fa']
- f_IC_fa = -(-model_parameters['C_fa'] +
- (1-Y_fa)*model_parameters['f_pro_fa']*model_parameters['C_pro'] +
- (1-Y_fa)*model_parameters['f_ac_fa']*model_parameters['C_ac'] +
- (1-Y_fa)*model_parameters['C_bac'])
-
- S[list(map(species.index, ["S_fa", "S_pro", "S_ac", "S_IN", "S_IC", "X_fa"])),
- reactions.index('Uptake of LCFA')] = [-1,
- (1-Y_fa) * model_parameters['f_pro_fa'],
- (1-Y_fa) * model_parameters['f_ac_fa'],
- -Y_fa * model_parameters['N_bac'],
- f_IC_fa,
- Y_fa]
-#HERE
- Y_ac_et=0 if nitrogen_limited else model_parameters['Y_ac_et']
- Y_ac_lac=0 if nitrogen_limited else model_parameters['Y_ac_lac']
- f_IC_ac_et = -((-1-(1-Y_ac_et) * model_parameters['f_et_ac'])*model_parameters['C_ac'] +
- (1-Y_ac_et)* model_parameters['f_et_ac']*model_parameters['C_et'] +
- (1-Y_ac_et) * model_parameters['f_bu_ac']*model_parameters['C_bu'] +
- (1-Y_ac_et)* model_parameters['C_bac'])
-
- f_IC_ac_lac = -((-1-(1-Y_ac_lac) * model_parameters['f_lac_ac'])*model_parameters['C_ac'] +
- (1-Y_ac_lac)* model_parameters['f_lac_ac']* model_parameters['C_lac'] +
- (1-Y_ac_lac)* model_parameters['f_bu_ac']* model_parameters['C_bu'] +
- (1-Y_ac_lac)* model_parameters['C_bac'])
-
- S[list(map(species.index, ["S_ac", "S_et", "S_bu", "S_IN", "S_IC", "S_h2", "X_ac_et"])),
- reactions.index('Uptake of acetate_et')] = [-1-(1-Y_ac_et) * model_parameters['f_et_ac'],
- (1-Y_ac_et) * model_parameters['f_et_ac'],
- (1-model_parameters['Y_ac']) * model_parameters['f_bu_ac'],
- -Y_ac_et * model_parameters['N_bac'],
- f_IC_ac_et,
- (1-Y_ac_et) * (1-model_parameters['f_bu_ac']),
- Y_ac_et]
-
- S[list(map(species.index, ["S_ac", "S_lac", "S_bu", "S_IN", "S_IC", "S_h2", "X_ac_lac"])),
- reactions.index('Uptake of acetate_lac')] = [-1-(1-Y_ac_lac) * model_parameters['f_lac_ac'],
- (1-Y_ac_lac) * model_parameters['f_lac_ac'],
- (1-Y_ac_lac) * model_parameters['f_bu_ac'],
- -Y_ac_lac * model_parameters['N_bac'],
- f_IC_ac_lac,
- (1-Y_ac_lac) * (1-model_parameters['f_bu_ac']),
- Y_ac_lac]
-
- Y_pro_et=0 if nitrogen_limited else model_parameters['Y_pro_et']
- Y_pro_lac=0 if nitrogen_limited else model_parameters['Y_pro_lac']
-
- f_IC_pro_et = -((-1-(1-Y_pro_et) * model_parameters['f_et_pro'])*model_parameters['C_pro'] +
- (1-Y_pro_et)*model_parameters['f_et_pro']*model_parameters['C_et'] +
- (1-Y_pro_et)*model_parameters['f_va_pro']*model_parameters['C_va'] +
- (1-Y_pro_et)*model_parameters['C_bac'])
-
- f_IC_pro_lac = -((-1-(1-Y_pro_lac) * model_parameters['f_lac_pro'])*model_parameters['C_pro'] +
- (1-Y_pro_lac)*model_parameters['f_lac_pro']*model_parameters['C_lac'] +
- (1-Y_pro_lac)*model_parameters['f_va_pro']*model_parameters['C_va'] +
- (1-Y_pro_lac)*model_parameters['C_bac'])
-
- S[list(map(species.index, ["S_pro", "S_et", "S_va","S_IC","S_IN","S_h2", "X_chain_et"])),
- reactions.index('Uptake of propionate_et')] = [-1-(1-model_parameters['Y_chain_et_pro']) * model_parameters['f_et_pro'],
- (1-model_parameters['Y_chain_et_pro']) * model_parameters['f_et_pro'],
- (1-model_parameters['Y_chain_et_pro']) * model_parameters['f_va_pro'],
- f_IC_pro_et,
- -model_parameters['Y_chain_et_pro'] * model_parameters['N_bac'],
- (1-model_parameters['Y_chain_et_pro']) * (1-model_parameters['f_va_pro']),
- model_parameters['Y_chain_et_pro']]
-
- S[list(map(species.index, ["S_pro", "S_lac", "S_va", "S_IC", "S_IN", "S_h2", "X_chain_lac"])),
- reactions.index('Uptake of propionate_lac')] = [-1-(1-model_parameters['Y_chain_lac_pro']) * model_parameters['f_lac_pro'],
- (1-model_parameters['Y_chain_lac_pro']) * model_parameters['f_lac_pro'],
- (1-model_parameters['Y_chain_lac_pro']) * model_parameters['f_va_pro'],
- f_IC_pro_lac,
- -model_parameters['Y_chain_lac_pro'] * model_parameters['N_bac'],
- (1-model_parameters['Y_chain_lac_pro']) * (1-model_parameters['f_va_pro']),
- model_parameters['Y_chain_lac_pro']]
-
- Y_bu_et=0 if nitrogen_limited else model_parameters['Y_bu_et']
- Y_pro_lac=0 if nitrogen_limited else model_parameters['Y_pro_lac']
-
- f_IC_bu_et = -((-1-(1-Y_bu_et) * model_parameters['f_et_bu'])*model_parameters['C_bu'] +
- (1-Y_bu_et)*model_parameters['f_et_bu']*model_parameters['C_et'] +
- (1-Y_bu_et)*model_parameters['f_cap_bu']*model_parameters['C_cap'] +
- (1-Y_bu_et)*model_parameters['C_bac'])
-
- f_IC_bu_lac = -((-1-(1-Y_pro_lac) * model_parameters['f_lac_bu'])*model_parameters['C_bu'] +
- (1-Y_pro_lac)*model_parameters['f_lac_bu']*model_parameters['C_lac'] +
- (1-Y_pro_lac)*model_parameters['f_cap_bu']*model_parameters['C_cap'] +
- (1-Y_pro_lac)*model_parameters['C_bac'])
-
- S[list(map(species.index, ["S_bu", "S_et", "S_cap", "S_IC", "S_IN", "S_h2", "X_chain_et"])),
- reactions.index('Uptake of butyrate_et')] = [-1-(1-Y_bu_et) * model_parameters['f_et_bu'],
- (1-Y_bu_et) * model_parameters['f_et_bu'],
- (1-Y_bu_et) * model_parameters['f_cap_bu'],
- f_IC_bu_et,
- -Y_bu_et * model_parameters['N_bac'],
- (1-Y_bu_et)*(1-model_parameters['f_cap_bu']),
- Y_bu_et]
-
- S[list(map(species.index, ["S_bu", "S_lac", "S_cap", "S_IC", "S_IN", "S_h2", "X_chain_lac"])),
- reactions.index('Uptake of butyrate_lac')] = [-1-(1-Y_pro_lac) * model_parameters['f_lac_bu'],
- (1-Y_pro_lac) * model_parameters['f_lac_bu'],
- (1-Y_pro_lac) * model_parameters['f_cap_bu'],
- f_IC_bu_lac,
- -Y_pro_lac * model_parameters['N_bac'],
- (1-Y_pro_lac)*(1-model_parameters['f_cap_bu']),
- Y_pro_lac]
-
- Y_va=0 if nitrogen_limited else model_parameters['Y_va']
- Y_cap=0 if nitrogen_limited else model_parameters['Y_cap']
- S[list(map(species.index, ["S_va", "S_pro", "X_VFA_deg"])),
- reactions.index('Uptake of valerate')] = [-1,
- (1-Y_va),
- Y_va]
-
- S[list(map(species.index, ["S_cap", "S_ac", "X_VFA_deg"])),
- reactions.index('Uptake of caproate')] = [-1,
- (1 - Y_cap),
- Y_cap]
-
- S[list(map(species.index, ["S_bu", "S_ac", "X_VFA_deg"])),
- reactions.index('Uptake of butyrate')] = [-1,
- (1 - model_parameters['Y_bu']),
- model_parameters['Y_bu']]
-
- Y_Me_ac=0 if nitrogen_limited else model_parameters["Y_Me_ac"]
- f_IC_Me_ach2 =0
- f_IC_Me_ach2 = -((1 - model_parameters['Y_h2_ac'])*model_parameters['f_ac_h2']*model_parameters['C_ac']+
- (1 -Y_Me_ac)*model_parameters['C_ch4']+
- Y_Me_ac*model_parameters['C_bac'])
-
-
-
- S[list(map(species.index, ["S_h2", "S_ac", "S_ch4", "X_Me_ac", 'S_IC'])),
- reactions.index('Methanogenessis from acetate and h2')] = [-1-(1 - model_parameters['Y_h2_ac'])*model_parameters['f_ac_h2'],
- (1 - model_parameters['Y_h2_ac'])*model_parameters['f_ac_h2'],
- (1 -model_parameters['Y_h2_ac']),
- model_parameters['Y_h2_ac'],
- f_IC_Me_ach2]
-
- f_IC_Me_CO2h2 = -(model_parameters['Y_h2_CO2']*model_parameters['C_ch4'] +
- model_parameters['Y_h2_CO2']*model_parameters['C_bac'])
-
- S[list(map(species.index, ["S_h2", "S_ch4", "X_Me_CO2", 'S_IC'])),
- reactions.index('Methanogenessis from CO2 and h2')] = [-1,
- (1 - model_parameters['Y_h2_CO2']),
- (model_parameters['Y_h2_CO2']),
- f_IC_Me_CO2h2]
-
- Y_ac_et_ox=0 if nitrogen_limited else model_parameters["Y_ac_et_ox"]
-
- f_IC_et_ox=-(-model_parameters['C_et'] +
- (1-Y_ac_et_ox)*model_parameters['C_bac']
- +Y_ac_et_ox*model_parameters['C_ac'])
-
- S[list(map(species.index, ["S_et", "X_et","S_ac","S_IC"])),
- reactions.index('Uptake of ethanol')] = [-1,Y_ac_et_ox,(1-Y_ac_et_ox),f_IC_et_ox]
-
-
- Y_pro_lac_ox=0 if nitrogen_limited else model_parameters['Y_pro_lac_ox']
- f_IC_lac_ox=-(-model_parameters['C_lac'] +
- (1-Y_pro_lac_ox)*model_parameters['C_bac']
- +Y_pro_lac_ox*model_parameters['C_pro'])
-
- S[list(map(species.index, ["S_lac", "X_lac","S_pro","S_IC"])),
- reactions.index('Uptake of lactate')] = [-1, Y_pro_lac_ox,(1-Y_pro_lac_ox),f_IC_lac_ox]
-
- S[list(map(species.index, ["X_su", "TSS"])),
- reactions.index('Decay of Xsu')] = [-1, 1]
-
- S[list(map(species.index, ["X_aa", "TSS"])),
- reactions.index('Decay of Xaa')] = [-1, 1]
-
- S[list(map(species.index, ["X_fa", "TSS"])),
- reactions.index('Decay of Xfa')] = [-1, 1]
-
- S[list(map(species.index, ["X_ac_et", "TSS"])),
- reactions.index('Decay of X_ac_et')] = [-1, 1]
-
- S[list(map(species.index, ["X_ac_lac", "TSS"])),
- reactions.index('Decay of X_ac_lac')] = [-1, 1]
-
- S[list(map(species.index, ["X_chain_et", "TSS"])),
- reactions.index('Decay of X_chain_et')] = [-1, 1]
-
- S[list(map(species.index, ["X_chain_lac", "TSS"])),
- reactions.index('Decay of X_chain_lac')] = [-1, 1]
-
- S[list(map(species.index, ["X_VFA_deg", "TSS"])),
- reactions.index('Decay of X_VFA_deg')] = [-1, 1]
-
- S[list(map(species.index, ["X_Me_ac", "TSS"])),
- reactions.index('Decay of X_Me_ac')] = [-1, 1]
-
- S[list(map(species.index, ["X_Me_CO2", "TSS"])),
- reactions.index('Decay of X_Me_CO2')] = [-1, 1]
-
- S[list(map(species.index, ["S_va_ion","S_va"])),
- reactions.index('Acid Base Equilibrium (Va)')] = [-1,1]
-
- S[list(map(species.index, ["S_bu_ion","S_bu"])),
- reactions.index('Acid Base Equilibrium (Bu)')] = [-1,1]
-
- S[list(map(species.index, ["S_pro_ion","S_pro"])),
- reactions.index('Acid Base Equilibrium (Pro)')] = [-1,1]
-
- S[list(map(species.index, ["S_cap_ion","S_cap"])),
- reactions.index('Acid Base Equilibrium (Cap)')] = [-1,1]
-
- S[list(map(species.index, ["S_lac_ion","S_lac"])),
- reactions.index('Acid Base Equilibrium (Lac)')] = [-1,1]
-
- S[list(map(species.index, ["S_ac_ion","S_ac"])),
- reactions.index('Acid Base Equilibrium (Ac)')] = [-1,1]
-
- S[list(map(species.index, ["S_co2", "S_hco3_ion"])), # I don't think this is right، should look at the reaction in ADM1
- reactions.index('Acid Base Equilibrium (CO2)')] = [-1, 1]
-
- S[list(map(species.index, ["S_nh3", "S_nh4_ion"])),
- reactions.index('Acid Base Equilibrium (In)')] = [-1, 1] # I don't think this is right، should look at the reaction in ADM1
-
- S[list(map(species.index, ["S_h2", "S_gas_h2"])),
- reactions.index('Gas Transfer H2')] = [-base_parameters['V_liq']/base_parameters['V_gas'], 1]
- S[list(map(species.index, ["S_ch4", "S_gas_ch4"])),
- reactions.index('Gas Transfer CH4')] = [-base_parameters['V_liq']/base_parameters['V_gas'], 1]
- S[list(map(species.index, ["S_co2", "S_gas_co2"])),
- reactions.index('Gas Transfer CO2')] = [-base_parameters['V_liq']/base_parameters['V_gas'], 1]
- return S
-
-
-build_e_adm_stoichiometric_matrix = build_e_adm_stoiciometric_matrix
-
-
-def e_adm_2_ode_sys(t: float, c: np.ndarray, model: Model)-> np.ndarray:
+def e_adm_ode_sys(t: float, c: np.ndarray, model: Model)-> np.ndarray:
"""
- This function is used to build the ODEs of the e-adm2 model.
+ This function is used to build the ODEs of the e-ADM model.
Args:
t (float):a matrix of zeros to be filled
@@ -1612,7 +1290,10 @@ def e_adm_2_ode_sys(t: float, c: np.ndarray, model: Model)-> np.ndarray:
I_pH_h2 = (model.model_parameters['K_pH_h2']**model.model_parameters['n_h2'])/(
c[model.species.index('S_H_ion')] ** model.model_parameters['n_h2'] + model.model_parameters['K_pH_h2']**model.model_parameters['n_h2'])
- I_IN_lim = 1 / (1+(c[model.species.index('S_IN')] / (model.model_parameters['K_S_IN']+10**-9)))
+ I_IN_lim = _monod_limitation(
+ c[model.species.index('S_IN')],
+ model.model_parameters['K_S_IN'],
+ )
I_h2_fa = 1 / (1+(c[model.species.index('S_h2')] /(model.model_parameters['K_I_h2_fa']+10**-9)))
@@ -1750,7 +1431,7 @@ def e_adm_2_ode_sys(t: float, c: np.ndarray, model: Model)-> np.ndarray:
model.model_parameters['K_a_co2'] * c[model.species.index('S_IC')])
v[model.reactions.index('Acid Base Equilibrium (In)')] = model.model_parameters['k_A_B_IN'] * \
(c[model.species.index('S_nh3')] * (model.model_parameters['K_a_IN'] + c[model.species.index('S_H_ion')]) -
- model.model_parameters['K_a_IN'] * c[model.species.index('S_IC')])
+ model.model_parameters['K_a_IN'] * c[model.species.index('S_IN')])
p_gas_h2 = c[model.species.index('S_gas_h2')] * model.base_parameters["R"] * model.base_parameters["T_op"] / 16
@@ -1807,383 +1488,3 @@ def e_adm_2_ode_sys(t: float, c: np.ndarray, model: Model)-> np.ndarray:
model.info["Fluxes"]=v
return dCdt[:, 0]
-
-def e_adm_ode_sys(t: float, c: np.ndarray, model: Model)-> np.ndarray:
- """
- This function is used to build the ODEs of the e_adm model.
-
- Args:
- t (float):a matrix of zeros to be filled
- c (np.ndarray): an array of concentrations to be filled
- Model (Model): The model to calculate ODE with
-
- Returns:
- np.ndarray: The output is dCdt, the change of concentration with respect to time.
- """
- c[c<0]=0
- c[model.species.index('S_H_ion')]=0.000001
- v = np.zeros((len(model.reactions), 1))
- if model.switch == "DAE":
-
- c[model.species.index('S_va_ion')]=model.model_parameters['K_a_va']/(model.model_parameters['K_a_va']+c[model.species.index('S_H_ion')])*c[model.species.index('S_va')]
-
- c[model.species.index('S_bu_ion')]=model.model_parameters['K_a_bu']/(model.model_parameters['K_a_bu']+c[model.species.index('S_H_ion')])*c[model.species.index('S_bu')]
-
- c[model.species.index('S_pro_ion')]=model.model_parameters['K_a_pro']/(model.model_parameters['K_a_pro']+c[model.species.index('S_H_ion')])*c[model.species.index('S_pro')]
-
- c[model.species.index('S_cap_ion')]=model.model_parameters['K_a_cap']/(model.model_parameters['K_a_cap']+c[model.species.index('S_H_ion')])*c[model.species.index('S_cap')]
-
- c[model.species.index('S_ac_ion')]=model.model_parameters['K_a_ac']/(model.model_parameters['K_a_ac']+c[model.species.index('S_H_ion')])*c[model.species.index('S_ac')]
-
- c[model.species.index('S_lac_ion')]=model.model_parameters['K_a_lac']/(model.model_parameters['K_a_lac']+c[model.species.index('S_H_ion')])*c[model.species.index('S_lac')]
- else:
- v[model.reactions.index('Acid Base Equilibrium (Va)')] = model.model_parameters['k_A_B_va'] * \
- (c[model.species.index('S_va_ion')] * (model.model_parameters['K_a_va'] + c[model.species.index('S_H_ion')]) -
- model.model_parameters['K_a_va'] * c[model.species.index('S_va')])
-
- v[model.reactions.index('Acid Base Equilibrium (Bu)')] = model.model_parameters['k_A_B_bu'] * \
- (c[model.species.index('S_bu_ion')] * (model.model_parameters['K_a_bu'] + c[model.species.index('S_H_ion')]) -
- model.model_parameters['K_a_bu'] * c[model.species.index('S_bu')])
-
- v[model.reactions.index('Acid Base Equilibrium (Pro)')] = model.model_parameters['k_A_B_pro'] * \
- (c[model.species.index('S_pro_ion')] * (model.model_parameters['K_a_pro'] + c[model.species.index('S_H_ion')]) -
- model.model_parameters['K_a_pro'] * c[model.species.index('S_pro')])
-
- v[model.reactions.index('Acid Base Equilibrium (Cap)')] = model.model_parameters['k_A_B_cap'] * \
- (c[model.species.index('S_cap_ion')] * (model.model_parameters['K_a_cap'] + c[model.species.index('S_H_ion')]) -
- model.model_parameters['K_a_cap'] * c[model.species.index('S_cap')])
-
- v[model.reactions.index('Acid Base Equilibrium (Lac)')] = model.model_parameters['k_A_B_lac'] * \
- (c[model.species.index('S_lac_ion')] * (model.model_parameters['K_a_lac'] + c[model.species.index('S_H_ion')]) -
- model.model_parameters['K_a_lac'] * c[model.species.index('S_lac')])
-
- v[model.reactions.index('Acid Base Equilibrium (Ac)')] = model.model_parameters['k_A_B_ac'] * \
- (c[model.species.index('S_ac_ion')] * (model.model_parameters['K_a_ac'] + c[model.species.index('S_H_ion')]) -
- model.model_parameters['K_a_ac'] * c[model.species.index('S_ac')])
-
- v[model.reactions.index('Acid Base Equilibrium (CO2)')] = model.model_parameters['k_A_B_co2'] * \
- (c[model.species.index('S_hco3_ion')] * (model.model_parameters['K_a_co2'] + c[model.species.index('S_H_ion')]) -
- model.model_parameters['K_a_co2'] * c[model.species.index('S_IC')])
-
- v[model.reactions.index('Acid Base Equilibrium (In)')] = model.model_parameters['k_A_B_IN'] * \
- (c[model.species.index('S_nh3')] * (model.model_parameters['K_a_IN'] + c[model.species.index('S_H_ion')]) -
- model.model_parameters['K_a_IN'] * c[model.species.index('S_IC')])
-
- c[model.species.index('S_nh4_ion')] = c[model.species.index(
- 'S_IN')] - c[model.species.index('S_nh3')]
- c[model.species.index('S_co2')] = c[model.species.index(
- 'S_IC')] - c[model.species.index('S_hco3_ion')]
- I_pH_aa = (model.model_parameters["K_pH_aa"] ** model.model_parameters['nn_aa'])/(np.power(
- c[model.species.index('S_H_ion')], model.model_parameters['nn_aa']) + np.power(model.model_parameters["K_pH_aa"], model.model_parameters['nn_aa']))
-
- I_pH_ac = (model.model_parameters['K_pH_ac'] ** model.model_parameters["n_ac"])/(
- c[model.species.index('S_H_ion')] ** model.model_parameters['n_ac'] + model.model_parameters['K_pH_ac'] ** model.model_parameters['n_ac'])
-
- I_pH_pro = (model.model_parameters['K_pH_pro'] ** model.model_parameters["n_pro"])/(
- c[model.species.index('S_H_ion')] ** model.model_parameters['n_pro'] + model.model_parameters['K_pH_pro'] ** model.model_parameters['n_pro'])
-
- I_pH_bu = (model.model_parameters['K_pH_bu'] ** model.model_parameters["n_bu"])/(
- c[model.species.index('S_H_ion')] ** model.model_parameters['n_bu'] + model.model_parameters['K_pH_bu'] ** model.model_parameters['n_bu'])
-
- I_pH_va = (model.model_parameters['K_pH_va'] ** model.model_parameters["n_va"])/(
- c[model.species.index('S_H_ion')] ** model.model_parameters['n_va'] + model.model_parameters['K_pH_va'] ** model.model_parameters['n_va'])
-
- I_pH_cap = (model.model_parameters['K_pH_cap'] ** model.model_parameters["n_cap"])/(
- c[model.species.index('S_H_ion')] ** model.model_parameters['n_cap'] + model.model_parameters['K_pH_cap'] ** model.model_parameters['n_cap'])
-
- I_pH_h2 = (model.model_parameters['K_pH_h2']**model.model_parameters['n_h2'])/(
- c[model.species.index('S_H_ion')] ** model.model_parameters['n_h2'] + model.model_parameters['K_pH_h2']**model.model_parameters['n_h2'])
-
- I_IN_lim = 1 / \
- (1+(model.model_parameters['K_S_IN'] / (c[model.species.index('S_IN')]+10**-9)))
-
- I_h2_fa = 1 / (1+(c[model.species.index('S_h2')] /
- (model.model_parameters['K_I_h2_fa']+10**-9)))
-
- I_h2_c4 = 1 / (1+(c[model.species.index('S_h2')] /
- (model.model_parameters['K_I_h2_c4']+10**-9)))
-
- I_h2_pro = (1/(1+(c[model.species.index('S_h2')] /
- (model.model_parameters['K_I_h2_pro']+10**-9))))
-
- I_nh3 = 1/(1+(c[model.species.index('S_nh3')] /
- (model.model_parameters['K_I_nh3']+10**-9)))
-
- I_h2_oxidation=(1/(1+(c[model.species.index('S_h2')] /
- (model.model_parameters['K_I_h2_ox']+10**-9))))
-
- # I5 = (I_pH_aa * I_IN_lim)
- # I6 = I5.copy()
- # I7 = (I_pH_aa * I_IN_lim * I_h2_fa)
- # I8 = (I_pH_aa * I_IN_lim * I_h2_c4)
- # I9 = I8.copy()
- # I10 = (I_pH_pro * I_IN_lim * I_h2_pro)
- # I11 = (I_pH_ac * I_IN_lim * I_nh3)
- # I12 = (I_pH_h2 * I_IN_lim)
- # I13 = (I_pH_cap * I_IN_lim * I_h2_c4)
- # I14 = (I_pH_bu * I_IN_lim * I_h2_c4)
- # I15 = (I_pH_va * I_IN_lim * I_h2_c4)
- # I16 = I_IN_lim * I_nh3*I_pH_aa*I_h2_oxidation
- I5 = 1
- I6 = 1
- I7 = 1
- I8 = 1
- I9 = 1 #one
- I10 = 1
- I11 = 1
- I12 = 1
- I13 = 1
- I14 = 1
- I15 = 1
- I16 = 1
-
-
-
- v[model.reactions.index(
- 'TSS_Disintegration')] = model.model_parameters["k_dis_TSS"]*c[model.species.index('TSS')]
-
- v[model.reactions.index(
- 'TDS_Disintegration')] = model.model_parameters["k_dis_TDS"]*c[model.species.index('TDS')]
-
- v[model.reactions.index('Hydrolysis carbohydrates')
- ] = model.model_parameters['k_hyd_ch']*c[model.species.index('X_ch')]
-
- v[model.reactions.index('Hydrolysis proteins')
- ] = model.model_parameters['k_hyd_pr']*c[model.species.index('X_pr')]
-
- v[model.reactions.index('Hydrolysis lipids')
- ] = model.model_parameters['k_hyd_li']*c[model.species.index('X_li')]
-
- v[model.reactions.index('Su_to_et')] = model.model_parameters['k_m_su_et']*c[model.species.index('S_su')] / \
- (model.model_parameters['K_S_su_et']+c[model.species.index('S_su')])*c[model.species.index('X_su')]*I5
-
- v[model.reactions.index('Su_to_lac')] = model.model_parameters['k_m_su_lac']*c[model.species.index('S_su')] / \
- (model.model_parameters['K_S_su_lac']+c[model.species.index('S_su')]
- )*c[model.species.index('X_su')]/(c[model.species.index('X_su')]+model.model_parameters['K_S_X_su_lac'])*I5
-
- v[model.reactions.index('Su_to_ac')] = model.model_parameters['k_m_su_ac']*c[model.species.index('S_su')] / \
- (model.model_parameters['K_S_su_ac']+c[model.species.index('S_su')]
- )*c[model.species.index('X_su')]*I5
-
- v[model.reactions.index('Su_to_pro')] = model.model_parameters['k_m_su_pro']*c[model.species.index('S_su')] / \
- (model.model_parameters['K_S_su_pro']+c[model.species.index('S_su')]
- )*c[model.species.index('X_su')]/(c[model.species.index('X_su')]+model.model_parameters['K_S_X_su_pro'])*I5
-
-
- v[model.reactions.index('aas_to_lac')] = model.model_parameters['k_m_aa_lac']*c[model.species.index('S_aa')] / \
- (model.model_parameters['K_S_aa_lac']+c[model.species.index('S_aa')]
- )*c[model.species.index('X_aa')]/(c[model.species.index('X_aa')]+model.model_parameters['K_S_X_aa_lac'])*I6
-
- v[model.reactions.index('aas_to_pro')] = model.model_parameters['k_m_aa_pro']*c[model.species.index('S_aa')] / \
- (model.model_parameters['K_S_aa_pro']+c[model.species.index('S_aa')]
- )*c[model.species.index('X_aa')]/(c[model.species.index('X_aa')]+model.model_parameters['K_S_X_aa_pro'])*I6
-
- v[model.reactions.index('aas_to_ac')] = model.model_parameters['k_m_aa_ac']*c[model.species.index('S_aa')] / \
- (model.model_parameters['K_S_aa_ac']+c[model.species.index('S_aa')]
- )*c[model.species.index('X_aa')]/(c[model.species.index('X_aa')]+model.model_parameters['K_S_X_aa_ac'])*I6
-
- v[model.reactions.index('Uptake of LCFA')] = model.model_parameters['k_m_fa']*c[model.species.index('S_fa')] / \
- (model.model_parameters['K_S_fa'] +
- c[model.species.index('S_fa')])*c[model.species.index('X_fa')]/(c[model.species.index('X_fa')]+model.model_parameters['K_S_X_fa'])*I7
-
- v[model.reactions.index('Uptake of acetate_et')] = model.model_parameters['k_m_ac_et']*c[model.species.index('S_ac')]*c[model.species.index('S_et')] / \
- (model.model_parameters['K_S_ac']*c[model.species.index('S_ac')]+model.model_parameters['K_S_ac_et']*c[model.species.index('S_et')]+c[model.species.index('S_ac')]*c[model.species.index('S_et')]+10**-9
- )*c[model.species.index('X_ac_et')]/(c[model.species.index('X_ac_et')]+model.model_parameters['K_S_X_ac_et'])*I11
-
- v[model.reactions.index('Uptake of acetate_lac')] = model.model_parameters['k_m_ac_lac']*c[model.species.index('S_ac')]*c[model.species.index('S_lac')] / \
- (model.model_parameters['K_S_ac']*c[model.species.index('S_ac')]+model.model_parameters['K_S_ac_lac']*c[model.species.index('S_lac')]+c[model.species.index('S_ac')]*c[model.species.index('S_lac')]+10**-9
- )*c[model.species.index('X_ac_lac')]/(c[model.species.index('X_ac_lac')]+model.model_parameters['K_S_X_ac_lac'])*I11
-
- v[model.reactions.index('Uptake of propionate_et')] = model.model_parameters['k_m_pro_et']*c[model.species.index('S_pro')]*c[model.species.index('S_et')] / \
- (model.model_parameters['K_S_pro']*c[model.species.index('S_pro')]+model.model_parameters['K_S_pro_et']*c[model.species.index('S_et')]+c[model.species.index('S_pro')]*c[model.species.index('S_et')]+10**-9
- )*c[model.species.index('X_chain_et')]/(c[model.species.index('X_chain_et')]+model.model_parameters['K_S_X_chain_et'])*I10
-
- v[model.reactions.index('Uptake of propionate_lac')] = model.model_parameters['k_m_pro_lac']*c[model.species.index('S_pro')]*c[model.species.index('S_lac')] / \
- (model.model_parameters['K_S_pro']*c[model.species.index('S_pro')]+model.model_parameters['K_S_pro_lac']*c[model.species.index('S_lac')]+c[model.species.index('S_pro')]*c[model.species.index('S_lac')]+10**-9
- )*c[model.species.index('X_chain_lac')]/(c[model.species.index('X_chain_lac')]+model.model_parameters['K_S_X_chain_lac'])*I10
-
- v[model.reactions.index('Uptake of butyrate_et')] = model.model_parameters['k_m_bu_et']*c[model.species.index('S_bu')]*c[model.species.index('S_et')] / \
- (model.model_parameters['K_S_bu']*c[model.species.index('S_bu')]+model.model_parameters['K_S_bu_et']*c[model.species.index('S_et')]+c[model.species.index('S_bu')]*c[model.species.index('S_et')]+10**-9
- )*c[model.species.index('X_chain_et')]*I14
-
- v[model.reactions.index('Uptake of butyrate_lac')] = model.model_parameters['k_m_bu_lac']*c[model.species.index('S_bu')]*c[model.species.index('S_lac')] / \
- (model.model_parameters['K_S_bu']*c[model.species.index('S_bu')]+model.model_parameters['K_S_bu_lac']*c[model.species.index('S_lac')]+c[model.species.index('S_bu')]*c[model.species.index('S_lac')]+10**-9
- )*c[model.species.index('X_chain_lac')]/(c[model.species.index('X_chain_lac')]+model.model_parameters['K_S_X_chain_lac'])*I14
-
- v[model.reactions.index('Uptake of butyrate')] = model.model_parameters['k_m_bu']*c[model.species.index('S_bu')]/ \
- (model.model_parameters['K_S_bu']+c[model.species.index('S_bu')])*c[model.species.index('X_VFA_deg')]/(c[model.species.index('X_VFA_deg')]+model.model_parameters['K_S_X_VFA_deg'])*I14
-
- v[model.reactions.index('Uptake of valerate')] = model.model_parameters['k_m_va']*c[model.species.index('S_va')] / \
- (model.model_parameters['K_S_va']+c[model.species.index('S_va')])*c[model.species.index('X_VFA_deg')]/(c[model.species.index('X_VFA_deg')]+model.model_parameters['K_S_X_VFA_deg'])*I15
-
- v[model.reactions.index('Uptake of caproate')] = model.model_parameters['k_m_cap']*c[model.species.index('S_cap')] / \
- (model.model_parameters['K_S_cap']+c[model.species.index('S_cap')])*c[model.species.index('X_VFA_deg')]/(c[model.species.index('X_VFA_deg')]+model.model_parameters['K_S_X_VFA_deg'])*I13
-
- v[model.reactions.index('Methanogenessis from acetate and h2')] = model.model_parameters['k_m_h2_Me_ac']*c[model.species.index('S_h2')]*c[model.species.index('S_ac')] / \
- (model.model_parameters['K_S_h2_Me_ac']*c[model.species.index('S_h2')]+model.model_parameters['K_S_ac_Me']*c[model.species.index(
- 'S_ac')]+c[model.species.index('S_ac')]*c[model.species.index('S_h2')]+10**-9)*c[model.species.index('X_Me_ac')]*I12
-
- v[model.reactions.index('Methanogenessis from CO2 and h2')] = model.model_parameters['k_m_h2_Me_CO2']*c[model.species.index('S_h2')]*c[model.species.index('S_co2')] / \
- (model.model_parameters['K_S_h2_Me_CO2']*c[model.species.index('S_h2')]+model.model_parameters['K_S_CO2_Me']*c[model.species.index(
- 'S_co2')]+c[model.species.index('S_co2')]*c[model.species.index('S_h2')]+10**-9)*c[model.species.index('X_Me_CO2')]*I12
-
-
- v[model.reactions.index('Uptake of ethanol')] = model.model_parameters['k_m_et']*c[model.species.index('S_et')] / \
- (model.model_parameters['K_S_et']+c[model.species.index('S_et')]
- )*c[model.species.index("X_et")]/(c[model.species.index("X_et")]+model.model_parameters['K_S_X_et'])*I16
-
- v[model.reactions.index('Uptake of lactate')] = model.model_parameters['k_m_lac']*c[model.species.index('S_lac')] / \
- (model.model_parameters['K_S_lac']+c[model.species.index('S_lac')]
- )*c[model.species.index('X_lac')]/(c[model.species.index('X_lac')]+model.model_parameters['K_S_X_lac'])*I16
-
- v[model.reactions.index(
- 'Decay of Xsu')] = model.model_parameters['k_dec_X_su']*c[model.species.index('X_su')]
-
- v[model.reactions.index(
- 'Decay of Xaa')] = model.model_parameters['k_dec_X_aa']*c[model.species.index('X_aa')]
-
- v[model.reactions.index(
- 'Decay of Xfa')] = model.model_parameters['k_dec_X_fa']*c[model.species.index('X_fa')]
-
- v[model.reactions.index(
- 'Decay of X_ac_et')] = model.model_parameters['k_dec_X_ac']*c[model.species.index('X_ac_et')]
-
- v[model.reactions.index(
- 'Decay of X_ac_lac')] = model.model_parameters['k_dec_X_ac']*c[model.species.index('X_ac_lac')]
-
- v[model.reactions.index(
- 'Decay of X_chain_et')] = model.model_parameters['k_dec_X_chain_et']*c[model.species.index('X_chain_et')]
-
- v[model.reactions.index('Decay of X_chain_lac')
- ] = model.model_parameters['k_dec_X_chain_lac']*c[model.species.index('X_chain_lac')]
-
- v[model.reactions.index(
- 'Decay of X_VFA_deg')] = model.model_parameters['k_dec_X_VFA_deg']*c[model.species.index('X_VFA_deg')]
-
- v[model.reactions.index(
- 'Decay of X_Me_ac')] = model.model_parameters['k_dec_X_Me_ac']*c[model.species.index('X_Me_ac')]
-
- v[model.reactions.index(
- 'Decay of X_Me_CO2')] = model.model_parameters['k_dec_X_Me_CO2']*c[model.species.index('X_Me_CO2')]
-
- v[model.reactions.index(
- 'Decay of Xet')] = model.model_parameters['k_dec_X_et']*c[model.species.index('X_et')]
-
- v[model.reactions.index(
- 'Decay of Xlac')] = model.model_parameters['k_dec_X_lac']*c[model.species.index('X_lac')]
-
-
-
- p_gas_h2 = c[model.species.index('S_gas_h2')] * model.base_parameters["R"] * \
- model.base_parameters["T_op"] / 16
- p_gas_ch4 = c[model.species.index('S_gas_ch4')] * model.base_parameters["R"] * \
- model.base_parameters["T_op"] / 64
- p_gas_co2 = c[model.species.index('S_gas_co2')] * model.base_parameters["R"] * \
- model.base_parameters["T_op"]
- p_gas_h2o = 0.0313 * \
- np.exp(5290 *
- (1 / model.base_parameters["T_base"] - 1 / model.base_parameters["T_op"]))
- P_gas = p_gas_h2 + p_gas_ch4 + p_gas_co2 + p_gas_h2o
- q_gas = max(
- 0, (model.model_parameters['k_p'] * (P_gas - model.base_parameters['P_atm'])))
- v[model.reactions.index('Gas Transfer H2')] = model.model_parameters['k_L_a'] * \
- (c[model.species.index('S_h2')] - 16 *
- model.model_parameters['K_H_h2'] * p_gas_h2)
-
- v[model.reactions.index('Gas Transfer CH4')] = max(0,model.model_parameters['k_L_a'] * \
- (c[model.species.index('S_ch4')] - 64 *
- model.model_parameters['K_H_ch4'] * p_gas_ch4))
- v[model.reactions.index('Gas Transfer CO2')] = max(0,model.model_parameters['k_L_a'] * \
- (c[model.species.index('S_co2')] -
- model.model_parameters['K_H_co2'] * p_gas_co2))
-
- dCdt = np.matmul(model.s, v)
-
- phi = c[model.species.index('S_cation')]+c[model.species.index('S_nh4_ion')]-c[model.species.index('S_hco3_ion')]-(c[model.species.index('S_lac_ion')] / 88) - (c[model.species.index('S_ac_ion')] / 64) - (c[model.species.index('S_pro_ion')] /
- 112) - (c[model.species.index('S_bu_ion')] / 160)-(c[model.species.index('S_cap_ion')] / 230) - (c[model.species.index('S_va_ion')] / 208) - c[model.species.index('S_anion')]
- if 'S_H_ion' in model.control_state.keys():
- c[model.species.index('S_H_ion')]=model.control_state['S_H_ion']
- else:
- c[model.species.index('S_H_ion')] = (-1 * phi / 2) + \
- (0.5 * np.sqrt(phi**2 + 4 * model.model_parameters['K_w']))
-
- dCdt[0: model.species.__len__()-3] = dCdt[0: model.species.__len__()-3]+model.base_parameters['q_in'] / \
- model.base_parameters["V_liq"] * \
- (model.inlet_conditions[0: model.species.__len__(
- )-3]-c[0: model.species.__len__()-3].reshape(-1, 1))
-
- dCdt[model.species.__len__()-3:] = dCdt[model.species.__len__()-3:]+q_gas/model.base_parameters["V_gas"] * \
- (model.inlet_conditions[model.species.__len__() -
- 3:]-c[model.species.__len__()-3:].reshape(-1, 1))
-
- dCdt[[model.species.index('S_H_ion'), model.species.index(
- 'S_co2'), model.species.index('S_nh4_ion')], 0] = 0
-
- if c[model.species.index('S_IN')]<0.01:
- model.nitrogen_limited=True
- else:
- model.nitrogen_limited=False
-
- if model.switch == "DAE":
- # dCdt[model.species.index('S_h2')] = 0
-
- dCdt[model.species.index('S_va_ion'):model.species.index('S_co2')] = 0
-
- dCdt[model.species.index('S_nh3')] = 0
-
- if model.control_state.keys():
- for state in model.control_state.keys():
- c[model.species.index(state)]=model.control_state[state]
- dCdt[model.species.index(state)]=0
- model.info["Fluxes"]=v
- return dCdt[:, 0]
-
-
-
-
-if __name__ == "__main__":
-
- local_params=dict(
- model_parameters="/Users/parsaghadermarzi/Desktop/Academics/Projects/Anaerobic_Digestion_Modeling/16s_study/Database/ADM_Parameters/Modified_ADM_Model_Parameters.json",
- base_parameters="/Users/parsaghadermarzi/Desktop/Academics/Projects/Anaerobic_Digestion_Modeling/16s_study/Database/ADM_Parameters/Modified_ADM_Base_Parameters.json",
- initial_conditions="/Users/parsaghadermarzi/Desktop/Academics/Projects/Anaerobic_Digestion_Modeling/16s_study/Database/ADM_Parameters/Modified_ADM_Initial_Conditions.json",
- inlet_conditions="/Users/parsaghadermarzi/Desktop/Academics/Projects/Anaerobic_Digestion_Modeling/16s_study/Database/ADM_Parameters/Modified_ADM_Inlet_Conditions.json",
- species="/Users/parsaghadermarzi/Desktop/Academics/Projects/Anaerobic_Digestion_Modeling/16s_study/Database/ADM_Parameters/Modified_ADM_Species.json",
- reactions="/Users/parsaghadermarzi/Desktop/Academics/Projects/Anaerobic_Digestion_Modeling/16s_study/Database/ADM_Parameters/Modified_ADM_Reactions.json",
- )
- params=utils.load_multiple_json_files(local_params)
- # params_adm1=utils.load_multiple_json_files(configs.ADM1_LOCAL)
- # pd.DataFrame(params.reactions)
- # model=Model(model_parameters=params.model_parameters,
- # base_parameters=params.base_parameters,
- # initial_conditions=params.initial_conditions,
- # build_stoichiometric_matrix=build_adm1_stoichiometric_matrix,
- # ode_system=adm1_ode_sys,
- # inlet_conditions=params.inlet_conditions,
- # species=params.species,
- # reactions=params.reactions,
- # feed=Feed)
- # model.solve_model(t_eval=np.linspace(0, 30, 1000))
- params.initial_conditions['S_cation']=0.1
- mod_adm1 = Model(model_parameters=params.model_parameters,
- base_parameters=params.base_parameters,
- initial_conditions=params.initial_conditions,
- inlet_conditions=params.inlet_conditions,
- feed=DEFAULT_FEED,
- reactions=params.reactions,
- species=params.species,
- ode_system=e_adm_2_ode_sys,
- build_stoichiometric_matrix=build_e_adm_2_stoichiometric_matrix,
- control_state={
-
- },
- name="Modified_ADM1",
- switch="DAE",
- metagenome_report=None)
- mod_adm1.control_state['S_H_ion']=0.000001
- mod_adm1.time_limit=100000
-
- mod_adm1.dash_app(mod_adm1.solve_model(t_eval=np.linspace(0, 30, 1000)))
-
-
-
diff --git a/adtoolbox/bio_struct.py b/adtoolbox/bio_struct.py
deleted file mode 100644
index 17abfa7..0000000
--- a/adtoolbox/bio_struct.py
+++ /dev/null
@@ -1,73 +0,0 @@
-Nucleotides=["A","C","G","T","U"]
-DNA_Codons = {
- # 'M' - START, '_' - STOP
- "GCT": "A", "GCC": "A", "GCA": "A", "GCG": "A",
- "TGT": "C", "TGC": "C",
- "GAT": "D", "GAC": "D",
- "GAA": "E", "GAG": "E",
- "TTT": "F", "TTC": "F",
- "GGT": "G", "GGC": "G", "GGA": "G", "GGG": "G",
- "CAT": "H", "CAC": "H",
- "ATA": "I", "ATT": "I", "ATC": "I",
- "AAA": "K", "AAG": "K",
- "TTA": "L", "TTG": "L", "CTT": "L", "CTC": "L", "CTA": "L", "CTG": "L",
- "ATG": "M",
- "AAT": "N", "AAC": "N",
- "CCT": "P", "CCC": "P", "CCA": "P", "CCG": "P",
- "CAA": "Q", "CAG": "Q",
- "CGT": "R", "CGC": "R", "CGA": "R", "CGG": "R", "AGA": "R", "AGG": "R",
- "TCT": "S", "TCC": "S", "TCA": "S", "TCG": "S", "AGT": "S", "AGC": "S",
- "ACT": "T", "ACC": "T", "ACA": "T", "ACG": "T",
- "GTT": "V", "GTC": "V", "GTA": "V", "GTG": "V",
- "TGG": "W",
- "TAT": "Y", "TAC": "Y",
- "TAA": "_", "TAG": "_", "TGA": "_"
-}
-
-RNA_Codons = {
- # 'M' - START, '_' - STOP
- "GCU": "A", "GCC": "A", "GCA": "A", "GCG": "A",
- "UGU": "C", "UGC": "C",
- "GAU": "D", "GAC": "D",
- "GAA": "E", "GAG": "E",
- "UUU": "F", "UUC": "F",
- "GGU": "G", "GGC": "G", "GGA": "G", "GGG": "G",
- "CAU": "H", "CAC": "H",
- "AUA": "I", "AUU": "I", "AUC": "I",
- "AAA": "K", "AAG": "K",
- "UUA": "L", "UUG": "L", "CUU": "L", "CUC": "L", "CUA": "L", "CUG": "L",
- "AUG": "M",
- "AAU": "N", "AAC": "N",
- "CCU": "P", "CCC": "P", "CCA": "P", "CCG": "P",
- "CAA": "Q", "CAG": "Q",
- "CGU": "R", "CGC": "R", "CGA": "R", "CGG": "R", "AGA": "R", "AGG": "R",
- "UCU": "S", "UCC": "S", "UCA": "S", "UCG": "S", "AGU": "S", "AGC": "S",
- "ACU": "T", "ACC": "T", "ACA": "T", "ACG": "T",
- "GUU": "V", "GUC": "V", "GUA": "V", "GUG": "V",
- "UGG": "W",
- "UAU": "Y", "UAC": "Y",
- "UAA": "_", "UAG": "_", "UGA": "_"
-}
-
-Amino_Acid_MWs={
-'A': 71.03711,
-'C': 103.00919,
-'D': 115.02694,
-'E': 129.04259,
-'F': 147.06841,
-'G': 57.02146,
-'H': 137.05891,
-'I': 113.08406,
-'K': 128.09496,
-'L': 113.08406,
-'M': 131.04049,
-'N': 114.04293,
-'P': 97.05276,
-'Q': 128.05858,
-'R': 156.10111,
-'S': 87.03203,
-'T': 101.04768,
-'V': 99.06841,
-'W': 186.07931,
-'Y': 163.06333
-}
diff --git a/adtoolbox/cli.py b/adtoolbox/cli.py
old mode 100755
new mode 100644
index 49031bb..159e73b
--- a/adtoolbox/cli.py
+++ b/adtoolbox/cli.py
@@ -1,496 +1,533 @@
-import argparse
-from re import M
-import configs
-import metagenomics_report
-import core
-from adtoolbox import __version__,Main_Dir
-from rich.console import Console
-import rich
-import adm
-from rich.table import Table
-from rich.prompt import Prompt
-from rich import markdown
import json
import os
-import numpy as np
import subprocess
+from pathlib import Path
+
+import click
+import numpy as np
import pandas as pd
-import utils
-class AParser(argparse.ArgumentParser):
- def _print_message(self, message, file=None):
- rich.print(message, file=file)
+import rich
+from rich import markdown
+from rich.console import Console
+from rich.prompt import Prompt
+from rich.table import Table
-def main():
- console = Console()
- console.rule("[bold red]ADToolBox")
-
- db_class=core.Database(config=configs.Database())
-
- parser = AParser(prog="ADToolBox",
- description="ADToolBox, a toolbox for anaerobic digestion modeling",
- epilog="ADToolBox-Chan Lab at Colorado State University.")
- parser.add_argument("-v", "--version", action="version",help="Prints the version of ADToolBox")
- parser.version = f"[green]ADToolBox v{__version__}"
- subparsers = parser.add_subparsers(dest="ADToolbox_Module", help='ADToolbox Modules:')
-
- ### Database Module -------------------------------------------------------------
-
-
- #### FEED DATABASE ####
- subparser_database = subparsers.add_parser('Database', help='This module provides a command line interface to build or download the databases that ADToolbox requires')
- db_subp=subparser_database.add_subparsers(dest="database_module", help='Database commands:')
-
- db_subp.add_parser("initialize-feed-db", help="Initialize the Feed DB")
- add_feed=db_subp.add_parser("add-feed", help="Add a feed to the feed database")
- add_feed.add_argument("-n", "--name", action="store", help="Name of the feed to be added to the database")
- add_feed.add_argument("-c", "--carbohydrates", action="store", help="Carbohydrate content of the feed to be added to the database in percentage",required=True,type=float)
- add_feed.add_argument("-p", "--proteins", action="store", help="Protein content of the feed to be added to the database in percentage",required=True,type=float)
- add_feed.add_argument("-l", "--lipids", action="store", help="Lipid content of the feed to be added to the database in percentage",required=True,type=float)
- add_feed.add_argument("-t","--tss", action="store", help="Total suspended solid content of the feed to be added to the database in percentage",required=True,type=float)
- add_feed.add_argument("-s","--si", action="store", help="Soluble inert content of the feed to be added to the database in percentage",required=True,type=float)
- add_feed.add_argument("-x","--xi", action="store", help="particulate inert content of the feed to be added to the database in percentage",required=True,type=float)
- add_feed.add_argument("-r","--reference", action="store", help="Reference where the numbers come from",required=True)
-
- show_feed_db=db_subp.add_parser("show-feed-db", help="Shows the feed database")
- show_feed_db.add_argument("-f","--filter", action="store", help="Filters the feed database",required=False)
-
-
-### METAGENOMICS STUDIES DATABASE ###
- db_subp.add_parser("initialize-metagenomics-studies-db", help="Initialize the Metagenomics Studies DB")
- add_metagenomics_study=db_subp.add_parser("add-metagenomics-study", help="Add a metagenomics study to the Kbase")
- add_metagenomics_study.add_argument("-n", "--name", help="Metagenomics Study Name to be added to the Kbase",required=True)
- add_metagenomics_study.add_argument("-t", "--type", help="Metagenomics Study Type to be added to the Kbase",required=True)
- add_metagenomics_study.add_argument("-m", "--microbiome", help="Microbiome where the metagenomics study belongs to",required=True)
- add_metagenomics_study.add_argument("-s","--sample_accession", help="SRA accession ID for the sample",required=True)
- add_metagenomics_study.add_argument("-c","--comments", help="Comments on the study of interest",required=True)
- add_metagenomics_study.add_argument("-p","--study_accession", help="SRA accession ID for the project",required=True)
-
-### PROTEIN DATABASE ###
- db_subp.add_parser("initialize-protein-db", help="Generates the protein database for ADToolbox")
- add_protein=db_subp.add_parser("add-protein", help="Add a protein to the protein database")
- add_protein.add_argument("-i", "--uniport-id", action="store", help="Uniport ID of the protein to be added to the database",required=True)
- add_protein.add_argument("-n", "--name", action="store", help="The name to be attached to the protein, usally is EC number",required=True)
-
-
-### DOWNLOAD DATABASES ###
-
- db_subp.add_parser("download-reaction-db", help="Downloads the reaction database in CSV format")
- db_subp.add_parser("download-seed-reaction-db", help="Downloads the seed reaction database in JSON format")
- db_subp.add_parser("build-protein-db", help="Generates the protein database for ADToolbox")
- db_subp.add_parser("download-protein-db", help="Downloads the protein database in fasta format; You can alternatively build it from reaction database.")
- db_subp.add_parser("download-amplicon-to-genome-dbs", help="downloads amplicon to genome databases")
- db_subp.add_parser("download-all-databases", help="downloads all databases that are required by ADToolbox at once")
-
-###
-
- ### Metagenomics Module ###
- meta_config_defult=configs.Metagenomics()
- subparser_metagenomics= subparsers.add_parser('Metagenomics', help="This module provides the import metagenomics functionalities of ADToolbox in the command line")
- metag_subp=subparser_metagenomics.add_subparsers(dest='metag_subparser',help='Available Metagenomics Commands:')
-
- metag_subp_1=metag_subp.add_parser('download_from_sra', help='This module provides a command line interface to download metagenomics data from SRA')
- metag_subp_1.add_argument("-s","--sample_accession",action="store",help="SRA accession ID for the sample",required=True)
- metag_subp_1.add_argument("-o","--output-dir",action="store",help="Output directory to store the downloaded data",required=True)
- metag_subp_1.add_argument("-c","--container",action="store",help="Container to use for the download: None, docker, or singualrity",default="None")
-
- metag_subp_1=metag_subp.add_parser('download_genome', help='This module provides a command line interface to download genomes from NCBI')
- metag_subp_1.add_argument("-g","--genome_accession",action="store",help="NCBI accession ID for the genome",required=True)
- metag_subp_1.add_argument("-o","--output-dir",action="store",help="Output directory to store the downloaded data",required=True)
- metag_subp_1.add_argument("-c","--container",action="store",help="Container to use for the download: None, docker, or singualrity",default="None")
-
-
- metag_subp_1=metag_subp.add_parser('align-genome' , help='Align Genomes to the protein database of ADToolbox, or any other fasta with protein sequences')
- metag_subp_1.add_argument("-n", "--name", action="store", help="An appropriate name for the genome that is to be aligned",required=True)
- metag_subp_1.add_argument("-i", "--input-file", action="store", help="Input the address of the JSON file includeing information about the genomes to be aligned",required=True)
- metag_subp_1.add_argument("-o", "--output-dir", action="store", help="Output the directory to store the alignment results",default=meta_config_defult.genome_alignment_output,required=True)
- metag_subp_1.add_argument("-c", "--container", action="store", help="Container to use for the alignment: None, docker, or singualrity",default="None")
- metag_subp_1.add_argument("-d", "--protein-db-dir", action="store", help="Directory containing the protein database to be used for alignment",default=meta_config_defult.protein_db,required=False)
-
- metag_subp_1=metag_subp.add_parser('align-multiple-genomes' , help='Align multiple Genomes to the protein database of ADToolbox, or any other fasta with protein sequences')
- metag_subp_1.add_argument("-i", "--input-file", action="store", help="The address to a JSON file that holds the information about the genomes",required=True)
- metag_subp_1.add_argument("-o", "--output-dir", action="store", help="Output the directory to store the alignment results",required=True)
- metag_subp_1.add_argument("-c", "--container", action="store", help="Container to use for the alignment: None, docker, or singualrity",default="None")
- metag_subp_1.add_argument("-d", "--protein-db-dir", action="store", help="Directory containing the protein database to be used for alignment",default=meta_config_defult.protein_db,required=False)
-
- metag_subp_1=metag_subp.add_parser('find-representative-genomes' , help='Finds representative genomes from the repseqs fasta file')
- metag_subp_1.add_argument("-i", "--input-file", action="store", help="The address to the repseqs fasta file",required=True)
- metag_subp_1.add_argument("-o", "--output-dir", action="store", help="The directory of the output file",required=True)
- metag_subp_1.add_argument("-c", "--container", action="store", help="Container to use for the alignment: None, docker, or singualrity",default="None")
- metag_subp_1.add_argument("-s", "--similarity", action="store", help="Similarity cutoff for clustering",default=0.97,type=float)
- metag_subp_1.add_argument("-f", "--format", action="store", help="Format of the output file. Either json or csv",default="csv")
-
-
-
- # metag_subp_1=metag_subp.add_parser('Metagenomics_Report', help='This module provides a command line interface to the metagenomics report web interface')
- # metag_subp_1.add_argument("-j","--json-file",help="Address to the JSON file that contains the metagenomics report",required=True)
- # metag_subp_1.add_argument("-m","--mds",help="Uses MDS plot if true else uses TSNE",action="store_true")
- # metag_subp_1.add_argument("-t","--threed",help="whether to use 3D plot instead of 2d",action="store_true")
- # metag_subp_1.add_argument("-n","--not-normalize",help="Do not normalize the data",action="store_true")
-
-
-
- # metag_subp_3=metag_subp.add_parser('align-genomes', help='Align Genomes to the protein database of ADToolbox, or any other fasta with protein sequences')
- # metag_subp_3.add_argument("-i", "--input-file", action="store", help="Input the address of the JSON file includeing information about the genomes to be aligned")
- # metag_subp_3.add_argument("-d", "--protein-db-dir", action="store", help="Directory containing the protein database to be used for alignment",default=meta_config_defult.protein_db)
- # metag_subp_3.add_argument("-o", "--output-dir", action="store", help="Output the directory to store the alignment results",default=meta_config_defult.genome_alignment_output)
- # metag_subp_3.add_argument("-b", "--bit-score", action="store", help="Minimum Bit Score cutoff for alignment",default=meta_config_defult.bit_score)
- # metag_subp_3.add_argument("-e", "--e-value", action="store", help="Minimum e-vlaue score cutoff for alignment",default=meta_config_defult.e_value)
-
- # metag_subp_4=metag_subp.add_parser("make-json-from-genomes",help="Generates JSON file required by Align-Genomes for custom genomes.")
- # metag_subp_4.add_argument("-i", "--input-file", action="store", help="Input the address of the CSV file includeing information about the genomes to be aligned",required=True)
- # metag_subp_4.add_argument("-o", "--output-file", action="store", help="Output the directory to store the JSON file.",required=True)
-
- # metag_subp_5=metag_subp.add_parser('map-genomes-to-adm', help='maps JSON file with genome infromation to ADM reactions')
- # metag_subp_5.add_argument("-i","--input-file",action="store",help="Input the address of the JSON file includeing information about the alignment of the genomes to the protein database")
- # metag_subp_5.add_argument("-m","--model",action="store",help="Model determines which mapping system you'd like to use; Current options: 'Modified_adm_reactions'",default="Modified_adm_reactions")
- # metag_subp_5.add_argument("-o","--output-dir",action="store",help="address to store the JSON report to be loaded with a model")
-
-
- doc_parser=subparsers.add_parser('Documentations', help='Documentations for using AD Toolbox')
- doc_parser.add_argument("-s", "--show", action="store_true", help="Documentation for a specific module")
-
- ### ADM module ###
- subparser_adm = subparsers.add_parser('ADM', help='This module provides a command line interface for running and visualizing the ADToolbox ADM and modified ADM models')
- adm_subp=subparser_adm.add_subparsers(dest='adm_Subparser',help='Available ADM Commands:')
- subparser_adm1 = adm_subp.add_parser('adm1',help='Original ADM1 Model')
- subparser_adm1.add_argument("--model-parameters", action="store", help="Model parameters for ADM 1")
- subparser_adm1.add_argument("--base-parameters", action="store", help="Provide json file with base parameters for original ADM1")
- subparser_adm1.add_argument("--initial-conditions", action="store", help="Provide json file with initial conditions for original ADM1")
- subparser_adm1.add_argument("--inlet-conditions", action="store", help="Provide json file with inlet conditions for original ADM1")
- subparser_adm1.add_argument("--reactions", action="store", help="Provide json file with reactions for original ADM1")
- subparser_adm1.add_argument("--species", action="store", help="Provide json file with species for original ADM1")
- subparser_adm1.add_argument("--metagenome-report", action="store", help="Provide json file with metagenome report for original ADM1")
- subparser_adm1.add_argument("--report", action="store", help="Describe how to report the results of original ADM1. Current options are: 'dash' and 'csv'")
-
- mod_adm_subp=adm_subp.add_parser('e-adm',help='eADM Model')
- mod_adm_subp.add_argument("--model-parameters", action="store", help="Model parameters for Modified ADM")
- mod_adm_subp.add_argument("--base-parameters", action="store", help="Provide json file with base parameters for modified ADM")
- mod_adm_subp.add_argument("--initial-conditions", action="store", help="Provide json file with initial conditions for modified ADM")
- mod_adm_subp.add_argument("--inlet-conditions", action="store", help="Provide json file with inlet conditions for modified ADM")
- mod_adm_subp.add_argument("--reactions", action="store", help="Provide json file with reactions for modified ADM")
- mod_adm_subp.add_argument("--species", action="store", help="Provide json file with species for modified ADM")
- mod_adm_subp.add_argument("--metagenome-report", action="store", help="Provide json file with metagenome report for modified ADM")
- mod_adm_subp.add_argument("--control-states", action="store", help="Provide a json file that contains the control states, and their values ")
- mod_adm_subp.add_argument("--report", action="store", help="Describe how to report the results of modified ADM. Current options are: 'dash' and 'csv'")
-
- # Mod_ADM_args=subparser_adm.add_subparsers(help='Modified ADM Args:')
-
- subparser_Configs = subparsers.add_parser('Configs', help='Configurations of ADToolBox')
- subparser_Configs.add_argument("-s", "--set-base-dir", action="store", help="Set the base directory for ADToolBox to work with")
- subparser_Configs.add_argument("-g", "--get-base-dir", action="store_true", help="Get the current base directory for ADToolBox")
-
- ### PARSE ARGS ###
-
- args=parser.parse_args()
-
- ### CLI config block ###
- if args.ADToolbox_Module == 'Configs':
-
- if args.set_base_dir:
- configs.set_base_dir(args.set_base_dir)
- elif args.get_base_dir:
- print(configs.get_base_dir())
- ### Database ###
-
- if args.ADToolbox_Module == 'Database' and "database_module" in args:
- if args.database_module=="initialize-feed-db":
- db_class.initialize_feed_db()
- elif args.database_module=="add-feed":
- feed=core.Feed(name=args.name,
- carbohydrates=args.carbohydrates,
- proteins=args.proteins,
- lipids=args.lipids,
- tss=args.tss,
- si=args.si,
- xi=args.xi,
- reference=args.reference)
- db_class.add_feed_to_feed_db(feed=feed)
-
- elif args.database_module=="show-feed-db":
- if args.filter:
- t=db_class.get_feed_from_feed_db(field_name="name",field_value=args.filter)
- else:
- t=db_class.get_feed_from_feed_db(field_name="name",query="")
- if t:
- feed_table = Table(title="Feed Database",safe_box=True,expand=True)
- for i in t[0].to_dict().keys():
- feed_table.add_column(i, justify="center", style="cyan",max_width=20)
- for i in t:
- feed_table.add_row(*map(str,list(i.to_dict().values())))
- console.print(feed_table)
- if args.ADToolbox_Module == 'Database' and "database_module" in args:
- if args.database_module=="initialize-metagenomics-studies-db":
- db_class.initialize_metagenomics_studies_db()
- elif args.database_module=="add-metagenomics-study":
- metagenomics_study=core.MetagenomicsStudy(name=args.name,
- study_type=args.type,
- microbiome=args.microbiome,
- sample_accession=args.sample_accession,
- comments=args.comments,
- study_accession=args.study_accession)
- db_class.add_metagenomics_study_to_metagenomics_studies_db(metagenomics_study=metagenomics_study)
-
-
-
- if args.ADToolbox_Module == 'Database' and "database_module" in args:
- if args.database_module=="initialize-protein-db":
- db_class.initialize_protein_db()
- elif args.database_module=="add-protein":
- db_class.add_protein_to_protein_db(protein_id=args.uniport_id,header_tail=args.name)
-
- elif args.database_module=="download-reaction-db":
- db_class.download_reaction_database()
-
- elif args.database_module=="download-seed-reaction-db":
- db_class.download_seed_databases()
-
- elif args.database_module=="build-protein-db":
- ecs=core.Database.ec_from_csv(configs.Database().csv_reaction_db)
- db_class.protein_db_from_ec(ecs)
- rich.print("[green]Protein DB built successfully")
-
- elif args.database_module=="download-feed-db":
- db_class.download_feed_database()
-
- elif args.database_module=="download-protein-db":
- db_class.download_protein_database()
-
- elif args.database_module=="download-amplicon-to-genome-dbs":
- db_class.download_amplicon_to_genome_db()
-
- elif args.database_module=="download-all-databases":
- db_class.download_all_databases()
-
-
-
-
-
-
-
- #### Metagenomics Module #####
- if args.ADToolbox_Module == 'Metagenomics' and "metag_subparser" in args and args.metag_subparser=="download_from_SRA":
- prefetch_script,sample_metadata=core.Metagenomics(meta_config_defult).seqs_from_sra(accession=args.sample_accession,target_dir=args.output_dir,container=args.container)
- subprocess.run(f"{prefetch_script}",shell=True)
- # core.Metagenomics(meta_config_defult).amplicon2genome()
- ### UNDER CONSTRUCTION ###
-
- if args.ADToolbox_Module == 'Metagenomics' and "metag_subparser" in args and args.metag_subparser=="download_genome":
- subprocess.run(core.Metagenomics(meta_config_defult).download_genome(identifier=args.genome_accession,
- output_dir=args.output_dir,
- container=args.container),shell=True)
-
-
- if args.ADToolbox_Module == 'Metagenomics' and "metag_subparser" in args and args.metag_subparser=="align-genome":
- if args.protein_db_dir:
- meta_config_defult.protein_db=args.protein_db_dir
- mg=core.Metagenomics(meta_config_defult).align_genome_to_protein_db(
- address=args.input_file,
- outdir=args.output_dir,
- name=args.name,
- container=args.container
+from adtoolbox import __version__, adm, configs, core, utils
+
+
+CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"]}
+console = Console()
+
+
+def _database(**config_overrides):
+ return core.Database(config=configs.Database(**config_overrides))
+
+
+def _metagenomics_config(protein_db=None, amplicon_to_genome_db=None):
+ config = configs.Metagenomics()
+ if protein_db:
+ config.protein_db = protein_db
+ if amplicon_to_genome_db:
+ config.amplicon2genome_db = amplicon_to_genome_db
+ matches = list(Path(amplicon_to_genome_db).rglob(config.gtdb_dir))
+ config.gtdb_dir_fasta = str(matches[0]) if matches else None
+ return config
+
+
+def _prompt_path(value, prompt, *, exists=None, file_okay=True, dir_okay=True, writable=False):
+ path_type = click.Path(exists=bool(exists), file_okay=file_okay, dir_okay=dir_okay, writable=writable)
+ path = value or click.prompt(prompt, type=path_type)
+ return os.path.abspath(os.path.expanduser(path_type.convert(path, None, None)))
+
+
+def _database_config_from_dir(output_dir):
+ return {"database_dir": output_dir}
+
+
+def _model_paths_from_dir(parameters_dir, prefix):
+ return {
+ "model_parameters": os.path.join(parameters_dir, f"{prefix}_model_parameters.json"),
+ "base_parameters": os.path.join(parameters_dir, f"{prefix}_base_parameters.json"),
+ "initial_conditions": os.path.join(parameters_dir, f"{prefix}_initial_conditions.json"),
+ "inlet_conditions": os.path.join(parameters_dir, f"{prefix}_inlet_conditions.json"),
+ "reactions": os.path.join(parameters_dir, f"{prefix}_reactions.json"),
+ "species": os.path.join(parameters_dir, f"{prefix}_species.json"),
+ }
+
+
+def _resolve_model_paths(parameters_dir, prefix, legacy_prefixes=(), **overrides):
+ if parameters_dir:
+ parameters_dir = _prompt_path(parameters_dir, "ADM parameter directory", exists=True, file_okay=False, dir_okay=True)
+ elif not any(overrides.values()):
+ parameters_dir = _prompt_path(None, "ADM parameter directory", exists=True, file_okay=False, dir_okay=True)
+
+ paths = _model_paths_from_dir(parameters_dir, prefix) if parameters_dir else {}
+ if parameters_dir and legacy_prefixes:
+ for key, path in list(paths.items()):
+ if os.path.exists(path):
+ continue
+ for legacy_prefix in legacy_prefixes:
+ legacy_path = _model_paths_from_dir(parameters_dir, legacy_prefix)[key]
+ if os.path.exists(legacy_path):
+ paths[key] = legacy_path
+ break
+ resolved = {}
+ for key, value in overrides.items():
+ resolved[key] = value or paths.get(key)
+ if not resolved[key]:
+ resolved[key] = _prompt_path(None, key.replace("_", " ").title() + " JSON path", exists=True, file_okay=True, dir_okay=False)
+ return resolved
+
+
+def _load_model_payload(models_json, model_key, *, parameters_dir, prefix, legacy_prefixes=(), **paths):
+ if models_json:
+ models_json = _prompt_path(models_json, "ADM models JSON", exists=True, file_okay=True, dir_okay=False)
+ try:
+ return utils.load_model_json(models_json, model_key)
+ except (KeyError, TypeError) as exc:
+ raise click.ClickException(str(exc)) from exc
+
+ paths = _resolve_model_paths(
+ parameters_dir,
+ prefix,
+ legacy_prefixes=legacy_prefixes,
+ **paths,
+ )
+ return utils.load_multiple_json_files(paths)._asdict()
+
+
+def _load_json(path):
+ with open(path) as f:
+ return json.load(f)
+
+
+def _print_feed_table(feeds):
+ if not feeds:
+ return
+
+ feed_table = Table(title="Feed Database", safe_box=True, expand=True)
+ for column in feeds[0].to_dict().keys():
+ feed_table.add_column(column, justify="center", style="cyan", max_width=20)
+ for feed in feeds:
+ feed_table.add_row(*map(str, feed.to_dict().values()))
+ console.print(feed_table)
+
+
+def _write_representative_genomes(results, output_dir, output_format):
+ if output_format == "csv":
+ pd.DataFrame.from_dict(results, orient="index").to_csv(
+ os.path.join(output_dir, "representative_genomes.csv")
)
- subprocess.run(mg,shell=True)
-
- if args.ADToolbox_Module == 'Metagenomics' and "metag_subparser" in args and args.metag_subparser=="align-multiple-genomes":
- if args.protein_db_dir:
- meta_config_defult.protein_db=args.protein_db_dir
- with open(args.input_file) as f:
- genomes=json.load(f)
- for genome in genomes:
- mg=core.Metagenomics(meta_config_defult).align_genome_to_protein_db(
- address=genomes[genome],
- outdir=args.output_dir,
- name=genome,
- container=args.container
- )
- subprocess.run(mg,shell=True)
-
- if args.ADToolbox_Module == 'Metagenomics' and "metag_subparser" in args and args.metag_subparser=="find-representative-genomes":
- meta_config_defult.vsearch_similarity=args.similarity
- print(args.output_dir)
- mg=core.Metagenomics(meta_config_defult).align_to_gtdb(
- query_dir=args.input_file,
- output_dir=args.output_dir,
- container=args.container,
+ elif output_format == "json":
+ with open(os.path.join(output_dir, "representative_genomes.json"), "w") as f:
+ json.dump(results, f)
+ else:
+ raise click.ClickException("Please provide a valid format for the output file")
+
+
+def _report_adm_solution(model, solution, report):
+ if report in (None, "dash"):
+ model.dash_app(solution)
+ elif report == "csv":
+ address = Prompt.ask("\n[yellow]Where do you want to save the csv file? ")
+ model.csv_report(solution, address)
+ else:
+ raise click.ClickException("Please provide a valid report option")
+
+
+@click.group(
+ name="ADToolBox",
+ context_settings=CONTEXT_SETTINGS,
+ help="ADToolBox, a toolbox for anaerobic digestion modeling",
+ no_args_is_help=True,
+ invoke_without_command=True,
+)
+@click.version_option(__version__, "-v", "--version", prog_name="ADToolBox")
+def main():
+ pass
+
+
+@main.group(name="Database", help="Build or download databases required by ADToolbox.", no_args_is_help=True)
+def database():
+ pass
+
+
+@database.command(name="initialize-feed-db", help="Initialize the Feed DB.")
+@click.option("--feed-db", help="Path where the feed database TSV should be created.")
+def initialize_feed_db(feed_db):
+ feed_db = _prompt_path(feed_db, "Feed database TSV path", file_okay=True, dir_okay=False, writable=True)
+ _database(feed_db=feed_db).initialize_feed_db()
+
+
+@database.command(name="add-feed", help="Add a feed to the feed database.")
+@click.option("--feed-db", help="Path to the feed database TSV.")
+@click.option("-n", "--name", required=True, help="Name of the feed to be added to the database.")
+@click.option("-c", "--carbohydrates", required=True, type=float, help="Carbohydrate content in percent.")
+@click.option("-p", "--proteins", required=True, type=float, help="Protein content in percent.")
+@click.option("-l", "--lipids", required=True, type=float, help="Lipid content in percent.")
+@click.option("-t", "--tss", required=True, type=float, help="Total suspended solid content in percent.")
+@click.option("-s", "--si", required=True, type=float, help="Soluble inert content in percent.")
+@click.option("-x", "--xi", required=True, type=float, help="Particulate inert content in percent.")
+@click.option("-r", "--reference", required=True, help="Reference where the numbers come from.")
+def add_feed(feed_db, name, carbohydrates, proteins, lipids, tss, si, xi, reference):
+ feed_db = _prompt_path(feed_db, "Feed database TSV path", file_okay=True, dir_okay=False, writable=True)
+ feed = core.Feed(
+ name=name,
+ carbohydrates=carbohydrates,
+ proteins=proteins,
+ lipids=lipids,
+ tss=tss,
+ si=si,
+ xi=xi,
+ reference=reference,
+ )
+ _database(feed_db=feed_db).add_feed_to_feed_db(feed=feed)
+
+
+@database.command(name="show-feed-db", help="Show the feed database.")
+@click.option("--feed-db", help="Path to the feed database TSV.")
+@click.option("-f", "--filter", "feed_filter", help="Filter the feed database by feed name.")
+def show_feed_db(feed_db, feed_filter):
+ feed_db = _prompt_path(feed_db, "Feed database TSV path", exists=True, file_okay=True, dir_okay=False)
+ db = _database(feed_db=feed_db)
+ if feed_filter:
+ feeds = db.get_feed_from_feed_db(field_name="name", query=feed_filter)
+ else:
+ feeds = db.get_feed_from_feed_db(field_name="name", query="")
+ _print_feed_table(feeds)
+
+
+@database.command(name="initialize-metagenomics-studies-db", help="Initialize the Metagenomics Studies DB.")
+@click.option("--studies-db", help="Path where the metagenomics studies TSV should be created.")
+def initialize_metagenomics_studies_db(studies_db):
+ studies_db = _prompt_path(studies_db, "Metagenomics studies TSV path", file_okay=True, dir_okay=False, writable=True)
+ _database(studies_local={"metagenomics_studies": studies_db}).initialize_metagenomics_studies_db()
+
+
+@database.command(name="add-metagenomics-study", help="Add a metagenomics study to the database.")
+@click.option("--studies-db", help="Path to the metagenomics studies TSV.")
+@click.option("-n", "--name", required=True, help="Metagenomics study name.")
+@click.option("-t", "--type", "study_type", required=True, help="Metagenomics study type.")
+@click.option("-m", "--microbiome", required=True, help="Microbiome where the study belongs.")
+@click.option("-s", "--sample-accession", required=True, help="SRA accession ID for the sample.")
+@click.option("-c", "--comments", required=True, help="Comments on the study of interest.")
+@click.option("-p", "--study-accession", required=True, help="SRA accession ID for the project.")
+def add_metagenomics_study(studies_db, name, study_type, microbiome, sample_accession, comments, study_accession):
+ studies_db = _prompt_path(studies_db, "Metagenomics studies TSV path", file_okay=True, dir_okay=False, writable=True)
+ study = core.MetagenomicsStudy(
+ name=name,
+ study_type=study_type,
+ microbiome=microbiome,
+ sample_accession=sample_accession,
+ comments=comments,
+ study_accession=study_accession,
+ )
+ _database(studies_local={"metagenomics_studies": studies_db}).add_metagenomics_study_to_metagenomics_studies_db(metagenomics_study=study)
+
+
+@database.command(name="initialize-protein-db", help="Initialize the protein database.")
+@click.option("--protein-db", help="Path where the protein FASTA database should be created.")
+def initialize_protein_db(protein_db):
+ protein_db = _prompt_path(protein_db, "Protein database FASTA path", file_okay=True, dir_okay=False, writable=True)
+ _database(protein_db=protein_db).initialize_protein_db()
+
+
+@database.command(name="add-protein", help="Add a protein to the protein database.")
+@click.option("--protein-db", help="Path to the protein FASTA database.")
+@click.option("-i", "--uniprot-id", "--uniport-id", required=True, help="UniProt ID of the protein.")
+@click.option("-n", "--name", required=True, help="Name attached to the protein, usually an EC number.")
+def add_protein(protein_db, uniprot_id, name):
+ protein_db = _prompt_path(protein_db, "Protein database FASTA path", file_okay=True, dir_okay=False, writable=True)
+ _database(protein_db=protein_db).add_protein_to_protein_db(protein_id=uniprot_id, header_tail=name)
+
+
+@database.command(name="download-reaction-db", help="Download the reaction database in CSV format.")
+@click.option("--reaction-db", help="Path where the reaction metadata CSV should be saved.")
+def download_reaction_db(reaction_db):
+ reaction_db = _prompt_path(reaction_db, "Reaction metadata CSV path", file_okay=True, dir_okay=False, writable=True)
+ _database(csv_reaction_db=reaction_db).download_reaction_database()
+
+
+@database.command(name="download-seed-reaction-db", help="Download the seed reaction database in JSON format.")
+@click.option("--seed-reaction-db", help="Path where the SEED reactions JSON should be saved.")
+@click.option("--seed-compound-db", help="Path where the SEED compounds JSON should be saved.")
+def download_seed_reaction_db(seed_reaction_db, seed_compound_db):
+ seed_reaction_db = _prompt_path(seed_reaction_db, "SEED reactions JSON path", file_okay=True, dir_okay=False, writable=True)
+ seed_compound_db = _prompt_path(seed_compound_db, "SEED compounds JSON path", file_okay=True, dir_okay=False, writable=True)
+ _database(reaction_db=seed_reaction_db, compound_db=seed_compound_db).download_seed_databases()
+
+
+@database.command(name="build-protein-db", help="Generate the protein database for ADToolbox.")
+@click.option("--reaction-db", help="Path to the reaction metadata CSV.")
+@click.option("--protein-db", help="Path where the protein FASTA database should be saved.")
+def build_protein_db(reaction_db, protein_db):
+ reaction_db = _prompt_path(reaction_db, "Reaction metadata CSV path", exists=True, file_okay=True, dir_okay=False)
+ protein_db = _prompt_path(protein_db, "Protein database FASTA path", file_okay=True, dir_okay=False, writable=True)
+ db = _database(csv_reaction_db=reaction_db, protein_db=protein_db)
+ ecs = core.Database.ec_from_csv(reaction_db)
+ db.protein_db_from_ec(ecs)
+ rich.print("[green]Protein DB built successfully")
+
+
+@database.command(name="download-feed-db", help="Download the feed database.")
+@click.option("--feed-db", help="Path where the feed database TSV should be saved.")
+def download_feed_db(feed_db):
+ feed_db = _prompt_path(feed_db, "Feed database TSV path", file_okay=True, dir_okay=False, writable=True)
+ _database(feed_db=feed_db).download_feed_database()
+
+
+@database.command(name="download-protein-db", help="Download the protein database in FASTA format.")
+@click.option("--protein-db", help="Path where the protein FASTA database should be saved.")
+def download_protein_db(protein_db):
+ protein_db = _prompt_path(protein_db, "Protein database FASTA path", file_okay=True, dir_okay=False, writable=True)
+ _database(protein_db=protein_db).download_protein_database()
+
+
+@database.command(name="download-amplicon-to-genome-dbs", help="Download amplicon-to-genome databases.")
+@click.option("--output-dir", help="Directory where the amplicon-to-genome databases should be saved.")
+def download_amplicon_to_genome_dbs(output_dir):
+ output_dir = _prompt_path(output_dir, "Amplicon-to-genome database directory", file_okay=False, dir_okay=True, writable=True)
+ _database(amplicon_to_genome_db=output_dir).download_amplicon_to_genome_db()
+
+
+@database.command(name="download-all-databases", help="Download all databases required by ADToolbox.")
+@click.option("--output-dir", help="Directory where all downloaded databases should be saved.")
+def download_all_databases(output_dir):
+ output_dir = _prompt_path(output_dir, "Database download directory", file_okay=False, dir_okay=True, writable=True)
+ _database(**_database_config_from_dir(output_dir)).download_all_databases()
+
+
+@main.group(
+ name="Metagenomics",
+ help="Import and process metagenomics data from the command line.",
+ no_args_is_help=True,
+)
+def metagenomics():
+ pass
+
+
+@metagenomics.command(name="download_from_sra", help="Download metagenomics data from SRA.")
+@click.option("-s", "--sample-accession", required=True, help="SRA accession ID for the sample.")
+@click.option("-o", "--output-dir", help="Output directory for downloaded data.")
+@click.option("-c", "--container", default="None", show_default=True, help="Container: None, docker, or singularity.")
+def download_from_sra(sample_accession, output_dir, container):
+ output_dir = _prompt_path(output_dir, "Downloaded SRA output directory", file_okay=False, dir_okay=True, writable=True)
+ config = _metagenomics_config()
+ prefetch_script, _ = core.Metagenomics(config).seqs_from_sra(
+ accession=sample_accession,
+ target_dir=output_dir,
+ container=container,
+ )
+ subprocess.run(prefetch_script, shell=True)
+
+
+@metagenomics.command(name="download_genome", help="Download a genome from NCBI.")
+@click.option("-g", "--genome-accession", required=True, help="NCBI accession ID for the genome.")
+@click.option("-o", "--output-dir", help="Output directory for downloaded data.")
+@click.option("-c", "--container", default="None", show_default=True, help="Container: None, docker, or singularity.")
+def download_genome(genome_accession, output_dir, container):
+ output_dir = _prompt_path(output_dir, "Downloaded genome output directory", file_okay=False, dir_okay=True, writable=True)
+ config = _metagenomics_config()
+ script = core.Metagenomics(config).download_genome(
+ identifier=genome_accession,
+ output_dir=output_dir,
+ container=container,
+ )
+ subprocess.run(script, shell=True)
+
+
+@metagenomics.command(name="align-genome", help="Align one genome to the ADToolbox protein database.")
+@click.option("-n", "--name", required=True, help="Name for the genome being aligned.")
+@click.option("-i", "--input-file", help="Genome FASTA or JSON file containing genome information.")
+@click.option("-o", "--output-dir", help="Output directory for alignment results.")
+@click.option("-c", "--container", default="None", show_default=True, help="Container: None, docker, or singularity.")
+@click.option("-d", "--protein-db", "--protein-db-dir", help="Path to the protein FASTA database.")
+def align_genome(name, input_file, output_dir, container, protein_db):
+ input_file = _prompt_path(input_file, "Genome input file", exists=True, file_okay=True, dir_okay=False)
+ output_dir = _prompt_path(output_dir, "Alignment output directory", file_okay=False, dir_okay=True, writable=True)
+ protein_db = _prompt_path(protein_db, "Protein database FASTA path", exists=True, file_okay=True, dir_okay=False)
+ config = _metagenomics_config(protein_db)
+ script = core.Metagenomics(config).align_genome_to_protein_db(
+ address=input_file,
+ outdir=output_dir,
+ name=name,
+ container=container,
+ )
+ subprocess.run(script, shell=True)
+
+
+@metagenomics.command(name="align-multiple-genomes", help="Align multiple genomes to the ADToolbox protein database.")
+@click.option("-i", "--input-file", help="JSON file containing genome names and input files.")
+@click.option("-o", "--output-dir", help="Output directory for alignment results.")
+@click.option("-c", "--container", default="None", show_default=True, help="Container: None, docker, or singularity.")
+@click.option("-d", "--protein-db", "--protein-db-dir", help="Path to the protein FASTA database.")
+def align_multiple_genomes(input_file, output_dir, container, protein_db):
+ input_file = _prompt_path(input_file, "Genome manifest JSON path", exists=True, file_okay=True, dir_okay=False)
+ output_dir = _prompt_path(output_dir, "Alignment output directory", file_okay=False, dir_okay=True, writable=True)
+ protein_db = _prompt_path(protein_db, "Protein database FASTA path", exists=True, file_okay=True, dir_okay=False)
+ config = _metagenomics_config(protein_db)
+ genomes = _load_json(input_file)
+ for genome, address in genomes.items():
+ script = core.Metagenomics(config).align_genome_to_protein_db(
+ address=address,
+ outdir=output_dir,
+ name=genome,
+ container=container,
)
- subprocess.run(mg,shell=True)
- res=core.Metagenomics(meta_config_defult).get_genomes_from_gtdb_alignment(args.output_dir)
- if args.format=="csv":
- pd.DataFrame.from_dict(res,orient="index").to_csv(os.path.join(args.output_dir,"representative_genomes.csv"))
- elif args.format=="json":
- with open(os.path.join(args.output_dir,"representative_genomes.json"),"w") as f:
- json.dump(res,f)
- else:
- raise ValueError("Please provide a valid format for the output file")
-
-
-
-
-
- # if args.ADToolbox_Module == 'Metagenomics' and "metag_Subparser" in args and args.metag_Subparser=="align-genomes":
- # if "input_file" in args and "output_dir" in args:
- # Meta_Config=configs.Metagenomics(genomes_json_info=args.input_file,genome_alignment_output=args.output_dir,genome_alignment_output_json=os.path.join(args.output_dir,"Alignment_Info.json"))
- # core.Metagenomics(Meta_Config).Align_Genomes()
-
-
- # if args.ADToolbox_Module == 'Metagenomics' and "metag_subparser" in args:
- # print(args)
- # ncomp=3 if args.threed else 2
- # method="MDS" if args.mds else "TSNE"
- # normalize=False if args.not_normalize else True
- # metagenomics_report.main(args.json_file,method=method,normalize=normalize,n_components=ncomp)
-
-
-
-
-
- if args.ADToolbox_Module == 'Documentations' and args.show:
- with open(configs.Documentation().readme,'r') as f:
- T=f.read()
- console.print(markdown.Markdown(T))
-
- if args.ADToolbox_Module == 'Database' and "Database_Module" in args and args.Database_Module=="build-protein-db" :
- ecs=db_class.ec_from_csv(configs.Database().csv_reaction_db)
- rich.print(u"[bold green]\u2713 All EC numbers were extracted!\n")
- db_class._initialize_database()
- db_class.protein_db_from_ec(ecs)
- rich.print(u"\n[bold green]\u2713 Protein Database was built!\n")
-
-
- if args.ADToolbox_Module == 'Database' and "Database_Module" in args and args.Database_Module=="download-feed-db":
- db_class.download_feed_database(db_class.config.feed_db)
- rich.print(u"[bold green]\u2713 Feed Database was downloaded!\n")
-
- if args.ADToolbox_Module == 'Database' and "Database_Module" in args and args.Database_Module=="download-reaction-db":
- db_class.download_reaction_database(db_class.config.csv_reaction_db)
- rich.print(u"[bold green]\u2713 Reaction Database was downloaded!\n")
-
- if args.ADToolbox_Module == 'Database' and "Database_Module" in args and args.Database_Module=="download-protein-db":
- db_class.download_protein_database(db_class.config.protein_db)
- rich.print(u"[bold green]\u2713 Protein Database was downloaded!\n")
-
- if args.ADToolbox_Module == 'Database' and "Database_Module" in args and args.Database_Module=="download-seed-reaction-db":
- db_class.download_seed_databases(db_class.config.reaction_db)
- rich.print(u"[bold green]\u2713 SEED Reaction Database was downloaded!\n")
-
- if args.ADToolbox_Module == 'Database' and "Database_Module" in args and args.Database_Module=="show-feed-db":
- with open(configs.Database().feed_db, 'r') as f:
- feed_db = json.load(f)
- colnames=feed_db[0].keys()
- feed_table = Table(title="Feed Database",expand=True,safe_box=True)
-
- for i in colnames:
- feed_table.add_column(i, justify="center", style="cyan", no_wrap=True)
- for i in feed_db:
- feed_table.add_row(*map(str,list(i.values())))
- console.print(feed_table)
-
-
-
- if "ADToolbox_Module" in args and args.ADToolbox_Module == 'ADM' and "adm_Subparser" in args and args.adm_Subparser == 'adm1':
-
- if args.model_parameters:
- with open(args.model_parameters) as f:
- adm_model_parameters=json.load(f)
- else:
- with open(configs.ADM1_LOCAL["model_parameters"]) as f:
- adm_model_parameters=json.load(f)
-
- if args.base_parameters:
- with open(args.base_parameters) as f:
- adm_base_parameters=json.load(f)
- else:
- with open(configs.ADM1_LOCAL["base_parameters"]) as f:
- adm_base_parameters=json.load(f)
-
- if args.initial_conditions:
- with open(args.initial_conditions) as f:
- adm_initial_conditions=json.load(f)
- else:
- with open(configs.ADM1_LOCAL["initial_conditions"]) as f:
- adm_initial_conditions=json.load(f)
-
- if args.inlet_conditions:
- with open(args.inlet_conditions) as f:
- adm_inlet_conditions=json.load(f)
- else:
- with open(configs.ADM1_LOCAL["inlet_conditions"]) as f:
- adm_inlet_conditions=json.load(f)
-
-
- if args.reactions:
- with open(args.reactions) as f:
- adm_reactions=json.load(f)
- else:
- with open(configs.ADM1_LOCAL["reactions"]) as f:
- adm_reactions=json.load(f)
-
- if args.species:
- with open(args.species) as f:
- adm_species=json.load(f)
- else:
- with open(configs.ADM1_LOCAL["species"]) as f:
- adm_species=json.load(f)
-
- if args.metagenome_report:
- with open(args.metagenome_report) as f:
- adm_metagenome_report=json.load(f)
- else:
- pass
-
- ADM1 = adm.Model(
- model_parameters=adm_model_parameters,
- base_parameters=adm_base_parameters,
- initial_conditions= adm_initial_conditions,
- inlet_conditions= adm_inlet_conditions,
- feed=adm.DEFAULT_FEED,
- reactions=adm_reactions,
- species=adm_species,
- ode_system=adm.adm1_ode_sys,
- build_stoichiometric_matrix=adm.build_adm1_stoichiometric_matrix,
- name="ADM1",
- switch="DAE")
- sol = ADM1.solve_model(t_eval=np.linspace(0,30, 10000))
-
- if args.report == 'dash' or args.report==None:
- ADM1.dash_app(sol)
- elif args.report == 'csv':
- Address=Prompt.ask("\n[yellow]Where do you want to save the csv file? ")
- ADM1.csv_report(sol,Address)
- else:
- print('Please provide a valid report option')
-
-
- elif "ADToolbox_Module" in args and args.ADToolbox_Module == 'ADM' and "adm_Subparser" in args and args.adm_Subparser == 'e-adm':
- params=utils.load_multiple_json_files(configs.E_ADM_2_LOCAL)
- control_state={"S_H_ion":10**(-6.5)}
- if args.control_states:
- with open(args.control_states) as f:
- control_state.update(json.load(f))
-
- mod_adm1 = adm.Model(model_parameters=params.model_parameters,
- base_parameters=params.base_parameters,
- initial_conditions=params.initial_conditions,
- inlet_conditions=params.inlet_conditions,
- feed=adm.DEFAULT_FEED,
- reactions=params.reactions,
- species=params.species,
- ode_system=adm.e_adm_2_ode_sys,
- build_stoichiometric_matrix=adm.build_e_adm_2_stoichiometric_matrix,
- control_state=control_state,
- name="Modified_ADM1",
- switch="DAE",
- )
- sol_mod_adm1 = mod_adm1.solve_model(t_eval=np.linspace(0,30, 10000),method="BDF")
-
- if args.report == 'dash' or args.report==None:
- mod_adm1.dash_app(sol_mod_adm1)
- elif args.report == 'csv':
- Address=Prompt.ask("\n[yellow]Where do you want to save the csv file? ")
- mod_adm1.csv_report(sol_mod_adm1,Address)
- else:
- print('Please provide a valid report option')
-
+ subprocess.run(script, shell=True)
+
+
+@metagenomics.command(name="find-representative-genomes", help="Find representative genomes from a repseqs FASTA file.")
+@click.option("-i", "--input-file", help="Path to the repseqs FASTA file.")
+@click.option("-o", "--output-dir", help="Output directory.")
+@click.option("--amplicon-to-genome-db", help="Directory containing the amplicon-to-genome database files.")
+@click.option("-c", "--container", default="None", show_default=True, help="Container: None, docker, or singularity.")
+@click.option("-s", "--similarity", default=0.97, show_default=True, type=float, help="Similarity cutoff for clustering.")
+@click.option("-f", "--format", "output_format", default="csv", show_default=True, type=click.Choice(["csv", "json"]), help="Output format.")
+def find_representative_genomes(input_file, output_dir, amplicon_to_genome_db, container, similarity, output_format):
+ input_file = _prompt_path(input_file, "Repseqs FASTA path", exists=True, file_okay=True, dir_okay=False)
+ output_dir = _prompt_path(output_dir, "Representative genomes output directory", file_okay=False, dir_okay=True, writable=True)
+ amplicon_to_genome_db = _prompt_path(amplicon_to_genome_db, "Amplicon-to-genome database directory", exists=True, file_okay=False, dir_okay=True)
+ config = _metagenomics_config(amplicon_to_genome_db=amplicon_to_genome_db)
+ config.vsearch_similarity = similarity
+ script = core.Metagenomics(config).align_to_gtdb(
+ query_dir=input_file,
+ output_dir=output_dir,
+ container=container,
+ )
+ subprocess.run(script, shell=True)
+ results = core.Metagenomics(config).get_genomes_from_gtdb_alignment(output_dir)
+ _write_representative_genomes(results, output_dir, output_format)
+
+
+@main.command(name="Documentations", help="Documentations for using ADToolbox.")
+@click.option("-s", "--show", is_flag=True, help="Show the README documentation.")
+def documentations(show):
+ if not show:
+ raise click.ClickException("Please use --show to display documentation.")
+ with open(configs.Documentation().readme, "r") as f:
+ console.print(markdown.Markdown(f.read()))
+
+
+@main.group(name="ADM", help="Run and visualize ADToolbox ADM models.", no_args_is_help=True)
+def adm_group():
+ pass
+
+
+def _adm_options(command):
+ command = click.option("--report", help="Report output: dash or csv.")(command)
+ command = click.option("--metagenome-report", help="JSON metagenome report for the model.")(command)
+ command = click.option("--models-json", help="JSON file containing all ADM models keyed by model name.")(command)
+ command = click.option("--species", help="JSON species file.")(command)
+ command = click.option("--reactions", help="JSON reactions file.")(command)
+ command = click.option("--inlet-conditions", help="JSON inlet conditions file.")(command)
+ command = click.option("--initial-conditions", help="JSON initial conditions file.")(command)
+ command = click.option("--base-parameters", help="JSON base parameters file.")(command)
+ command = click.option("--model-parameters", help="JSON model parameters file.")(command)
+ command = click.option("--parameters-dir", help="Directory containing the ADM JSON parameter files.")(command)
+ return command
+
+
+@adm_group.command(name="adm1", help="Original ADM1 model.")
+@_adm_options
+def adm1(
+ parameters_dir,
+ model_parameters,
+ base_parameters,
+ initial_conditions,
+ inlet_conditions,
+ reactions,
+ species,
+ models_json,
+ metagenome_report,
+ report,
+):
+ params = _load_model_payload(
+ models_json,
+ "adm1",
+ parameters_dir=parameters_dir,
+ prefix="adm1",
+ model_parameters=model_parameters,
+ base_parameters=base_parameters,
+ initial_conditions=initial_conditions,
+ inlet_conditions=inlet_conditions,
+ reactions=reactions,
+ species=species,
+ )
+ if metagenome_report:
+ _load_json(metagenome_report)
+
+ model = adm.Model(
+ model_parameters=params["model_parameters"],
+ base_parameters=params["base_parameters"],
+ initial_conditions=params["initial_conditions"],
+ inlet_conditions=params["inlet_conditions"],
+ feed=adm.DEFAULT_FEED,
+ reactions=params["reactions"],
+ species=params["species"],
+ ode_system=adm.adm1_ode_sys,
+ build_stoichiometric_matrix=adm.build_adm1_stoichiometric_matrix,
+ name="ADM1",
+ switch="DAE",
+ )
+ solution = model.solve_model(t_eval=np.linspace(0, 30, 10000))
+ _report_adm_solution(model, solution, report)
+
+
+@adm_group.command(name="e-adm", help="eADM model.")
+@_adm_options
+@click.option("--control-states", help="JSON file containing control states and their values.")
+def e_adm(
+ parameters_dir,
+ model_parameters,
+ base_parameters,
+ initial_conditions,
+ inlet_conditions,
+ reactions,
+ species,
+ models_json,
+ metagenome_report,
+ report,
+ control_states,
+):
+ params = _load_model_payload(
+ models_json,
+ "e_adm",
+ parameters_dir=parameters_dir,
+ prefix="e_adm",
+ legacy_prefixes=("e_adm_2",),
+ model_parameters=model_parameters,
+ base_parameters=base_parameters,
+ initial_conditions=initial_conditions,
+ inlet_conditions=inlet_conditions,
+ reactions=reactions,
+ species=species,
+ )
+
+ if metagenome_report:
+ _load_json(metagenome_report)
+
+ control_state = {"S_H_ion": 10 ** (-6.5)}
+ if control_states:
+ control_state.update(_load_json(control_states))
+
+ model = adm.Model(
+ model_parameters=params["model_parameters"],
+ base_parameters=params["base_parameters"],
+ initial_conditions=params["initial_conditions"],
+ inlet_conditions=params["inlet_conditions"],
+ feed=adm.DEFAULT_FEED,
+ reactions=params["reactions"],
+ species=params["species"],
+ ode_system=adm.e_adm_ode_sys,
+ build_stoichiometric_matrix=adm.build_e_adm_stoichiometric_matrix,
+ control_state=control_state,
+ name="e-ADM",
+ switch="DAE",
+ )
+ solution = model.solve_model(t_eval=np.linspace(0, 30, 10000), method="BDF")
+ _report_adm_solution(model, solution, report)
+
if __name__ == "__main__":
main()
diff --git a/adtoolbox/configs.py b/adtoolbox/configs.py
index ef4bb8e..ff88864 100644
--- a/adtoolbox/configs.py
+++ b/adtoolbox/configs.py
@@ -1,340 +1,342 @@
import os
-from adtoolbox import Main_Dir, PKG_DATA
import pathlib
-import rich
-import json
import warnings
-"""
-This module contains all the paths to the files and directories used in the program.
+from adtoolbox import PKG_DATA
"""
+Path builders and static configuration values for ADToolbox.
+Configuration objects do not read or write global state. Pass the directory a
+workflow should use, and the object derives its file paths from that directory.
+"""
-RXN_DB = os.path.join(Main_Dir, "Database", "Reaction_Metadata.csv")
-
-Seed_RXN_DB = os.path.join(Main_Dir, "Database", "reactions.json")
-Seed_COMPOUNDS_DB = os.path.join(Main_Dir, "Database", "compounds.json")
ADTOOLBOX_CONTAINERS = {
- 'docker_x86': "parsaghadermazi/adtoolbox:x86",
- 'docker_arm64': "parsaghadermazi/adtoolbox:arm64",
- 'singularity_x86': "docker://parsaghadermazi/adtoolbox:x86",
- 'singularity_arm64': "docker://parsaghadermazi/adtoolbox:arm64"}
-
-E_ADM_2_REMOTE = {
- "model_parameters": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm_2/e_adm_2_model_parameters.json",
- "base_parameters": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm_2/e_adm_2_base_parameters.json",
- "initial_conditions": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm_2/e_adm_2_initial_conditions.json",
- "inlet_conditions": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm_2/e_adm_2_inlet_conditions.json",
- "reactions": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm_2/e_adm_2_reactions.json",
- "species": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm_2/e_adm_2_species.json"
- }
-
-E_ADM_2_LOCAL = {
- "model_parameters":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_2_model_parameters.json"),
- "base_parameters":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_2_base_parameters.json"),
- "initial_conditions":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_2_initial_conditions.json"),
- "inlet_conditions":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_2_inlet_conditions.json"),
- "reactions":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_2_reactions.json"),
- "species":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_2_species.json"),
+ "docker_x86": "parsaghadermazi/adtoolbox:x86",
+ "docker_arm64": "parsaghadermazi/adtoolbox:arm64",
+ "singularity_x86": "docker://parsaghadermazi/adtoolbox:x86",
+ "singularity_arm64": "docker://parsaghadermazi/adtoolbox:arm64",
}
-E_ADM_LOCAL={
- "model_parameters":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_model_parameters.json"),
- "base_parameters":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_base_parameters.json"),
- "initial_conditions":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_initial_conditions.json"),
- "inlet_conditions":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_inlet_conditions.json"),
- "reactions":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_reactions.json"),
- "species":os.path.join(Main_Dir, "Database","ADM_Parameters","e_adm_species.json"),
- }
-
-E_ADM_REMOTE={
- "model_parameters":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/e_adm/e_adm_model_parameters.json",
- "base_parameters":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/e_adm/e_adm_base_parameters.json",
- "initial_conditions":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/e_adm/e_adm_initial_conditions.json",
- "inlet_conditions":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/e_adm/e_adm_inlet_conditions.json",
- "reactions":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/e_adm/e_adm_reactions.json",
- "species":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/e_adm/e_adm_species.json"
- }
-
-ADM1_LOCAL={
- "model_parameters":os.path.join(Main_Dir, "Database","ADM_Parameters","adm1_model_parameters.json"),
- "base_parameters":os.path.join(Main_Dir, "Database","ADM_Parameters","adm1_base_parameters.json"),
- "initial_conditions":os.path.join(Main_Dir, "Database","ADM_Parameters","adm1_initial_conditions.json"),
- "inlet_conditions":os.path.join(Main_Dir, "Database","ADM_Parameters","adm1_inlet_conditions.json"),
- "reactions":os.path.join(Main_Dir, "Database","ADM_Parameters","adm1_reactions.json"),
- "species":os.path.join(Main_Dir, "Database","ADM_Parameters","adm1_species.json"),
- }
-
-ADM1_REMOTE={
- "model_parameters":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_model_parameters.json",
- "base_parameters":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_base_parameters.json",
- "initial_conditions":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_initial_conditions.json",
- "inlet_conditions":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_inlet_conditions.json",
- "reactions":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_reactions.json",
- "species":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_species.json"
- }
-EXTERNAL_LINKS={
- "cazy_links":["http://www.cazy.org/Glycoside-Hydrolases.html",
- "http://www.cazy.org/Polysaccharide-Lyases.html",
- "http://www.cazy.org/Carbohydrate-Esterases.html"
- ],
- "amplicon2genome":{'Version': 'https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/VERSION',
- 'MD5SUM': 'https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/MD5SUM',
- 'FILE_DESCRIPTIONS': 'https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/FILE_DESCRIPTIONS',
- 'metadata_field_desc': 'https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/auxillary_files/metadata_field_desc.tsv',
- 'bac120_ssu': 'https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/genomic_files_all/ssu_all.fna.gz'
- },
-
- "seed_rxn_url":"https://github.com/modelSEED/modelSEEDDatabase/raw/master/Biochemistry/reactions.json",
- "seed_compound_url":"https://github.com/ModelSEED/ModelSEEDDatabase/raw/master/Biochemistry/compounds.json",
-
+E_ADM_REMOTE = {
+ "model_parameters": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm/e_adm_model_parameters.json",
+ "base_parameters": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm/e_adm_base_parameters.json",
+ "initial_conditions": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm/e_adm_initial_conditions.json",
+ "inlet_conditions": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm/e_adm_inlet_conditions.json",
+ "reactions": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm/e_adm_reactions.json",
+ "species": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/e_adm/e_adm_species.json",
}
-INTERNAL_LINKS={
- "protein_db_url":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/Protein_DB.fasta",
- "adtoolbox_rxn_db_url":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/Reaction_Metadata.csv",
- "feed_db_url":"https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/feed_db.tsv",
- "qiime_classifier_db_url":"https://data.qiime2.org/2022.11/common/silva-138-99-515-806-nb-classifier.qza",
- "metagenomics_studies":"https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/Kbase/metagenomics_studies.tsv",
- "experimental_data_db":"https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/experimental_data_references.json"
+ADM1_REMOTE = {
+ "model_parameters": "https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_model_parameters.json",
+ "base_parameters": "https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_base_parameters.json",
+ "initial_conditions": "https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_initial_conditions.json",
+ "inlet_conditions": "https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_inlet_conditions.json",
+ "reactions": "https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_reactions.json",
+ "species": "https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/adm1/adm1_species.json",
}
+EXTERNAL_LINKS = {
+ "cazy_links": [
+ "http://www.cazy.org/Glycoside-Hydrolases.html",
+ "http://www.cazy.org/Polysaccharide-Lyases.html",
+ "http://www.cazy.org/Carbohydrate-Esterases.html",
+ ],
+ "amplicon2genome": {
+ "Version": "https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/VERSION",
+ "MD5SUM": "https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/MD5SUM",
+ "FILE_DESCRIPTIONS": "https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/FILE_DESCRIPTIONS",
+ "metadata_field_desc": "https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/auxillary_files/metadata_field_desc.tsv",
+ "bac120_ssu": "https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/genomic_files_all/ssu_all.fna.gz",
+ },
+ "seed_rxn_url": "https://github.com/modelSEED/modelSEEDDatabase/raw/master/Biochemistry/reactions.json",
+ "seed_compound_url": "https://github.com/ModelSEED/ModelSEEDDatabase/raw/master/Biochemistry/compounds.json",
+}
+INTERNAL_LINKS = {
+ "protein_db_url": "https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/Protein_DB.fasta",
+ "adtoolbox_rxn_db_url": "https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/Reaction_Metadata.csv",
+ "feed_db_url": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/feed_db.tsv",
+ "qiime_classifier_db_url": "https://data.qiime2.org/2022.11/common/silva-138-99-515-806-nb-classifier.qza",
+ "metagenomics_studies": "https://github.com/ParsaGhadermazi/Database/raw/main/ADToolbox/Kbase/metagenomics_studies.tsv",
+ "experimental_data_db": "https://raw.githubusercontent.com/ParsaGhadermazi/Database/main/ADToolbox/experimental_data_references.json",
+}
-STUDIES_LOCAL={
- "metagenomics_studies":os.path.join(Main_Dir,"Database","Studies","metagenomics_studies.tsv"),
- "experimental_data_db":os.path.join(Main_Dir,"Database","Studies","experimental_data_references.json")
+E_ADM_MICROBIAL_GROUPS_MAPPING = {
+ "Hydrolysis carbohydrates": "X_ch",
+ "Hydrolysis proteins": "X_pr",
+ "Hydrolysis lipids": "X_li",
+ "Uptake of sugars": "X_su",
+ "Uptake of amino acids": "X_aa",
+ "Uptake of LCFA": "X_fa",
+ "Uptake of acetate_et": "X_ac_et",
+ "Uptake of acetate_lac": "X_ac_lac",
+ "Uptake of propionate_et": "X_chain_et",
+ "Uptake of propionate_lac": "X_chain_lac",
+ "Uptake of butyrate_et": "X_chain_et",
+ "Uptake of butyrate_lac": "X_chain_lac",
+ "Uptake of valerate": "X_VFA_deg",
+ "Uptake of caproate": "X_VFA_deg",
+ "Methanogenessis from acetate and h2": "X_Me_ac",
+ "Methanogenessis from CO2 and h2": "X_Me_CO2",
+ "Uptake of ethanol": "X_et",
+ "Uptake of lactate": "X_lac",
}
-E_ADM_MICROBIAL_GROUPS_MAPPING={
- "Hydrolysis carbohydrates":"X_ch",
- "Hydrolysis proteins":"X_pr",
- "Hydrolysis lipids":"X_li",
- "Uptake of sugars":"X_su",
- "Uptake of amino acids":"X_aa",
- "Uptake of LCFA":"X_fa",
- "Uptake of acetate_et":"X_ac_et",
- "Uptake of acetate_lac":"X_ac_lac",
- "Uptake of propionate_et":"X_chain_et",
- "Uptake of propionate_lac":"X_chain_lac",
- "Uptake of butyrate_et":"X_chain_et",
- "Uptake of butyrate_lac":"X_chain_lac",
- "Uptake of valerate":"X_VFA_deg",
- "Uptake of caproate":"X_VFA_deg",
- "Methanogenessis from acetate and h2":"X_Me_ac",
- "Methanogenessis from CO2 and h2":"X_Me_CO2",
- "Uptake of ethanol":"X_et",
- "Uptake of lactate":"X_lac",
- }
+
+
+def _norm(path: str | os.PathLike | None, default: str | os.PathLike = ".") -> str:
+ return os.path.abspath(os.path.expanduser(os.fspath(path or default)))
+
+
+def _join(root: str, *parts: str) -> str:
+ return os.path.join(root, *parts)
+
+
+def adm_parameter_paths(parameters_dir: str | os.PathLike, prefix: str) -> dict[str, str]:
+ parameters_dir = _norm(parameters_dir)
+ return {
+ "model_parameters": _join(parameters_dir, f"{prefix}_model_parameters.json"),
+ "base_parameters": _join(parameters_dir, f"{prefix}_base_parameters.json"),
+ "initial_conditions": _join(parameters_dir, f"{prefix}_initial_conditions.json"),
+ "inlet_conditions": _join(parameters_dir, f"{prefix}_inlet_conditions.json"),
+ "reactions": _join(parameters_dir, f"{prefix}_reactions.json"),
+ "species": _join(parameters_dir, f"{prefix}_species.json"),
+ }
class Database:
- "An instance of this class will hold all the configuration information for core.Database functionalities."
-
- def __init__(self,
- compound_db:str=Seed_COMPOUNDS_DB,
- reaction_db:str=Seed_RXN_DB,
- local_compound_db:str=os.path.join(Main_Dir, "Database", 'Local_compounds.json'),
- local_reaction_db:str=os.path.join(Main_Dir, "Database", 'Local_reactions.json'),
- csv_reaction_db:str=os.path.join(Main_Dir, "Database", 'Reaction_Metadata.csv'),
- feed_db=os.path.join(Main_Dir, "Database", 'feed_db.tsv'),
- amplicon_to_genome_db=os.path.join(Main_Dir,'Database','Amplicon2GenomeDBs'),
- cazy_links:str=EXTERNAL_LINKS["cazy_links"],
- amplicon_to_genome_urls:dict=EXTERNAL_LINKS["amplicon2genome"],
- adm_parameters_urls:dict=E_ADM_REMOTE,
- adm_parameters:dict=E_ADM_LOCAL,
- seed_rxn_url:str =EXTERNAL_LINKS["seed_rxn_url"],
- seed_compound_url:str =EXTERNAL_LINKS["seed_compound_url"],
- protein_db_url:str =INTERNAL_LINKS["protein_db_url"],
- adtoolbox_rxn_db_url:str =INTERNAL_LINKS["adtoolbox_rxn_db_url"],
- feed_db_url:str =INTERNAL_LINKS["feed_db_url"],
- qiime_classifier_db:str=os.path.join(Main_Dir, "Database","qiime2_classifier_db" ,'qiime2_classifier_db.qza'),
- qiime_classifier_db_url:str=INTERNAL_LINKS["qiime_classifier_db_url"],
- adtoolbox_singularity=ADTOOLBOX_CONTAINERS["singularity_x86"],
- adtoolbox_docker=ADTOOLBOX_CONTAINERS["docker_x86"],
- protein_db=os.path.join(Main_Dir, "Database", 'Protein_DB.fasta'),
- adm_microbial_groups_mapping=E_ADM_MICROBIAL_GROUPS_MAPPING,
- metacyc_protein_db:str=os.path.join(Main_Dir, "Database", 'metacyc_protein_db.fasta'),
- studies_remote=INTERNAL_LINKS,
- studies_local=STUDIES_LOCAL,
- check_sanity:bool=False
- ):
- self.compound_db = compound_db
- self.reaction_db = reaction_db
- self.local_compound_db = local_compound_db
- self.local_reaction_db = local_reaction_db
- self.csv_reaction_db = csv_reaction_db
- self.feed_db = feed_db
- self.amplicon_to_genome_db = amplicon_to_genome_db
- self.cazy_links = cazy_links
- self.amplicon_to_genome_urls = amplicon_to_genome_urls
- self.adm_parameters_urls = adm_parameters_urls
- self.adm_parameters = adm_parameters
- self.seed_rxn_url = seed_rxn_url
- self.seed_compound_url = seed_compound_url
- self.protein_db_url = protein_db_url
- self.adtoolbox_rxn_db_url = adtoolbox_rxn_db_url
- self.feed_db_url = feed_db_url
- self.qiime_classifier_db = qiime_classifier_db
- self.qiime_classifier_db_url = qiime_classifier_db_url
- self.adtoolbox_singularity=adtoolbox_singularity
- self.adtoolbox_docker=adtoolbox_docker
- self.protein_db=protein_db
- self.adm_microbial_groups_mapping=adm_microbial_groups_mapping
- self.studies_remote=studies_remote
- self.studies_local=studies_local
- self.metacyc_protein_db=metacyc_protein_db
- self.protein_db_mmseqs=pathlib.Path(protein_db).parent.joinpath("protein_db_mmseqs")
- if check_sanity:
- self.check_adm_parameters()
-
- def check_adm_parameters(self):
- branches=all([pathlib.Path(x).parent==pathlib.Path(self.adm_parameters["model_parameters"]).parent for x in self.adm_parameters.values()])
- if not branches:
- warnings.warn("The ADM parameters are not in the same directory!")
+ "Configuration for core.Database functionality."
+
+ def __init__(
+ self,
+ database_dir: str | os.PathLike = ".",
+ *,
+ compound_db: str | None = None,
+ reaction_db: str | None = None,
+ local_compound_db: str | None = None,
+ local_reaction_db: str | None = None,
+ csv_reaction_db: str | None = None,
+ feed_db: str | None = None,
+ amplicon_to_genome_db: str | None = None,
+ adm_models: str | None = None,
+ cazy_links: list[str] = EXTERNAL_LINKS["cazy_links"],
+ amplicon_to_genome_urls: dict = EXTERNAL_LINKS["amplicon2genome"],
+ adm_parameters_urls: dict = E_ADM_REMOTE,
+ adm_parameters: dict | None = None,
+ seed_rxn_url: str = EXTERNAL_LINKS["seed_rxn_url"],
+ seed_compound_url: str = EXTERNAL_LINKS["seed_compound_url"],
+ protein_db_url: str = INTERNAL_LINKS["protein_db_url"],
+ adtoolbox_rxn_db_url: str = INTERNAL_LINKS["adtoolbox_rxn_db_url"],
+ feed_db_url: str = INTERNAL_LINKS["feed_db_url"],
+ qiime_classifier_db: str | None = None,
+ qiime_classifier_db_url: str = INTERNAL_LINKS["qiime_classifier_db_url"],
+ adtoolbox_singularity: str = ADTOOLBOX_CONTAINERS["singularity_x86"],
+ adtoolbox_docker: str = ADTOOLBOX_CONTAINERS["docker_x86"],
+ protein_db: str | None = None,
+ adm_microbial_groups_mapping: dict = E_ADM_MICROBIAL_GROUPS_MAPPING,
+ metacyc_protein_db: str | None = None,
+ studies_remote: dict = INTERNAL_LINKS,
+ studies_local: dict | None = None,
+ check_sanity: bool = False,
+ ):
+ self.database_dir = _norm(database_dir)
+ adm_parameters_dir = _join(self.database_dir, "ADM_Parameters")
+ studies_dir = _join(self.database_dir, "Studies")
+
+ self.compound_db = _norm(compound_db or _join(self.database_dir, "compounds.json"))
+ self.reaction_db = _norm(reaction_db or _join(self.database_dir, "reactions.json"))
+ self.local_compound_db = _norm(local_compound_db or _join(self.database_dir, "Local_compounds.json"))
+ self.local_reaction_db = _norm(local_reaction_db or _join(self.database_dir, "Local_reactions.json"))
+ self.csv_reaction_db = _norm(csv_reaction_db or _join(self.database_dir, "Reaction_Metadata.csv"))
+ self.feed_db = _norm(feed_db or _join(self.database_dir, "feed_db.tsv"))
+ self.amplicon_to_genome_db = _norm(amplicon_to_genome_db or _join(self.database_dir, "Amplicon2GenomeDBs"))
+ self.adm_models = _norm(adm_models or _join(adm_parameters_dir, "models.json"))
+ self.cazy_links = cazy_links
+ self.amplicon_to_genome_urls = amplicon_to_genome_urls
+ self.adm_parameters_urls = adm_parameters_urls
+ self.adm_parameters = adm_parameters or adm_parameter_paths(adm_parameters_dir, "e_adm")
+ self.adm_parameters = {key: _norm(value) for key, value in self.adm_parameters.items()}
+ self.seed_rxn_url = seed_rxn_url
+ self.seed_compound_url = seed_compound_url
+ self.protein_db_url = protein_db_url
+ self.adtoolbox_rxn_db_url = adtoolbox_rxn_db_url
+ self.feed_db_url = feed_db_url
+ self.qiime_classifier_db = _norm(qiime_classifier_db or _join(self.database_dir, "qiime2_classifier_db", "qiime2_classifier_db.qza"))
+ self.qiime_classifier_db_url = qiime_classifier_db_url
+ self.adtoolbox_singularity = adtoolbox_singularity
+ self.adtoolbox_docker = adtoolbox_docker
+ self.protein_db = _norm(protein_db or _join(self.database_dir, "Protein_DB.fasta"))
+ self.adm_microbial_groups_mapping = adm_microbial_groups_mapping
+ self.studies_remote = studies_remote
+ default_studies_local = {
+ "metagenomics_studies": _join(studies_dir, "metagenomics_studies.tsv"),
+ "experimental_data_db": _join(studies_dir, "experimental_data_references.json"),
+ }
+ if studies_local:
+ default_studies_local.update(studies_local)
+ self.studies_local = {key: _norm(value) for key, value in default_studies_local.items()}
+ self.metacyc_protein_db = _norm(metacyc_protein_db or _join(self.database_dir, "metacyc_protein_db.fasta"))
+ self.protein_db_mmseqs = pathlib.Path(self.protein_db).parent.joinpath("protein_db_mmseqs")
+
+ # Compatibility aliases for older examples/tests that treated Database as
+ # the active ADM parameter config.
+ self.model_parameters = self.adm_parameters["model_parameters"]
+ self.base_parameters = self.adm_parameters["base_parameters"]
+ self.initial_conditions = self.adm_parameters["initial_conditions"]
+ self.inlet_conditions = self.adm_parameters["inlet_conditions"]
+ self.reactions = self.adm_parameters["reactions"]
+ self.species = self.adm_parameters["species"]
+
+ if check_sanity:
+ self.check_adm_parameters()
+
+ def check_adm_parameters(self):
+ branches = all(
+ pathlib.Path(path).parent == pathlib.Path(self.adm_parameters["model_parameters"]).parent
+ for path in self.adm_parameters.values()
+ )
+ if not branches:
+ warnings.warn("The ADM parameters are not in the same directory!")
+
class Metagenomics:
- """
- An instance of this class will hold all the configuration information for core.Metagenomics functionalities.
- """
- ### Here we have some class variables that are used in the class
- gtdb_dir="ssu_all*.fna"
- def __init__(self,
- amplicon2genome_k=10,
- vsearch_similarity=0.97,
- genomes_base_dir=os.path.join(Main_Dir,"Genomes"),
- align_to_gtdb_outputs_dir=os.path.join(Main_Dir,"Genomes"),
- amplicon2genome_db=Database().amplicon_to_genome_db,
- qiime_outputs_dir=os.path.join(Main_Dir,'Metagenomics_Data','QIIME_Outputs'),
- genome_alignment_script=os.path.join(Main_Dir,"Metagenomics_Data","QIIME_Outputs","genome_alignment_script.sh"),
- vsearch_threads:int=4,
- rsync_download_dir=os.path.join(Main_Dir,"Genomes","rsync_download.sh"),
- adtoolbox_singularity=ADTOOLBOX_CONTAINERS["singularity_x86"],
- adtoolbox_docker=ADTOOLBOX_CONTAINERS["docker_x86"],
- genome_alignment_output=os.path.join(Main_Dir,"Outputs"),
- csv_reaction_db=Database().csv_reaction_db,
- sra=os.path.join(Main_Dir,"Metagenomics_Analysis","SRA"),
- bit_score=40,
- e_value=10**-5,
- qiime2_docker_image="quay.io/qiime2/core:2022.2",
- qiime2_singularity_image="docker://quay.io/qiime2/core:2022.2",
- qiime2_paired_end_bash_str=os.path.join(PKG_DATA,"qiime_template_paired.txt"),
- qiime2_single_end_bash_str=os.path.join(PKG_DATA,"qiime_template_single.txt"),
- qiime_classifier_db=Database().qiime_classifier_db,
- protein_db:str=Database().protein_db,
- protein_db_mmseqs:str=Database().protein_db_mmseqs,
- adm_mapping=E_ADM_MICROBIAL_GROUPS_MAPPING,
- qiime2_p_trunc_len:tuple[int,int]=("250","250"),
- ):
- self.k = amplicon2genome_k
- self.vsearch_similarity = vsearch_similarity
- self.align_to_gtdb_outputs_dir = align_to_gtdb_outputs_dir
- self.amplicon2genome_db = amplicon2genome_db
- self.qiime_outputs_dir = qiime_outputs_dir
- self.protein_db=protein_db
-
- self.protein_db_mmseqs=protein_db_mmseqs
- self.seed_rxn_db=Seed_RXN_DB
- self.genome_alignment_output = genome_alignment_output
- self.bit_score = bit_score
- self.e_value = e_value
- self.vsearch_threads=vsearch_threads
- self.csv_reaction_db=csv_reaction_db
- self.sra=sra
- self.qiime2_singularity_image=qiime2_singularity_image
- self.qiime2_docker_image=qiime2_docker_image
- self.qiime2_paired_end_bash_str=qiime2_paired_end_bash_str
- self.qiime2_single_end_bash_str=qiime2_single_end_bash_str
- self.qiime_classifier_db=qiime_classifier_db
- if list(pathlib.Path(self.amplicon2genome_db).rglob(Metagenomics.gtdb_dir)):
- self.gtdb_dir_fasta=str(list(pathlib.Path(self.amplicon2genome_db).rglob(Metagenomics.gtdb_dir))[0])
- else:
- self.gtdb_dir_fasta=None
- self.genome_alignment_script=genome_alignment_script
- self.adtoolbox_singularity=adtoolbox_singularity
- self.adtoolbox_docker=adtoolbox_docker
- self.rsync_download_dir=rsync_download_dir
- self.genomes_base_dir=genomes_base_dir
- self.adm_mapping=adm_mapping
- self.qiime2_p_trunc_len=qiime2_p_trunc_len
+ "Configuration for core.Metagenomics functionality."
+
+ gtdb_dir = "ssu_all*.fna"
+
+ def __init__(
+ self,
+ metagenomics_dir: str | os.PathLike = ".",
+ *,
+ database_dir: str | os.PathLike | None = None,
+ database: Database | None = None,
+ amplicon2genome_k=10,
+ vsearch_similarity=0.97,
+ genomes_base_dir: str | None = None,
+ align_to_gtdb_outputs_dir: str | None = None,
+ amplicon2genome_db: str | None = None,
+ qiime_outputs_dir: str | None = None,
+ genome_alignment_script: str | None = None,
+ vsearch_threads: int = 4,
+ rsync_download_dir: str | None = None,
+ adtoolbox_singularity: str = ADTOOLBOX_CONTAINERS["singularity_x86"],
+ adtoolbox_docker: str = ADTOOLBOX_CONTAINERS["docker_x86"],
+ genome_alignment_output: str | None = None,
+ csv_reaction_db: str | None = None,
+ sra: str | None = None,
+ bit_score=40,
+ e_value=10**-5,
+ qiime2_docker_image="quay.io/qiime2/core:2022.2",
+ qiime2_singularity_image="docker://quay.io/qiime2/core:2022.2",
+ qiime2_paired_end_bash_str=os.path.join(PKG_DATA, "qiime_template_paired.txt"),
+ qiime2_single_end_bash_str=os.path.join(PKG_DATA, "qiime_template_single.txt"),
+ qiime_classifier_db: str | None = None,
+ protein_db: str | None = None,
+ protein_db_mmseqs: str | None = None,
+ adm_mapping=E_ADM_MICROBIAL_GROUPS_MAPPING,
+ qiime2_p_trunc_len: tuple[int, int] = ("250", "250"),
+ ):
+ self.metagenomics_dir = _norm(metagenomics_dir)
+ database = database or Database(database_dir=database_dir or self.metagenomics_dir)
+
+ self.k = amplicon2genome_k
+ self.vsearch_similarity = vsearch_similarity
+ self.genomes_base_dir = genomes_base_dir or _join(self.metagenomics_dir, "Genomes")
+ self.align_to_gtdb_outputs_dir = align_to_gtdb_outputs_dir or self.genomes_base_dir
+ self.amplicon2genome_db = amplicon2genome_db or database.amplicon_to_genome_db
+ self.qiime_outputs_dir = qiime_outputs_dir or _join(self.metagenomics_dir, "QIIME_Outputs")
+ self.protein_db = protein_db or database.protein_db
+ self.protein_db_mmseqs = protein_db_mmseqs or database.protein_db_mmseqs
+ self.seed_rxn_db = database.reaction_db
+ self.genome_alignment_output = genome_alignment_output or _join(self.metagenomics_dir, "Outputs")
+ self.bit_score = bit_score
+ self.e_value = e_value
+ self.vsearch_threads = vsearch_threads
+ self.csv_reaction_db = csv_reaction_db or database.csv_reaction_db
+ self.sra = sra or _join(self.metagenomics_dir, "SRA")
+ self.qiime2_singularity_image = qiime2_singularity_image
+ self.qiime2_docker_image = qiime2_docker_image
+ self.qiime2_paired_end_bash_str = qiime2_paired_end_bash_str
+ self.qiime2_single_end_bash_str = qiime2_single_end_bash_str
+ self.qiime_classifier_db = qiime_classifier_db or database.qiime_classifier_db
+ self.gtdb_dir_fasta = None
+ matches = list(pathlib.Path(self.amplicon2genome_db).rglob(Metagenomics.gtdb_dir))
+ if matches:
+ self.gtdb_dir_fasta = str(matches[0])
+ self.genome_alignment_script = genome_alignment_script or _join(self.qiime_outputs_dir, "genome_alignment_script.sh")
+ self.adtoolbox_singularity = adtoolbox_singularity
+ self.adtoolbox_docker = adtoolbox_docker
+ self.rsync_download_dir = rsync_download_dir or _join(self.genomes_base_dir, "rsync_download.sh")
+ self.adm_mapping = adm_mapping
+ self.qiime2_p_trunc_len = qiime2_p_trunc_len
+
+
class Annotation:
- def __init__(self,
- metacyc_protein_db:str=Database().metacyc_protein_db
-
- ):
-
- self.metacyc_protein_db=metacyc_protein_db
-
-
+ def __init__(self, annotation_dir: str | os.PathLike = ".", *, metacyc_protein_db: str | None = None):
+ self.annotation_dir = _norm(annotation_dir)
+ self.metacyc_protein_db = metacyc_protein_db or _join(self.annotation_dir, "metacyc_protein_db.fasta")
+
+
class Documentation:
- def __init__(self,
- readme=os.path.join(PKG_DATA,"README.md")):
- self.readme = readme
+ def __init__(self, documentation_dir: str | os.PathLike | None = None, *, readme: str | None = None):
+ self.documentation_dir = _norm(documentation_dir or PKG_DATA)
+ self.readme = readme or _join(self.documentation_dir, "README.md")
+
+
+class Studies:
+ def __init__(
+ self,
+ studies_dir: str | os.PathLike = ".",
+ *,
+ metagenomics_studies: str | None = None,
+ experimental_data_db: str | None = None,
+ ):
+ self.studies_dir = _norm(studies_dir)
+ self.metagenomics_studies = metagenomics_studies or _join(self.studies_dir, "metagenomics_studies.tsv")
+ self.experimental_data_db = experimental_data_db or _join(self.studies_dir, "experimental_data_references.json")
+ self.experimental_data_references = self.experimental_data_db
+
class Utils:
- """
- An instance of this class will hold all the configuration information for utils module functionalities."""
- def __init__(self,
- slurm_template:str=os.path.join(PKG_DATA,"slurm_template.txt"),
- docker_template_qiime:str=None,
- singularity_template_qiime:str=None,
- slurm_executer:str='',
- slurm_wall_time:str='24:00:00',
- slurm_job_name:str='ADToolbox',
- slurm_outlog:str='ADToolbox.log',
- slurm_cpus:str="12",
- slurm_memory:str="100G",
- slurm_save_dir:str=os.getcwd(),
- adtoolbox_singularity:str=ADTOOLBOX_CONTAINERS["singularity_x86"],
- adtoolbox_docker:str=ADTOOLBOX_CONTAINERS["docker_x86"]
- ) -> None:
- self.slurm_template = slurm_template
- self.docker_template_qiime = docker_template_qiime
- self.singularity_template_qiime = singularity_template_qiime
- self.slurm_executer = slurm_executer
- self.slurm_wall_time = slurm_wall_time
- self.slurm_job_name = slurm_job_name
- self.slurm_outlog=slurm_outlog
- self.slurm_cpus = slurm_cpus
- self.slurm_save_dir = slurm_save_dir
- self.slurm_memory = slurm_memory
- self.adtoolbox_singularity=adtoolbox_singularity
- self.adtoolbox_docker=adtoolbox_docker
-
-
-def get_base_dir():
- "This function returns the current base directory of the program."
- return Main_Dir
-
-def set_base_dir(path:str):
- """This function changes the base directory of the program"""
- global Main_Dir
- ans=input("This will change the base directory of the program. Are you sure you want to continue? (y/n)")
- if ans == "y":
- with open(os.path.join(PKG_DATA,"ADToolbox_Configs.json"),'r') as f:
- conf = json.load(f)
- try:
- os.makedirs(path,exist_ok=True)
- except Exception:
- rich.print("[red]Base directory not changed")
- return
- else:
-
- Main_Dir=path
- conf["Base_Dir"]=path
- with open(os.path.join(PKG_DATA,"ADToolbox_Configs.json"),'w') as f:
- json.dump(conf,f)
-
- rich.print("[green]Base directory changed")
- else:
- rich.print("[red]Base directory not changed")
-
-
-
-
-
-if __name__=="__main__":
- t=Database()
- t.adm_parameters["model_parameters"]=os.path.join(Main_Dir, "Database","somewhere_else","e_adm_model_parameters.json")
- t.check_adm_parameters()
\ No newline at end of file
+ "Configuration for utility helpers."
+
+ def __init__(
+ self,
+ utils_dir: str | os.PathLike = ".",
+ *,
+ slurm_template: str = os.path.join(PKG_DATA, "slurm_template.txt"),
+ docker_template_qiime: str | None = None,
+ singularity_template_qiime: str | None = None,
+ slurm_executer: str = "",
+ slurm_wall_time: str = "24:00:00",
+ slurm_job_name: str = "ADToolbox",
+ slurm_outlog: str = "ADToolbox.log",
+ slurm_cpus: str = "12",
+ slurm_memory: str = "100G",
+ slurm_save_dir: str | None = None,
+ adtoolbox_singularity: str = ADTOOLBOX_CONTAINERS["singularity_x86"],
+ adtoolbox_docker: str = ADTOOLBOX_CONTAINERS["docker_x86"],
+ ) -> None:
+ self.utils_dir = _norm(utils_dir)
+ self.slurm_template = slurm_template
+ self.docker_template_qiime = docker_template_qiime
+ self.singularity_template_qiime = singularity_template_qiime
+ self.slurm_executer = slurm_executer
+ self.slurm_wall_time = slurm_wall_time
+ self.slurm_job_name = slurm_job_name
+ self.slurm_outlog = slurm_outlog
+ self.slurm_cpus = slurm_cpus
+ self.slurm_save_dir = slurm_save_dir or self.utils_dir
+ self.slurm_memory = slurm_memory
+ self.adtoolbox_singularity = adtoolbox_singularity
+ self.adtoolbox_docker = adtoolbox_docker
+
+
+_DEFAULT_DATABASE = Database()
+RXN_DB = _DEFAULT_DATABASE.csv_reaction_db
+Seed_RXN_DB = _DEFAULT_DATABASE.reaction_db
+Seed_COMPOUNDS_DB = _DEFAULT_DATABASE.compound_db
+E_ADM_LOCAL = _DEFAULT_DATABASE.adm_parameters
+ADM1_LOCAL = adm_parameter_paths(os.path.join(_DEFAULT_DATABASE.database_dir, "ADM_Parameters"), "adm1")
+STUDIES_LOCAL = _DEFAULT_DATABASE.studies_local
diff --git a/adtoolbox/core.py b/adtoolbox/core.py
index 793dadf..c363ec8 100644
--- a/adtoolbox/core.py
+++ b/adtoolbox/core.py
@@ -23,7 +23,6 @@
import configs
from rich.progress import track,Progress
import rich
-from adtoolbox import Main_Dir
from typing import Iterable
from typing import Union
from dataclasses import dataclass
@@ -463,8 +462,8 @@ class Database:
>>> assert type(db)==Database and type(db.config)==configs.Database
'''
- def __init__(self, config:configs.Database=configs.Database())->None:
- self.config = config
+ def __init__(self, config:configs.Database|None=None)->None:
+ self.config = config or configs.Database()
def initialize_protein_db(self)->None:
@@ -2350,5 +2349,3 @@ def annotate_with_metacyc(self,
-
-
diff --git a/adtoolbox/metagenomics_report.py b/adtoolbox/metagenomics_report.py
deleted file mode 100644
index f1531c1..0000000
--- a/adtoolbox/metagenomics_report.py
+++ /dev/null
@@ -1,461 +0,0 @@
-import plotly.express as px
-from dash import Dash, html, dcc
-import plotly.graph_objects as go
-from dash import Dash, dcc,ctx, html, Input, Output,dash_table,callback,no_update
-from dash.dash_table.Format import Format, Scheme, Sign, Symbol
-import pandas as pd
-import dash_bootstrap_components as dbc
-import json
-from collections import OrderedDict
-from sklearn.manifold import MDS,TSNE
-import base64
-from adtoolbox import core,adm,configs
-import numpy as np
-
-"""
-samples file should be formatted like this:
-
-{
- "sample1":
- {
- "src":"Path/to/figure",
- "data":{
- "X_ch":0.1,
- ....
- },
- "group":"group1"
- },
- "sample2":
- {
- "src":"Path/to/figure",
- "data":{
- "X_ch":0.1,
- ....
- },
- "group":"group2"
- },
- ...
-}
-
-"""
-
-
-# Small molecule drugbank dataset
-# Source: https://raw.githubusercontent.com/plotly/dash-sample-apps/main/apps/dash-drug-discovery/data/small_molecule_drugbank.csv'
-# data_path = '/Users/parsaghadermarzi/Desktop/Academics/Projects/Anaerobic_Digestion_Modeling/experiment/datasets/small_molecule_drugbank.csv'
-
-# df = pd.read_csv(data_path, header=0, index_col=0)
-
-# fig = go.Figure(data=[
-# go.Scatter(
-# x=df["LOGP"],
-# y=df["PKA"],
-# mode="markers",
-# marker=dict(
-# colorscale='viridis',
-# color=df["MW"],
-# size=df["MW"],
-# colorbar={"title": "Molecular Weight"},
-# line={"color": "#444"},
-# reversescale=True,
-# sizeref=45,
-# sizemode="diameter",
-# opacity=0.8,
-# )
-# )
-# ])
-
-# turn off native plotly.js hover effects - make sure to use
-# hoverinfo="none" rather than "skip" which also halts events.
-# fig.update_traces(hoverinfo="none", hovertemplate=None)
-
-# fig.update_layout(
-# xaxis=dict(title='Log P'),
-# yaxis=dict(title='pkA'),
-# plot_bgcolor='rgba(255,255,255,0.1)'
-# )
-_compounds=["S_bu","S_ac","S_lac","S_et"]
-
-
-
-
-TOTALL_MICROBIAL_COD=10
-DURATION=5
-
-def process_input(json_data,method="MDS",normalize=True,n_components=2):
- samples=list(json_data.keys())
- df=pd.DataFrame([json_data[i]["data"] for i in samples],index=samples)
- df=df.div(df.sum(axis=1), axis=0)
- df_copy=df.copy()
- X=df.to_numpy()
- if method=="MDS":
- mds=MDS(n_components=n_components,max_iter=10000)
- X=mds.fit_transform(X)
- elif method=="TSNE":
- tsne=TSNE(n_components=n_components,n_iter=10000)
- X=tsne.fit_transform(X)
- df=pd.DataFrame(X,index=df_copy.index,columns=["x","y"] if n_components==2 else ["x","y","z"])
- df["group"]=[json_data[i]["group"] for i in samples]
- df["src"]=[json_data[i]["src"] for i in samples]
- df_copy["group"]=df["group"]
- return df,df_copy
-
-
-def main(json_file:str,method:str="MDS",normalize:bool=True,n_components:int=2):
- with open(json_file,"r") as f:
- json_data=json.load(f)
-
- df,df_copy=process_input(json_data,method=method,normalize=normalize,n_components=n_components)
-
- if n_components==2:
- fig=px.scatter(df,x="x",y="y",color="group",hover_name=process_input(json_data,method="MDS",normalize=True)[0].index,hover_data=["src"])
- else:
- fig=px.scatter_3d(df,x="x",y="y",z="z",color="group",hover_name=process_input(json_data,method="MDS",normalize=True)[0].index,hover_data=["src"])
-
- fig.update_traces(hoverinfo="none", hovertemplate=None)
- fig.update_traces(marker=dict(size=15,))
- #increase the font size
- fig.update_layout(
- font=dict(
- size=19,
- )
- )
- # convert df_copy to tall format
-
- df_copy_=df_copy.reset_index().melt(id_vars=["index","group"],var_name="compound",value_name="concentration")
-
- fig_cod_portions=px.box(df_copy_,x="compound",y="concentration",color="group",)
- fig_cod_portions.update_layout(font=dict(size=19,))
-
-
-
- #### Modeling Panel ####
-
- base_feed=adm.DEFAULT_FEED
-
- with open(configs.Database().model_parameters,"r") as f:
- mp=json.load(f)
- with open(configs.Database().base_parameters,"r") as f:
- bp=json.load(f)
- with open(configs.Database().species,"r") as f:
- sp=json.load(f)
- with open(configs.Database().reactions,"r") as f:
- rxns=json.load(f)
- with open(configs.Database().initial_conditions,"r") as f:
- ic=json.load(f)
- with open(configs.Database().inlet_conditions,"r") as f:
- inc=json.load(f)
-
-
- base_model=adm.Model(model_parameters=mp,
- base_parameters=bp,
- initial_conditions=ic,
- inlet_conditions=inc,
- feed=base_feed,
- species=sp,
- reactions=rxns,
- ode_system=adm.modified_adm_ode_sys,
- build_stoichiometric_matrix=adm.build_modified_adm_stoichiometric_matrix,
- )
- sol_df={}
-
- for i in json_data.keys():
- prep={"sample":i,
- "host":json_data[i]["group"],}
- ic_=ic.copy()
- for j in json_data[i]["data"].keys():
- ic_[j]=df_copy.loc[i,j]*TOTALL_MICROBIAL_COD
- model=adm.Model(model_parameters=mp,
- base_parameters=bp,
- initial_conditions=ic_,
- inlet_conditions=inc,
- feed=base_feed,
- species=sp,
- reactions=rxns,
- ode_system=adm.modified_adm_ode_sys,
- build_stoichiometric_matrix=adm.build_modified_adm_stoichiometric_matrix,
- )
- sol=model.solve_model(np.linspace(0, DURATION, 1000))
- prep.update({"sol":sol.y})
- sol_df.update({i:prep})
- comp_inds=[sp.index(i) for i in _compounds]
- solution=[]
- for sample in sol_df.keys():
- for ind in comp_inds:
- solution.append({"sample":sample,
- "host":sol_df[sample]["host"],
- "compound":sp[ind],
- "concentration":sol_df[sample]["sol"][ind,-1]})
-
-
- solution_df=pd.DataFrame(solution)
- conc_plot=px.box(solution_df,x="compound",y="concentration",color="host",points="all")
- ## add all points and make the font size bigger
- conc_plot.update_traces(marker=dict(size=6,),
- pointpos=0,)
- conc_plot.update_layout(font=dict(size=19,))
-
-
-
- app = Dash(__name__,external_stylesheets=[dbc.themes.FLATLY])
- styles={
- 'table_width': '95%',
- 'padding-left': '20px',
- 'container_width': '95%'
- }
- app.layout =html.Div([dbc.Container(
- html.H1("ADToolbox Metagenomics Report",
- style={"font-size":"70px", "padding-top":"50px"}),
- className="text-white bg-primary",
- style={"height":"300px","text-align": "center"},
- fluid=True),
- dbc.Container([
- dbc.Row(
- [dbc.Card([
- html.H2("High-Level Relationship Between Samples",style={"font-size":"40px","padding-top":"5px"}),
- dcc.Graph(figure=fig,
- id='MDS_Plot',
- clear_on_unhover=True,
- style={
- "height":"800px",
- "padding-top":"20px",
- "padding-bottom":"20px",
- "width":styles['container_width'],
- "align-items": "center",
- "display": "inline-block",}
- ),
- dcc.Tooltip(id="cod-tooltip"),],
- style={"align-items": "center"},
- class_name='bg-light'
-
- ),
- dbc.Card([
- html.H2("Portion of COD Concentrations of ADM Microbial Species",style={"font-size":"40px","padding-top":"5px"}),
- dcc.Graph(figure=fig_cod_portions,
- id='box_plot',
- clear_on_unhover=True,
- style={
- "height":"800px",
- "padding-top":"20px",
- "padding-bottom":"20px",
- "width":styles['container_width'],
- "align-items": "center",
- "display": "inline-block",}
- )],
- style={"align-items": "center","padding-top":"10px" },
- class_name='bg-light'),
-
- dbc.Card([
- dbc.Row([
- dbc.Col([
- html.H2("Select Species to Show",style={"width":"300px","font-size":"25px","padding-bottom":"5px","align-items":"center",},),
- dcc.Checklist(sp, id="species",
- value=_compounds,
- style={"font-size":"22px",
- "padding-left":"5px",
- "padding-buttom":"100px",
- "height":"150px",
- "overflow-x":"scroll",
- "width":"250px",
- "background-color":"#f8f9fa",
- "color":"#808080"
- },
-
- inline=False,
- labelStyle={'display': 'block'}),],style={"padding-top":"5px",
- "height":"280px",
- "padding-bottom":"50px"}),
- dbc.Col(
- [
- html.H2("Feed Composition",style={"width":"300px","font-size":"25px","padding-bottom":"5px","align-items":"center",},),
- dash_table.DataTable(
- id='feed_comp',
- columns=[{"name": i, "id": i} for i in ["Lipid","Carbohydrates","Proteins"]],
- data=[
- {"Lipid":10,"Carbohydrates":20,"Proteins":10}
- ],
- editable=True,
- style_header={
- 'backgroundColor': 'gray',
- 'fontWeight': 'bold',
- "fontFamily": "system-ui",
- 'color':'white',
- 'font-size':'20px',
- 'height': '60px',
- 'width':'200px',
- 'text-align':'center',
-
- },
- style_data={
- 'backgroundColor': 'white',
- 'color': 'black',
- 'font-size':'20px',
- 'height': '60px',
- 'text-align':'center',
- 'width':'150px',}
- ),
- dbc.Spinner(html.Div(id="loading-output"),
- color="primary",type="grow",
- fullscreen=True,
- fullscreen_style={"background-color":"rgba(255,255,255,0.8)"}
- ),
- ]
- , style={"width":"150px"}),
- dbc.Col([
- html.H3("Feed Characteristics",style={"font-size":"25px","padding-bottom":"5px","align-items":"center",},),
- dash_table.DataTable(
- id='feed_char',
- columns=[{"name": i, "id": i} for i in ["TSS","Total COD","Particulate Inerts","Soluble Inerts"]],
-
- data=[
- {"TSS":10,"Total COD":20,"Particulate Inerts":10,"Soluble Inerts":10}
- ],
- editable=True,
- style_header={
- 'backgroundColor': 'gray',
- 'fontWeight': 'bold',
- "fontFamily": "system-ui",
- 'color':'white',
- 'font-size':'20px',
- 'height': '60px',
- 'width':'200px',
- 'text-align':'center',
-
- },
- style_data={
- 'backgroundColor': 'white',
- 'color': 'black',
- 'font-size':'20px',
- 'height': '60px',
- 'text-align':'center',
- 'width':'150px',}
- ),
-
-
- ]),
-
-
- ],class_name='text-white bg-primary',style={"width":"95%","padding-top":"25px","height":"250px" }),
- dcc.Graph(figure=conc_plot,id="conc_plot",
- style={"height":"800px","padding-top":"20px",
- "padding-bottom":"20px","width":styles['container_width'],
- "align-items": "center","display": "inline-block",})
-
-
-
-
-
- ],style={"align-items": "center","padding-top":"5px" },class_name='bg-light'),
-
- ]),]),])
-
-
-
-
-
- @callback(
- Output("cod-tooltip", "show"),
- Output("cod-tooltip", "bbox"),
- Output("cod-tooltip", "children"),
- Input("MDS_Plot", "hoverData"),
- )
- def display_hover(hoverData):
- if hoverData is None:
- return False, no_update, no_update
- pt = hoverData["points"][0]
- bbox = pt["bbox"]
- img_src=base64.b64encode(open(pt["customdata"][0], 'rb').read()).decode('ascii')
- children = [
- html.Div([
- html.Img(src='data:image/png;base64,{}'.format(img_src), style={"width": "100%"}),
- # html.P(f"{form}"),
- # html.P(f"{desc}"),
- ], style={'width': '500px', 'white-space': 'normal'})
- ]
-
- return True, bbox, children
-
-
- @callback(
- Output("conc_plot", "figure"),
- Output("loading-output", "children"),
- Input("species", "value"),
- Input("feed_comp", "data"),
- Input("feed_char", "data")
- )
- def checkbox_update(value,data1,data2):
- if ctx.triggered[0]["prop_id"]=="feed_comp.data" or ctx.triggered[0]["prop_id"]=="feed_char.data":
-
- ic_["TSS"]=float(data2[0]["TSS"])
- ic_["TDS"]=float(data2[0]["Total COD"])-float(data2[0]["TSS"])
- feed=core.Feed(
- carbohydrates=float(data1[0]["Carbohydrates"]),
- proteins=float(data1[0]["Proteins"]),
- lipids=float(data1[0]["Lipid"]),
- tss=float(data2[0]["TSS"]),
- si=float(data2[0]["Soluble Inerts"]),
- xi=float(data2[0]["Particulate Inerts"]),)
-
- sol_df_={}
- for i in json_data.keys():
- prep={"sample":i,
- "host":json_data[i]["group"],}
- for j in json_data[i]["data"].keys():
- ic_[j]=df_copy.loc[i,j]*TOTALL_MICROBIAL_COD
- model=adm.Model(model_parameters=mp,
- base_parameters=bp,
- initial_conditions=ic_,
- inlet_conditions=inc,
- feed=feed,
- species=sp,
- reactions=rxns,
- ode_system=adm.modified_adm_ode_sys,
- build_stoichiometric_matrix=adm.build_modified_adm_stoichiometric_matrix,
- )
- sol=model.solve_model(np.linspace(0, DURATION, 1000))
- prep.update({"sol":sol.y})
- sol_df_.update({i:prep})
- comp_inds=[sp.index(i) for i in value]
- solution=[]
- for sample in sol_df_.keys():
- for ind in comp_inds:
- solution.append({"sample":sample,
- "host":sol_df_[sample]["host"],
- "compound":sp[ind],
- "concentration":sol_df_[sample]["sol"][ind,-1]})
-
-
- solution_df=pd.DataFrame(solution)
- conc_plot=px.box(solution_df,x="compound",y="concentration",color="host",points="all")
- conc_plot.update_traces(marker=dict(size=6,),
- pointpos=0,)
- conc_plot.update_layout(font=dict(size=19,))
- else:
- inds=[sp.index(i) for i in value]
- solution=[]
- for sample in sol_df.keys():
- for ind in inds:
- solution.append({"sample":sample,
- "host":sol_df[sample]["host"],
- "compound":sp[ind],
- "concentration":sol_df[sample]["sol"][ind,-1]})
- solution_df=pd.DataFrame(solution)
- conc_plot=px.box(solution_df,x="compound",y="concentration",color="host",points="all")
- ## add all points and make the font size bigger
- conc_plot.update_traces(marker=dict(size=6,),
- pointpos=0,)
- conc_plot.update_layout(font=dict(size=19,))
- return conc_plot, ""
-
-
-
- @callback(Output("loading", "children"), Input("feed_comp", "data"))
- def input_triggers_spinner(value):
- return value
-
- app.run_server()
-
-
-
-if __name__ == "__main__":
- main("/Users/parsaghadermarzi/Desktop/Academics/Projects/Anaerobic_Digestion_Modeling/experiment/full_data.json",method="MDS",normalize=True,n_components=3)
\ No newline at end of file
diff --git a/adtoolbox/optimize.py b/adtoolbox/optimize.py
index 6975c54..d69c0dd 100644
--- a/adtoolbox/optimize.py
+++ b/adtoolbox/optimize.py
@@ -1,6 +1,5 @@
from adtoolbox import core,configs
from adtoolbox.core import Experiment
-from adtoolbox import Main_Dir
from adtoolbox import adm
import pandas as pd
import numpy as np
@@ -21,10 +20,11 @@
import os
from functools import lru_cache
start_time=time.strftime("%Y-%m-%d-%H-%M-%S")
-log_dir=os.path.join(Main_Dir,"logs",f"optimize_{start_time}")
+log_base_dir = os.path.join(os.getcwd(), "logs")
+log_dir=os.path.join(log_base_dir,f"optimize_{start_time}")
-if not os.path.exists(os.path.join(Main_Dir,"logs")):
- os.makedirs(os.path.join(Main_Dir,"logs"))
+if not os.path.exists(log_base_dir):
+ os.makedirs(log_base_dir)
logging.basicConfig(
filename=f"{log_dir}.log",
@@ -696,7 +696,7 @@ def calculate_fit_stats(model:adm.Model,data:Iterable[core.Experiment])->Validat
if __name__ == "__main__":
import utils
- params=utils.load_multiple_json_files(configs.E_ADM_2_LOCAL)
+ params=utils.load_multiple_json_files(configs.E_ADM_LOCAL)
model=adm.Model(
initial_conditions=params.initial_conditions,
inlet_conditions=params.inlet_conditions,
@@ -706,8 +706,8 @@ def calculate_fit_stats(model:adm.Model,data:Iterable[core.Experiment])->Validat
feed=adm.DEFAULT_FEED,
base_parameters=params.base_parameters,
control_state={},
- build_stoichiometric_matrix=adm.build_e_adm_2_stoichiometric_matrix,
- ode_system=adm.e_adm_2_ode_sys,
+ build_stoichiometric_matrix=adm.build_e_adm_stoichiometric_matrix,
+ ode_system=adm.e_adm_ode_sys,
)
db=core.Database(configs.Database())
exp=db.get_experiment_from_experiments_db("name","")[:3]
diff --git a/adtoolbox/pipeline.py b/adtoolbox/pipeline.py
deleted file mode 100644
index 0be7921..0000000
--- a/adtoolbox/pipeline.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import configs
-import inspect
-import rich
-from typing import Callable
-
-class Pipeline:
- """A class for running a chain of commands in series with parallelism."""
- def __init__(self,commands:list[Callable],arguments:dict,validate:bool=True):
- self.commands=commands
- self.arguments=arguments
- self._required_args=sum(list(inspect.signature(command).parameters.keys()) for command in self.commands)
- if validate:
- self.validate()
-
- def validate(self):
- pass
-
-
-
-
-
-
-
-
-
-
-
-
-
- def run(self):
- pass
-
- @staticmethod
- def extract_reqs_sats(command):
- """Extracts the requirements and satisfactions from a command using the tags in the docstrings"""
-
- if "Requires:" in command.__doc__ and "Satisfies:" in command.__doc__:
- reqs=re.findall(".+",command.__doc__)
- for ind,i in enumerate(reqs):
- reqs[ind]=i.replace("","").replace("","")
- sats=re.findall(".+",command.__doc__)
- for ind,i in enumerate(sats):
- sats[ind]=i.replace("","").replace("","")
- else:
- raise Exception(f"The command docstring for {command.__name__} is not properly formatted. Please use the following tags: and for requirements and satisfactions respectively.")
-
- return reqs,sats
\ No newline at end of file
diff --git a/adtoolbox/tables.py b/adtoolbox/tables.py
index 38086c3..88c2d82 100644
--- a/adtoolbox/tables.py
+++ b/adtoolbox/tables.py
@@ -3,7 +3,6 @@
- kbase class design
"""
import os
-from __init__ import Main_Dir
import rich
import configs
import dash
diff --git a/adtoolbox/utils.py b/adtoolbox/utils.py
index 6595591..16ef1f6 100644
--- a/adtoolbox/utils.py
+++ b/adtoolbox/utils.py
@@ -394,6 +394,40 @@ def load_multiple_json_files(json_files:dict[str,str])->dict:
jsons_tuple=jsons_tuple(**jsons)
return jsons_tuple
+
+def load_json_entry(json_file: str, entry_key: str, required_keys: Iterable[str] | None = None) -> dict:
+ """Load one top-level entry from a keyed JSON file."""
+ with open(json_file, "r") as f:
+ entries = json.load(f)
+
+ if entry_key not in entries:
+ available = ", ".join(sorted(entries))
+ raise KeyError(f"{entry_key!r} was not found in {json_file}. Available keys: {available}")
+
+ entry = entries[entry_key]
+ if not isinstance(entry, dict):
+ raise TypeError(f"{entry_key!r} in {json_file} must be a JSON object")
+
+ if required_keys:
+ missing = sorted(set(required_keys) - set(entry))
+ if missing:
+ raise KeyError(f"{entry_key!r} in {json_file} is missing required keys: {', '.join(missing)}")
+
+ return entry
+
+
+def load_model_json(json_file: str, model_key: str) -> dict:
+ """Load one ADM model from a JSON file containing all models."""
+ required_keys = [
+ "model_parameters",
+ "base_parameters",
+ "initial_conditions",
+ "inlet_conditions",
+ "reactions",
+ "species",
+ ]
+ return load_json_entry(json_file, model_key, required_keys=required_keys)
+
def needs_repair(func):
def to_be_repaired(*args,**kwargs):
warn("This function is not optimized yet or have issues in running. Please use it with caution.")
diff --git a/docs/ADM_Models.md b/docs/ADM_Models.md
new file mode 100644
index 0000000..147b698
--- /dev/null
+++ b/docs/ADM_Models.md
@@ -0,0 +1,513 @@
+# ADM Models
+
+ADToolbox exposes two anaerobic digestion models:
+
+| CLI command | Model | Parameter folder | Stoichiometric builder | ODE system |
+| --- | --- | --- | --- | --- |
+| `adtoolbox ADM adm1` | ADM1 | `adm1` | `adm.build_adm1_stoichiometric_matrix` | `adm.adm1_ode_sys` |
+| `adtoolbox ADM e-adm` | e-ADM | `e_adm` | `adm.build_e_adm_stoichiometric_matrix` | `adm.e_adm_ode_sys` |
+
+The CLI and public API use only the names ADM1 and e-ADM. The preferred parameter format is one `models.json` file containing all models, keyed by model name.
+
+## Model Inputs
+
+The canonical model input is a single JSON file with one top-level key per model:
+
+```json
+{
+ "adm1": {
+ "species": [],
+ "reactions": [],
+ "model_parameters": {},
+ "base_parameters": {},
+ "initial_conditions": {},
+ "inlet_conditions": {}
+ },
+ "e_adm": {
+ "species": [],
+ "reactions": [],
+ "model_parameters": {},
+ "base_parameters": {},
+ "initial_conditions": {},
+ "inlet_conditions": {}
+ }
+}
+```
+
+The first layer is always the model key. The second layer is the complete model payload used to instantiate `adm.Model`.
+
+| Top-level key | Public model | CLI command |
+| --- | --- | --- |
+| `adm1` | ADM1 | `adtoolbox ADM adm1 --models-json models.json` |
+| `e_adm` | e-ADM | `adtoolbox ADM e-adm --models-json models.json` |
+
+The older six-file layout is still supported as a compatibility path, either by passing `--parameters-dir` or by passing each file explicitly.
+
+| Input file | ADM1 name | e-ADM name | Description |
+| --- | --- | --- | --- |
+| Model parameters | `adm1_model_parameters.json` | `e_adm_model_parameters.json` | Kinetic, equilibrium, inhibition, gas transfer, and yield parameters used in reaction rates and acid/base calculations. |
+| Base parameters | `adm1_base_parameters.json` | `e_adm_base_parameters.json` | Reactor-level constants such as liquid volume, gas volume, influent flow, gas transfer constants, pressure, temperature, and gas constants. |
+| Initial conditions | `adm1_initial_conditions.json` | `e_adm_initial_conditions.json` | Initial concentration of every model state. Keys must match the species list. |
+| Inlet conditions | `adm1_inlet_conditions.json` | `e_adm_inlet_conditions.json` | Influent concentration of every model state, using the same species names with `_in` appended. |
+| Reactions | `adm1_reactions.json` | `e_adm_reactions.json` | Ordered reaction names. This order defines the columns of the stoichiometric matrix and the reaction-rate vector. |
+| Species | `adm1_species.json` | `e_adm_species.json` | Ordered state names. This order defines the rows of the stoichiometric matrix and the concentration vector. |
+
+The CLI also accepts:
+
+| Option | Applies to | Description |
+| --- | --- | --- |
+| `--models-json` | ADM1, e-ADM | Preferred input. JSON file containing all models keyed by model name. |
+| `--parameters-dir` | ADM1, e-ADM | Directory containing the six JSON files for the selected model. |
+| `--model-parameters`, `--base-parameters`, `--initial-conditions`, `--inlet-conditions`, `--reactions`, `--species` | ADM1, e-ADM | Override individual JSON file paths. |
+| `--report` | ADM1, e-ADM | Output mode. Use `csv` to write a report or `dash` to open the interactive app. If omitted, the model is solved without creating an output view. |
+| `--control-states` | e-ADM | JSON object of states to hold constant. By default, e-ADM holds `S_H_ion` at `10^-6.5`. |
+
+### ADM1 Input Contract
+
+| Input object | Required shape | Required naming rule | How it is used |
+| --- | --- | --- | --- |
+| `species` | list of 38 strings | Names must match every key in `initial_conditions`; each inlet key must be `species_name + "_in"`. | Defines the order of the state vector `c`. |
+| `reactions` | list of 28 strings | Names must match the reaction names used in `build_adm1_stoichiometric_matrix` and `adm1_ode_sys`. | Defines the order of the reaction vector `v` and the columns of `S`. |
+| `initial_conditions` | object with 38 numeric values | Keys are exactly the ADM1 species names. | Converted to `y0`, the initial state passed to `solve_ivp`. |
+| `inlet_conditions` | object with 38 numeric values | Keys are exactly the ADM1 species names with `_in` appended. | Converted to `c_in`, used in the liquid and gas flow terms. |
+| `base_parameters` | object with reactor constants | Must include `q_in`, `V_liq`, `V_gas`, `R`, `T_op`, `T_base`, `P_atm`, and `K_W` or equivalent water-equilibrium value used by the model. | Controls hydraulic dilution, gas headspace scaling, and gas partial pressures. |
+| `model_parameters` | object with kinetic, yield, fraction, acid/base, inhibition, and gas-transfer constants | Must include all keys referenced by ADM1 rates and stoichiometry, such as `k_dis`, `k_hyd_*`, `k_m_*`, `K_S_*`, `Y_*`, `f_*`, `C_*`, `N_*`, `K_a_*`, `K_pH_*`, `K_I_*`, `k_L_a`, `K_H_*`, and `k_p`. | Controls reaction rates, stoichiometric coefficients, inhibition factors, acid/base rates, and gas transfer. |
+
+### e-ADM Input Contract
+
+| Input object | Required shape | Required naming rule | How it is used |
+| --- | --- | --- | --- |
+| `species` | list of 49 strings | Names must match every key in `initial_conditions`; each inlet key must be `species_name + "_in"`. | Defines the order of the state vector `c`. |
+| `reactions` | list of 45 strings | Names must match the reaction names used in `build_e_adm_stoichiometric_matrix` and `e_adm_ode_sys`. | Defines the order of the reaction vector `v` and the columns of `S`. |
+| `initial_conditions` | object with 49 numeric values | Keys are exactly the e-ADM species names. | Converted to `y0`, after applying any `control_state` overrides. |
+| `inlet_conditions` | object with 49 numeric values | Keys are exactly the e-ADM species names with `_in` appended. | Converted to `c_in`, used in the liquid and gas flow terms. |
+| `base_parameters` | object with reactor constants | Must include `q_in`, `V_liq`, `V_gas`, `R`, `T_op`, `T_base`, `P_atm`, and `K_W`. | Controls hydraulic dilution, gas headspace scaling, and gas partial pressures. |
+| `model_parameters` | object with kinetic, yield, fraction, acid/base, inhibition, and gas-transfer constants | Must include all keys referenced by e-ADM rates and stoichiometry, including `Y_su`, `Y_aa`, `Y_fa`, `Y_ac_et`, `Y_ac_lac`, `Y_pro_et`, `Y_pro_lac`, `Y_bu_et`, `Y_bu_lac`, `Y_va`, `Y_cap`, `Y_bu`, `Y_Me_ac`, `Y_Me_CO2`, `Y_ac_et_ox`, and `Y_pro_lac_ox`. | Controls reaction rates, stoichiometric coefficients, inhibition factors, acid/base rates, and gas transfer. |
+| `control_state` | optional object | Keys must be valid species names. | Overrides initial conditions and forces selected derivatives to zero. The CLI sets `S_H_ion = 10^-6.5` by default for e-ADM. |
+
+### Other Keyed Database Files
+
+The same first-layer-key pattern should be used for other structured databases. For example, feeds can live in one `feeds.json` file:
+
+```json
+{
+ "food_waste": {
+ "name": "food_waste",
+ "carbohydrates": 10,
+ "proteins": 20,
+ "lipids": 20,
+ "si": 30,
+ "xi": 50,
+ "tss": 80
+ },
+ "manure": {
+ "name": "manure",
+ "carbohydrates": 5,
+ "proteins": 15,
+ "lipids": 5,
+ "si": 20,
+ "xi": 55,
+ "tss": 70
+ }
+}
+```
+
+That keeps the rule consistent: one file per database type, one top-level key per named item.
+
+## Model Outputs
+
+| Output | Source | Description |
+| --- | --- | --- |
+| Concentration trajectories | `Model.solve_model(...)` | Returns a SciPy `OdeResult`. `sol.t` contains time points and `sol.y` contains species concentrations ordered exactly like `model.species`. |
+| CSV report | `--report csv` or `Model.csv_report(...)` | Writes `_Report.csv`. Rows are species and columns are simulated time points. |
+| Interactive dashboard | `--report dash` or `Model.dash_app(...)` | Opens a Dash app with concentration plots and model tables. |
+| Reaction fluxes | `model.info["Fluxes"]` | The most recent reaction-rate vector `v`, ordered exactly like `model.reactions`. |
+| Stoichiometric matrix | `model.s` | Matrix `S` with shape `number_of_species x number_of_reactions`. Entry `S[i, j]` is the coefficient for species `i` in reaction `j`. |
+
+ADM1 has 38 species and 28 reactions. e-ADM has 49 species and 45 reactions.
+
+### Output Shapes
+
+| Output | ADM1 shape | e-ADM shape | Notes |
+| --- | --- | --- | --- |
+| `sol.t` | `(n_time_points,)` | `(n_time_points,)` | Time is in days in the default examples. The CLI uses `np.linspace(0, 30, 10000)`. |
+| `sol.y` | `(38, n_time_points)` | `(49, n_time_points)` | Rows follow `model.species`; columns follow `sol.t`. |
+| `model.s` | `(38, 28)` | `(49, 45)` | Rows follow species; columns follow reactions. |
+| `model.info["Fluxes"]` | `(28, 1)` | `(45, 1)` | Stores the most recent flux calculation from the ODE function. |
+| CSV report | 38 rows plus header | 49 rows plus header | The first column is the species index. Remaining columns are simulated time points. |
+
+The solver returns a fallback solution filled with `1e10` if integration fails. That is a failure sentinel, not a physical concentration.
+
+## Mathematical Setup
+
+The JSON files describe the state names, reaction names, and parameter values. The Python model converts them into a dynamic system by building a stoichiometric matrix and evaluating reaction rates at every time step.
+
+| Step | Formula | Meaning |
+| --- | --- | --- |
+| Species vector | `c(t) = [c_1(t), ..., c_n(t)]^T` | Concentrations are ordered by the species JSON file. |
+| Reaction-rate vector | `v(c, theta) = [v_1, ..., v_m]^T` | Fluxes are ordered by the reactions JSON file and are calculated from concentrations and parameters. |
+| Stoichiometric matrix | `S in R^(n x m)` | Rows are species, columns are reactions. `S[i, j]` converts reaction `j` into the concentration change of species `i`. |
+| Reaction contribution | `r(c, theta) = S v(c, theta)` | Net production or consumption of every species from biochemical, acid/base, and gas-transfer reactions. |
+| Liquid flow contribution | `(q_in / V_liq) * (c_in - c)` | Continuous stirred tank dilution or influent loading for liquid-phase states. |
+| Gas flow contribution | `(q_gas / V_gas) * (c_gas,in - c_gas)` | Headspace gas outflow for gas states. |
+| Gas flow rate | `q_gas = max(0, k_p * (P_gas - P_atm))` | Gas leaves only when calculated gas pressure exceeds atmospheric pressure. |
+| Final derivative | `dc/dt = S v(c, theta) + flow terms` | This is the vector returned to `scipy.integrate.solve_ivp`. |
+
+The implemented derivative can be written as:
+
+```text
+c = current state vector
+c_in = inlet state vector
+S = stoichiometric matrix
+v = reaction-rate vector
+
+r = S @ v
+
+for liquid states:
+ dc_liq/dt = r_liq + (q_in / V_liq) * (c_in,liq - c_liq)
+
+for gas states:
+ dc_gas/dt = r_gas + (q_gas / V_gas) * (c_in,gas - c_gas)
+```
+
+The gas states are the final three species in both models:
+
+```text
+S_gas_h2, S_gas_ch4, S_gas_co2
+```
+
+The gas pressure and gas outflow equations are:
+
+```text
+p_gas_h2 = S_gas_h2 * R * T_op / 16
+p_gas_ch4 = S_gas_ch4 * R * T_op / 64
+p_gas_co2 = S_gas_co2 * R * T_op
+p_gas_h2o = 0.0313 * exp(5290 * (1 / T_base - 1 / T_op))
+
+P_gas = p_gas_h2 + p_gas_ch4 + p_gas_co2 + p_gas_h2o
+q_gas = max(0, k_p * (P_gas - P_atm))
+```
+
+For any reaction `j`, the instantaneous contribution to species `i` is:
+
+```text
+dc_i/dt from reaction j = S[i, j] * v_j
+```
+
+This is why reaction and species names are used to build `S`: the equations are much easier to audit than when the matrix is filled with positional numbers.
+
+## Reaction Rate Forms
+
+| Reaction type | Formula pattern | Used for |
+| --- | --- | --- |
+| First-order conversion | `v_j = k * X` | Disintegration, hydrolysis, and decay reactions. |
+| Single-substrate uptake | `v_j = k_m * S_a / (K_S + S_a) * X * I` | Sugar, amino acid, LCFA, acetate, hydrogen, ethanol, lactate, and VFA uptake reactions. |
+| Competitive ADM1 C4 uptake | `v_j = k_m * S_a / (K_S + S_a) * X_c4 * S_a / (S_va + S_bu + eps) * I` | ADM1 valerate and butyrate uptake. |
+| Two-substrate uptake | `v_j = k_m * S_a * S_b / (K_a * S_a + K_b * S_b + S_a * S_b + eps) * X * I` | e-ADM syntrophic reactions that require paired substrates. |
+| Inhibition or limitation | `I = product(I_pH, I_H2, I_NH3, I_IN, ...)` | Multiplies uptake rates to suppress a reaction under limiting or inhibitory conditions. |
+| Acid/base kinetic form | `v_AB = k_AB * (S_ion * (K_a + S_H) - K_a * S_total)` | Kinetic acid/base reactions when the state is not solved algebraically. |
+| DAE acid/base update | `S_ion = K_a / (K_a + S_H) * S_total` | Algebraic speciation used when `model.switch == "DAE"`. |
+| Gas transfer | `v_gas = k_La * (S_liq - H * p_gas)` | Transfer between dissolved gas states and headspace gas states. |
+
+### Acid/Base Equations
+
+ADM1 and e-ADM both calculate kinetic acid/base rates, then set selected acid/base derivatives to zero in DAE mode. The kinetic form is:
+
+```text
+v_AB,acid = k_A_B,acid * (S_ion * (K_a,acid + S_H) - K_a,acid * S_total)
+```
+
+For carbonate and inorganic nitrogen:
+
+```text
+v_AB,co2 = k_A_B_co2 * (S_hco3_ion * (K_a_co2 + S_H) - K_a_co2 * S_IC)
+v_AB,IN = k_A_B_IN * (S_nh3 * (K_a_IN + S_H) - K_a_IN * S_IN)
+```
+
+In DAE mode, ionized species are updated algebraically. e-ADM explicitly updates:
+
+```text
+S_va_ion = K_a_va / (K_a_va + S_H) * S_va
+S_bu_ion = K_a_bu / (K_a_bu + S_H) * S_bu
+S_pro_ion = K_a_pro / (K_a_pro + S_H) * S_pro
+S_cap_ion = K_a_cap / (K_a_cap + S_H) * S_cap
+S_ac_ion = K_a_ac / (K_a_ac + S_H) * S_ac
+S_lac_ion = K_a_lac / (K_a_lac + S_H) * S_lac
+S_hco3_ion = S_IC - S_co2
+```
+
+Hydrogen ion concentration is calculated from electroneutrality unless it is controlled:
+
+```text
+S_H = -phi / 2 + 0.5 * sqrt(phi^2 + 4 * K_w)
+```
+
+When `S_H_ion` is included in `control_state`, the controlled value is used and `dS_H_ion/dt = 0`.
+
+### Inhibition Equations
+
+The pH inhibition terms use Hill-type functions:
+
+```text
+I_pH_x = K_pH_x^n_x / (S_H^n_x + K_pH_x^n_x)
+```
+
+Nitrogen limitation is a Monod term:
+
+```text
+I_IN_lim = S_IN / (K_S_IN + S_IN + eps)
+```
+
+Hydrogen and ammonia inhibition terms use:
+
+```text
+I_h2_x = 1 / (1 + S_h2 / (K_I_h2_x + eps))
+I_nh3 = 1 / (1 + S_nh3 / (K_I_nh3 + eps))
+```
+
+ADM1 uses the same conceptual forms, with its original `I_IN_lim = 1 / (1 + K_S_IN / S_IN)` expression.
+
+## ADM1 Reactions
+
+The ADM1 reactions follow the Batstone ADM1 structure: disintegration, hydrolysis, soluble-substrate uptake, biomass decay, acid/base speciation, and gas transfer.
+
+### ADM1 Stoichiometric Coefficients
+
+ADM1 uses yield coefficients `Y_*`, product fractions `f_*`, carbon contents `C_*`, and nitrogen contents `N_*` to fill `S`. Nitrogen limitation sets selected yields to zero before `S` is built.
+
+For the main carbon-balance terms:
+
+```text
+Y_su = 0 if nitrogen_limited else Y_su
+Y_aa = 0 if nitrogen_limited else Y_aa
+Y_fa = 0 if nitrogen_limited else Y_fa
+
+s_1 = -C_xc + f_sI_xc*C_sI + f_ch_xc*C_ch + f_pr_xc*C_pr + f_li_xc*C_li + f_xI_xc*C_xI
+s_2 = -C_ch + C_su
+s_3 = -C_pr + C_aa
+s_4 = -C_li + (1 - f_fa_li)*C_su + f_fa_li*C_fa
+s_5 = -C_su + (1 - Y_su)*(f_bu_su*C_bu + f_pro_su*C_pro + f_ac_su*C_ac) + Y_su*C_bac
+s_6 = -C_aa + (1 - Y_aa)*(f_va_aa*C_va + f_bu_aa*C_bu + f_pro_aa*C_pro + f_ac_aa*C_ac) + Y_aa*C_bac
+s_7 = -C_fa + (1 - Y_fa)*0.7*C_ac + Y_fa*C_bac
+s_8 = -C_va + (1 - Y_c4)*0.54*C_pro + (1 - Y_c4)*0.31*C_ac + Y_c4*C_bac
+s_9 = -C_bu + (1 - Y_c4)*0.8*C_ac + Y_c4*C_bac
+s_10 = -C_pro + (1 - Y_pro)*0.57*C_ac + Y_pro*C_bac
+s_11 = -C_ac + (1 - Y_ac)*C_ch4 + Y_ac*C_bac
+s_12 = (1 - Y_h2)*C_ch4 + Y_h2*C_bac
+s_13 = -C_bac + C_xc
+```
+
+These terms are inserted into the `S_IC` row with negative signs for conversion reactions and positive return through decay. For example:
+
+```text
+S[S_IC, Uptake of sugars] = -s_5
+S[S_IC, Uptake of acetate] = -s_11
+S[S_IC, Decay of Xsu] = -s_13
+```
+
+Nitrogen stoichiometry follows the same pattern:
+
+```text
+S[S_IN, Uptake of sugars] = -Y_su * N_bac
+S[S_IN, Uptake of amino acids] = N_aa - Y_aa * N_bac
+S[S_IN, Uptake of acetate] = -Y_ac * N_bac
+S[S_IN, Decay of Xsu] = N_bac - N_xc
+```
+
+| Reaction | Rate expression | Main conversion represented in `S` |
+| --- | --- | --- |
+| `Disintegration` | `k_dis * X_xc` | Composite particulate matter `X_xc` is split into carbohydrates `X_ch`, proteins `X_pr`, lipids `X_li`, soluble inert `S_I`, particulate inert `X_I`, inorganic carbon `S_IC`, and inorganic nitrogen `S_IN`. |
+| `Hydrolysis carbohydrates` | `k_hyd_ch * X_ch` | Particulate carbohydrates become soluble sugars `S_su`, with carbon correction through `S_IC`. |
+| `Hydrolysis of proteins` | `k_hyd_pr * X_pr` | Particulate proteins become amino acids `S_aa`, with carbon correction through `S_IC`. |
+| `Hydrolysis of lipids` | `k_hyd_li * X_li` | Lipids split into LCFA `S_fa` and sugars `S_su`, with carbon correction through `S_IC`. |
+| `Uptake of sugars` | `k_m_su * S_su / (K_S_su + S_su) * X_su * I5` | Sugars are consumed to grow `X_su` and produce butyrate `S_bu`, propionate `S_pro`, acetate `S_ac`, hydrogen `S_h2`, inorganic carbon, and nitrogen demand. |
+| `Uptake of amino acids` | `k_m_aa * S_aa / (K_S_aa + S_aa) * X_aa * I6` | Amino acids are consumed to grow `X_aa` and produce valerate `S_va`, butyrate, propionate, acetate, hydrogen, inorganic carbon, and inorganic nitrogen. |
+| `Uptake of LCFA` | `k_m_fa * S_fa / (K_S_fa + S_fa) * X_fa * I7` | LCFA are consumed to grow `X_fa` and produce acetate, hydrogen, inorganic carbon, and nitrogen demand. |
+| `Uptake of valerate` | `k_m_c4 * S_va / (K_S_c4 + S_va) * X_c4 * S_va / (S_va + S_bu + eps) * I8` | Valerate is consumed by `X_c4`, producing propionate, acetate, hydrogen, biomass, carbon, and nitrogen demand. |
+| `Uptake of butyrate` | `k_m_c4 * S_bu / (K_S_c4 + S_bu) * X_c4 * S_bu / (S_bu + S_va + eps) * I9` | Butyrate is consumed by `X_c4`, producing acetate, hydrogen, biomass, carbon, and nitrogen demand. |
+| `Uptake of propionate` | `k_m_pr * S_pro / (K_S_pro + S_pro) * X_pro * I10` | Propionate is consumed to grow `X_pro` and produce acetate, hydrogen, carbon, and nitrogen demand. |
+| `Uptake of acetate` | `k_m_ac * S_ac / (K_S_ac + S_ac) * X_ac * I11` | Acetate is consumed by acetoclastic methanogens, producing methane `S_ch4`, `X_ac`, carbon correction, and nitrogen demand. |
+| `Uptake of Hydrogen` | `k_m_h2 * S_h2 / (K_S_h2 + S_h2) * X_h2 * I12` | Hydrogen is consumed by hydrogenotrophic methanogens, producing methane `S_ch4`, `X_h2`, carbon correction, and nitrogen demand. |
+| `Decay of Xsu` | `k_dec_X_su * X_su` | Sugar degraders decay back to composite particulate matter `X_xc`, with carbon and nitrogen returned through `S_IC` and `S_IN`. |
+| `Decay of Xaa` | `k_dec_X_aa * X_aa` | Amino acid degraders decay to `X_xc`, with carbon and nitrogen returned. |
+| `Decay of Xfa` | `k_dec_X_fa * X_fa` | LCFA degraders decay to `X_xc`, with carbon and nitrogen returned. |
+| `Decay of Xc4` | `k_dec_X_c4 * X_c4` | C4 degraders decay to `X_xc`, with carbon and nitrogen returned. |
+| `Decay of Xpro` | `k_dec_X_pro * X_pro` | Propionate degraders decay to `X_xc`, with carbon and nitrogen returned. |
+| `Decay of Xac` | `k_dec_X_ac * X_ac` | Acetoclastic methanogens decay to `X_xc`, with carbon and nitrogen returned. |
+| `Decay of Xh2` | `k_dec_X_h2 * X_h2` | Hydrogenotrophic methanogens decay to `X_xc`, with carbon and nitrogen returned. |
+| `Acid Base Equilibrium (Va)` | `k_A_B_va * (S_va_ion * (K_a_va + S_H) - K_a_va * S_va)` | Valerate speciation between total valerate `S_va` and ionized valerate `S_va_ion`. |
+| `Acid Base Equilibrium (Bu)` | `k_A_B_bu * (S_bu_ion * (K_a_bu + S_H) - K_a_bu * S_bu)` | Butyrate speciation between `S_bu` and `S_bu_ion`. |
+| `Acid Base Equilibrium (Pro)` | `k_A_B_pro * (S_pro_ion * (K_a_pro + S_H) - K_a_pro * S_pro)` | Propionate speciation between `S_pro` and `S_pro_ion`. |
+| `Acid Base Equilibrium (Ac)` | `k_A_B_ac * (S_ac_ion * (K_a_ac + S_H) - K_a_ac * S_ac)` | Acetate speciation between `S_ac` and `S_ac_ion`. |
+| `Acid Base Equilibrium (CO2)` | `k_A_B_co2 * (S_hco3_ion * (K_a_co2 + S_H) - K_a_co2 * S_IC)` | Carbonate speciation through bicarbonate `S_hco3_ion` and inorganic carbon `S_IC`. |
+| `Acid Base Equilibrium (In)` | `k_A_B_IN * (S_nh3 * (K_a_IN + S_H) - K_a_IN * S_IN)` | Nitrogen speciation between ammonia `S_nh3`, ammonium `S_nh4_ion`, and total inorganic nitrogen `S_IN`. |
+| `Gas Transfer H2` | `k_L_a * (S_h2 - 16 * K_H_h2 * p_gas_h2)` | Dissolved hydrogen leaves the liquid and enters `S_gas_h2` with `V_liq / V_gas` scaling. |
+| `Gas Transfer CH4` | `k_L_a * (S_ch4 - 64 * K_H_ch4 * p_gas_ch4)` | Dissolved methane leaves the liquid and enters `S_gas_ch4` with `V_liq / V_gas` scaling. |
+| `Gas Transfer CO2` | `k_L_a * (S_co2 - K_H_co2 * p_gas_co2)` | Dissolved carbon dioxide leaves the liquid and enters `S_gas_co2` with `V_liq / V_gas` scaling. |
+
+### ADM1 Inhibition Factors
+
+| Factor | Formula pattern | Applied to |
+| --- | --- | --- |
+| `I5` | `I_pH_aa * I_IN_lim` | Sugar uptake. |
+| `I6` | `I5` | Amino acid uptake. |
+| `I7` | `I_pH_aa * I_IN_lim * I_h2_fa` | LCFA uptake. |
+| `I8`, `I9` | `I_pH_aa * I_IN_lim * I_h2_c4` | Valerate and butyrate uptake. |
+| `I10` | `I_pH_aa * I_IN_lim * I_h2_pro` | Propionate uptake. |
+| `I11` | `I_pH_ac * I_IN_lim * I_nh3` | Acetate uptake. |
+| `I12` | `I_pH_h2 * I_IN_lim` | Hydrogen uptake. |
+
+## e-ADM Reactions
+
+e-ADM keeps the same dynamic structure but expands the soluble fermentation network. It separates ethanol-linked and lactate-linked routes, adds caproate, lactate, ethanol, explicit TSS/TDS disintegration, and two methanogenesis routes.
+
+### e-ADM Stoichiometric Coefficients
+
+e-ADM uses the same matrix logic as ADM1, but most soluble conversions are written as explicit product fractions plus a carbon-balance residual. Selected yields are set to zero under nitrogen limitation.
+
+For sugar, amino acid, and LCFA uptake:
+
+```text
+Y_su = 0 if nitrogen_limited else Y_su
+Y_aa = 0 if nitrogen_limited else Y_aa
+Y_fa = 0 if nitrogen_limited else Y_fa
+
+f_ac_su = 1 - f_pro_su - f_et_su - f_lac_su
+f_ac_aa = 1 - f_pro_aa - f_et_aa - f_lac_aa
+f_ac_fa = 1 - f_pro_fa - f_et_fa - f_lac_fa
+
+f_IC_su = -(-C_su + (1-Y_su)*f_pro_su*C_pro + (1-Y_su)*f_et_su*C_et
+ + (1-Y_su)*f_lac_su*C_lac + (1-Y_su)*f_ac_su*C_ac + Y_su*C_bac)
+
+f_IC_aa = -(-C_aa + (1-Y_aa)*f_pro_aa*C_pro + (1-Y_aa)*f_et_aa*C_et
+ + (1-Y_aa)*f_lac_aa*C_lac + (1-Y_aa)*f_ac_aa*C_ac + Y_aa*C_bac)
+
+f_IC_fa = -(-C_fa + (1-Y_fa)*f_pro_fa*C_pro + (1-Y_fa)*f_et_fa*C_et
+ + (1-Y_fa)*f_lac_fa*C_lac + (1-Y_fa)*f_ac_fa*C_ac + Y_fa*C_bac)
+```
+
+For chain elongation and VFA conversion, e-ADM uses paired substrate routes:
+
+```text
+f_IC_ac_et = -(-C_ac + f_et_ac*C_et + (1-f_et_ac-Y_ac_et)*f_bu_ac*C_bu + Y_ac_et*C_bac)
+f_IC_ac_lac = -(-C_ac + f_lac_ac*C_lac + (1-f_lac_ac-Y_ac_lac)*f_bu_ac*C_bu + Y_ac_lac*C_bac)
+
+f_IC_pro_et = -(-C_pro + f_et_pro*C_et + (1-f_et_pro-Y_pro_et)*f_va_pro*C_va + Y_pro_et*C_bac)
+f_IC_pro_lac = -(-C_pro + f_lac_pro*C_lac + (1-f_lac_pro-Y_pro_lac)*f_va_pro*C_va + Y_pro_lac*C_bac)
+
+f_IC_bu_et = -(-C_bu + f_et_bu*C_et + (1-f_et_bu-Y_bu_et)*f_cap_bu*C_cap + Y_bu_et*C_bac)
+f_IC_bu_lac = -(-C_bu + f_lac_bu*C_lac + (1-f_lac_bu-Y_bu_lac)*f_cap_bu*C_cap + Y_bu_lac*C_bac)
+```
+
+Methanogenesis and oxidation use:
+
+```text
+f_IC_Me_ach2 = -(f_ac_h2*C_ac + (1 - Y_Me_ac)*C_ch4 + Y_Me_ac*C_bac)
+f_IC_et_ox = -(-C_et + (1-Y_ac_et_ox)*C_bac + Y_ac_et_ox*C_ac)
+f_IC_lac_ox = -(-C_lac + (1-Y_pro_lac_ox)*C_bac + Y_pro_lac_ox*C_pro)
+```
+
+The stoichiometric matrix then combines these residuals with explicit product coefficients. For example:
+
+```text
+S[S_su, Uptake of sugars] = -1
+S[S_pro, Uptake of sugars] = (1 - Y_su) * f_pro_su
+S[S_et, Uptake of sugars] = (1 - Y_su) * f_et_su
+S[S_lac, Uptake of sugars] = (1 - Y_su) * f_lac_su
+S[S_ac, Uptake of sugars] = (1 - Y_su) * f_ac_su
+S[S_IN, Uptake of sugars] = -Y_su * N_bac
+S[S_IC, Uptake of sugars] = f_IC_su
+S[X_su, Uptake of sugars] = Y_su
+```
+
+| Reaction | Rate expression | Main conversion represented in `S` |
+| --- | --- | --- |
+| `TSS_Disintegration` | `k_dis_TSS * TSS` | Total suspended solids are split into `X_ch`, `X_pr`, `X_li`, and inert particulate biomass `X_I` using feed fractions. |
+| `TDS_Disintegration` | `k_dis_TDS * TDS` | Total dissolved solids are split into `X_ch`, `X_pr`, `X_li`, and soluble inert `S_I` using feed fractions. |
+| `Hydrolysis carbohydrates` | `k_hyd_ch * X_ch` | Particulate carbohydrate is hydrolyzed to soluble sugar `S_su`. |
+| `Hydrolysis proteins` | `k_hyd_pr * X_pr` | Particulate protein is hydrolyzed to amino acids `S_aa`. |
+| `Hydrolysis lipids` | `k_hyd_li * X_li` | Particulate lipids are hydrolyzed to LCFA `S_fa`. |
+| `Uptake of sugars` | `k_m_su * S_su / (K_S_su + S_su) * X_su * I5` | Sugars are consumed to grow `X_su` and form propionate, ethanol, lactate, acetate, carbon, and nitrogen demand. |
+| `Uptake of amino acids` | `k_m_aa * S_aa / (K_S_aa + S_aa) * X_aa * I6` | Amino acids are consumed to grow `X_aa` and form propionate, ethanol, lactate, acetate, inorganic carbon, and inorganic nitrogen. |
+| `Uptake of LCFA` | `k_m_fa * S_fa / (K_S_fa + S_fa) * X_fa * I7` | LCFA are consumed to grow `X_fa` and form propionate, ethanol, lactate, acetate, carbon, and nitrogen demand. |
+| `Uptake of acetate_et` | `k_m_ac * S_ac * S_et / (K_S_ac*S_ac + K_S_ac_et*S_et + S_ac*S_et + eps) * X_ac_et * I11` | Acetate and ethanol are converted by `X_ac_et`, producing butyrate, hydrogen, carbon correction, and new biomass. |
+| `Uptake of acetate_lac` | `k_m_ac * S_ac * S_lac / (K_S_ac*S_ac + K_S_ac_lac*S_lac + S_ac*S_lac + eps) * X_ac_lac * I11` | Acetate and lactate are converted by `X_ac_lac`, producing butyrate, hydrogen, carbon correction, and new biomass. |
+| `Uptake of propionate_et` | `k_m_pro * S_pro * S_et / (K_S_pro*S_pro + K_S_pro_et*S_et + S_pro*S_et + eps) * X_chain_et * I10` | Propionate and ethanol are converted by chain-elongating biomass, producing valerate, hydrogen, carbon correction, and `X_chain_et`. |
+| `Uptake of propionate_lac` | `k_m_pro * S_pro * S_lac / (K_S_pro*S_pro + K_S_pro_lac*S_lac + S_pro*S_lac + eps) * X_chain_lac * I10` | Propionate and lactate are converted by chain-elongating biomass, producing valerate, hydrogen, carbon correction, and `X_chain_lac`. |
+| `Uptake of butyrate_et` | `k_m_bu * S_bu * S_et / (K_S_bu*S_bu + K_S_bu_et*S_et + S_bu*S_et + eps) * X_chain_et * I14` | Butyrate and ethanol are converted to caproate, hydrogen, carbon correction, and `X_chain_et`. |
+| `Uptake of butyrate_lac` | `k_m_bu * S_bu * S_lac / (K_S_bu*S_bu + K_S_bu_lac*S_lac + S_bu*S_lac + eps) * X_chain_lac * I14` | Butyrate and lactate are converted to caproate, hydrogen, carbon correction, and `X_chain_lac`. |
+| `Uptake of valerate` | `k_m_va * S_va / (K_S_va + S_va) * X_VFA_deg * I15` | Valerate is degraded to propionate and `X_VFA_deg`. |
+| `Uptake of caproate` | `k_m_cap * S_cap / (K_S_cap + S_cap) * X_VFA_deg * I13` | Caproate is degraded to acetate and `X_VFA_deg`. |
+| `Uptake of butyrate` | `k_m_bu_deg * S_bu / (K_S_bu + S_bu) * X_VFA_deg * I13` | Butyrate is degraded to acetate and `X_VFA_deg`. |
+| `Methanogenessis from acetate and h2` | `k_m_h2_Me_ac * S_gas_h2 * S_ac / (K_S_h2_Me_ac*S_gas_h2 + K_S_ac_Me*S_ac + S_ac*S_gas_h2 + eps) * X_Me_ac * I12` | Acetate and gas-phase hydrogen are converted to dissolved methane `S_ch4`, methanogenic biomass `X_Me_ac`, carbon correction, and nitrogen demand. |
+| `Methanogenessis from CO2 and h2` | `k_m_h2_Me_CO2 * S_gas_h2 * S_gas_co2 / (K_S_h2_Me_CO2*S_gas_h2 + K_S_CO2_Me*S_gas_co2 + S_gas_co2*S_gas_h2 + eps) * X_Me_CO2 * I12` | Gas-phase hydrogen and carbon dioxide are converted to gas-phase methane `S_gas_ch4`, `X_Me_CO2`, gas-phase carbon dioxide change, and nitrogen demand. |
+| `Uptake of ethanol` | `k_m_et * S_et / (K_S_et + S_et) * X_et * I16` | Ethanol is oxidized to acetate, inorganic carbon, and `X_et`. |
+| `Uptake of lactate` | `k_m_lac * S_lac / (K_S_lac + S_lac) * X_lac * I16` | Lactate is oxidized to propionate, inorganic carbon, and `X_lac`. |
+| `Decay of Xsu` | `k_dec_X_su * X_su` | Sugar degraders decay to TSS, returning biomass carbon and nitrogen. |
+| `Decay of Xaa` | `k_dec_X_aa * X_aa` | Amino acid degraders decay to TSS, returning biomass carbon and nitrogen. |
+| `Decay of Xfa` | `k_dec_X_fa * X_fa` | LCFA degraders decay to TSS, returning biomass carbon and nitrogen. |
+| `Decay of X_ac_et` | `k_dec_X_ac * X_ac_et` | Acetate-ethanol consumers decay to TSS, returning biomass carbon and nitrogen. |
+| `Decay of X_ac_lac` | `k_dec_X_ac * X_ac_lac` | Acetate-lactate consumers decay to TSS, returning biomass carbon and nitrogen. |
+| `Decay of Xpro` | Not currently assigned in `e_adm_ode_sys` | Listed in the reaction set but not given a rate in the current ODE block. If kept, it behaves as zero-flux unless populated elsewhere. |
+| `Decay of X_chain_et` | `k_dec_X_chain_et * X_chain_et` | Ethanol-linked chain elongators decay to TSS, returning biomass carbon and nitrogen. |
+| `Decay of X_chain_lac` | `k_dec_X_chain_lac * X_chain_lac` | Lactate-linked chain elongators decay to TSS, returning biomass carbon and nitrogen. |
+| `Decay of X_VFA_deg` | `k_dec_X_VFA_deg * X_VFA_deg` | VFA degraders decay to TSS, returning biomass carbon and nitrogen. |
+| `Decay of X_Me_ac` | `k_dec_X_Me_ac * X_Me_ac` | Acetate/hydrogen methanogens decay to TSS, returning biomass carbon and nitrogen. |
+| `Decay of X_Me_CO2` | `k_dec_X_Me_CO2 * X_Me_CO2` | CO2/hydrogen methanogens decay to TSS, returning biomass carbon and nitrogen. |
+| `Decay of Xet` | `k_dec_X_et * X_et` | Ethanol oxidizers decay. This rate is present in the ODE; the current stoichiometric builder should be checked if this flux is expected to affect states. |
+| `Decay of Xlac` | `k_dec_X_lac * X_lac` | Lactate oxidizers decay. This rate is present in the ODE; the current stoichiometric builder should be checked if this flux is expected to affect states. |
+| `Acid Base Equilibrium (Va)` | `k_A_B_va * (S_va_ion * (K_a_va + S_H) - K_a_va * S_va)` | Valerate speciation between `S_va` and `S_va_ion`. |
+| `Acid Base Equilibrium (Bu)` | `k_A_B_bu * (S_bu_ion * (K_a_bu + S_H) - K_a_bu * S_bu)` | Butyrate speciation between `S_bu` and `S_bu_ion`. |
+| `Acid Base Equilibrium (Pro)` | `k_A_B_pro * (S_pro_ion * (K_a_pro + S_H) - K_a_pro * S_pro)` | Propionate speciation between `S_pro` and `S_pro_ion`. |
+| `Acid Base Equilibrium (Cap)` | `k_A_B_cap * (S_cap_ion * (K_a_cap + S_H) - K_a_cap * S_cap)` | Caproate speciation between `S_cap` and `S_cap_ion`. |
+| `Acid Base Equilibrium (Lac)` | `k_A_B_lac * (S_lac_ion * (K_a_lac + S_H) - K_a_lac * S_lac)` | Lactate speciation between `S_lac` and `S_lac_ion`. |
+| `Acid Base Equilibrium (Ac)` | `k_A_B_ac * (S_ac_ion * (K_a_ac + S_H) - K_a_ac * S_ac)` | Acetate speciation between `S_ac` and `S_ac_ion`. |
+| `Acid Base Equilibrium (CO2)` | `k_A_B_co2 * (S_hco3_ion * (K_a_co2 + S_H) - K_a_co2 * S_IC)` | Carbonate speciation through bicarbonate `S_hco3_ion` and inorganic carbon `S_IC`. |
+| `Acid Base Equilibrium (In)` | `k_A_B_IN * (S_nh3 * (K_a_IN + S_H) - K_a_IN * S_IN)` | Nitrogen speciation between ammonia `S_nh3`, ammonium `S_nh4_ion`, and total inorganic nitrogen `S_IN`. |
+| `Gas Transfer H2` | `max(0, k_L_a * (S_h2 - 16 * K_H_h2 * p_gas_h2))` | Dissolved hydrogen leaves the liquid and enters `S_gas_h2` with `V_liq / V_gas` scaling. |
+| `Gas Transfer CH4` | `max(0, k_L_a * (S_ch4 - 64 * K_H_ch4 * p_gas_ch4))` | Dissolved methane leaves the liquid and enters `S_gas_ch4` with `V_liq / V_gas` scaling. |
+| `Gas Transfer CO2` | `max(0, k_L_a * (S_co2 - K_H_co2 * p_gas_co2))` | Dissolved carbon dioxide leaves the liquid and enters `S_gas_co2` with `V_liq / V_gas` scaling. |
+
+### e-ADM Inhibition Factors
+
+| Factor | Formula pattern | Applied to |
+| --- | --- | --- |
+| `I5` | `I_pH_aa * I_IN_lim` | Sugar uptake. |
+| `I6` | `I5` | Amino acid uptake. |
+| `I7` | `I_pH_aa * I_IN_lim * I_h2_fa` | LCFA uptake. |
+| `I10` | `I_pH_pro * I_IN_lim * I_h2_pro` | Propionate plus ethanol or lactate uptake. |
+| `I11` | `I_pH_ac * I_IN_lim * I_nh3` | Acetate plus ethanol or lactate uptake. |
+| `I12` | `I_pH_h2 * I_IN_lim` | Methanogenesis. |
+| `I13` | `I_pH_cap * I_IN_lim * I_h2_c4` | Caproate uptake and direct butyrate degradation. |
+| `I14` | `I_pH_bu * I_IN_lim * I_h2_c4` | Butyrate plus ethanol or lactate uptake. |
+| `I15` | `I_pH_va * I_IN_lim * I_h2_c4` | Valerate uptake. |
+| `I16` | `I_IN_lim * I_nh3 * I_pH_aa * I_h2_oxidation` | Ethanol and lactate oxidation. |
+
+## Methane-Producing Reactions
+
+| Model | Methane-producing reactions |
+| --- | --- |
+| ADM1 | `Uptake of acetate`, `Uptake of Hydrogen` |
+| e-ADM | `Methanogenessis from acetate and h2`, `Methanogenessis from CO2 and h2` |
+
+`Gas Transfer CH4` does not create methane. It moves methane between dissolved `S_ch4` and gas-phase `S_gas_ch4`.
+
+## State Vectors
+
+### ADM1 Species
+
+`S_su`, `S_aa`, `S_fa`, `S_va`, `S_bu`, `S_pro`, `S_ac`, `S_h2`, `S_ch4`, `S_IC`, `S_IN`, `S_I`, `X_xc`, `X_ch`, `X_pr`, `X_li`, `X_su`, `X_aa`, `X_fa`, `X_c4`, `X_pro`, `X_ac`, `X_h2`, `X_I`, `S_cation`, `S_anion`, `S_H_ion`, `S_va_ion`, `S_bu_ion`, `S_pro_ion`, `S_ac_ion`, `S_hco3_ion`, `S_co2`, `S_nh3`, `S_nh4_ion`, `S_gas_h2`, `S_gas_ch4`, `S_gas_co2`
+
+### e-ADM Species
+
+`S_su`, `S_aa`, `S_fa`, `S_va`, `S_bu`, `S_pro`, `S_et`, `S_lac`, `S_cap`, `S_ac`, `S_h2`, `S_ch4`, `S_IC`, `S_IN`, `S_I`, `TSS`, `TDS`, `X_ch`, `X_pr`, `X_li`, `X_su`, `X_aa`, `X_ac_et`, `X_ac_lac`, `X_fa`, `X_VFA_deg`, `X_et`, `X_lac`, `X_chain_et`, `X_chain_lac`, `X_Me_ac`, `X_Me_CO2`, `X_I`, `S_cation`, `S_anion`, `S_H_ion`, `S_va_ion`, `S_bu_ion`, `S_pro_ion`, `S_cap_ion`, `S_lac_ion`, `S_ac_ion`, `S_hco3_ion`, `S_co2`, `S_nh3`, `S_nh4_ion`, `S_gas_h2`, `S_gas_ch4`, `S_gas_co2`
+
+## Minimal CLI Run
+
+```bash
+adtoolbox ADM adm1 --models-json /path/to/ADToolbox/models.json --report csv
+```
+
+```bash
+adtoolbox ADM e-adm --models-json /path/to/ADToolbox/models.json --report csv
+```
diff --git a/docs/API.md b/docs/API.md
index 092e563..ac6fa8e 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -1,16 +1,16 @@
# API
-ADToolbox has its own way of figuring out the path to the required files and configurations required for running different methods. The entire toolbox relies on the configs module. Objects of different classes in ADToolbox are instantiated by an instance of the corresponding class in the configs module. For instance, if you want to use the methods of the metagenomics class in core module, you should do the following:
+ADToolbox configuration objects derive file paths from the directory that you pass to them. There is no global project or base directory. Objects in the core module can still be instantiated with a matching object from the configs module. For instance, if you want to use the methods of the metagenomics class in core module, you should do the following:
```
from adtoolbox import configs and core
-metag_conf=configs.Metagenomics()
+metag_conf=configs.Metagenomics("./my_metagenomics_run", database_dir="./my_database")
metag_object=core.Metagenomics(metag_conf)
```
-Doing this will result in that any core.Metagenomics method will refer to the defult configurations defined in the configs module. If you want to overwright the defult configuration, you can pass the desired argument to the configs.Metagenomics constructor. For example, if you want to change the docker repository for VSEARCH
+Doing this makes any core.Metagenomics method use paths under the selected run and database directories. If you want to overwrite a default configuration, pass the desired argument to the configs.Metagenomics constructor. For example, if you want to change the docker repository for VSEARCH
you can:
```
@@ -107,4 +107,3 @@ This module includes the following classes:
::: adtoolbox.adm
-
diff --git a/docs/CLI.md b/docs/CLI.md
index c46e99c..1d9d33e 100644
--- a/docs/CLI.md
+++ b/docs/CLI.md
@@ -1,472 +1,246 @@
-# ADToolbox Commandline Interface
+# ADToolbox Command Line Interface
--------------
-## Initialization
-First, we need to initialize the CLI:
-After installing ADToolbox, type and execute the following in your terminal to initialize the base directory for ADToolbox files:
+The ADToolbox command line interface is installed as `adtoolbox`.
+```bash
+adtoolbox --help
+adtoolbox --version
```
-ADToolbox
-```
-You should see the following if you are running this for the first time:
-
-```
-No Base Directory Found:
-Where do you want to store your ADToolbox Data?:
-
-```
-Type the **absolute path** directory of interest. Don't worry if you mess this part up. You can change this later as well. you can type '.' for now and change this later.
-
-You can access all the commands along with their brief explanation by:
-
-```
-ADToolbox --help
-
-```
-
--------------
-## ADToolbox Modules
-
-This toolbox is comprised of different modules:
-
-1. Configs Module
-
-2. Database Module
-
-3. Metagenomics Module
-
-4. ADM Module
-
-5. Documentations Module
-
--------------
-### 1. Configs Module
-
-After installation, the base working directory must be specified:
-
-```
-ADToolbox Configs --help
-
-────────────────────────────────── ADToolBox───────────────────────────────────
-
-usage: ADToolBox Configs [-h] [-s SET_BASE_DIR] [-g] [--get-base-dir]
-
-optional arguments:
- -h, --help show this help message and exit
- -s SET_BASE_DIR, --set-base-dir SET_BASE_DIR
- Set the base directory for ADToolBox to work with
- -g, --get-base-dir Get the current base directory for ADToolBox
-
-
-```
-This will give you a list of all functionalities that are related to the configurations of the toolbox. Here we go one by one in the correct order:
-
-- set-base-dir: The first configuration command will allow you to set the base directory for ADToolbox to work. This could be an existing folder somewhere in your files or a directory that you are willing to create. If the directory does not already exit, it will be automatically created after this command. For example if I want to set the base directory to be ADToolbox directory on my desktop the command would be, in MacOS, something like this:
-
-```
-
-ADToolbox Configs --set-base-dir ~/Desktop/ADToolbox
-
-```
-
-Anything that you will do from now on, will be saved in this directory.
-
-
--------------
-### 2. Database Module
-
-Any database that is used by ADToolbox can be modified from this module. Type the following in your commandline to find all of the database module's commands:
-
-```
-ADToolbox Database --help
-──────────────────────────── ADToolBox ────────────────────────────
-usage: ADToolBox Database [-h]
- {initialize-feed-db,add-feed,sh
-ow-feed-db,initialize-metagenomics-studies-db,add-metagen
-omics-study,initialize-protein-db,add-protein,download-re
-action-db,download-seed-reaction-db,build-protein-db,down
-load-protein-db,download-amplicon-to-genome-dbs,download-
-all-databases}
- ...
-
-positional arguments:
- {initialize-feed-db,add-feed,show-feed-db,initialize-me
-tagenomics-studies-db,add-metagenomics-study,initialize-p
-rotein-db,add-protein,download-reaction-db,download-seed-
-reaction-db,build-protein-db,download-protein-db,download
--amplicon-to-genome-dbs,download-all-databases}
- Database commands:
- initialize-feed-db Initialize the Feed DB
- add-feed Add a feed to the feed database
- show-feed-db Shows the feed database
- initialize-metagenomics-studies-db
- Initialize the Metagenomics Studies DB
- add-metagenomics-study
- Add a metagenomics study to the Kbase
- initialize-protein-db
- Generates the protein database for ADToolbox
- add-protein Add a protein to the protein database
- download-reaction-db
- Downloads the reaction database in CSV
- format
- download-seed-reaction-db
- Downloads the seed reaction database in
- JSON format
- build-protein-db Generates the protein database for
- ADToolbox
- download-protein-db
- Downloads the protein database in fasta
- format; You can alternatively build it
- from reaction database.
- download-amplicon-to-genome-dbs
- downloads amplicon to genome databases
- download-all-databases
- downloads all databases that are required by ADToolbox at once
-
-options:
- -h, --help show this help message and exit
-```
-
-We will now go over these commands one by one:
-
-- initialize-feed-db: This will create an empty JSON file in the Database sub-directory in your base directory that will hold all the future feed information that you add. You can run this command by:
-
-```
-ADToolbox Database initialize-feed-db
-
-```
-
-- add-feed: This will add feed data to the database. Such data includes: the name of the feed (-n, --name), carbohydrate content of the feed in a percentage (-c, --carbohydrates), protein content of the feed in a percecntage (-p, --proteins), lipid content of the feed in a percentage (-l, --lipids), total suspended solid content of the feed in a percentage (-t, --tss), soluable inert content of feed in a percentage (-s, --si), particulate inert content of feed in a percentage (-x, --xi), and a reference where numbers came from (-r, --reference). This command is run by:
-
-```
-ADToolbox Database add-feed
-
-```
-An example of this would look like:
-
-```
-ADToolbox Database add-feed -n "test feed" -c 20 -p 20 -l 20 -t 20 -s 20 -x 20 -r "test reference"
-
-```
-
-- show-feed-db: As the name implies, this will show the user the feed database along with any values they have added to it, in the command window. This command is run by:
-
-```
-ADToolbox Database show-feed-db
-
-```
-- initialize-metagenomics-studies-db: This will create an empty TSV file in the Database sub-directory in your base directory that will hold all the future information about various metagenomics studies that you add. You can run this command by:
-
-```
-ADToolbox Database initialize-metagenomics-studies-db
-
-```
-- add-metagenomics-study: This command will add a metagenomics study to the Kbase and will require the study name (-n,--name), study type (-t, --type), microbiome where the metagenomics study belongs to (-m, --microbiome), SRA accession ID for the sample (-s, --sample_accesion), SRA accession ID for the project (-p, --study_accesion), and comments on the study of interest (-c, --comments). This command is run by:
-
-```
-ADToolbox Database add-metagenomics-study
-
-```
-An example of this would look like:
-
-```
-ADToolbox Database add-metagenomics-study -n test_study -t 16s -m "anaerobic digestion" -s 11111111 -c "this is just a test" -p 222222
+The CLI does not create or store a global project directory. Commands that need files or directories accept those paths directly. If a required path is omitted, the command prompts for it.
-```
-- initialize-protein-db: This will create an empty JSON file in the Database sub-directory in your base directory that will hold all the future protein information that you add. You can run this command by:
+## Modules
-```
-ADToolbox Database initialize-protein-db
+| Module | Purpose |
+| --- | --- |
+| `Database` | Initialize, edit, download, and build ADToolbox databases. |
+| `Metagenomics` | Download genomes or SRA data and align genomes to protein databases. |
+| `ADM` | Run ADM1 and e-ADM models. |
+| `Documentations` | Print package documentation in the terminal. |
-```
-- add-protein: As the name implies, this will add information about a protein to the empty protein database. Information about such protein includes its UniProt ID (-i, --uniprot-id), and the name attached to the protein which is usually the EC number (-n, --name). You can run this command by:
+Every command supports `-h` and `--help`.
+```bash
+adtoolbox Database --help
+adtoolbox ADM adm1 --help
```
-ADToolbox Database add-protein
-```
-An example of this would look like:
+## Database
-```
-ADToolbox Database add-protein -i ATEST1 -n 1.1.1.1
-
-```
+Database commands work with explicit file paths. The path can point to a local database you already maintain, a reference file copied from `reference_data`, or a new file you want ADToolbox to create.
-*NOTE*: Skip the following download commands if you have run ```ADToolbox Configs download-all-databases```
-```
+| Command | Required path option | Purpose |
+| --- | --- | --- |
+| `initialize-feed-db` | `--feed-db` | Create an empty feed TSV. |
+| `add-feed` | `--feed-db` | Add one feed row to a feed TSV. |
+| `show-feed-db` | `--feed-db` | Print the feed TSV, optionally filtered by feed name. |
+| `download-feed-db` | `--feed-db` | Download the reference feed TSV. |
+| `initialize-metagenomics-studies-db` | `--studies-db` | Create an empty metagenomics studies TSV. |
+| `add-metagenomics-study` | `--studies-db` | Add one metagenomics study row. |
+| `initialize-protein-db` | `--protein-db` | Create an empty protein FASTA database. |
+| `add-protein` | `--protein-db` | Add one protein FASTA entry. |
+| `download-reaction-db` | `--reaction-db` | Download reaction metadata as CSV. |
+| `download-seed-reaction-db` | `--seed-reaction-db`, `--seed-compound-db` | Download SEED reaction and compound JSON files. |
+| `build-protein-db` | `--reaction-db`, `--protein-db` | Build a protein FASTA database from reaction metadata. |
+| `download-protein-db` | `--protein-db` | Download the reference protein FASTA database. |
+| `download-amplicon-to-genome-dbs` | `--output-dir` | Download amplicon-to-genome mapping databases. |
+| `download-all-databases` | `--output-dir` | Download the standard ADToolbox database bundle. |
-- download-reaction-db: As the name implies, this will download the ADToolbox reaction database. This is required for many important modules of the toolbox
+Examples:
-```
-ADToolbox Database download-reaction-db
+```bash
+adtoolbox Database initialize-feed-db --feed-db ./database/feed_db.tsv
+adtoolbox Database add-feed \
+ --feed-db ./database/feed_db.tsv \
+ --name "food waste" \
+ --carbohydrates 42 \
+ --proteins 20 \
+ --lipids 18 \
+ --tss 80 \
+ --si 5 \
+ --xi 15 \
+ --reference "example reference"
+adtoolbox Database show-feed-db --feed-db ./database/feed_db.tsv
+adtoolbox Database show-feed-db --feed-db ./database/feed_db.tsv --filter "food waste"
```
-- download-protein-db: Downloads the protein database in fasta format; You can alternatively build it from reaction database if you have downloaded it; Check below.
+To download the full reference database bundle:
+```bash
+adtoolbox Database download-all-databases --output-dir ./database
```
-ADToolbox Database download-protein-db
+To build a protein database from reaction metadata:
+```bash
+adtoolbox Database build-protein-db \
+ --reaction-db ./database/Reaction_Metadata.csv \
+ --protein-db ./database/Protein_DB.fasta
```
-- build-protein-db: Generates the protein database for ADToolbox from the reaction database:
+## Metagenomics
-```
+Metagenomics commands also take explicit inputs and output directories.
-ADToolbox Database build-protein-db
+| Command | Purpose |
+| --- | --- |
+| `download_from_sra` | Download reads from SRA by sample accession. |
+| `download_genome` | Download a genome from NCBI by genome accession. |
+| `align-genome` | Align one genome to a protein FASTA database. |
+| `align-multiple-genomes` | Align multiple genomes listed in a JSON manifest. |
+| `find-representative-genomes` | Find representative genomes from a repseqs FASTA file. |
-```
+Use `--container None` for local execution, or `--container docker` / `--container singularity` when running through a container backend.
-- download-amplicon-to-genome-dbs: If you need to use the 16s mapping to the protein database and ADM, you will need to download the required databases using this command:
+Examples:
+```bash
+adtoolbox Metagenomics download_from_sra \
+ --sample-accession SRR28403133 \
+ --output-dir ./metagenomics/sra \
+ --container None
-```
-
-ADToolbox Database download-amplicon-to-genome-dbs
+adtoolbox Metagenomics download_genome \
+ --genome-accession GCA_021152825.1 \
+ --output-dir ./metagenomics/genomes \
+ --container None
+adtoolbox Metagenomics align-genome \
+ --name GCA_021152825_1 \
+ --input-file ./metagenomics/genomes/GCA_021152825.1.fna \
+ --output-dir ./metagenomics/alignment \
+ --protein-db ./database/Protein_DB.fasta \
+ --container None
```
-- download-seed-reaction-db: This will download the SEED reaction database in JSON format.
+For multiple genomes, the input JSON maps genome names to input files:
+```json
+{
+ "genome_1": "./genomes/genome_1.fna",
+ "genome_2": "./genomes/genome_2.fna"
+}
```
-ADToolbox Database download-seed-reaction-db
-
-```
-```
--------------
-### 3. Metagenomics Module
-
-Metagenomics module of ADToolbox is designed to input metagenomics data into consideration when designing an AD process.
-You can observe all the functionalities by:
+Run the batch alignment with:
+```bash
+adtoolbox Metagenomics align-multiple-genomes \
+ --input-file ./metagenomics/genomes.json \
+ --output-dir ./metagenomics/alignment \
+ --protein-db ./database/Protein_DB.fasta \
+ --container None
```
-ADToolbox Metagenomics --help
-
-──────────────────────────── ADToolBox ────────────────────────────
-usage: ADToolBox Metagenomics [-h]
- {download_from_sra}
- ...
-
-positional arguments:
- {download_from_sra,download_genome}
- download_from_sra This module provides a command line interface to download
- metagenomics data from SRA
- download_genome This module provides a command line interface to download
- genomes from NCBI
- align-genome Align genomes to the protein database
- of ADToolbox, or any other fasta with
- protein sequences
- align-multiple-genomes
- Align multiple Genomes to the protein
- database of ADToolbox, or any other
- fasta with protein sequences
- find-representative-genomes
- Finds representative genomes from the
- repseqs fasta file
-options:
- -h, --help show this help message and exit
+## ADM
-```
-- download_from_sra: This command takes a sample accesion ID (-s, --sample_accesion) for a sample, downloads it, and places it into a directory provided by the you (-o, --output-dir). It also requires you to state a container you are using. If you are downloading locally, put "None". Otherwise, you can use the containers docker or singularity. You can run this command by:
+The ADM CLI currently exposes two model families:
-```
-ADToolbox Metagenomics download_from_sra
+| Command | Model key | Purpose |
+| --- | --- | --- |
+| `adm1` | `adm1` | Run the original ADM1 model. |
+| `e-adm` | `e_adm` | Run the extended e-ADM model. |
-```
-An example of this command would look like:
+The recommended input format is one consolidated model JSON file keyed by model name. The repository includes a reference example at `reference_data/models.json`.
+```bash
+adtoolbox ADM adm1 --models-json reference_data/models.json --report csv
+adtoolbox ADM e-adm --models-json reference_data/models.json --report csv
```
-ADToolbox Metagenomics download_from_sra -s SRR28403133 -o OUTPUT/DIRECTORY/PATHNAME -c None
-```
-- download_genome: This command requires you to provide a NCBI accesion ID for a genome (-g, --genome_accesion), and output directory (-o,--output-dir), and a container (-c, --container). It will then take the NCBI accesion ID for a genome and download it in the directory provided by you. If you are downloading locally, put "None" as your container option. Otherwise, you can use the containers docker or singularity. You can run this command by:
+When `--report csv` is used, the CLI asks where to save the output CSV. When `--report dash` is used, or when `--report` is omitted, the CLI opens the interactive Dash visualization.
-```
-ADToolbox Metagenomics download_genome
+The e-ADM command can also accept a control-state JSON file:
+```bash
+adtoolbox ADM e-adm \
+ --models-json reference_data/models.json \
+ --control-states ./control_states.json \
+ --report csv
```
-An example of this command would look like:
-```
-ADToolbox Metagenomics download_genome -g GCA021152825.1 -o OUTPUT/DIRECTORY/PATHNAME -c None
+If `--control-states` is omitted, e-ADM uses:
+```json
+{
+ "S_H_ion": 3.162277660168379e-7
+}
```
-- align-genome: This command requires that you to give a name for the genome (-n,--name),the address of the JSON file that includes information about the genome to be aligned (-i,--input-file), and output directory to store alignment results (-o,--output-dir), a container to use for the alignment (-c,--container), and the directory containing the protein database to be used for the alignment (-d, --protein-db-dir). If you are downloading locally, put "None" as your container option. Otherwise, you can use the containers docker or singularity. Overall, this command takes a genome and aligns it to a protein sequence. You can run this command by:
-```
-ADToolBox Metagenomics align-genome
+The consolidated model JSON has this structure:
+```json
+{
+ "adm1": {
+ "model_parameters": {},
+ "base_parameters": {},
+ "initial_conditions": {},
+ "inlet_conditions": {},
+ "reactions": {},
+ "species": {}
+ },
+ "e_adm": {
+ "model_parameters": {},
+ "base_parameters": {},
+ "initial_conditions": {},
+ "inlet_conditions": {},
+ "reactions": {},
+ "species": {}
+ }
+}
```
-An example of this code would look like:
-```
-ADToolbox Metagenomics align-genome -n "test genome" -i INPUT/PATHNAME/OF/GENOME -o OUTPUT/PATHNAME/DIRECTORY -c None -d PATHNAME/OF/PROTEIN
+For compatibility with older database layouts, each ADM command can still load six separate JSON files:
-```
-- align-multiple-genomes: This command allows you to align multiple genomes to the protein database of ADToolbox, or any other fasta file with protein sequences. It requires to user to input the address to a JSON file that holds the information about the genomes (-i,--input-file), an output directory to store the alignment results (-o,--output-dir), a container to use for the alignment (-c,--container), and the directory containing the protein database to be used for alignment (-d,--protein-db-dir). If you are downloading locally, put "None" as your container option. Otherwise, you can use the containers docker or singularity. This command can be run by:
+| Option | Contents |
+| --- | --- |
+| `--model-parameters` | Kinetic and model-specific parameters. |
+| `--base-parameters` | Shared physical and biochemical constants. |
+| `--initial-conditions` | Initial state values. |
+| `--inlet-conditions` | Influent state values. |
+| `--reactions` | Reaction names and ordering. |
+| `--species` | Species names and ordering. |
-```
-ADToolbox Metagenomics align-multiple-genomes
+You can pass those files directly:
+```bash
+adtoolbox ADM adm1 \
+ --model-parameters ./ADM_Parameters/adm1_model_parameters.json \
+ --base-parameters ./ADM_Parameters/adm1_base_parameters.json \
+ --initial-conditions ./ADM_Parameters/adm1_initial_conditions.json \
+ --inlet-conditions ./ADM_Parameters/adm1_inlet_conditions.json \
+ --reactions ./ADM_Parameters/adm1_reactions.json \
+ --species ./ADM_Parameters/adm1_species.json \
+ --report csv
```
-An example of this command looks like:
-```
-ADToolbox Metagenomics align-multiple-genomes -i PATHNAME/TO/FILE/OF/GENOMES -o OUTPUT/DIRECTORY -c None -d DIRECTORY/OF/PROTEIN/DATABSE
+Or pass a directory containing consistently named files:
+```bash
+adtoolbox ADM adm1 --parameters-dir ./ADM_Parameters --report csv
+adtoolbox ADM e-adm --parameters-dir ./ADM_Parameters --report csv
```
-- find-represenative-genomes: This command maps represenative amplicon sequences to a representative genome in GTDB database. It requires the user to provide the address to the repseqs fasta file (-i,--input-file), the directory of the output file (-o, --output-dir), a container used for the alignment (-c,--container), and the format of the output file which can be json or csv (-f,--format). Something optional that you can provide is the similarity cutoff for clustering; though, the default is 0.97 (-s,--similarity). If you are downloading locally, put "None" as your container option. Otherwise, you can use the containers docker or singularity. You can run this code by:
-```
-ADToolbox Metagenomics find-representative-genomes
+For `e-adm`, the CLI first looks for `e_adm_*.json` files and then falls back to the legacy `e_adm_2_*.json` file names.
-```
-An example of this code will look like:
+## Documentation
-```
-ADToolbox Metagenomics find-representative-genomes -i PATHNAME/TO/REPSEQS/FASTA/FILE -o PATHNAME/TO/OUTPUT/DIRECTORY -c None -f csv
+Print the package README in the terminal:
+```bash
+adtoolbox Documentations --show
```
--------------------------------
-### 4. ADM Module
-
-ADM module provides all the tools needed to run instances of ADM Model. This includes the original ADM, Batstone et al., and the Modified-ADM suggested by the Authors of ADToolbox. In order to find out about all the functionalities in this module, you can run:
-
-```
+## Reference Data
-ADToolbox ADM --help
-────────────────────────────────── ADToolBox ───────────────────────────────────
-usage: ADToolBox ADM [-h] {original-adm1,modified-adm,show-escher-map} ...
+This repository includes clean reference JSON files that mirror the current database shape:
-positional arguments:
- {original-adm1,modified-adm,show-escher-map}
- Available ADM Commands:
- original-adm1 Original ADM1:
- modified-adm Modified ADM:
+| File | Contents |
+| --- | --- |
+| `reference_data/models.json` | ADM1 and e-ADM requirements keyed by model name. |
+| `reference_data/feeds.json` | Feed entries keyed by normalized feed name. |
+| `reference_data/experiments.json` | Experiment entries keyed by normalized experiment name. |
-options:
- -h, --help show this help message and exit
-
-```
-
-- original-adm1: If you want to run the original ADM, batstone et al, in your browser you can run this command with the required parameters in JSON format:
-
-```
-ADToolbox ADM original-adm1 --help
-────────────────────────────────── ADToolBox ───────────────────────────────────
-usage: ADToolBox ADM original-adm1 [-h] [--model-parameters MODEL_PARAMETERS]
- [--base-parameters BASE_PARAMETERS]
- [--initial-conditions INITIAL_CONDITIONS]
- [--inlet-conditions INLET_CONDITIONS]
- [--reactions REACTIONS] [--species SPECIES]
- [--metagenome-report METAGENOME_REPORT]
- [--report REPORT]
-
-options:
- -h, --help show this help message and exit
- --model-parameters MODEL_PARAMETERS
- Model parameters for ADM 1
- --base-parameters BASE_PARAMETERS
- Provide json file with base parameters for original
- ADM1
- --initial-conditions INITIAL_CONDITIONS
- Provide json file with initial conditions for original
- ADM1
- --inlet-conditions INLET_CONDITIONS
- Provide json file with inlet conditions for original
- ADM1
- --reactions REACTIONS
- Provide json file with reactions for original ADM1
- --species SPECIES Provide json file with species for original ADM1
- --metagenome-report METAGENOME_REPORT
- Provide json file with metagenome report for original
- ADM1
- --report REPORT Describe how to report the results of original ADM1.
- Current options are: 'dash' and 'csv'
-
-
-```
-
-Every argument is optional, and their role is clear from the comments in front of them, So we just provide a full example of this command:
-
-
-```
-ADToolbox ADM original-adm1 \
---model-parameters ~/Desktop/Model_Parameters.json \
---base-parameters ~/Desktop/Base_Parameters.json \
---initial-conditions ~/Desktop/Initial_Conditions.json \
---inlet-conditions ~/Desktop/Inlet-Conditions.json \
---reactions ~/Desktop/Reactions.json
---species ~/Desktop/Species.json
---metagenome-report ~/Desktop/ADM_Mapping_Report.json
---repor dash
-
-```
-**NOTE** if you choose dash for your report, the CLI will prompt you to open your browser in the instructed address, if you choose csv, it will generate a CSV file that includes concentration profiles simulated over time.
-
----------------
-
-- modified-adm: This command is exactly similar to the previous one, except that it requires parameters taylored for modified ADM:
-
-```
-
-ADToolbox ADM modified-adm --help
-────────────────────────────────── ADToolBox ───────────────────────────────────
-usage: ADToolBox ADM modified-adm [-h] [--model-parameters MODEL_PARAMETERS]
- [--base-parameters BASE_PARAMETERS]
- [--initial-conditions INITIAL_CONDITIONS]
- [--inlet-conditions INLET_CONDITIONS]
- [--reactions REACTIONS] [--species SPECIES]
- [--metagenome-report METAGENOME_REPORT]
- [--report REPORT]
-
-options:
- -h, --help show this help message and exit
- --model-parameters MODEL_PARAMETERS
- Model parameters for Modified ADM
- --base-parameters BASE_PARAMETERS
- Provide json file with base parameters for modified
- ADM
- --initial-conditions INITIAL_CONDITIONS
- Provide json file with initial conditions for modified
- ADM
- --inlet-conditions INLET_CONDITIONS
- Provide json file with inlet conditions for modified
- ADM
- --reactions REACTIONS
- Provide json file with reactions for modified ADM
- --species SPECIES Provide json file with species for modified ADM
- --metagenome-report METAGENOME_REPORT
- Provide json file with metagenome report for modified
- ADM
- --report REPORT Describe how to report the results of modified ADM.
- Current options are: 'dash' and 'csv'
-
-```
-
-The usage is exactly the same as the original-adm
-
--------------------------
-
-- show-escher-map: This command will prompt you to open an escher map for the modified-adm model in your browser with the instructed address:
-
-```
-ADToolbox ADM show-escher-map
-
-```
-
--------------
-### 5. Documentations Module
-
-You can view the documentaion in your CLI using rich's markdown render. You can do this by:
-
-```
-ADToolbox Documentations --show
-
-```
+These files are meant as portable examples and test fixtures. Production runs can point the CLI at any equivalent local files.
diff --git a/docs/modeling.html b/docs/modeling.html
index dbbf5db..926ee72 100644
--- a/docs/modeling.html
+++ b/docs/modeling.html
@@ -7777,7 +7777,7 @@
Building a map for the model (o
-
You built your first model successfully! Now lets use a prebuilt ADM model to analyze. Here we will use e-adm2 which is an extended version of ADM1 that includes more details on VFA metabolism
+
You built your first model successfully! Now lets use a prebuilt ADM model to analyze. Here we will use e-ADM which is an extended version of ADM1 that includes more details on VFA metabolism
@@ -7804,7 +7804,7 @@
Building a map for the model (o
In [ ]:
-
db=core.Database(configs.Database(adm_parameters_urls=configs.E_ADM_2_REMOTE,adm_parameters=configs.E_ADM_2_LOCAL))#To make sure the parameters are up to date
+
db=core.Database(configs.Database(adm_parameters_urls=configs.E_ADM_REMOTE,adm_parameters=configs.E_ADM_LOCAL))#To make sure the parameters are up to datedb.download_adm_parameters(verbose=False)
@@ -7818,7 +7818,7 @@
Building a map for the model (o
-
As an example, we want to compare gas production between three microbiomes explored in Ding et al. The data for this study is added to the database before (see Parameter Tuning notebook). First lets load the model parameters.The address to the parameter files are in E_ADM_2_LOCAL variable in the configs module and they are in json format. You can either load the files one by one or use a helper function like below:
+
As an example, we want to compare gas production between three microbiomes explored in Ding et al. The data for this study is added to the database before (see Parameter Tuning notebook). First lets load the model parameters.The address to the parameter files are in E_ADM_LOCAL variable in the configs module and they are in json format. You can either load the files one by one or use a helper function like below:
Building a map for the model (o
inlet_conditions=params.inlet_conditions,species=params.species,reactions=params.reactions,
- build_stoichiometric_matrix=adm.build_e_adm_2_stoichiometric_matrix,
- ode_system=adm.e_adm_2_ode_sys,
+ build_stoichiometric_matrix=adm.build_e_adm_stoichiometric_matrix,
+ ode_system=adm.e_adm_ode_sys,feed=feed,control_state={'S_H_ion':10**(-6.5)},)
diff --git a/docs/parameter_tuning.html b/docs/parameter_tuning.html
index 8efa5f5..eb892f5 100644
--- a/docs/parameter_tuning.html
+++ b/docs/parameter_tuning.html
@@ -9209,8 +9209,8 @@
The CLI and public API use only the names ADM1 and e-ADM. The preferred parameter format is one models.json file containing all models, keyed by model name.
+
Model Inputs
+
The canonical model input is a single JSON file with one top-level key per model:
Output mode. Use csv to write a report or dash to open the interactive app. If omitted, the model is solved without creating an output view.
+
+
+
--control-states
+
e-ADM
+
JSON object of states to hold constant. By default, e-ADM holds S_H_ion at 10^-6.5.
+
+
+
+
ADM1 Input Contract
+
+
+
+
Input object
+
Required shape
+
Required naming rule
+
How it is used
+
+
+
+
+
species
+
list of 38 strings
+
Names must match every key in initial_conditions; each inlet key must be species_name + "_in".
+
Defines the order of the state vector c.
+
+
+
reactions
+
list of 28 strings
+
Names must match the reaction names used in build_adm1_stoichiometric_matrix and adm1_ode_sys.
+
Defines the order of the reaction vector v and the columns of S.
+
+
+
initial_conditions
+
object with 38 numeric values
+
Keys are exactly the ADM1 species names.
+
Converted to y0, the initial state passed to solve_ivp.
+
+
+
inlet_conditions
+
object with 38 numeric values
+
Keys are exactly the ADM1 species names with _in appended.
+
Converted to c_in, used in the liquid and gas flow terms.
+
+
+
base_parameters
+
object with reactor constants
+
Must include q_in, V_liq, V_gas, R, T_op, T_base, P_atm, and K_W or equivalent water-equilibrium value used by the model.
+
Controls hydraulic dilution, gas headspace scaling, and gas partial pressures.
+
+
+
model_parameters
+
object with kinetic, yield, fraction, acid/base, inhibition, and gas-transfer constants
+
Must include all keys referenced by ADM1 rates and stoichiometry, such as k_dis, k_hyd_*, k_m_*, K_S_*, Y_*, f_*, C_*, N_*, K_a_*, K_pH_*, K_I_*, k_L_a, K_H_*, and k_p.
+
Controls reaction rates, stoichiometric coefficients, inhibition factors, acid/base rates, and gas transfer.
+
+
+
+
e-ADM Input Contract
+
+
+
+
Input object
+
Required shape
+
Required naming rule
+
How it is used
+
+
+
+
+
species
+
list of 49 strings
+
Names must match every key in initial_conditions; each inlet key must be species_name + "_in".
+
Defines the order of the state vector c.
+
+
+
reactions
+
list of 45 strings
+
Names must match the reaction names used in build_e_adm_stoichiometric_matrix and e_adm_ode_sys.
+
Defines the order of the reaction vector v and the columns of S.
+
+
+
initial_conditions
+
object with 49 numeric values
+
Keys are exactly the e-ADM species names.
+
Converted to y0, after applying any control_state overrides.
+
+
+
inlet_conditions
+
object with 49 numeric values
+
Keys are exactly the e-ADM species names with _in appended.
+
Converted to c_in, used in the liquid and gas flow terms.
+
+
+
base_parameters
+
object with reactor constants
+
Must include q_in, V_liq, V_gas, R, T_op, T_base, P_atm, and K_W.
+
Controls hydraulic dilution, gas headspace scaling, and gas partial pressures.
+
+
+
model_parameters
+
object with kinetic, yield, fraction, acid/base, inhibition, and gas-transfer constants
+
Must include all keys referenced by e-ADM rates and stoichiometry, including Y_su, Y_aa, Y_fa, Y_ac_et, Y_ac_lac, Y_pro_et, Y_pro_lac, Y_bu_et, Y_bu_lac, Y_va, Y_cap, Y_bu, Y_Me_ac, Y_Me_CO2, Y_ac_et_ox, and Y_pro_lac_ox.
+
Controls reaction rates, stoichiometric coefficients, inhibition factors, acid/base rates, and gas transfer.
+
+
+
control_state
+
optional object
+
Keys must be valid species names.
+
Overrides initial conditions and forces selected derivatives to zero. The CLI sets S_H_ion = 10^-6.5 by default for e-ADM.
+
+
+
+
Other Keyed Database Files
+
The same first-layer-key pattern should be used for other structured databases. For example, feeds can live in one feeds.json file:
That keeps the rule consistent: one file per database type, one top-level key per named item.
+
Model Outputs
+
+
+
+
Output
+
Source
+
Description
+
+
+
+
+
Concentration trajectories
+
Model.solve_model(...)
+
Returns a SciPy OdeResult. sol.t contains time points and sol.y contains species concentrations ordered exactly like model.species.
+
+
+
CSV report
+
--report csv or Model.csv_report(...)
+
Writes <model.name>_Report.csv. Rows are species and columns are simulated time points.
+
+
+
Interactive dashboard
+
--report dash or Model.dash_app(...)
+
Opens a Dash app with concentration plots and model tables.
+
+
+
Reaction fluxes
+
model.info["Fluxes"]
+
The most recent reaction-rate vector v, ordered exactly like model.reactions.
+
+
+
Stoichiometric matrix
+
model.s
+
Matrix S with shape number_of_species x number_of_reactions. Entry S[i, j] is the coefficient for species i in reaction j.
+
+
+
+
ADM1 has 38 species and 28 reactions. e-ADM has 49 species and 45 reactions.
+
Output Shapes
+
+
+
+
Output
+
ADM1 shape
+
e-ADM shape
+
Notes
+
+
+
+
+
sol.t
+
(n_time_points,)
+
(n_time_points,)
+
Time is in days in the default examples. The CLI uses np.linspace(0, 30, 10000).
+
+
+
sol.y
+
(38, n_time_points)
+
(49, n_time_points)
+
Rows follow model.species; columns follow sol.t.
+
+
+
model.s
+
(38, 28)
+
(49, 45)
+
Rows follow species; columns follow reactions.
+
+
+
model.info["Fluxes"]
+
(28, 1)
+
(45, 1)
+
Stores the most recent flux calculation from the ODE function.
+
+
+
CSV report
+
38 rows plus header
+
49 rows plus header
+
The first column is the species index. Remaining columns are simulated time points.
+
+
+
+
The solver returns a fallback solution filled with 1e10 if integration fails. That is a failure sentinel, not a physical concentration.
+
Mathematical Setup
+
The JSON files describe the state names, reaction names, and parameter values. The Python model converts them into a dynamic system by building a stoichiometric matrix and evaluating reaction rates at every time step.
+
+
+
+
Step
+
Formula
+
Meaning
+
+
+
+
+
Species vector
+
c(t) = [c_1(t), ..., c_n(t)]^T
+
Concentrations are ordered by the species JSON file.
+
+
+
Reaction-rate vector
+
v(c, theta) = [v_1, ..., v_m]^T
+
Fluxes are ordered by the reactions JSON file and are calculated from concentrations and parameters.
+
+
+
Stoichiometric matrix
+
S in R^(n x m)
+
Rows are species, columns are reactions. S[i, j] converts reaction j into the concentration change of species i.
+
+
+
Reaction contribution
+
r(c, theta) = S v(c, theta)
+
Net production or consumption of every species from biochemical, acid/base, and gas-transfer reactions.
+
+
+
Liquid flow contribution
+
(q_in / V_liq) * (c_in - c)
+
Continuous stirred tank dilution or influent loading for liquid-phase states.
+
+
+
Gas flow contribution
+
(q_gas / V_gas) * (c_gas,in - c_gas)
+
Headspace gas outflow for gas states.
+
+
+
Gas flow rate
+
q_gas = max(0, k_p * (P_gas - P_atm))
+
Gas leaves only when calculated gas pressure exceeds atmospheric pressure.
+
+
+
Final derivative
+
dc/dt = S v(c, theta) + flow terms
+
This is the vector returned to scipy.integrate.solve_ivp.
+
+
+
+
The implemented derivative can be written as:
+
c = current state vector
+c_in = inlet state vector
+S = stoichiometric matrix
+v = reaction-rate vector
+
+r = S @ v
+
+for liquid states:
+ dc_liq/dt = r_liq + (q_in / V_liq) * (c_in,liq - c_liq)
+
+for gas states:
+ dc_gas/dt = r_gas + (q_gas / V_gas) * (c_in,gas - c_gas)
+
+
The gas states are the final three species in both models:
For any reaction j, the instantaneous contribution to species i is:
+
dc_i/dt from reaction j = S[i, j] * v_j
+
+
This is why reaction and species names are used to build S: the equations are much easier to audit than when the matrix is filled with positional numbers.
ADM1 uses the same conceptual forms, with its original I_IN_lim = 1 / (1 + K_S_IN / S_IN) expression.
+
ADM1 Reactions
+
The ADM1 reactions follow the Batstone ADM1 structure: disintegration, hydrolysis, soluble-substrate uptake, biomass decay, acid/base speciation, and gas transfer.
+
ADM1 Stoichiometric Coefficients
+
ADM1 uses yield coefficients Y_*, product fractions f_*, carbon contents C_*, and nitrogen contents N_* to fill S. Nitrogen limitation sets selected yields to zero before S is built.
Nitrogen speciation between ammonia S_nh3, ammonium S_nh4_ion, and total inorganic nitrogen S_IN.
+
+
+
Gas Transfer H2
+
k_L_a * (S_h2 - 16 * K_H_h2 * p_gas_h2)
+
Dissolved hydrogen leaves the liquid and enters S_gas_h2 with V_liq / V_gas scaling.
+
+
+
Gas Transfer CH4
+
k_L_a * (S_ch4 - 64 * K_H_ch4 * p_gas_ch4)
+
Dissolved methane leaves the liquid and enters S_gas_ch4 with V_liq / V_gas scaling.
+
+
+
Gas Transfer CO2
+
k_L_a * (S_co2 - K_H_co2 * p_gas_co2)
+
Dissolved carbon dioxide leaves the liquid and enters S_gas_co2 with V_liq / V_gas scaling.
+
+
+
+
ADM1 Inhibition Factors
+
+
+
+
Factor
+
Formula pattern
+
Applied to
+
+
+
+
+
I5
+
I_pH_aa * I_IN_lim
+
Sugar uptake.
+
+
+
I6
+
I5
+
Amino acid uptake.
+
+
+
I7
+
I_pH_aa * I_IN_lim * I_h2_fa
+
LCFA uptake.
+
+
+
I8, I9
+
I_pH_aa * I_IN_lim * I_h2_c4
+
Valerate and butyrate uptake.
+
+
+
I10
+
I_pH_aa * I_IN_lim * I_h2_pro
+
Propionate uptake.
+
+
+
I11
+
I_pH_ac * I_IN_lim * I_nh3
+
Acetate uptake.
+
+
+
I12
+
I_pH_h2 * I_IN_lim
+
Hydrogen uptake.
+
+
+
+
e-ADM Reactions
+
e-ADM keeps the same dynamic structure but expands the soluble fermentation network. It separates ethanol-linked and lactate-linked routes, adds caproate, lactate, ethanol, explicit TSS/TDS disintegration, and two methanogenesis routes.
+
e-ADM Stoichiometric Coefficients
+
e-ADM uses the same matrix logic as ADM1, but most soluble conversions are written as explicit product fractions plus a carbon-balance residual. Selected yields are set to zero under nitrogen limitation.
Gas-phase hydrogen and carbon dioxide are converted to gas-phase methane S_gas_ch4, X_Me_CO2, gas-phase carbon dioxide change, and nitrogen demand.
+
+
+
Uptake of ethanol
+
k_m_et * S_et / (K_S_et + S_et) * X_et * I16
+
Ethanol is oxidized to acetate, inorganic carbon, and X_et.
+
+
+
Uptake of lactate
+
k_m_lac * S_lac / (K_S_lac + S_lac) * X_lac * I16
+
Lactate is oxidized to propionate, inorganic carbon, and X_lac.
+
+
+
Decay of Xsu
+
k_dec_X_su * X_su
+
Sugar degraders decay to TSS, returning biomass carbon and nitrogen.
+
+
+
Decay of Xaa
+
k_dec_X_aa * X_aa
+
Amino acid degraders decay to TSS, returning biomass carbon and nitrogen.
+
+
+
Decay of Xfa
+
k_dec_X_fa * X_fa
+
LCFA degraders decay to TSS, returning biomass carbon and nitrogen.
+
+
+
Decay of X_ac_et
+
k_dec_X_ac * X_ac_et
+
Acetate-ethanol consumers decay to TSS, returning biomass carbon and nitrogen.
+
+
+
Decay of X_ac_lac
+
k_dec_X_ac * X_ac_lac
+
Acetate-lactate consumers decay to TSS, returning biomass carbon and nitrogen.
+
+
+
Decay of Xpro
+
Not currently assigned in e_adm_ode_sys
+
Listed in the reaction set but not given a rate in the current ODE block. If kept, it behaves as zero-flux unless populated elsewhere.
+
+
+
Decay of X_chain_et
+
k_dec_X_chain_et * X_chain_et
+
Ethanol-linked chain elongators decay to TSS, returning biomass carbon and nitrogen.
+
+
+
Decay of X_chain_lac
+
k_dec_X_chain_lac * X_chain_lac
+
Lactate-linked chain elongators decay to TSS, returning biomass carbon and nitrogen.
+
+
+
Decay of X_VFA_deg
+
k_dec_X_VFA_deg * X_VFA_deg
+
VFA degraders decay to TSS, returning biomass carbon and nitrogen.
+
+
+
Decay of X_Me_ac
+
k_dec_X_Me_ac * X_Me_ac
+
Acetate/hydrogen methanogens decay to TSS, returning biomass carbon and nitrogen.
+
+
+
Decay of X_Me_CO2
+
k_dec_X_Me_CO2 * X_Me_CO2
+
CO2/hydrogen methanogens decay to TSS, returning biomass carbon and nitrogen.
+
+
+
Decay of Xet
+
k_dec_X_et * X_et
+
Ethanol oxidizers decay. This rate is present in the ODE; the current stoichiometric builder should be checked if this flux is expected to affect states.
+
+
+
Decay of Xlac
+
k_dec_X_lac * X_lac
+
Lactate oxidizers decay. This rate is present in the ODE; the current stoichiometric builder should be checked if this flux is expected to affect states.
ADToolbox has its own way of figuring out the path to the required files and configurations required for running different methods. The entire toolbox relies on the configs module. Objects of different classes in ADToolbox are instantiated by an instance of the corresponding class in the configs module. For instance, if you want to use the methods of the metagenomics class in core module, you should do the following:
+
ADToolbox configuration objects derive file paths from the directory that you pass to them. There is no global project or base directory. Objects in the core module can still be instantiated with a matching object from the configs module. For instance, if you want to use the methods of the metagenomics class in core module, you should do the following:
from adtoolbox import configs and core
-metag_conf=configs.Metagenomics()
+metag_conf=configs.Metagenomics("./my_metagenomics_run", database_dir="./my_database")
metag_object=core.Metagenomics(metag_conf)
-
Doing this will result in that any core.Metagenomics method will refer to the defult configurations defined in the configs module. If you want to overwright the defult configuration, you can pass the desired argument to the configs.Metagenomics constructor. For example, if you want to change the docker repository for VSEARCH
+
Doing this makes any core.Metagenomics method use paths under the selected run and database directories. If you want to overwrite a default configuration, pass the desired argument to the configs.Metagenomics constructor. For example, if you want to change the docker repository for VSEARCH
you can:
from adtoolbox import core
@@ -2815,11 +3016,12 @@
1. Experiment
+
-
+
-
-
This class creates an interface for the experimental data to be used in different places in ADToolbox.
+
+
This class creates an interface for the experimental data to be used in different places in ADToolbox.
First you should give each experiment a name. Time must be a list of time points in days, and there must be a time 0 point assinged to each experiment.
variables must be a list of integers that represent the variables that are the index of the ADM species that we have concentration data for.
data must be a list of lists. Each list in the list must be a list of concentrations for each species at each time point.
@@ -2829,122 +3031,184 @@
1. Experiment
to query for Experiment objects you can query by name or reference or model_type. So, having a descriptive reference can be useful for querying as well.
default model name is "e_adm". This can be changed by passing a different model name to the model_name argument. This also helps with querying.
-
Parameters:
-
-
-
-
Name
-
Type
-
Description
-
Default
-
-
-
-
-
name
-
- str
-
-
A unique name for the experiment.
-
- required
-
-
-
-
time
-
- list
-
-
A list of time points in days.
-
- required
-
-
-
-
variables
-
- list
-
-
A list of strings that represent the species that are in the used model (most commonly ADM) that we have concentration data for.
-
- required
-
-
-
-
data
-
- list
-
-
A list of lists. Each list in the list must be a list of concentrations for each species at each time point.
A dictionary of initial concentrations for the ADM species. Defaults to {}.
-
- dataclasses.field(default_factory=dict)
-
-
-
-
base_parameters
-
- dict
-
-
A dictionary of base parameters for the model. Defaults to {}.
-
- dataclasses.field(default_factory=dict)
-
-
-
-
constants
-
- list
-
-
A list of strings that represent the species that are in the used model (most commonly ADM) that are held constant during the simulations. Their value will come from the initial_concentrations. Defaults to [].
-
- dataclasses.field(default_factory=tuple)
-
-
-
-
reference
-
- str
-
-
A reference for the experimental data. Defaults to ''.
-
- ''
-
-
+
+
Parameters:
+
+
-
model_name
-
- str
-
-
The name of the model that the experimental data is for. Defaults to "e_adm".
-
- 'e_adm'
-
+
Name
+
Type
+
Description
+
Default
-
-
+
+
+
+
+ name
+
+
+ str
+
+
+
+
A unique name for the experiment.
+
+
+
+ required
+
+
+
+
+ time
+
+
+ list
+
+
+
+
A list of time points in days.
+
+
+
+ required
+
+
+
+
+ variables
+
+
+ list
+
+
+
+
A list of strings that represent the species that are in the used model (most commonly ADM) that we have concentration data for.
+
+
+
+ required
+
+
+
+
+ data
+
+
+ list
+
+
+
+
A list of lists. Each list in the list must be a list of concentrations for each species at each time point.
A dictionary of initial concentrations for the ADM species. Defaults to {}.
+
+
+
+ dict()
+
+
+
+
+ base_parameters
+
+
+ dict
+
+
+
+
A dictionary of base parameters for the model. Defaults to {}.
+
+
+
+ dict()
+
+
+
+
+ constants
+
+
+ list
+
+
+
+
A list of strings that represent the species that are in the used model (most commonly ADM) that are held constant during the simulations. Their value will come from the initial_concentrations. Defaults to [].
+
+
+
+ tuple()
+
+
+
+
+ reference
+
+
+ str
+
+
+
+
A reference for the experimental data. Defaults to ''.
+
+
+
+ ''
+
+
+
+
+ model_name
+
+
+ str
+
+
+
+
The name of the model that the experimental data is for. Defaults to "e_adm".
@dataclass
+classExperiment:
+""" This class creates an interface for the experimental data to be used in different places in ADToolbox. First you should give each experiment a name. Time must be a list of time points in days, and there must be a time 0 point assinged to each experiment. variables must be a list of integers that represent the variables that are the index of the ADM species that we have concentration data for.
@@ -3064,17 +3334,17 @@
1. Experiment
model_name:str="e_adm"
- def__post_init__(self):
+ def__post_init__(self):self.data=np.array(self.data).Tself.validate()
- defvalidate(self):
+ defvalidate(self):assertlen(self.time)==self.data.shape[0],"Number of time points must match number of rows in data."assertlen(self.variables)==self.data.shape[1],"Number of variables must match number of columns in data."assertself.time[0]==0,"Time must start at 0."return"successful"
- defto_dict(self):
+ defto_dict(self):return{"name":self.name,"time":self.time,"variables":self.variables,
@@ -3086,9 +3356,9 @@
The Feed class is used to store the feed information, and later use it in the e_adm model.
+
+
The Feed class is used to store the feed information, and later use it in the e_adm model.
all the entered numbers must in percentages. Carbohudrates, lipids, and proteins and si must sum up to 100,
and they form the total dissolved solids. Carbohydrates, lipids, proteins, and xi must sum up to 100, and they form the total suspended solids.
IMPORTANT: It is assumed that lipid, proteins and carbohydrates have the same fraction in soluble and insoluble fractions.
-
Parameters:
-
-
-
-
Name
-
Type
-
Description
-
Default
-
-
-
-
-
name
-
- str
-
-
A unique name for the feed.
-
- required
-
-
-
-
carbohydrates
-
- float
-
-
percentage of carbohydrates in the feed.
-
- required
-
-
-
-
lipids
-
- float
-
-
percentage of lipids in the feed.
-
- required
-
-
-
-
proteins
-
- float
-
-
percentage of proteins in the feed.
-
- required
-
-
-
-
tss
-
- float
-
-
percentage of total COD in the form of suspended solids.
-
- required
-
-
-
-
si
-
- float
-
-
percentage of percentage of soluble inorganics in the TDS.
-
- required
-
-
-
-
xi
-
- float
-
-
percentage of percentage of insoluble inorganics in the TSS.
-
- required
-
-
+
+
Parameters:
+
+
-
reference
-
- str
-
-
A reference for the feed data. Defaults to ''.
-
- ''
-
+
Name
+
Type
+
Description
+
Default
-
-
+
+
+
+
+ name
+
+
+ str
+
+
+
+
A unique name for the feed.
+
+
+
+ required
+
+
+
+
+ carbohydrates
+
+
+ float
+
+
+
+
percentage of carbohydrates in the feed.
+
+
+
+ required
+
+
+
+
+ lipids
+
+
+ float
+
+
+
+
percentage of lipids in the feed.
+
+
+
+ required
+
+
+
+
+ proteins
+
+
+ float
+
+
+
+
percentage of proteins in the feed.
+
+
+
+ required
+
+
+
+
+ tss
+
+
+ float
+
+
+
+
percentage of total COD in the form of suspended solids.
+
+
+
+ required
+
+
+
+
+ si
+
+
+ float
+
+
+
+
percentage of percentage of soluble inorganics in the TDS.
+
+
+
+ required
+
+
+
+
+ xi
+
+
+ float
+
+
+
+
percentage of percentage of insoluble inorganics in the TSS.
@dataclass
+classFeed:
- """
+""" The Feed class is used to store the feed information, and later use it in the e_adm model. all the entered numbers must in percentages. Carbohudrates, lipids, and proteins and si must sum up to 100, and they form the total dissolved solids. Carbohydrates, lipids, proteins, and xi must sum up to 100, and they form the total suspended solids.
@@ -3318,7 +3646,7 @@
1. Experiment
xi:float# percentage of percentage of insoluble inorganics in the TSSreference:str=''# A reference for the feed data
- def__post_init__(self):
+ def__post_init__(self):ifself.carbohydrates+self.lipids+self.proteins>100:raiseValueError("The sum of the percentages must less than 100")ifself.carbohydrates+self.lipids+self.proteins+self.si<1:
@@ -3335,7 +3663,7 @@
@dataclass
+classMetagenomicsStudy:
+""" This class is used to communicate between the metagenomics studies database and the ADM model. Args:
@@ -3515,7 +3889,7 @@
This class provides a simple interface between information about biochemical reactions and multiple functionalities of ADToolbox.
+
+
This class provides a simple interface between information about biochemical reactions and multiple functionalities of ADToolbox.
In order to instantiate a reaction object, you need to pass a dictionary of the reaction information.
This dictionary must include 'name','stoichiometry' keys. This follows the format of the seed database.
stoichiometry must be formatted like seed database. The seed database format is as follows:
stoichiometry: '-1:cpd00079:0:0:"D-glucose-6-phosphate";1:cpd00072:0:0:"D-fructose-6-phosphate"'
-
Parameters:
-
-
-
-
Name
-
Type
-
Description
-
Default
-
-
-
+
+
Parameters:
+
+
-
data
-
- dict
-
-
A dictionary containing the reaction information. This follows the format of the seed database.
-
- required
-
+
Name
+
Type
+
Description
+
Default
-
-
+
+
+
+
+ data
+
+
+ dict
+
+
+
+
A dictionary containing the reaction information. This follows the format of the seed database.
classReaction:
+""" This class provides a simple interface between information about biochemical reactions and multiple functionalities of ADToolbox. In order to instantiate a reaction object, you need to pass a dictionary of the reaction information. This dictionary must include 'name','stoichiometry' keys. This follows the format of the seed database.
@@ -3654,15 +4044,15 @@
1. Experiment
D-glucose-6-phosphate aldose-ketose-isomerase """
- def__init__(self,data:dict)->None:
+ def__init__(self,data:dict)->None:self.data=data
- def__str__(self)->str:
+ def__str__(self)->str:returnself.data['name']@property
- defstoichiometry(self)->dict:
- """
+ defstoichiometry(self)->dict:
+""" Returns the stoichiometry of the reaction by the seed id of the compounds as key and the stoichiometric coefficient as value. Examples:
@@ -3679,9 +4069,9 @@
Returns the stoichiometry of the reaction by the seed id of the compounds as key and the
-stoichiometric coefficient as value.
+
+
+
Returns the stoichiometry of the reaction by the seed id of the compounds as key and the
+stoichiometric coefficient as value.
+Examples:
+ >>> A={"name":'D-glucose-6-phosphate aldose-ketose-isomerase',"stoichiometry":'-1:cpd00079:0:0:"D-glucose-6-phosphate";1:cpd00072:0:0:"D-fructose-6-phosphate"'}
+ >>> a=Reaction(A)
+ >>> a.stoichiometry=={'cpd00079': -1, 'cpd00072': 1}
+ True
This class provides a simple interface between information about metabolites and multiple functionalities of ADToolbox.
+
+
This class provides a simple interface between information about metabolites and multiple functionalities of ADToolbox.
In order to instantiate a metabolite object, you need to pass a dictionary of the metabolite information.
This dictionary must include 'name','mass','formula' keys. This follows the format of the seed database.
formula must be formatted like seed database. The seed database format is as follows:
@@ -3788,31 +4191,39 @@
Possibly the main advantage of instantiating a metabolite object is that it provides a COD attribute that can be used to convert
the concentration of the metabolite from g/l to gCOD/l. This is useful for comparing the experimental data with the model outputs.
-
Parameters:
-
-
-
-
Name
-
Type
-
Description
-
Default
-
-
-
+
+
Parameters:
+
+
-
data
-
- dict
-
-
A dictionary containing the metabolite information. This follows the format of the seed database.
-
- required
-
+
Name
+
Type
+
Description
+
Default
-
-
+
+
+
+
+ data
+
+
+ dict
+
+
+
+
A dictionary containing the metabolite information. This follows the format of the seed database.
classMetabolite:
+""" This class provides a simple interface between information about metabolites and multiple functionalities of ADToolbox. In order to instantiate a metabolite object, you need to pass a dictionary of the metabolite information. This dictionary must include 'name','mass','formula' keys. This follows the format of the seed database.
@@ -3920,16 +4337,16 @@
"""
- def__init__(self,data):
+ def__init__(self,data):self.data=dataself.cod=self.cod_calc()self.mw=self.data.get('mass',None)
- def__str__(self)->str:
+ def__str__(self)->str:returnself.data['name']
- defcod_calc(self,add_h:float=0,add_c:float=0,add_o:float=0)->float:
- """
+ defcod_calc(self,add_h:float=0,add_c:float=0,add_o:float=0)->float:
+""" Calculates the conversion rates for g/l -> gCOD/l In some cases we would like to add extra atoms for COD calculations For example, model seed biochemistry database only uses acetate instead of acetic acid.
@@ -3976,9 +4393,9 @@
Calculates the conversion rates for g/l -> gCOD/l
+
+
+
Calculates the conversion rates for g/l -> gCOD/l
In some cases we would like to add extra atoms for COD calculations
For example, model seed biochemistry database only uses acetate instead of acetic acid.
The 1 hydrogen difference changes the COD conversion rate. For this reason we can add extra atoms to the formula
to calculate the COD conversion rate without changing anything else.
-
Parameters:
-
-
-
-
Name
-
Type
-
Description
-
Default
-
-
-
-
-
add_h
-
- float
-
-
The number of extra hydrogen atoms to add to the formula for COD calculation.
-
- 0
-
-
-
-
add_c
-
- float
-
-
The number of extra carbon atoms to add to the formula for COD calculation.
-
- 0
-
-
+
+
Parameters:
+
+
-
add_o
-
- float
-
-
The number of extra oxygen atoms to add to the formula for COD calculation.
-
- 0
-
+
Name
+
Type
+
Description
+
Default
-
-
+
+
+
+
+ add_h
+
+
+ float
+
+
+
+
The number of extra hydrogen atoms to add to the formula for COD calculation.
+
+
+
+ 0
+
+
+
+
+ add_c
+
+
+ float
+
+
+
+
The number of extra carbon atoms to add to the formula for COD calculation.
+
+
+
+ 0
+
+
+
+
+ add_o
+
+
+ float
+
+
+
+
The number of extra oxygen atoms to add to the formula for COD calculation.
defcod_calc(self,add_h:float=0,add_c:float=0,add_o:float=0)->float:
+""" Calculates the conversion rates for g/l -> gCOD/l In some cases we would like to add extra atoms for COD calculations For example, model seed biochemistry database only uses acetate instead of acetic acid.
@@ -4197,8 +4647,8 @@
else:return'None'
-
-
+
+
@@ -4206,7 +4656,7 @@
-
+
6.SeedDB
@@ -4214,49 +4664,65 @@
+
-
+
-
-
This class is designed to interact with seed database. The main advantage of using this class is that it can be used to instantiate
+
+
This class is designed to interact with seed database. The main advantage of using this class is that it can be used to instantiate
a reaction and metabolite object, and it provides extra functionalities that rely on information in the seed database. For example,
If there is a chemical formula assigned to a metabolite in the seed database, then the informattion about the COD of that metabolite
can be computed using the chemical formula.
-
Parameters:
-
-
-
-
Name
-
Type
-
Description
-
Default
-
-
-
+
+
Parameters:
+
+
-
config
-
- configs.SeedDB
-
-
An instance of the SeedDB class in the configs module. This class contains the information about the seed database.
-
- required
-
+
Name
+
Type
+
Description
+
Default
-
-
+
+
+
+
+ config
+
+
+ SeedDB
+
+
+
+
An instance of the SeedDB class in the configs module. This class contains the information about the seed database.
classSeedDB:
- """
+""" This class is designed to interact with seed database. The main advantage of using this class is that it can be used to instantiate a reaction and metabolite object, and it provides extra functionalities that rely on information in the seed database. For example, If there is a chemical formula assigned to a metabolite in the seed database, then the informattion about the COD of that metabolite
@@ -4364,13 +4829,13 @@
"""
- def__init__(self,config:configs.Database)->None:
+ def__init__(self,config:configs.Database)->None:self.reaction_db=config.reaction_dbself.compound_db=config.compound_db
- definstantiate_rxns(self,seed_id:str)->Reaction:
- """
+ definstantiate_rxns(self,seed_id:str)->Reaction:
+""" This method is used to instantiate reaction objects from the seed database. in order to instantiate a reaction object, you need to pass the seed identifier for that reaction.
@@ -4392,8 +4857,8 @@
db=pd.read_json(self.reaction_db)returnReaction(data=db[db["id"]==seed_id].to_dict(orient="records")[0])
- definstantiate_metabs(self,seed_id:str)->Metabolite:
- """
+ definstantiate_metabs(self,seed_id:str)->Metabolite:
+""" This method is used to instantiate metabolite objects from the seed database. In order to instantiate a metabolite object, you need to pass the seed identifier for that metabolite.
@@ -4414,8 +4879,8 @@
db=pd.read_json(self.compound_db)returnMetabolite(data=db[db["id"]==seed_id].to_dict(orient="records")[0])
- defget_seed_rxn_from_ec(self,ec_number:str)->list:
- """
+ defget_seed_rxn_from_ec(self,ec_number:str)->list:
+""" This method is used to get the seed reaction identifiers for a given EC number. Args:
@@ -4438,9 +4903,9 @@
defget_seed_rxn_from_ec(self,ec_number:str)->list:
+""" This method is used to get the seed reaction identifiers for a given EC number. Args:
@@ -4568,83 +5048,98 @@
This method is used to instantiate metabolite objects from the seed database.
+
+
+
This method is used to instantiate metabolite objects from the seed database.
In order to instantiate a metabolite object, you need to pass the seed identifier for that metabolite.
definstantiate_metabs(self,seed_id:str)->Metabolite:
+""" This method is used to instantiate metabolite objects from the seed database. In order to instantiate a metabolite object, you need to pass the seed identifier for that metabolite.
@@ -4686,90 +5180,99 @@
This method is used to instantiate reaction objects from the seed database.
+
+
+
This method is used to instantiate reaction objects from the seed database.
in order to instantiate a reaction object, you need to pass the seed identifier for that reaction.
definstantiate_rxns(self,seed_id:str)->Reaction:
+""" This method is used to instantiate reaction objects from the seed database. in order to instantiate a reaction object, you need to pass the seed identifier for that reaction.
@@ -4813,8 +5315,8 @@
This class is designed to supply any data requirement for ADToolbox. All functionalisties for saving, loading, and querying data are implemented here.
+
+
This class is designed to supply any data requirement for ADToolbox. All functionalisties for saving, loading, and querying data are implemented here.
ADToolbox in general contains the following databases:
@@ -4870,39 +5373,54 @@
This class is instantiated with a configs.Database object. This object contains the paths to all the databases that ADToolbox uses.
Please refer to the documentation of each method for more information on the required configurations.
-
Parameters:
-
-
-
-
Name
-
Type
-
Description
-
Default
-
-
-
+
+
Parameters:
+
+
-
config
-
- configs.Database
-
-
A configs.Database object. Defaults to configs.Database().
-
- configs.Database()
-
+
Name
+
Type
+
Description
+
Default
-
-
+
+
+
+
+ config
+
+
+ Database
+
+
+
+
A configs.Database object. Defaults to configs.Database().
classDatabase:
- '''
+''' This class is designed to supply any data requirement for ADToolbox. All functionalisties for saving, loading, and querying data are implemented here. ADToolbox in general contains the following databases:
@@ -5974,12 +6492,12 @@
>>> assert type(db)==Database and type(db.config)==configs.Database '''
- def__init__(self,config:configs.Database=configs.Database())->None:
- self.config=config
+ def__init__(self,config:configs.Database|None=None)->None:
+ self.config=configorconfigs.Database()
- definitialize_protein_db(self)->None:
- """This function intializes ADToolbox's protein database by creating an empty fasta file.
+ definitialize_protein_db(self)->None:
+"""This function intializes ADToolbox's protein database by creating an empty fasta file. Be careful, this will overwrite any existing file with the same name. Logically, this needs method needs config.protein_db to be defined.
@@ -6001,8 +6519,8 @@
withopen(self.config.protein_db,'w')asf:pass
- definitialize_reaction_db(self)->None:
- r"""This function intializes ADToolbox's reaction database by creating an empty tsv file.
+ definitialize_reaction_db(self)->None:
+r"""This function intializes ADToolbox's reaction database by creating an empty tsv file. Be careful, this will overwrite any existing file with the same name. Required Configs:
@@ -6020,8 +6538,8 @@
"""pd.DataFrame(columns=["ec_numbers","seed_ids","reaction_names","adm1_reaction","e_adm_reactions","pathways"]).to_csv(self.config.reaction_db,index=False,sep="\t")
- definitialize_feed_db(self)->None:
- r"""This function intializes ADToolbox's Feed database by creating an empty tsv file.
+ definitialize_feed_db(self)->None:
+r"""This function intializes ADToolbox's Feed database by creating an empty tsv file. Be careful, this will overwrite any existing file with the same name. Required Configs:
@@ -6039,8 +6557,8 @@
"""pd.DataFrame(columns=["name","carbohydrates","lipids","proteins","tss","si","xi","reference"]).to_csv(self.config.feed_db,index=False,sep="\t")
- definitialize_metagenomics_studies_db(self)->None:
- r"""This function intializes ADToolbox's Metagenomics studies database by creating an empty tsv file.
+ definitialize_metagenomics_studies_db(self)->None:
+r"""This function intializes ADToolbox's Metagenomics studies database by creating an empty tsv file. Be careful, this will overwrite any existing file with the same name. Required Configs:
@@ -6058,8 +6576,8 @@
"""pd.DataFrame(columns=["name","study_type","microbiome","sample_accession","comments","study_accession"]).to_csv(self.config.studies_local["metagenomics_studies"],index=False,sep="\t")
- definitialize_experimental_data_db(self)->None:
- """This function intializes ADToolbox's experimental data database by creating an empty json file.
+ definitialize_experimental_data_db(self)->None:
+"""This function intializes ADToolbox's experimental data database by creating an empty json file. Be careful, this will overwrite any existing file with the same name. Required Configs:
@@ -6080,10 +6598,10 @@
pd.DataFrame(columns=["name","initial_concentrations","time","variables","data","reference"]).to_json(self.config.studies_local["experimental_data_db"],orient="records")
- deffilter_seed_from_ec(self,
+ deffilter_seed_from_ec(self,ec_list:list[str],save:bool=False)->tuple:
- """
+""" This function takes a list of EC numbers and filters the seed database to find the seed reactions that have the EC numbers in their EC number list. This will help to trim the large seed database to a smaller one that only contains the reactions that are relevant to the AD process.
@@ -6123,8 +6641,8 @@
- defget_protein_seqs_from_uniprot(self,uniprot_id:str)->str:
- """
+ defget_protein_seqs_from_uniprot(self,uniprot_id:str)->str:
+""" This function takes a uniprot id and fetches the protein sequence from Uniprot. Args:
@@ -6157,8 +6675,8 @@
return''.join(file.text.split('\n')[1:-1])
- defproteins_from_ec(self,ec_number:str)->dict:
- """
+ defproteins_from_ec(self,ec_number:str)->dict:
+""" This function returns a dictionary of protein sequences for a given EC number. The keys are the uniprot ids and ec number compatible with ADToolbox protein database and the values are the protein sequences. Since ADToolbox deals with microbial process,
@@ -6203,8 +6721,8 @@
returnprotein_seqs
- defbuild_protein_db_from_reactions_db(self):
- r"""
+ defbuild_protein_db_from_reactions_db(self):
+r""" This function builds the protein database from the reaction database. It takes the reaction database and finds the protein sequences for each EC number in the reaction database. Then it saves the protein sequences in a fasta file.
@@ -6241,11 +6759,11 @@
f.write(">"+key+"\n")f.write(value+"\n")
- defcazy_ec(self)->list:
+ defcazy_ec(self)->list:pass
- defadd_protein_to_protein_db(self,protein_id:str,header_tail:str)->None:
- """
+ defadd_protein_to_protein_db(self,protein_id:str,header_tail:str)->None:
+""" This funciton adds a protein sequence to the protein database. It takes a uniprot id and an EC number it is assigned to and adds the corresponding protein sequence to the protein database.
@@ -6275,8 +6793,8 @@
f.write(">"+protein_id+"|"+header_tail+"\n")f.write(self.get_protein_seqs_from_uniprot(protein_id)+"\n")
- defadd_proteins_from_ecnumbers_to_protein_db(self,ec_numbers:list)->None:
- """
+ defadd_proteins_from_ecnumbers_to_protein_db(self,ec_numbers:list)->None:
+""" This function adds protein sequences to the protein database from a list of EC numbers. It takes a list of EC numbers and finds the protein sequences for each EC number in the list. Then it saves the protein sequences in a fasta file.
@@ -6309,8 +6827,8 @@
f.write(">"+key+"\n")f.write(value+"\n")
- defadd_feed_to_feed_db(self,feed:Feed)->None:
- r"""
+ defadd_feed_to_feed_db(self,feed:Feed)->None:
+r""" This function adds a feed to the feed database. It takes the feed name and the feed composition and adds them to the feed database. Required Configs:
@@ -6339,8 +6857,8 @@
feed_db=pd.concat([feed_db,pd.DataFrame([feed.to_dict()])],ignore_index=True,axis=0)feed_db.to_csv(self.config.feed_db,index=False,sep="\t")
- defremove_feed_from_feed_db(self,field_name:str,query:str)->None:
- r"""
+ defremove_feed_from_feed_db(self,field_name:str,query:str)->None:
+r""" This function removes studyes that contain the query in the given column, field name, from the feed database. Required Configs:
@@ -6371,8 +6889,8 @@
feed_db=feed_db[feed_db[field_name].str.contains(query)==False]feed_db.to_csv(self.config.feed_db,index=False,sep="\t")
- defget_feed_from_feed_db(self,field_name:str,query:str)->list[Feed]:
- r"""
+ defget_feed_from_feed_db(self,field_name:str,query:str)->list[Feed]:
+r""" This function returns a feed from the feed database. It takes the query string and the column name to query and returns the feed that contains the query string in the given column. Required Configs:
@@ -6405,8 +6923,8 @@
feed_db=feed_db[feed_db[field_name].str.contains(query)]return[Feed(**feed.to_dict())for_,feedinfeed_db.iterrows()]
- defadd_metagenomics_study_to_metagenomics_studies_db(self,metagenomics_study:MetagenomicsStudy)->None:
- r"""
+ defadd_metagenomics_study_to_metagenomics_studies_db(self,metagenomics_study:MetagenomicsStudy)->None:
+r""" This function adds a metagenomics study to the metagenomics studies database. It takes a metagenomics study and adds it to the metagenomics studies database. Required Configs:
@@ -6431,8 +6949,8 @@
metagenomics_studies_db=pd.concat([metagenomics_studies_db,pd.DataFrame([metagenomics_study.to_dict()])],ignore_index=True,axis=0)metagenomics_studies_db.to_csv(self.config.studies_local["metagenomics_studies"],index=False,sep="\t")
- defremove_metagenomics_study_from_metagenomics_studies_db(self,field_name:str,query:str)->None:
- r"""
+ defremove_metagenomics_study_from_metagenomics_studies_db(self,field_name:str,query:str)->None:
+r""" This function removes studies that contain the query in the given column, field name, from the metagenomics studies database. Required Configs:
@@ -6461,8 +6979,8 @@
metagenomics_studies_db=metagenomics_studies_db[metagenomics_studies_db[field_name].str.contains(query)==False]metagenomics_studies_db.to_csv(self.config.studies_local["metagenomics_studies"],index=False,sep="\t")
- defget_metagenomics_study_from_metagenomics_studies_db(self,field_name:str,query:str)->list[MetagenomicsStudy]:
- r"""
+ defget_metagenomics_study_from_metagenomics_studies_db(self,field_name:str,query:str)->list[MetagenomicsStudy]:
+r""" This function returns a metagenomics study from the metagenomics studies database. It takes the query string and the column name to query and returns the metagenomics study that contains the query string in the given column. Required Configs:
@@ -6494,8 +7012,8 @@
metagenomics_studies_db=metagenomics_studies_db[metagenomics_studies_db[field_name].str.contains(query)]return[MetagenomicsStudy(**metagenomics_study.to_dict())for_,metagenomics_studyinmetagenomics_studies_db.iterrows()]
- defadd_experiment_to_experiments_db(self,experiment:Experiment,force:bool=False)->None:
- r"""
+ defadd_experiment_to_experiments_db(self,experiment:Experiment,force:bool=False)->None:
+r""" This function adds an experiment to the experiments database. It takes an experiment and adds it to the experiments database. Required Configs:
@@ -6525,7 +7043,8 @@
self.remove_experiment_from_experiments_db("name",exp.name)else:
- raiseValueError("Experiment already exists in the database!")
+ ifself.get_experiment_from_experiments_db("name",experiment.name):
+ raiseValueError("Experiment already exists in the database!")withopen(self.config.studies_local["experimental_data_db"],"r")asf:experiments_db=json.load(f)
@@ -6533,8 +7052,8 @@
withopen(self.config.studies_local["experimental_data_db"],"w")asf:json.dump(experiments_db,f)
- defremove_experiment_from_experiments_db(self,field_name:str,query:str)->None:
- r"""
+ defremove_experiment_from_experiments_db(self,field_name:str,query:str)->None:
+r""" This function removes experiments that contain the query in the given column, field name, from the experiments database. Required Configs:
@@ -6567,8 +7086,8 @@
withopen(self.config.studies_local["experimental_data_db"],"w")asf:json.dump(experiments_db,f)
- defget_experiment_from_experiments_db(self,field_name:str,query:str)->list[Experiment]:
- r"""
+ defget_experiment_from_experiments_db(self,field_name:str,query:str)->list[Experiment]:
+r""" This function returns an experiment from the experiments database. It takes the query string and the column name to query and returns the experiment that contains the query string in the given column. Required Configs:
@@ -6607,8 +7126,8 @@
experiment["feed"]=Feed(**experiment["feed"])return[Experiment(**experiment)forexperimentinexperiments_db]
- defbuild_mmseqs_database(self,container:str="None")->str:
- """Builds an indexed mmseqs database from the ADToolbox's fasta protein database.
+ defbuild_mmseqs_database(self,container:str="None")->str:
+"""Builds an indexed mmseqs database from the ADToolbox's fasta protein database. Required Configs: - config.protein_db
@@ -6642,8 +7161,8 @@
returnscript
- defdownload_adm_parameters(self,verbose:bool=True)->None:
- """
+ defdownload_adm_parameters(self,verbose:bool=True)->None:
+""" Downloads the parameters needed for running ADM models in ADToolbox. Required Configs:
@@ -6681,8 +7200,8 @@
ifverbose:rich.print(f"[green]{param} downloaded to {self.config.adm_parameters[param]}")
- defdownload_seed_databases(self,verbose:bool=True)->None:
- """This function will download the seed databases, both compound and reaction databases.
+ defdownload_seed_databases(self,verbose:bool=True)->None:
+"""This function will download the seed databases, both compound and reaction databases. Required Configs: - config.seed_rxn_url
@@ -6716,8 +7235,8 @@
ifverbose:rich.print(f"[green]Compound database downloaded to {self.config.compound_db}")
- defdownload_protein_database(self,verbose:bool=True)->None:
- """
+ defdownload_protein_database(self,verbose:bool=True)->None:
+""" Downloads the prebuilt protein database from the remote repository. Required Configs:
@@ -6746,8 +7265,8 @@
ifverbose:rich.print(f"[green]Protein database downloaded to {self.config.protein_db}")
- defdownload_reaction_database(self,verbose:bool=True)->None:
- """
+ defdownload_reaction_database(self,verbose:bool=True)->None:
+""" This function will download the reaction database from the remote repository. Required Configs:
@@ -6778,8 +7297,8 @@
rich.print(f"[green]Reaction database downloaded to {self.config.csv_reaction_db}")
- defdownload_feed_database(self,verbose:bool=True)->None:
- """
+ defdownload_feed_database(self,verbose:bool=True)->None:
+""" This function will download the feed database from the remote repository. Required Configs:
@@ -6808,7 +7327,7 @@
ifverbose:rich.print(f"[green]Qiime's classifier database downloaded to {self.config.qiime_classifier_db}")
- defdownload_studies_database(self,verbose:bool=True)->None:
- """
+ defdownload_studies_database(self,verbose:bool=True)->None:
+""" This function will download the required files for studies functionality. Args:
@@ -6851,8 +7370,8 @@
ifverbose:rich.print(f"[bold green]Downloaded {self.config.studies_remote[i]}[/bold green]")
- defdownload_amplicon_to_genome_db(self,verbose:bool=True):
- """
+ defdownload_amplicon_to_genome_db(self,verbose:bool=True):
+""" This function will automatically download the GTDB-tk database for genome assignment. Required Configs:
@@ -6934,8 +7453,8 @@
- defdownload_all_databases(self,verbose:bool=True)->None:
- """
+ defdownload_all_databases(self,verbose:bool=True)->None:
+""" This function will download all the required databases for all the functionalities of ADToolbox. NOTE: each method that this function calls is individually tested so it is skipped from testing!
@@ -6978,9 +7497,9 @@
defadd_experiment_to_experiments_db(self,experiment:Experiment,force:bool=False)->None:
+r""" This function adds an experiment to the experiments database. It takes an experiment and adds it to the experiments database. Required Configs:
@@ -7120,7 +7650,8 @@
self.remove_experiment_from_experiments_db("name",exp.name)else:
- raiseValueError("Experiment already exists in the database!")
+ ifself.get_experiment_from_experiments_db("name",experiment.name):
+ raiseValueError("Experiment already exists in the database!")withopen(self.config.studies_local["experimental_data_db"],"r")asf:experiments_db=json.load(f)
@@ -7128,57 +7659,65 @@
with open(self.config.studies_local["experimental_data_db"],"w")asf:json.dump(experiments_db,f)
defadd_feed_to_feed_db(self,feed:Feed)->None:
+r""" This function adds a feed to the feed database. It takes the feed name and the feed composition and adds them to the feed database. Required Configs:
@@ -7248,57 +7788,65 @@
This function adds a metagenomics study to the metagenomics studies database. It takes a metagenomics study and adds it to the metagenomics studies database.
+
+
+
This function adds a metagenomics study to the metagenomics studies database. It takes a metagenomics study and adds it to the metagenomics studies database.