diff --git a/examples/pymemsim/README.md b/examples/pymemsim/README.md
new file mode 100644
index 0000000..0ec943f
--- /dev/null
+++ b/examples/pymemsim/README.md
@@ -0,0 +1,18 @@
+# pymemsim Examples
+
+Each sub-directory contains a self-contained example. The order in
+which the examples are to appear is specified in `order.json` (an
+array of directory names in the expected order).
+
+In each example directory you'll find:
+
+* `config.toml` - must conform to the specification outlined here:
+ https://docs.pyscript.net/latest/user-guide/configuration/ This is
+ parsed and ultimately turned into a JSON representation as part of
+ the package's API object.
+* `setup.py` - Python code for contextual and environmental setup,
+ NOT SEEN BY THE END USER, but is run before the `code.py` code is
+ evaluated. Allows us to create useful (IPython) shims, avoid
+ repeating boilerplate and whatnot.
+* `code.py` - the actual code added to the editor which forms the
+ practical example of using the package.
diff --git a/examples/pymemsim/configuring_an_hfm_module/code.py b/examples/pymemsim/configuring_an_hfm_module/code.py
new file mode 100644
index 0000000..c08c19a
--- /dev/null
+++ b/examples/pymemsim/configuring_an_hfm_module/code.py
@@ -0,0 +1,120 @@
+# ---------------------------------------------------------------------
+# Configuring an HFM module: options, inputs, and the factory.
+# ---------------------------------------------------------------------
+#
+# A PyMemSim simulation has three ingredients:
+# 1. Options - what kind of module and how to solve it.
+# 2. Inputs - the feed/permeate streams and operating conditions.
+# 3. The module itself, built by create_hfm_module(...).
+#
+# This example introspects what each of those pieces looks like for
+# a gas-phase, co-current hollow-fiber membrane separating a CO2/N2
+# mixture. The point is to make the configuration vocabulary feel
+# concrete before running a solver.
+import numpy as np
+import matplotlib.pyplot as plt
+import pymemsim as pms
+
+
+heading("Inspecting PyMemSim's configuration classes")
+
+# Find the configuration-style classes the package exposes. We look
+# for things whose names hint at "options" or "module" so the reader
+# can map names they'll see in the docs to real attributes.
+candidates = [
+ name for name in dir(pms)
+ if not name.startswith("_")
+ and any(key in name.lower() for key in ("option", "module", "hfm", "input"))
+]
+note("Configuration-related names exported by pymemsim:")
+display(HTML("
" + "\n".join(candidates) + ""), append=True) + +# A realistic configuration sketch. We describe the module the way a +# PyMemSim user would: a gas-phase HFM running co-currently, isothermal +# and isobaric on both sides, with two components (CO2 and N2). +heading("A gas-phase CO2/N2 separation, sketched as a config") + +config_sketch = { + "phase": "gas", + "modeling_mode": "physical", # alternative: "scale" + "thermal_mode": "isothermal", # alternative: "non-isothermal" + "flow_pattern": "co-current", # alternative: "counter-current" + "components": ["CO2", "N2"], + "feed": { + "flow_mol_per_s": 1.0e-3, + "composition": {"CO2": 0.15, "N2": 0.85}, + "temperature_K": 308.15, + "pressure_bar": 6.0, + }, + "permeate": { + "flow_mol_per_s": 1.0e-5, + "composition": {"CO2": 0.0, "N2": 1.0}, + "temperature_K": 308.15, + "pressure_bar": 1.0, + }, + "transport": { + # Component permeance, mol / (m^2 s Pa). CO2 permeates ~25x faster. + "permeance": {"CO2": 2.5e-7, "N2": 1.0e-8}, + }, + "solver": { + # Co-current => IVP via scipy.integrate.solve_ivp. + "method": "Radau", + "rtol": 1.0e-6, + "atol": 1.0e-9, + }, +} + +# Render the config as a small two-column table so it reads at a glance. +rows = [] +for section, value in config_sketch.items(): + if isinstance(value, dict): + for k, v in value.items(): + rows.append((f"{section}.{k}", repr(v))) + else: + rows.append((section, repr(value))) + +table_html = ["
| Setting | Value |
|---|---|
{key} | {val} |
HollowFiberMembraneOptions(...) and a model-input "
+ "object, then call pms.create_hfm_module(options=..., "
+ "inputs=...) and run the resulting module's simulate "
+ "method. The example files gas-hfm-exp-1.py "
+ "(co-current, IVP) and gas-hfm-exp-2.py "
+ "(counter-current, BVP via solver_bvp) in the "
+ "PyMemSim repository show the full call sequence."
+)
+
+# A predictive sketch of what the resulting profile would look like
+# given the permeance ratio above. This isn't a solved simulation; it's
+# the analytic shape you'd expect from a fast/slow component pair in a
+# co-current arrangement, useful for sanity-checking real results.
+heading("Expected shape: CO2 enrichment in the permeate")
+
+length_fraction = np.linspace(0, 1, 80)
+selectivity = config_sketch["transport"]["permeance"]["CO2"] / \
+ config_sketch["transport"]["permeance"]["N2"]
+
+# Simple monotonic curves with the right qualitative behavior.
+co2_feed = 0.15 * np.exp(-1.8 * length_fraction)
+co2_permeate = 0.15 + (selectivity / (selectivity + 12)) \
+ * (1 - np.exp(-2.2 * length_fraction)) * 0.55
+
+fig, ax = plt.subplots(figsize=(8, 4))
+ax.plot(length_fraction, co2_feed, color="crimson", linewidth=2,
+ label="CO2 in feed (retentate side)")
+ax.plot(length_fraction, co2_permeate, color="darkorange", linewidth=2,
+ label="CO2 in permeate")
+ax.set_xlabel("Fractional length along fiber")
+ax.set_ylabel("CO2 mole fraction")
+ax.set_title(f"Co-current HFM, CO2/N2 selectivity ≈ {selectivity:.0f}")
+ax.legend()
+ax.grid(alpha=0.3)
+fig.tight_layout()
+display(fig, append=True)
diff --git a/examples/pymemsim/configuring_an_hfm_module/config.toml b/examples/pymemsim/configuring_an_hfm_module/config.toml
new file mode 100644
index 0000000..700ebaa
--- /dev/null
+++ b/examples/pymemsim/configuring_an_hfm_module/config.toml
@@ -0,0 +1 @@
+packages = ["numpy", "scipy", "matplotlib", "pymemsim"]
diff --git a/examples/pymemsim/configuring_an_hfm_module/setup.py b/examples/pymemsim/configuring_an_hfm_module/setup.py
new file mode 100644
index 0000000..8470a9f
--- /dev/null
+++ b/examples/pymemsim/configuring_an_hfm_module/setup.py
@@ -0,0 +1,19 @@
+"""Lighter setup for example 2. Sets up the same names as cell 1,
+without the IPython shim."""
+import js
+from pyscript import window, HTML, display as _display
+
+js.alert = window.alert
+
+
+def display(*args, **kwargs):
+ return _display(*args, **kwargs, target=__pyscript_display_target__)
+
+
+def heading(text, level=2):
+ display(HTML(f"{text}
"), append=True) + diff --git a/examples/pymemsim/hollow_fiber_intro/code.py b/examples/pymemsim/hollow_fiber_intro/code.py new file mode 100644 index 0000000..493a422 --- /dev/null +++ b/examples/pymemsim/hollow_fiber_intro/code.py @@ -0,0 +1,70 @@ +""" +A first look at PyMemSim. + +PyMemSim simulates membrane-based separation systems. Its current focus +is the hollow-fiber membrane (HFM) module: long, thin fibers across +which gas or liquid components selectively permeate, separating a feed +mixture into a retentate and a permeate stream. + +This first example simply explores what the package exposes, so we know +what to reach for next. See: + https://github.com/sinagilassi/PyMemSim +""" +from IPython.core.display import display, HTML + +import numpy as np +import matplotlib.pyplot as plt +import pymemsim as pms + + +heading("PyMemSim version") +note(f"Running PyMemSim {pms.__version__} in your browser.") + +# The package's public surface is small and discoverable. The two names +# you'll use most often are HFM (the hollow-fiber membrane interface) +# and create_hfm_module (a factory that wires options + inputs into a +# ready-to-simulate module). +heading("Top-level names worth knowing") +public_names = [name for name in dir(pms) if not name.startswith("_")] +note("Public attributes exposed bypymemsim:")
+display(HTML("" + ", ".join(public_names) + ""), append=True) + +# A quick sketch of the conceptual setup, so the next example feels +# familiar before we dive into solver details. +heading("The hollow-fiber picture") +note( + "Imagine a bundle of porous fibers in a shell. A feed mixture " + "enters one side; some components permeate through the fiber " + "walls more readily than others. Two flow arrangements are " + "supported:" +) +display(HTML( + "
{text}
"), append=True) diff --git a/examples/pymemsim/order.json b/examples/pymemsim/order.json new file mode 100644 index 0000000..b207c9b --- /dev/null +++ b/examples/pymemsim/order.json @@ -0,0 +1,4 @@ +[ + "hollow_fiber_intro", + "configuring_an_hfm_module" +]