pyreactlab-core 0.1.4__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/PKG-INFO +1 -1
  2. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyproject.toml +74 -74
  3. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/__init__.py +8 -2
  4. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/app.py +82 -6
  5. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/configs/info.py +1 -1
  6. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/core/chem_react.py +105 -2
  7. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/docs/chem_utils.py +92 -2
  8. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/models/reaction.py +25 -8
  9. pyreactlab_core-0.1.6/pyreactlab_core/utils/component_tools.py +38 -0
  10. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core.egg-info/PKG-INFO +1 -1
  11. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core.egg-info/SOURCES.txt +1 -0
  12. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/LICENSE +0 -0
  13. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/README.md +0 -0
  14. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/configs/__init__.py +0 -0
  15. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/configs/constants.py +0 -0
  16. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/core/__init__.py +0 -0
  17. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/docs/__init__.py +0 -0
  18. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/docs/chem_balance.py +0 -0
  19. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/models/__init__.py +0 -0
  20. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/utils/__init__.py +0 -0
  21. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core/utils/tools.py +0 -0
  22. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core.egg-info/dependency_links.txt +0 -0
  23. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core.egg-info/requires.txt +0 -0
  24. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/pyreactlab_core.egg-info/top_level.txt +0 -0
  25. {pyreactlab_core-0.1.4 → pyreactlab_core-0.1.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyreactlab-core
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: pyreactlab-core is the core foundation of the PyReactLab ecosystem, offering shared data structures and algorithms for chemical reaction representation, stoichiometry, and reaction analysis.
5
5
  Author-email: Sina Gilassi <sina.gilassi@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -1,74 +1,74 @@
1
- [build-system]
2
- requires = ["setuptools>=61.0", "wheel"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "pyreactlab-core"
7
- version = "0.1.4"
8
- description = "pyreactlab-core is the core foundation of the PyReactLab ecosystem, offering shared data structures and algorithms for chemical reaction representation, stoichiometry, and reaction analysis."
9
- readme = "README.md"
10
- requires-python = ">=3.11"
11
- license = "Apache-2.0"
12
- license-files = ["LICENSE"]
13
- authors = [
14
- {name = "Sina Gilassi", email = "sina.gilassi@gmail.com"}
15
- ]
16
- keywords = [
17
- "chemical-engineering",
18
- "chemical-reactions",
19
- "reaction-representation",
20
- "reaction-stoichiometry",
21
- "reaction-analysis",
22
- ]
23
- classifiers = [
24
- "Development Status :: 1 - Planning",
25
- "Intended Audience :: Education",
26
- "Programming Language :: Python :: 3.11",
27
- "Operating System :: Unix",
28
- "Operating System :: MacOS :: MacOS X",
29
- "Operating System :: Microsoft :: Windows",
30
- ]
31
- dependencies = [
32
- "scipy>=1.17.1",
33
- "numpy>=2.4.3",
34
- "pydantic>=2.12.5",
35
- "pydantic-settings>=2.12.0",
36
- "rich>=14.2.0",
37
- "pythermodb-settings",
38
- ]
39
-
40
- [project.urls]
41
- Homepage = "https://github.com/sinagilassi/PyReactLab-Core"
42
- Documentation = "https://pyreactlab-core.readthedocs.io/en/latest/"
43
- Source = "https://github.com/sinagilassi/PyReactLab-Core"
44
- Tracker = "https://github.com/sinagilassi/PyReactLab-Core/issues"
45
-
46
- [tool.setuptools]
47
- include-package-data = true
48
-
49
- [tool.setuptools.packages.find]
50
- where = ["."]
51
- include = ["pyreactlab_core*"]
52
- exclude = [
53
- "tests",
54
- "tests.*",
55
- "examples",
56
- "examples.*",
57
- "notebooks",
58
- "notebooks.*",
59
- "statics",
60
- "statics.*",
61
- "private",
62
- "private.*",
63
- "app",
64
- "app.*"
65
- ]
66
-
67
- [tool.setuptools.package-data]
68
- pyreactlab_core = [
69
- "config/*.yml",
70
- "data/*.csv",
71
- "templates/*.html",
72
- "static/*",
73
- "static/**/*"
74
- ]
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pyreactlab-core"
7
+ version = "0.1.6"
8
+ description = "pyreactlab-core is the core foundation of the PyReactLab ecosystem, offering shared data structures and algorithms for chemical reaction representation, stoichiometry, and reaction analysis."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "Apache-2.0"
12
+ license-files = ["LICENSE"]
13
+ authors = [
14
+ {name = "Sina Gilassi", email = "sina.gilassi@gmail.com"}
15
+ ]
16
+ keywords = [
17
+ "chemical-engineering",
18
+ "chemical-reactions",
19
+ "reaction-representation",
20
+ "reaction-stoichiometry",
21
+ "reaction-analysis",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 1 - Planning",
25
+ "Intended Audience :: Education",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Operating System :: Unix",
28
+ "Operating System :: MacOS :: MacOS X",
29
+ "Operating System :: Microsoft :: Windows",
30
+ ]
31
+ dependencies = [
32
+ "scipy>=1.17.1",
33
+ "numpy>=2.4.3",
34
+ "pydantic>=2.12.5",
35
+ "pydantic-settings>=2.12.0",
36
+ "rich>=14.2.0",
37
+ "pythermodb-settings",
38
+ ]
39
+
40
+ [project.urls]
41
+ Homepage = "https://github.com/sinagilassi/PyReactLab-Core"
42
+ Documentation = "https://pyreactlab-core.readthedocs.io/en/latest/"
43
+ Source = "https://github.com/sinagilassi/PyReactLab-Core"
44
+ Tracker = "https://github.com/sinagilassi/PyReactLab-Core/issues"
45
+
46
+ [tool.setuptools]
47
+ include-package-data = true
48
+
49
+ [tool.setuptools.packages.find]
50
+ where = ["."]
51
+ include = ["pyreactlab_core*"]
52
+ exclude = [
53
+ "tests",
54
+ "tests.*",
55
+ "examples",
56
+ "examples.*",
57
+ "notebooks",
58
+ "notebooks.*",
59
+ "statics",
60
+ "statics.*",
61
+ "private",
62
+ "private.*",
63
+ "app",
64
+ "app.*"
65
+ ]
66
+
67
+ [tool.setuptools.package-data]
68
+ pyreactlab_core = [
69
+ "config/*.yml",
70
+ "data/*.csv",
71
+ "templates/*.html",
72
+ "static/*",
73
+ "static/**/*"
74
+ ]
@@ -8,7 +8,12 @@ from .configs.info import (
8
8
  __license__,
9
9
  )
10
10
 
11
- from .app import rxn, rxn_stoichiometry, rxns_stoichiometry
11
+ from .app import (
12
+ rxn,
13
+ rxn_stoichiometry_matrix,
14
+ rxns_stoichiometry,
15
+ build_rxns_stoichiometry
16
+ )
12
17
 
13
18
  __all__ = [
14
19
  # config
@@ -20,6 +25,7 @@ __all__ = [
20
25
  "__license__",
21
26
  # app
22
27
  "rxn",
23
- "rxn_stoichiometry",
28
+ "rxn_stoichiometry_matrix",
24
29
  "rxns_stoichiometry",
30
+ "build_rxns_stoichiometry",
25
31
  ]
@@ -1,9 +1,10 @@
1
1
  # import libs
2
2
  import logging
3
- from typing import List, Optional, Dict
3
+ from typing import List, Optional, Dict, Tuple
4
+ from pythermodb_settings.models import Component, ComponentKey
4
5
  # locals
5
6
  from .models.reaction import Reaction
6
- from .docs.chem_utils import build_stoichiometry_matrix
7
+ from .docs.chem_utils import build_stoichiometry_matrix, build_rxn_stoichiometry_source
7
8
 
8
9
  # NOTE: configure logger
9
10
  logger = logging.getLogger(__name__)
@@ -11,7 +12,7 @@ logger = logging.getLogger(__name__)
11
12
 
12
13
  def rxn(
13
14
  reaction_str: str,
14
- name: Optional[str] = None
15
+ name: Optional[str] = None,
15
16
  ) -> Optional[Reaction]:
16
17
  """
17
18
  Create and analyze a chemical reaction.
@@ -50,7 +51,7 @@ def rxn(
50
51
  return None
51
52
 
52
53
 
53
- def rxn_stoichiometry(
54
+ def rxn_stoichiometry_matrix(
54
55
  reaction: Reaction,
55
56
  ) -> Optional[List[float]]:
56
57
  """
@@ -85,6 +86,8 @@ def rxn_stoichiometry(
85
86
 
86
87
  def rxns_stoichiometry(
87
88
  reactions: List[Reaction],
89
+ components: Optional[List[Component]] = None,
90
+ component_key: ComponentKey = "Name-Formula"
88
91
  ) -> Optional[Dict]:
89
92
  """
90
93
  Get the reaction stoichiometry matrices for a list of chemical reactions.
@@ -109,11 +112,16 @@ def rxns_stoichiometry(
109
112
  return None
110
113
 
111
114
  # SECTION: retrieve stoichiometry matrices
112
- result = build_stoichiometry_matrix(reactions=reactions)
115
+ result = build_stoichiometry_matrix(
116
+ reactions=reactions,
117
+ components=components,
118
+ component_key=component_key
119
+ )
113
120
 
114
121
  # NOTE: res
115
122
  return {
116
- "components": result["component_list"],
123
+ "components": result["components"],
124
+ "component_list": result["component_list"],
117
125
  "component_ids": result["component_dict"],
118
126
  "stoichiometry_matrices_list": result["comp_coeff"],
119
127
  "stoichiometry_matrices_dict": result["comp_list"],
@@ -121,3 +129,71 @@ def rxns_stoichiometry(
121
129
  except Exception as e:
122
130
  logger.error(f"Error retrieving reaction stoichiometry matrices: {e}")
123
131
  return None
132
+
133
+ # SECTION: Build stoichiometry for reactions
134
+
135
+
136
+ def build_rxns_stoichiometry(
137
+ reactions: List[Reaction],
138
+ components: List[Component],
139
+ component_key: ComponentKey
140
+ ) -> Optional[
141
+ Dict[str, List[Dict[str, float]] | List[List[float]]]
142
+ ]:
143
+ """
144
+ Build the reaction stoichiometry matrices for a list of chemical reactions.
145
+
146
+ Parameters
147
+ ----------
148
+ reactions : List[Reaction]
149
+ List of Reaction instances.
150
+ components : List[Component]
151
+ List of all components involved in the reactions.
152
+ component_key : ComponentKey
153
+ The key to use for mapping components (e.g., "Name-Formula").
154
+
155
+ Returns
156
+ -------
157
+ Optional[Dict[str, List[Dict[str, float]] | List[List[float]]]]
158
+ A dictionary containing the stoichiometry source and matrices if successful, None otherwise. The dictionary has the following structure:
159
+ - "source": List[Dict[str, float]] - A list of dictionaries representing the stoichiometry source for each reaction.
160
+ - "matrix": List[List[float]] - A list of stoichiometry matrices corresponding to each reaction.
161
+ """
162
+ try:
163
+ # SECTION: validate inputs
164
+ if (
165
+ not isinstance(reactions, list) or
166
+ not all(isinstance(rxn, Reaction) for rxn in reactions)
167
+ ):
168
+ logger.error("Invalid reactions list provided.")
169
+ return None
170
+
171
+ if (
172
+ not isinstance(components, list) or
173
+ not all(isinstance(comp, Component) for comp in components)
174
+ ):
175
+ logger.error("Invalid components list provided.")
176
+ return None
177
+
178
+ # SECTION: build stoichiometry source
179
+ stoichiometry_source = build_rxn_stoichiometry_source(
180
+ reactions=reactions,
181
+ components=components,
182
+ component_key=component_key
183
+ )
184
+
185
+ # >> check
186
+ if not stoichiometry_source:
187
+ logger.error("Failed to build reaction stoichiometry source.")
188
+ return None
189
+
190
+ # result
191
+ res = {
192
+ "source": stoichiometry_source[0],
193
+ "matrix": stoichiometry_source[1]
194
+ }
195
+
196
+ return res
197
+ except Exception as e:
198
+ logger.error(f"Error building reaction stoichiometry: {e}")
199
+ return None
@@ -1,5 +1,5 @@
1
1
  # version
2
- __version__ = "0.1.4"
2
+ __version__ = "0.1.6"
3
3
  # author
4
4
  __author__ = "Sina Gilassi"
5
5
  # email
@@ -2,13 +2,16 @@
2
2
  import logging
3
3
  import re
4
4
  from typing import Dict, Any, List, Optional, Literal, TypedDict
5
- from pythermodb_settings.models import Component
5
+ from pythermodb_settings.models import Component, ComponentKey
6
+ from pythermodb_settings.utils import set_component_id
7
+ # locals
6
8
  from ..configs.constants import (
7
9
  R_CONST_J__molK,
8
10
  PRESSURE_REF_Pa,
9
11
  TEMPERATURE_REF_K,
10
12
  )
11
13
 
14
+
12
15
  # NOTE: logger
13
16
  logger = logging.getLogger(__name__)
14
17
 
@@ -69,10 +72,14 @@ class ChemReact:
69
72
  # NOTE: component checker
70
73
  _component_checker: bool = False
71
74
 
75
+ # NOTE: stoichiometry source
76
+ _stoichiometry_source: dict[str, Any] = {}
77
+
72
78
  def __init__(
73
79
  self,
74
80
  reaction_mode_symbol: ReactionMode,
75
- components: Optional[List[Component]]
81
+ components: Optional[List[Component]],
82
+ component_keys: Optional[List[ComponentKey]] = None
76
83
  ):
77
84
  """
78
85
  Initialize the ChemReactUtils class.
@@ -83,6 +90,8 @@ class ChemReact:
83
90
  The symbol used to separate reactants and products in a reaction equation.
84
91
  components : Optional[List[Component]]
85
92
  A list of Component objects involved in the reaction.
93
+ component_keys : List[ComponentKey], optional
94
+ The key used to identify components in the reaction.
86
95
 
87
96
  Notes
88
97
  -----
@@ -98,6 +107,12 @@ class ChemReact:
98
107
  # NOTE: set components
99
108
  self.components = components
100
109
 
110
+ # NOTE: set component key
111
+ if component_keys is not None:
112
+ self.component_keys = component_keys
113
+ else:
114
+ self.component_keys = []
115
+
101
116
  # SECTION: Component id
102
117
  # NOTE: component ids
103
118
  if components is None:
@@ -115,6 +130,12 @@ class ChemReact:
115
130
  raise ValueError("System inputs are not set.")
116
131
  return self._system_inputs
117
132
 
133
+ @property
134
+ def stoichiometry_source(self) -> Dict[str, Any]:
135
+ """Get the stoichiometry source."""
136
+ # res
137
+ return self._stoichiometry_source
138
+
118
139
  def count_carbon(self, molecule: str, coefficient: float) -> float:
119
140
  """
120
141
  Count the number of carbon atoms in a molecule.
@@ -396,6 +417,11 @@ class ChemReact:
396
417
  products,
397
418
  )
398
419
 
420
+ # SECTION: build stoichiometry source
421
+ stoichiometry_source = self.build_stoichiometry_source(
422
+ reaction_stoichiometry=reaction_stoichiometry
423
+ )
424
+
399
425
  # res
400
426
  res = {
401
427
  'name': name,
@@ -411,6 +437,7 @@ class ChemReact:
411
437
  'reaction_coefficients': reaction_coefficients,
412
438
  'reaction_stoichiometry': reaction_stoichiometry,
413
439
  'reaction_stoichiometry_matrix': reaction_stoichiometry_matrix,
440
+ 'reaction_stoichiometry_source': stoichiometry_source,
414
441
  'carbon_count': carbon_count,
415
442
  'reaction_state': reaction_state,
416
443
  'reaction_phase': reaction_phase,
@@ -1017,3 +1044,79 @@ class ChemReact:
1017
1044
  return component_map
1018
1045
  except Exception as e:
1019
1046
  raise Exception(f"Error mapping components: {e}")
1047
+
1048
+ def reaction_stoichiometry_dict(
1049
+ self,
1050
+ reaction_stoichiometry: Dict[str, float],
1051
+ component_key: ComponentKey = "Name-Formula"
1052
+ ) -> Dict[str, float]:
1053
+ '''
1054
+ Generate the reaction stoichiometry matrix.
1055
+
1056
+ Parameters
1057
+ ----------
1058
+ reaction_stoichiometry: dict
1059
+ A dictionary containing the stoichiometry of the reaction, where keys are component IDs and values are their coefficients.
1060
+
1061
+ Returns
1062
+ -------
1063
+ dict
1064
+ A dictionary representing the reaction stoichiometry, where keys are component IDs and values are their coefficients.
1065
+ '''
1066
+ # >> check
1067
+ if self.components is None:
1068
+ return {}
1069
+
1070
+ # NOTE: component ids
1071
+ component_ids = list(reaction_stoichiometry.keys())
1072
+
1073
+ id_to_component = {}
1074
+ for comp in self.components:
1075
+ comp_id = set_component_id(comp, 'Formula-State') # type: ignore
1076
+ if comp_id in component_ids:
1077
+ # create component id
1078
+ comp_id_new = set_component_id(
1079
+ comp,
1080
+ component_key
1081
+ )
1082
+ id_to_component[comp_id_new] = reaction_stoichiometry[comp_id]
1083
+ else:
1084
+ logging.warning(
1085
+ f"Component '{comp_id}' not found in reaction stoichiometry.")
1086
+
1087
+ return id_to_component
1088
+
1089
+ def build_stoichiometry_source(
1090
+ self,
1091
+ reaction_stoichiometry: Dict[str, float],
1092
+ ) -> Dict[str, Any]:
1093
+ """
1094
+ Build the stoichiometry source for the reaction according to the component keys.
1095
+
1096
+ Parameters
1097
+ ----------
1098
+ reaction_stoichiometry : Dict[str, float]
1099
+ A dictionary containing the stoichiometry of the reaction, where keys are component IDs and values are their coefficients.
1100
+ """
1101
+ # >> check
1102
+ if self.components is None:
1103
+ return {}
1104
+
1105
+ # NOTE: component ids
1106
+ component_ids = list(reaction_stoichiometry.keys())
1107
+
1108
+ # NOTE: build stoichiometry source
1109
+ stoichiometry_source = {}
1110
+
1111
+ for key in self.component_keys:
1112
+ id_to_component = self.reaction_stoichiometry_dict(
1113
+ reaction_stoichiometry,
1114
+ component_key=key
1115
+ )
1116
+
1117
+ # set
1118
+ stoichiometry_source[key] = id_to_component
1119
+
1120
+ # set stoichiometry source
1121
+ self._stoichiometry_source = stoichiometry_source
1122
+ return stoichiometry_source
@@ -1,14 +1,21 @@
1
1
  # import libs
2
2
  import logging
3
- from typing import List, Optional
3
+ from typing import List, Optional, Tuple, Dict
4
+ from pythermodb_settings.models import Component, ComponentKey
5
+ from pythermodb_settings.utils import set_component_id
4
6
  # locals
5
7
  from ..models.reaction import Reaction
8
+ from ..utils.component_tools import map_component_ids
6
9
 
7
10
  # NOTE: configure logger
8
11
  logger = logging.getLogger(__name__)
9
12
 
10
13
 
11
- def build_stoichiometry_matrix(reactions: List[Reaction]):
14
+ def build_stoichiometry_matrix(
15
+ reactions: List[Reaction],
16
+ components: Optional[List[Component]],
17
+ component_key: ComponentKey = "Name-Formula"
18
+ ):
12
19
  '''
13
20
  Build stoichiometry matrix for reactions
14
21
 
@@ -16,6 +23,10 @@ def build_stoichiometry_matrix(reactions: List[Reaction]):
16
23
  ----------
17
24
  reactions : List[Reaction]
18
25
  List of Reaction instances
26
+ components : Optional[List[Component]]
27
+ List of Component instances
28
+ component_key : ComponentKey
29
+ The key used to identify components in the reaction.
19
30
 
20
31
  Returns
21
32
  -------
@@ -102,8 +113,18 @@ def build_stoichiometry_matrix(reactions: List[Reaction]):
102
113
  [comp_list[j][item] for item in component_dict.keys()] for j in range(reaction_num)
103
114
  ]
104
115
 
116
+ # NOTE: map component ids to components
117
+ components_ext = {}
118
+ if components is not None:
119
+ components_ext = map_component_ids(
120
+ component_ids=component_list,
121
+ component=components,
122
+ component_key=component_key
123
+ )
124
+
105
125
  # res
106
126
  return {
127
+ "components": components_ext,
107
128
  "component_list": component_list,
108
129
  "component_dict": component_dict,
109
130
  "component_state_list": component_state_list,
@@ -112,3 +133,72 @@ def build_stoichiometry_matrix(reactions: List[Reaction]):
112
133
  }
113
134
  except Exception as e:
114
135
  raise Exception(f"Error defining component ID: {e}")
136
+
137
+
138
+ # SECTION: build stoichiometry matrix for reactions
139
+ def build_rxn_stoichiometry_source(
140
+ reactions: List[Reaction],
141
+ components: List[Component],
142
+ component_key: ComponentKey
143
+ ) -> Optional[
144
+ Tuple[
145
+ List[Dict[str, float]],
146
+ List[List[float]]
147
+ ]
148
+ ]:
149
+ try:
150
+ # NOTE: stoichiometry source
151
+ stoichiometry_source = []
152
+
153
+ # iterate over reactions
154
+ for reaction in reactions:
155
+ # stoichiometry
156
+ stoichiometry_ = reaction.reaction_stoichiometry_source.get(
157
+ component_key, {})
158
+ # >> check
159
+ if not stoichiometry_:
160
+ logger.warning(
161
+ f"Stoichiometry source not found for reaction: {reaction.name}")
162
+ return None
163
+
164
+ # store
165
+ stoichiometry_source.append(stoichiometry_)
166
+
167
+ # NOTE: map component ids to components
168
+ components_source = [
169
+ set_component_id(
170
+ component=item,
171
+ component_key=component_key
172
+ ) for item in components
173
+ ]
174
+
175
+ # NOTE: stoichiometry
176
+ stoichiometry_result: List[Dict[str, float]] = []
177
+
178
+ # iterate over stoichiometry source
179
+ for i in range(len(reactions)):
180
+ sto_ = {}
181
+ for item in components_source:
182
+ # raw data
183
+ sto_[item] = 0.0
184
+
185
+ # update
186
+ stoichiometry_result.append(sto_)
187
+
188
+ # update stoichiometry result
189
+ for i, item in enumerate(stoichiometry_result):
190
+ for key, value in stoichiometry_source[i].items():
191
+ item[key] = value
192
+
193
+ # NOTE: create a matrix of stoichiometry
194
+ stoichiometry_result_matrix: List[List[float]] = []
195
+ for item in stoichiometry_result:
196
+ row = []
197
+ for key in components_source:
198
+ row.append(float(item[key]))
199
+ stoichiometry_result_matrix.append(row)
200
+
201
+ return stoichiometry_result, stoichiometry_result_matrix
202
+ except Exception as e:
203
+ logger.error(f"Error building reaction stoichiometry source: {e}")
204
+ return None
@@ -1,9 +1,9 @@
1
1
  # import libs
2
2
  from __future__ import annotations
3
-
3
+ import logging
4
4
  from typing import Any, Dict, Optional, List
5
5
  from pydantic import BaseModel, Field, computed_field, model_validator
6
- from pythermodb_settings.models import Component
6
+ from pythermodb_settings.models import Component, ComponentKey
7
7
  # local imports
8
8
  from ..core.chem_react import (
9
9
  ChemReact,
@@ -11,6 +11,9 @@ from ..core.chem_react import (
11
11
  PhaseRule
12
12
  )
13
13
 
14
+ # NOTE: set up logger
15
+ logger = logging.getLogger(__name__)
16
+
14
17
 
15
18
  class Reaction(BaseModel):
16
19
  """
@@ -79,6 +82,14 @@ class Reaction(BaseModel):
79
82
  default_factory=dict,
80
83
  description="A dictionary containing the analysis results of the reaction."
81
84
  )
85
+ component_keys: List[ComponentKey] = Field(
86
+ default_factory=lambda: [
87
+ "Formula-State",
88
+ "Name-State",
89
+ "Name-Formula",
90
+ ],
91
+ description="The key used to identify components in the reaction analysis."
92
+ )
82
93
 
83
94
  @model_validator(mode="after")
84
95
  def _run_existing_analysis(self):
@@ -97,7 +108,8 @@ class Reaction(BaseModel):
97
108
  # NOTE: analyze reaction
98
109
  util = ChemReact(
99
110
  reaction_mode_symbol=self.reaction_mode_symbol,
100
- components=self.components
111
+ components=self.components,
112
+ component_keys=self.component_keys
101
113
  )
102
114
 
103
115
  # NOTE: perform analysis
@@ -141,8 +153,8 @@ class Reaction(BaseModel):
141
153
 
142
154
  @computed_field
143
155
  @property
144
- def reaction_coefficients(self) -> Dict[str, float]:
145
- return self.analysis.get("reaction_coefficients", {})
156
+ def reaction_coefficients(self) -> float:
157
+ return self.analysis.get("reaction_coefficients", 0.0)
146
158
 
147
159
  @computed_field
148
160
  @property
@@ -156,8 +168,13 @@ class Reaction(BaseModel):
156
168
 
157
169
  @computed_field
158
170
  @property
159
- def carbon_count(self) -> int:
160
- return self.analysis.get("carbon_count", 0)
171
+ def reaction_stoichiometry_source(self) -> Dict[str, Dict[str, float]]:
172
+ return self.analysis.get("reaction_stoichiometry_source", {})
173
+
174
+ @computed_field
175
+ @property
176
+ def carbon_count(self) -> Dict[str, float]:
177
+ return self.analysis.get("carbon_count", {})
161
178
 
162
179
  @computed_field
163
180
  @property
@@ -166,7 +183,7 @@ class Reaction(BaseModel):
166
183
 
167
184
  @computed_field
168
185
  @property
169
- def reaction_phase(self) -> Optional[PhaseRule]:
186
+ def reaction_phase(self) -> Optional[str]:
170
187
  return self.analysis.get("reaction_phase", None)
171
188
 
172
189
  @computed_field
@@ -0,0 +1,38 @@
1
+ # import libs
2
+ import logging
3
+ from typing import Dict, Any, List, Optional, Literal
4
+ from pythermodb_settings.models import Component, ComponentKey
5
+ from pythermodb_settings.utils import set_component_id
6
+
7
+
8
+ def map_component_ids(
9
+ component_ids: list[str],
10
+ component: List[Component],
11
+ component_key: ComponentKey
12
+ ):
13
+ """
14
+ Map component IDs to their corresponding components.
15
+
16
+ Parameters
17
+ ----------
18
+ component_ids : list[str]
19
+ A list of component IDs to be mapped.
20
+ component : List[Component]
21
+ A list of Component objects to be mapped against.
22
+ component_key : ComponentKey
23
+ The key used to identify components in the reaction.
24
+
25
+ Returns
26
+ -------
27
+ Dict[str, Component]
28
+ A dictionary mapping component IDs to their corresponding Component objects.
29
+ """
30
+ id_to_component = {}
31
+
32
+ # iterate over components and map ids
33
+ for comp in component:
34
+ comp_id = set_component_id(comp, component_key)
35
+ if comp_id in component_ids:
36
+ id_to_component[comp_id] = comp
37
+
38
+ return id_to_component
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyreactlab-core
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: pyreactlab-core is the core foundation of the PyReactLab ecosystem, offering shared data structures and algorithms for chemical reaction representation, stoichiometry, and reaction analysis.
5
5
  Author-email: Sina Gilassi <sina.gilassi@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -19,4 +19,5 @@ pyreactlab_core/docs/chem_utils.py
19
19
  pyreactlab_core/models/__init__.py
20
20
  pyreactlab_core/models/reaction.py
21
21
  pyreactlab_core/utils/__init__.py
22
+ pyreactlab_core/utils/component_tools.py
22
23
  pyreactlab_core/utils/tools.py
File without changes