Skip to content

Commit abc7c07

Browse files
committed
Use Markdown for adapter descriptions
1 parent 368cfaf commit abc7c07

14 files changed

Lines changed: 150 additions & 39 deletions

File tree

backend/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ dependencies = [
1313
"fastapi",
1414
"gunicorn>=23.0.0,<24.0.0",
1515
"httpx",
16+
"markdown>=3.10,<4.0",
1617
"msal",
18+
"nh3>=0.3,<0.4",
1719
"neqsim==3.1.0",
1820
"opentelemetry-instrumentation-fastapi",
1921
"opentelemetry-instrumentation-httpx",
@@ -41,6 +43,7 @@ dev = [
4143
"pytest-alembic>=0.12.1",
4244
"pytest-asyncio",
4345
"ruff",
46+
"types-Markdown",
4447
]
4548

4649
[build-system]

backend/src/acidwatch_api/models/arcs.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@
77
from acidwatch_api.models.datamodel import Phase
88
from acidwatch_api.settings import SETTINGS
99

10-
DESCRIPTION: str = """Automated Reactions for CO2 Storage (ARCS) model.
11-
ARCS combines first-principles calculations with Monte-Carlo sampling and models possible reactions that may occur under a given set of conditions.
12-
This process identifies the most frequently occurring reactions and paths, final products, and expected concentrations.
13-
14-
Source code found at https://github.com/equinor/arcs/tree/21ded96960d28d549c0950fbc1aa09c94159f652
15-
"""
10+
DESCRIPTION: str = """\
11+
Automated Reactions for CO2 Storage (ARCS) model.
12+
13+
ARCS combines first-principles calculations with Monte-Carlo sampling and
14+
models possible reactions that may occur under a given set of conditions.
15+
This process identifies the most frequently occurring reactions and paths,
16+
final products, and expected concentrations.
17+
18+
Source code found [on GitHub (equinor/arcs)](https://github.com/equinor/arcs/tree/21ded96960d28d549c0950fbc1aa09c94159f652).
19+
"""
1620

1721

1822
class ArcsAdapter(BaseAdapter):

backend/src/acidwatch_api/models/arcs_exp.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,20 @@
55
from acidwatch_api.models.datamodel import Phase
66
from acidwatch_api.settings import SETTINGS
77

8-
DESCRIPTION: str = """Automated Reactions for CO2 Storage (ARCS) model.
9-
ARCS combines first-principles calculations with Monte-Carlo sampling and models possible reactions that may occur under a given set of conditions.
10-
This process identifies the most frequently occurring reactions and paths, final products, and expected concentrations.
11-
12-
This model is under significant development and expected to deviate while developed. Therefore a development version of it has been released while work is ongoing
13-
Source code found at https://github.com/badw/arcs
14-
"""
8+
DESCRIPTION: str = """\
9+
Automated Reactions for CO2 Storage (ARCS) model.
10+
11+
ARCS combines first-principles calculations with Monte-Carlo sampling and
12+
models possible reactions that may occur under a given set of conditions.
13+
This process identifies the most frequently occurring reactions and paths,
14+
final products, and expected concentrations.
15+
16+
This model is under significant development and is expected to change while
17+
developed. Therefore a development version of it has been released while work
18+
is ongoing.
19+
20+
Source code found [on GitHub (badw/arcs)](https://github.com/badw/arcs).
21+
"""
1522

1623

1724
class ArcsExpAdapter(BaseAdapter):

backend/src/acidwatch_api/models/base.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
from __future__ import annotations
2+
from functools import lru_cache
3+
import nh3
4+
from markdown import markdown
5+
import textwrap
26

37
import typing
48
from collections import defaultdict
@@ -257,7 +261,8 @@ def __init_subclass__(cls) -> None:
257261
]
258262

259263
description: Annotated[
260-
str, Doc("A description for model which is displayed in the frontend")
264+
str,
265+
Doc("A Markdown description for the model."),
261266
]
262267

263268
category: Annotated[
@@ -277,6 +282,14 @@ def __init_subclass__(cls) -> None:
277282

278283
base_url: Annotated[str | None, Doc("BaseURL for accessing a remote model")] = None
279284

285+
@classmethod
286+
@lru_cache()
287+
def description_as_html(cls) -> str:
288+
"""Get the description as rendered HTML"""
289+
text = textwrap.dedent(cls.description).strip()
290+
html = markdown(text, extensions=["extra", "sane_lists"])
291+
return nh3.clean(html)
292+
280293
@property
281294
def client(self) -> httpx.AsyncClient:
282295
"""A ready-to-use client to communicate with an external model

backend/src/acidwatch_api/models/datamodel.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ class ModelInfo(BaseModel):
166166
model_id: str
167167
display_name: str
168168
description: str
169+
description_html: str
169170
category: str
170171
valid_substances: list[str]
171172
parameters: dict[str, Any]

backend/src/acidwatch_api/models/gibbs_minimization_model.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,26 @@
7676
# "i-pentane"
7777
]
7878

79-
DESCRIPTION: str = """The model's primary advantage lies in its ability to analyze complex systems, such as CO2 with impurities, without the need to specify individual reactions. By focusing only on the thermodynamic principles that govern the system's behavior, it identifies the stable state corresponding to the minimum total Gibbs free energy at given temperature and pressure.
80-
81-
However, the model also has limitations. It requires the input of all possible species that could form from the elements present missing any potential species may lead to incorrect equilibrium calculations (that is does not necessary mean poor description of real case scenario). Additionally, the model does not account for kinetics or activation energy, which are crucial for understanding the speed of reactions and the energy barriers that must be overcome for reactions to occur. As a result, while the model can predict the equilibrium state, it cannot guarantee that the real CO2 with impurities system actually reach that state.
82-
83-
The model uses neqsim library for the fluid description (EOS)."""
79+
DESCRIPTION: str = """\
80+
The model's primary advantage lies in its ability to analyze complex systems,
81+
such as CO2 with impurities, without the need to specify individual reactions.
82+
By focusing only on the thermodynamic principles that govern the system's
83+
behavior, it identifies the stable state corresponding to the minimum total
84+
Gibbs free energy at given temperature and pressure.
85+
86+
However, the model also has limitations. It requires the input of all possible
87+
species that could form from the elements present; missing any potential
88+
species may lead to incorrect equilibrium calculations (that does not
89+
necessarily mean a poor description of the real case scenario). Additionally,
90+
the model does not account for kinetics or activation energy, which are crucial
91+
for understanding the speed of reactions and the energy barriers that must be
92+
overcome for reactions to occur. As a result, while the model can predict the
93+
equilibrium state, it cannot guarantee that the real CO2-with-impurities system
94+
actually reaches that state.
95+
96+
The model uses the [neqsim](https://github.com/equinor/neqsim) library for the
97+
fluid description (EOS).
98+
"""
8499

85100

86101
class _EquationOfState(StrEnum):

backend/src/acidwatch_api/models/solubilityccs.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,19 @@
99
from solubilityccs import Fluid, ModelResults # type: ignore
1010
from solubilityccs.neqsim_functions import get_co2_parameters # type: ignore
1111

12-
DESCRIPTION: str = """Solubility model detects acid formation risks in CO2 streams.
13-
14-
It uses the SRK-CPA (Soave-Redlich-Kwong Cubic Plus Association) equation of state to calculate fugacity coefficients and activity models to determine component activities in multiphase systems.
12+
DESCRIPTION: str = """\
13+
Solubility model detects acid formation risks in CO2 streams.
14+
15+
It uses the SRK-CPA (Soave-Redlich-Kwong Cubic Plus Association) equation of
16+
state to calculate fugacity coefficients and activity models to determine
17+
component activities in multiphase systems.
1518
1619
The model currently supports the following chemical systems:
17-
CO₂-water (binary system)
18-
CO₂-water-H₂SO₄ (ternary system with sulfuric acid)
19-
CO₂-water-HNO₃ (ternary system with nitric acid)"""
20+
21+
- CO₂-water (binary system)
22+
- CO₂-water-H₂SO₄ (ternary system with sulfuric acid)
23+
- CO₂-water-HNO₃ (ternary system with nitric acid)
24+
"""
2025

2126

2227
class SolubilityCCSParameters(BaseParameters):

backend/src/acidwatch_api/models/tocomo.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,29 @@
66

77
router = APIRouter()
88

9-
DESCRIPTION: str = """The Total Consumption Model (ToCoMo) estimates final concentrations of chemicals based on initial input concentrations using a series of chemical reactions.
9+
DESCRIPTION: str = """\
10+
The Total Consumption Model (ToCoMo) estimates final concentrations of
11+
chemicals based on initial input concentrations using a series of chemical
12+
reactions.
1013
1114
The model applies the following reactions in a specific order:
1215
13-
3. H₂S + 3 NO₂ → SO₂ + H₂O + 3 NO
14-
2. 2 NO + O₂ → 2 NO₂
15-
1. NO₂ + SO₂ + H₂O → NO + H₂SO₄
16-
4. 3 NO₂ + H₂O → 2 HNO₃ + NO
17-
5. 2 NO₂ + H₂O → HNO₃ + HNO₂
18-
6. 8 H₂S + 4 O₂ → 8 H₂O + S₈
16+
| | | | |
17+
|----|-----------------|---|------------------|
18+
| 1. | H₂S + 3 NO₂ | → | SO₂ + H₂O + 3 NO |
19+
| 2. | 2 NO + O₂ | → | 2 NO₂ |
20+
| 3. | NO₂ + SO₂ + H₂O | → | NO + H₂SO₄ |
21+
| 4. | 3 NO₂ + H₂O | → | 2 HNO₃ + NO |
22+
| 5. | 2 NO₂ + H₂O | → | HNO₃ + HNO₂ |
23+
| 6. | 8 H₂S + 4 O₂ | → | 8 H₂O + S₈ |
1924
20-
The model operates as follows:
21-
We go through the list in the order given and try to apply the reaction.
22-
If it is not possible with the current reaction, we proceed to the next one.
23-
If a reaction can occur, it will be applied, and then we start from the top again.
25+
The model operates as follows: we go through the list in the order given and
26+
try to apply the reaction. If it is not possible with the current reaction, we
27+
proceed to the next one. If a reaction can occur, it will be applied, and then
28+
we start from the top again.
2429
25-
This iterative approach allows ToCoMo to simulate the chemical interactions and provide estimates of final concentrations based on the initial conditions.
30+
This iterative approach allows ToCoMo to simulate the chemical interactions and
31+
provide estimates of final concentrations based on the initial conditions.
2632
"""
2733

2834

backend/src/acidwatch_api/routes/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ def get_models(
181181
display_name=adapter.display_name,
182182
category=adapter.category,
183183
description=adapter.description,
184+
description_html=adapter.description_as_html(),
184185
valid_substances=adapter.valid_substances,
185186
parameters=get_parameters_schema(adapter),
186187
)

backend/tests/models/test_adapter.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,19 @@ def test_adapter_with_invalid_parameters_type():
5858
class DummyAdapter(base.BaseAdapter):
5959
model_id = "dummy"
6060
parameters = 3
61+
62+
63+
def test_adapter_description_is_rendered_to_html_once():
64+
class MarkdownAdapter(base.BaseAdapter):
65+
model_id = "markdown_dummy"
66+
display_name = "Markdown Dummy"
67+
description = "# Title\n\nSome **markdown** body."
68+
category = "ChemicalEquilibrium"
69+
valid_substances = ["H2O"]
70+
71+
async def run(self):
72+
raise NotImplementedError()
73+
74+
assert MarkdownAdapter.description_as_html() == (
75+
"<h1>Title</h1>\n<p>Some <strong>markdown</strong> body.</p>"
76+
)

0 commit comments

Comments
 (0)