has been replaced in registry\n",
" self._register(ID)\n"
]
}
],
"source": [
"# A dict sets ports individually; 'else' covers the rest\n",
"M_mix = su.Mixer('M_mix', ins=('a', 'b'), outs='c',\n",
" init_with={'ins0': 'Stream', 'else': 'WasteStream'})\n",
"print('ins0:', type(M_mix.ins[0]).__name__,\n",
" '| ins1:', type(M_mix.ins[1]).__name__,\n",
" '| outs0:', type(M_mix.outs[0]).__name__)"
]
},
{
"cell_type": "markdown",
"id": "2f5bf2ad",
"metadata": {},
"source": "\n\n**Tip:** By default, `diagram()` renders an inline picture of the flowsheet. You can pass a different `format` (notably `format='html'` for an interactive diagram with hover-able stream and unit information) or save it to a file with the `file` kwarg (e.g., `M1.diagram(file='M1', format='png')`). If `diagram()` produces nothing, you likely don't have the `graphviz` package installed (it renders the diagrams); see QSDsan's [graphviz FAQ](https://qsdsan.readthedocs.io/en/latest/faq/errors.html#graphviz-installation).\n\n
"
},
{
"cell_type": "markdown",
"id": "208de147",
"metadata": {},
"source": [
"### 2.2. Retrieving design and cost"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "cc3938f0",
"metadata": {
"execution": {
"iopub.execute_input": "2026-05-29T15:55:51.767290Z",
"iopub.status.busy": "2026-05-29T15:55:51.767290Z",
"iopub.status.idle": "2026-05-29T15:55:53.322769Z",
"shell.execute_reply": "2026-05-29T15:55:53.320378Z"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\Yalin\\AppData\\Local\\Temp\\ipykernel_68680\\3311111030.py:4: RuntimeWarning: undocked inlet ins1 from M1; ins1 is now docked at M2\n",
" M2 = su.MixTank('M2', ins=(ins1, ins2, ins3), outs='M2out', # init_with='WasteStream',\n",
"C:\\Users\\Yalin\\AppData\\Local\\Temp\\ipykernel_68680\\3311111030.py:4: RuntimeWarning: undocked inlet ins2 from M1; ins2 is now docked at M2\n",
" M2 = su.MixTank('M2', ins=(ins1, ins2, ins3), outs='M2out', # init_with='WasteStream',\n",
"C:\\Users\\Yalin\\AppData\\Local\\Temp\\ipykernel_68680\\3311111030.py:4: RuntimeWarning: undocked inlet ins3 from M1; ins3 is now docked at M2\n",
" M2 = su.MixTank('M2', ins=(ins1, ins2, ins3), outs='M2out', # init_with='WasteStream',\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"MixTank: M2\n",
"ins...\n",
"[0] ins1\n",
"phase: 'l', T: 298.15 K, P: 101325 Pa\n",
"flow: 1e+05 g/hr H2O\n",
" WasteStream-specific properties:\n",
" pH : 7.0\n",
" Alkalinity : 2.5 mmol/L\n",
"[1] ins2\n",
"phase: 'l', T: 298.15 K, P: 101325 Pa\n",
"flow (g/hr): X_GAO_PHA 10\n",
" X_GAO_Gly 10\n",
" H2O 1e+05\n",
" WasteStream-specific properties:\n",
" pH : 7.0\n",
" Alkalinity : 2.5 mmol/L\n",
" COD : 199.4 mg/L\n",
" BOD : 115.6 mg/L\n",
" TC : 70.6 mg/L\n",
" TOC : 70.6 mg/L\n",
" TSS : 143.7 mg/L\n",
"[2] ins3\n",
"phase: 'l', T: 298.15 K, P: 101325 Pa\n",
"flow (g/hr): S_F 4.3\n",
" S_U_Inf 1.07\n",
" C_B_Subst 2\n",
" X_B_Subst 11.3\n",
" X_U_Inf 2.79\n",
" X_Ig_ISS 2.62\n",
" S_NH4 1.25\n",
" S_PO4 0.4\n",
" S_K 1.4\n",
" S_Ca 7\n",
" S_Mg 2.5\n",
" S_CO3 6\n",
" S_N2 0.9\n",
" S_CAT 0.15\n",
" S_AN 0.6\n",
" ... 4.98e+04\n",
" WasteStream-specific properties:\n",
" pH : 7.0\n",
" Alkalinity : 10.0 mmol/L\n",
" COD : 430.0 mg/L\n",
" BOD : 221.8 mg/L\n",
" TC : 265.0 mg/L\n",
" TOC : 137.6 mg/L\n",
" TN : 40.0 mg/L\n",
" TP : 10.0 mg/L\n",
" TK : 28.0 mg/L\n",
" TSS : 209.3 mg/L\n",
"outs...\n",
"[0] M2out\n",
"phase: 'l', T: 298.15 K, P: 101325 Pa\n",
"flow: 0\n",
" WasteStream-specific properties: None for empty waste streams\n"
]
}
],
"source": [
"# Note that `Mixer` does nothing other than mix the influents,\n",
"# let's using another example\n",
"qs.set_thermo(cmps) # here we need to reset the `cmps` since I introduced the `biosteam` environment\n",
"M2 = su.MixTank('M2', ins=(ins1, ins2, ins3), outs='M2out', # init_with='WasteStream',\n",
" tau=1, kW_per_m3=1)\n",
"M2.show()"
]
},
{
"cell_type": "markdown",
"id": "23de76be",
"metadata": {},
"source": [
"Two things to take note of in the example above:\n",
"- By setting `outs='M2out'`, I set the ID of the effluent to be `M2out`\n",
" - You can also make a stream ahead of time and set the effluent to that stream (e.g., `outs=qs.WasteStream('M2out')`\n",
" - If the unit has multiple effluents, then you'll want to use an Iterable (e.g., tuple, list), e.g., `outs=['M2out1', qs.WasteStream('M2out2')]`\n",
" - This is applicable to `ins` as well\n",
"- You will see warnings about streams being undocked from the previous unit and docked at the new unit, this is because we set the `ins` of `M2` to be the same as the `ins` of `M1`. Since one stream can only go to one unit, these streams will be taken away from `M1` and connect to `M2`"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "401cb26d",
"metadata": {
"execution": {
"iopub.execute_input": "2026-05-29T15:55:53.322769Z",
"iopub.status.busy": "2026-05-29T15:55:53.322769Z",
"iopub.status.idle": "2026-05-29T15:55:53.335002Z",
"shell.execute_reply": "2026-05-29T15:55:53.335002Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Mix tank Units M2\n",
"Electricity Power kW 0.313\n",
" Cost USD/hr 0.0245\n",
"Design Residence time hr 1\n",
" Total volume m^3 0.313\n",
"Purchase cost Tank USD 7.09e+03\n",
"Total purchase cost USD 7.09e+03\n",
"Utility cost USD/hr 0.0245\n"
]
}
],
"source": [
"# Because `M2` is a `MixTank`, we can look at its design\n",
"M2.simulate() # runs _run then _summary (_design + _cost); see tutorial 5 §1.1\n",
"print(M2.results()) # you can see the design and capital/power cost"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "59098df1",
"metadata": {
"execution": {
"iopub.execute_input": "2026-05-29T15:55:53.339532Z",
"iopub.status.busy": "2026-05-29T15:55:53.335002Z",
"iopub.status.idle": "2026-05-29T15:55:53.645190Z",
"shell.execute_reply": "2026-05-29T15:55:53.645190Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Heat exchanger Units H1\n",
"Low pressure steam Duty kJ/hr 3.18e+03\n",
" Flow kmol/hr 0.0822\n",
" Cost USD/hr 0.0196\n",
"Design Area ft^2 0.0505\n",
" Overall heat transfer coefficient kW/m^2/K 0.5\n",
" Log-mean temperature difference K 377\n",
" Fouling correction factor 1\n",
" Operating pressure psi 50\n",
" Total tube length ft 0.116\n",
" Inner pipe weight kg 0.12\n",
" Outer pipe weight kg 0.193\n",
" Total steel weight kg 0.313\n",
"Purchase cost Double pipe USD 65.3\n",
"Total purchase cost USD 65.3\n",
"Utility cost USD/hr 0.0196\n"
]
}
],
"source": [
"# If there is utility usage, it will be shown in the results as well\n",
"ws5 = qs.WasteStream('ws5', H2O=10, T=20)\n",
"H1 = su.HXutility(ins=ws5, T=50)\n",
"H1.simulate()\n",
"print(H1.results())"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "6c71ac75",
"metadata": {
"execution": {
"iopub.execute_input": "2026-05-29T15:55:53.645190Z",
"iopub.status.busy": "2026-05-29T15:55:53.645190Z",
"iopub.status.idle": "2026-05-29T15:55:53.651627Z",
"shell.execute_reply": "2026-05-29T15:55:53.651627Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"7093.933003892887"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# You can also retrieve information such as\n",
"M2.purchase_cost # this is the sum"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "ea4f99a7",
"metadata": {
"execution": {
"iopub.execute_input": "2026-05-29T15:55:53.655641Z",
"iopub.status.busy": "2026-05-29T15:55:53.654639Z",
"iopub.status.idle": "2026-05-29T15:55:53.659651Z",
"shell.execute_reply": "2026-05-29T15:55:53.659651Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"{'Tank': 7093.933003892887}"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"M2.purchase_costs # this is a `dict` contains all the entries"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "91be16c7",
"metadata": {
"execution": {
"iopub.execute_input": "2026-05-29T15:55:53.661941Z",
"iopub.status.busy": "2026-05-29T15:55:53.661941Z",
"iopub.status.idle": "2026-05-29T15:55:53.665427Z",
"shell.execute_reply": "2026-05-29T15:55:53.665427Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"M2 contains the following cost items:\n",
" Tank costs 11705\n",
"The sum of all these cost items is 11705.\n"
]
}
],
"source": [
"# (this unit only has one cost item, but the pattern generalizes)\n",
"print(f'{M2.ID} contains the following cost items:')\n",
"for item_name, item_cost in M2.installed_costs.items():\n",
" print(f' {item_name} costs {item_cost:.0f}')\n",
"print(f'The sum of all these cost items is {M2.installed_cost:.0f}.')"
]
},
{
"cell_type": "markdown",
"id": "3a33ca98",
"metadata": {},
"source": [
"\n",
"\n",
"**Baseline, purchase, and installed cost.** Following the bare-module method (Seider et al.), BioSTEAM derives both costs from a **baseline purchase cost** (`baseline_purchase_costs`) using four per-item factors, each defaulting to 1:\n",
"\n",
"- `F_D` (design), `F_P` (pressure), and `F_M` (material) give the **purchase cost**: `purchase = baseline × F_D × F_P × F_M`.\n",
"- `F_BM` (bare-module) rolls in installation, piping, instrumentation, etc. to give the **installed cost**: `installed = baseline × (F_BM + F_D × F_P × F_M - 1)`.\n",
"\n",
"Each factor lives in its own dict (`F_BM`, `F_D`, `F_P`, `F_M`). For the `MixTank` above, only `F_M` (2.0) and `F_BM` (2.3) differ from 1, so its installed cost is `baseline × (2.3 + 2.0 - 1)`, not `purchase × F_BM`.\n",
"\n",
"
"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "d5d0b2ee",
"metadata": {
"execution": {
"iopub.execute_input": "2026-05-29T15:55:53.668442Z",
"iopub.status.busy": "2026-05-29T15:55:53.667437Z",
"iopub.status.idle": "2026-05-29T15:55:53.673502Z",
"shell.execute_reply": "2026-05-29T15:55:53.672490Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"{'Tank': 2.3}"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"M2.F_BM # bare-module factor for each cost item"
]
},
{
"cell_type": "markdown",
"id": "c55a074d",
"metadata": {},
"source": [
"\n",
"\n",
"**Operating cost beyond utilities.** The `Additional OPEX` row in `results()` is `unit.add_OPEX` — costs such as chemicals or labor, given as a float or a `dict` of USD/hr. The fraction of time a unit actually runs is `unit.uptime_ratio` (0–1), which scales these operating costs in TEA.\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"id": "4891ee4a",
"metadata": {},
"source": [
"\n",
"\n",
"**Tip:** Some units may require specific components or certain number of influents, for example\n",
"\n",
"
"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "a4a731ea",
"metadata": {
"execution": {
"iopub.execute_input": "2026-05-29T15:55:53.675040Z",
"iopub.status.busy": "2026-05-29T15:55:53.675040Z",
"iopub.status.idle": "2026-05-29T15:55:55.459912Z",
"shell.execute_reply": "2026-05-29T15:55:55.458684Z"
},
"tags": [
"raises-exception"
]
},
"outputs": [
{
"ename": "UndefinedComponent",
"evalue": "'NH3'",
"output_type": "error",
"traceback": [
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
"\u001b[31mKeyError\u001b[39m Traceback (most recent call last)",
"\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\Yalin\\Documents\\Coding\\QSDsan-platform\\.venv\\Lib\\site-packages\\thermosteam\\_chemicals.py:1283\u001b[39m, in \u001b[36mCompiledChemicals._get_index_and_kind\u001b[39m\u001b[34m(self, key)\u001b[39m\n\u001b[32m 1282\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m key.\u001b[34m__hash__\u001b[39m \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m: key = \u001b[38;5;28mtuple\u001b[39m(key)\n\u001b[32m-> \u001b[39m\u001b[32m1283\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43mindex_cache\u001b[39;49m\u001b[30;43m[\u001b[39;49m\u001b[30;43mkey\u001b[39;49m\u001b[30;43m]\u001b[39;49m\n\u001b[32m 1284\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n",
"\u001b[31mKeyError\u001b[39m: 'NH3'",
"\nDuring handling of the above exception, another exception occurred:\n",
"\u001b[31mKeyError\u001b[39m Traceback (most recent call last)",
"\u001b[36mFile \u001b[39m\u001b[32m~\\Documents\\Coding\\QSDsan-platform\\QSDsan\\qsdsan\\_components.py:751\u001b[39m, in \u001b[36mCompiledComponents.index\u001b[39m\u001b[34m(self, ID)\u001b[39m\n\u001b[32m 750\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m'''Return index of specified component.'''\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m751\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m: \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_index\u001b[39;49m\u001b[30;43m[\u001b[39;49m\u001b[30;43mID\u001b[39;49m\u001b[30;43m]\u001b[39;49m\n\u001b[32m 752\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n",
"\u001b[31mKeyError\u001b[39m: 'NH3'",
"\nDuring handling of the above exception, another exception occurred:\n",
"\u001b[31mUndefinedComponent\u001b[39m Traceback (most recent call last)",
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[21]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# You'll receive an `UndefinedComponent` error\u001b[39;00m\n\u001b[32m 2\u001b[39m bad_su = su.Excretion()\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m bad_su.simulate()\n",
"\u001b[36mFile \u001b[39m\u001b[32m~\\Documents\\Coding\\QSDsan-platform\\QSDsan\\qsdsan\\_sanunit.py:436\u001b[39m, in \u001b[36mSanUnit.simulate\u001b[39m\u001b[34m(self, run, design_kwargs, cost_kwargs, **kwargs)\u001b[39m\n\u001b[32m 408\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34msimulate\u001b[39m(\u001b[38;5;28mself\u001b[39m, run=\u001b[38;5;28;01mTrue\u001b[39;00m, design_kwargs={}, cost_kwargs={}, **kwargs):\n\u001b[32m 409\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m'''\u001b[39;00m\n\u001b[32m 410\u001b[39m \u001b[33;03m Converge mass and energy flows, design, and cost the unit.\u001b[39;00m\n\u001b[32m 411\u001b[39m \n\u001b[32m (...)\u001b[39m\u001b[32m 434\u001b[39m \u001b[33;03m `scipy.integrate.solve_ivp `_\u001b[39;00m\n\u001b[32m 435\u001b[39m \u001b[33;03m '''\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m436\u001b[39m \u001b[30;43msuper\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m)\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43msimulate\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mrun\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mrun\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mdesign_kwargs\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mdesign_kwargs\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mcost_kwargs\u001b[39;49m\u001b[30;43m=\u001b[39;49m\u001b[30;43mcost_kwargs\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 437\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m.isdynamic:\n\u001b[32m 438\u001b[39m sys = \u001b[38;5;28mself\u001b[39m._mock_dyn_sys\n",
"\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\Yalin\\Documents\\Coding\\QSDsan-platform\\.venv\\Lib\\site-packages\\biosteam\\_unit.py:1464\u001b[39m, in \u001b[36mUnit.simulate\u001b[39m\u001b[34m(self, run, design_kwargs, cost_kwargs)\u001b[39m\n\u001b[32m 1462\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m ps \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m._specifications: ps.compile_path(\u001b[38;5;28mself\u001b[39m)\n\u001b[32m 1463\u001b[39m \u001b[38;5;28mself\u001b[39m._load_stream_links()\n\u001b[32m-> \u001b[39m\u001b[32m1464\u001b[39m \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mrun\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 1465\u001b[39m \u001b[38;5;28mself\u001b[39m._summary(design_kwargs, cost_kwargs)\n",
"\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\Yalin\\Documents\\Coding\\QSDsan-platform\\.venv\\Lib\\site-packages\\biosteam\\_unit.py:48\u001b[39m, in \u001b[36mphenomena_based_run\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 46\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mphenomena_based_run\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n\u001b[32m 47\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m._recycle_system \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m._system.algorithm == \u001b[33m'\u001b[39m\u001b[33mPhenomena based\u001b[39m\u001b[33m'\u001b[39m):\n\u001b[32m---> \u001b[39m\u001b[32m48\u001b[39m \u001b[30;43mUnit\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mrun\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mself\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 49\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[32m 50\u001b[39m ins = \u001b[38;5;28mself\u001b[39m.ins\n",
"\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\Yalin\\Documents\\Coding\\QSDsan-platform\\.venv\\Lib\\site-packages\\thermosteam\\network.py:1560\u001b[39m, in \u001b[36mAbstractUnit.run\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 1558\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m._outs: i.empty()\n\u001b[32m 1559\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[32m-> \u001b[39m\u001b[32m1560\u001b[39m \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_run_with_specifications\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n",
"\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\Yalin\\Documents\\Coding\\QSDsan-platform\\.venv\\Lib\\site-packages\\thermosteam\\network.py:1576\u001b[39m, in \u001b[36mAbstractUnit._run_with_specifications\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 1574\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m.run_after_specifications: \u001b[38;5;28mself\u001b[39m._run()\n\u001b[32m 1575\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m1576\u001b[39m \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_run\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n",
"\u001b[36mFile \u001b[39m\u001b[32m~\\Documents\\Coding\\QSDsan-platform\\QSDsan\\qsdsan\\unit_operations\\static\\_excretion.py:85\u001b[39m, in \u001b[36mExcretion._run\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 81\u001b[39m factor = \u001b[32m24\u001b[39m * \u001b[32m1e3\u001b[39m \u001b[38;5;66;03m# from g per person per day to kg per hour\u001b[39;00m\n\u001b[32m 83\u001b[39m ur_N = (\u001b[38;5;28mself\u001b[39m.p_veg+\u001b[38;5;28mself\u001b[39m.p_anim)/factor*\u001b[38;5;28mself\u001b[39m.N_prot \\\n\u001b[32m 84\u001b[39m * \u001b[38;5;28mself\u001b[39m.N_exc*\u001b[38;5;28mself\u001b[39m.N_ur*not_wasted\n\u001b[32m---> \u001b[39m\u001b[32m85\u001b[39m \u001b[30;43mur\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mimass\u001b[39;49m\u001b[30;43m[\u001b[39;49m\u001b[30;43m'\u001b[39;49m\u001b[30;43mNH3\u001b[39;49m\u001b[30;43m'\u001b[39;49m\u001b[30;43m]\u001b[39;49m = ur_N * \u001b[38;5;28mself\u001b[39m.N_ur_NH3\n\u001b[32m 86\u001b[39m ur.imass[\u001b[33m'\u001b[39m\u001b[33mNonNH3\u001b[39m\u001b[33m'\u001b[39m] = ur_N - ur.imass[\u001b[33m'\u001b[39m\u001b[33mNH3\u001b[39m\u001b[33m'\u001b[39m]\n\u001b[32m 88\u001b[39m ur.imass[\u001b[33m'\u001b[39m\u001b[33mP\u001b[39m\u001b[33m'\u001b[39m] = (\u001b[38;5;28mself\u001b[39m.p_veg*\u001b[38;5;28mself\u001b[39m.P_prot_v+\u001b[38;5;28mself\u001b[39m.p_anim*\u001b[38;5;28mself\u001b[39m.P_prot_a)/factor \\\n\u001b[32m 89\u001b[39m * \u001b[38;5;28mself\u001b[39m.P_exc*\u001b[38;5;28mself\u001b[39m.P_ur*not_wasted\n",
"\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\Yalin\\Documents\\Coding\\QSDsan-platform\\.venv\\Lib\\site-packages\\thermosteam\\indexer.py:544\u001b[39m, in \u001b[36mChemicalIndexer.__setitem__\u001b[39m\u001b[34m(self, key, data)\u001b[39m\n\u001b[32m 543\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__setitem__\u001b[39m(\u001b[38;5;28mself\u001b[39m, key, data):\n\u001b[32m--> \u001b[39m\u001b[32m544\u001b[39m index, kind = \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_chemicals\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_get_index_and_kind\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mkey\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 545\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m kind \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 546\u001b[39m reset_sparse_chemical_data(\u001b[38;5;28mself\u001b[39m.data, data)\n",
"\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\Yalin\\Documents\\Coding\\QSDsan-platform\\.venv\\Lib\\site-packages\\thermosteam\\_chemicals.py:1293\u001b[39m, in \u001b[36mCompiledChemicals._get_index_and_kind\u001b[39m\u001b[34m(self, key)\u001b[39m\n\u001b[32m 1286\u001b[39m \u001b[38;5;66;03m# [int|None] Kind of index:\u001b[39;00m\n\u001b[32m 1287\u001b[39m \u001b[38;5;66;03m# None - all\u001b[39;00m\n\u001b[32m 1288\u001b[39m \u001b[38;5;66;03m# 0 - chemical\u001b[39;00m\n\u001b[32m 1289\u001b[39m \u001b[38;5;66;03m# 1 - chemical group\u001b[39;00m\n\u001b[32m 1290\u001b[39m \u001b[38;5;66;03m# 2 - nested chemical group\u001b[39;00m\n\u001b[32m 1291\u001b[39m \u001b[38;5;66;03m# 3 - array\u001b[39;00m\n\u001b[32m 1292\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m isa(key, \u001b[38;5;28mstr\u001b[39m):\n\u001b[32m-> \u001b[39m\u001b[32m1293\u001b[39m index = \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mindex\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mkey\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 1294\u001b[39m kind = \u001b[32m0\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m isa(index, \u001b[38;5;28mint\u001b[39m) \u001b[38;5;28;01melse\u001b[39;00m \u001b[32m1\u001b[39m\n\u001b[32m 1295\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m isa(key, \u001b[38;5;28mtuple\u001b[39m):\n",
"\u001b[36mFile \u001b[39m\u001b[32m~\\Documents\\Coding\\QSDsan-platform\\QSDsan\\qsdsan\\_components.py:753\u001b[39m, in \u001b[36mCompiledComponents.index\u001b[39m\u001b[34m(self, ID)\u001b[39m\n\u001b[32m 751\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m: \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m._index[ID]\n\u001b[32m 752\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m753\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m UndefinedComponent(ID)\n",
"\u001b[31mUndefinedComponent\u001b[39m: 'NH3'"
]
}
],
"source": [
"# You'll receive an `UndefinedComponent` error\n",
"bad_su = su.Excretion()\n",
"bad_su.simulate()"
]
},
{
"cell_type": "markdown",
"id": "bc000b77",
"metadata": {},
"source": [
"For those units, the best way is to look at the documentation/examples (e.g., for the above case, check the `bwaise` system referenced in the [Excretion documentation](https://qsdsan.readthedocs.io/en/latest/api/unit_operations/static/Excretion.html))."
]
},
{
"cell_type": "markdown",
"id": "nav-footer-4_sanunit_basic",
"metadata": {},
"source": [
"\n",
"\n",
"---\n",
"\n",
"↑ Back to top\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 5
}