OpenSimula 0.8.7__tar.gz → 0.8.9__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 (78) hide show
  1. {opensimula-0.8.7/src/opensimula.egg-info → opensimula-0.8.9}/PKG-INFO +26 -3
  2. {opensimula-0.8.7 → opensimula-0.8.9}/README.md +23 -2
  3. {opensimula-0.8.7 → opensimula-0.8.9}/pyproject.toml +7 -1
  4. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/Component.py +117 -7
  5. opensimula-0.8.9/src/opensimula/Iterative_process.py +85 -0
  6. opensimula-0.8.9/src/opensimula/Message.py +35 -0
  7. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/Parameter_container.py +46 -7
  8. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/Parameters.py +125 -2
  9. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/Project.py +84 -20
  10. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/Simulation.py +44 -10
  11. opensimula-0.8.9/src/opensimula/Variable.py +67 -0
  12. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Building.py +17 -3
  13. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Construction.py +9 -5
  14. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/File_met.py +88 -60
  15. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/HVAC_SZW_system.py +22 -22
  16. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Opening.py +9 -1
  17. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Space.py +4 -1
  18. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/visual_3D/Environment_3D.py +23 -5
  19. {opensimula-0.8.7 → opensimula-0.8.9/src/opensimula.egg-info}/PKG-INFO +26 -3
  20. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_Case_600FF.py +3 -3
  21. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_Case_610.py +20 -4
  22. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_Construction.py +35 -0
  23. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_File_met.py +19 -0
  24. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_HVAC_DX_system.py +12 -12
  25. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_HVAC_FAN_COIL_water_system.py +10 -10
  26. opensimula-0.8.9/test/test_Iterative_process.py +30 -0
  27. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_Project.py +27 -0
  28. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_editor_schema.py +15 -9
  29. opensimula-0.8.7/src/opensimula/Iterative_process.py +0 -47
  30. opensimula-0.8.7/src/opensimula/Message.py +0 -19
  31. opensimula-0.8.7/src/opensimula/Variable.py +0 -41
  32. opensimula-0.8.7/test/test_Iterative_process.py +0 -13
  33. {opensimula-0.8.7 → opensimula-0.8.9}/LICENSE +0 -0
  34. {opensimula-0.8.7 → opensimula-0.8.9}/setup.cfg +0 -0
  35. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/Child.py +0 -0
  36. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/__init__.py +0 -0
  37. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Building_surface.py +0 -0
  38. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Calculator.py +0 -0
  39. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Chiller_heat_pump.py +0 -0
  40. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/DX_unit.py +0 -0
  41. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Day_schedule.py +0 -0
  42. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Fan.py +0 -0
  43. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/File_data.py +0 -0
  44. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Frame.py +0 -0
  45. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Glazing.py +0 -0
  46. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/HVAC_DX_system.py +0 -0
  47. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/HVAC_MZW_system.py +0 -0
  48. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/HVAC_perfect_system.py +0 -0
  49. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/HVAC_water_system.py +0 -0
  50. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Material.py +0 -0
  51. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Opening_type.py +0 -0
  52. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Pump.py +0 -0
  53. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Solar_surface.py +0 -0
  54. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Space_type.py +0 -0
  55. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Surface.py +0 -0
  56. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Test_component.py +0 -0
  57. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Water_coil.py +0 -0
  58. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Week_schedule.py +0 -0
  59. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/Year_schedule.py +0 -0
  60. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/components/__init__.py +0 -0
  61. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/editor/__init__.py +0 -0
  62. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/editor/schema.py +0 -0
  63. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/editor/static/editor.css +0 -0
  64. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/editor/static/editor.js +0 -0
  65. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/editor/validation.py +0 -0
  66. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/editor/widget.py +0 -0
  67. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula/visual_3D/Polygon_3D.py +0 -0
  68. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula.egg-info/SOURCES.txt +0 -0
  69. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula.egg-info/dependency_links.txt +0 -0
  70. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula.egg-info/requires.txt +0 -0
  71. {opensimula-0.8.7 → opensimula-0.8.9}/src/opensimula.egg-info/top_level.txt +0 -0
  72. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_Calculator.py +0 -0
  73. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_File_data.py +0 -0
  74. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_HVAC_DX_Equipment.py +0 -0
  75. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_HVAC_water_system_process.py +0 -0
  76. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_Schedules.py +0 -0
  77. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_editor_widget.py +0 -0
  78. {opensimula-0.8.7 → opensimula-0.8.9}/test/test_underground_repeated_simulation.py +0 -0
@@ -1,8 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opensimula
3
- Version: 0.8.7
3
+ Version: 0.8.9
4
4
  Summary: Component-based time simulation environment in Python
5
+ Author: Luis Pérez-Lombard, Ismael R. Maestre
5
6
  Author-email: "Juan F. Coronel" <jfc@us.es>
7
+ Maintainer-email: "Juan F. Coronel" <jfc@us.es>
6
8
  Requires-Python: >=3.12
7
9
  Description-Content-Type: text/markdown
8
10
  License-File: LICENSE
@@ -24,8 +26,10 @@ Dynamic: license-file
24
26
 
25
27
  # OpenSimula
26
28
 
29
+ [![Tests](https://github.com/jfCoronel/OpenSimula/actions/workflows/tests.yml/badge.svg)](https://github.com/jfCoronel/OpenSimula/actions/workflows/tests.yml)
27
30
  [![PyPI version](https://img.shields.io/pypi/v/opensimula)](https://pypi.org/project/opensimula/)
28
31
  [![Python versions](https://img.shields.io/pypi/pyversions/opensimula)](https://pypi.org/project/opensimula/)
32
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23210985.svg)](https://doi.org/10.5281/zenodo.23210985)
29
33
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
30
34
 
31
35
  **OpenSimula** is a component-based time simulation environment in Python, focused on the
@@ -162,9 +166,28 @@ reference, is at [jfcoronel.github.io/OpenSimula](https://jfcoronel.github.io/Op
162
166
  Bugs and feature requests are tracked on
163
167
  [GitHub Issues](https://github.com/jfCoronel/OpenSimula/issues).
164
168
 
165
- ## Main Developers
169
+ ## Contributing
166
170
 
167
- * [Juan F. Coronel](http://jfc.us.es), Universidad de Sevilla
171
+ Contributions are welcome: bug reports, fixes, new components, validation cases and examples.
172
+ See [CONTRIBUTING.md](https://github.com/jfCoronel/OpenSimula/blob/main/CONTRIBUTING.md) for how to set up a development environment, run the
173
+ tests and submit a pull request.
174
+
175
+ ## Citing OpenSimula
176
+
177
+ If you use OpenSimula in your research, please cite it with its DOI,
178
+ [10.5281/zenodo.23210985](https://doi.org/10.5281/zenodo.23210985), which always resolves to
179
+ the latest version (each version also has its own DOI, listed on
180
+ [Zenodo](https://doi.org/10.5281/zenodo.23210985)). The full metadata is in
181
+ [CITATION.cff](https://github.com/jfCoronel/OpenSimula/blob/main/CITATION.cff) (GitHub's "Cite this repository" button generates APA and BibTeX
182
+ entries from it).
183
+
184
+ ## Authors
185
+
186
+ * [Juan F. Coronel](http://jfc.us.es), Universidad de Sevilla — creator, lead developer and maintainer
187
+ * Luis Pérez-Lombard, Universidad de Sevilla — reviewer and advisor on the HVAC models, tester
188
+ and co-author of the validation test cases
189
+ * Ismael R. Maestre, Universidad de Cádiz — reviewer and advisor on the building envelope
190
+ models, tester and co-author of the validation test cases
168
191
 
169
192
  ## License
170
193
 
@@ -2,8 +2,10 @@
2
2
 
3
3
  # OpenSimula
4
4
 
5
+ [![Tests](https://github.com/jfCoronel/OpenSimula/actions/workflows/tests.yml/badge.svg)](https://github.com/jfCoronel/OpenSimula/actions/workflows/tests.yml)
5
6
  [![PyPI version](https://img.shields.io/pypi/v/opensimula)](https://pypi.org/project/opensimula/)
6
7
  [![Python versions](https://img.shields.io/pypi/pyversions/opensimula)](https://pypi.org/project/opensimula/)
8
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23210985.svg)](https://doi.org/10.5281/zenodo.23210985)
7
9
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
10
 
9
11
  **OpenSimula** is a component-based time simulation environment in Python, focused on the
@@ -140,9 +142,28 @@ reference, is at [jfcoronel.github.io/OpenSimula](https://jfcoronel.github.io/Op
140
142
  Bugs and feature requests are tracked on
141
143
  [GitHub Issues](https://github.com/jfCoronel/OpenSimula/issues).
142
144
 
143
- ## Main Developers
145
+ ## Contributing
144
146
 
145
- * [Juan F. Coronel](http://jfc.us.es), Universidad de Sevilla
147
+ Contributions are welcome: bug reports, fixes, new components, validation cases and examples.
148
+ See [CONTRIBUTING.md](https://github.com/jfCoronel/OpenSimula/blob/main/CONTRIBUTING.md) for how to set up a development environment, run the
149
+ tests and submit a pull request.
150
+
151
+ ## Citing OpenSimula
152
+
153
+ If you use OpenSimula in your research, please cite it with its DOI,
154
+ [10.5281/zenodo.23210985](https://doi.org/10.5281/zenodo.23210985), which always resolves to
155
+ the latest version (each version also has its own DOI, listed on
156
+ [Zenodo](https://doi.org/10.5281/zenodo.23210985)). The full metadata is in
157
+ [CITATION.cff](https://github.com/jfCoronel/OpenSimula/blob/main/CITATION.cff) (GitHub's "Cite this repository" button generates APA and BibTeX
158
+ entries from it).
159
+
160
+ ## Authors
161
+
162
+ * [Juan F. Coronel](http://jfc.us.es), Universidad de Sevilla — creator, lead developer and maintainer
163
+ * Luis Pérez-Lombard, Universidad de Sevilla — reviewer and advisor on the HVAC models, tester
164
+ and co-author of the validation test cases
165
+ * Ismael R. Maestre, Universidad de Cádiz — reviewer and advisor on the building envelope
166
+ models, tester and co-author of the validation test cases
146
167
 
147
168
  ## License
148
169
 
@@ -1,9 +1,14 @@
1
1
  [project]
2
2
  name = "opensimula"
3
- version = "0.8.7"
3
+ version = "0.8.9"
4
4
  requires-python = ">=3.12"
5
5
  authors = [
6
6
  { name="Juan F. Coronel", email="jfc@us.es" },
7
+ { name="Luis Pérez-Lombard" },
8
+ { name="Ismael R. Maestre" },
9
+ ]
10
+ maintainers = [
11
+ { name="Juan F. Coronel", email="jfc@us.es" },
7
12
  ]
8
13
  description = "Component-based time simulation environment in Python"
9
14
  readme = "README.md"
@@ -28,6 +33,7 @@ dev = [
28
33
  "mkdocs>=1.6.1",
29
34
  "pytest>=8.4.2",
30
35
  "marimo>=0.19.0",
36
+ "mkdocstrings[python]>=1.0.8",
31
37
  ]
32
38
 
33
39
  [tool.setuptools]
@@ -5,9 +5,26 @@ from opensimula.Variable import Variable
5
5
 
6
6
 
7
7
  class Component(Parameter_container):
8
- """Base Class for all the components"""
8
+ """Base Class for all the components
9
+
10
+ A component has parameters (inherited from Parameter_container, with `name`,
11
+ `description` and `type`) and variables (time series filled during the simulation).
12
+ Components are created by the project (`Project.new_component()`, `read_dict()`,
13
+ `read_json()`), not directly.
14
+
15
+ New component types inherit from this class: they add their parameters and variables
16
+ in `__init__()`, validate them in `check()` and override the simulation methods
17
+ (`pre_simulation()`, `pre_iteration()`, `iteration()`, `post_iteration()`,
18
+ `post_simulation()`) that the project calls in this order. See the developer guide.
19
+ """
9
20
 
10
21
  def __init__(self, name, proj):
22
+ """Create new component
23
+
24
+ Args:
25
+ name (str): name of the component
26
+ proj (Project): project the component belongs to
27
+ """
11
28
  Parameter_container.__init__(self, proj._sim_)
12
29
  self._variables_ = {}
13
30
  self.add_parameter(Parameter_string("type", "Component"))
@@ -16,35 +33,62 @@ class Component(Parameter_container):
16
33
  self._project_ = proj
17
34
 
18
35
  def project(self):
36
+ """Project the component belongs to
37
+
38
+ Returns:
39
+ Project: parent project
40
+ """
19
41
  return self._project_
20
42
 
21
43
  def add_variable(self, variable):
22
- """add new Variable"""
44
+ """Add a new variable to the component
45
+
46
+ Args:
47
+ variable (Variable): variable to add, replaces any variable with the same key
48
+ """
23
49
  variable.parent = self
24
50
  variable._sim_ = self._sim_
25
51
  self._variables_[variable.key] = variable
26
52
 
27
53
  def del_variable(self, variable):
54
+ """Remove a variable from the component
55
+
56
+ Args:
57
+ variable (Variable): variable to remove
58
+ """
28
59
  self._variables_.pop(variable.key,None)
29
60
 
30
61
  def variable(self, key):
62
+ """Find and return a variable using its key
63
+
64
+ Args:
65
+ key (str): key of the variable, e.g. "temperature"
66
+
67
+ Returns:
68
+ Variable: the variable (KeyError if it does not exist)
69
+ """
31
70
  return self._variables_[key]
32
71
 
33
72
  def variable_dict(self):
73
+ """Variables of the component
74
+
75
+ Returns:
76
+ dict: {key: Variable}
77
+ """
34
78
  return self._variables_
35
79
 
36
80
  def variable_dataframe(self, units=False, frequency=None, value="mean", interval=None, pos_neg_columns=[]):
37
- """_summary_
81
+ """Variables of the component as a table
38
82
 
39
83
  Args:
40
- units (bool, optional): Includes unit in the name of the variable. Defaults to True.
84
+ units (bool, optional): Includes unit in the name of the variable. Defaults to False.
41
85
  frequency (None or str, optional): frequency of the values: None, "hourly", "daily", "monthly", "yearly". Defaults to None.
42
86
  value (str, optional): "mean", "sum", "sum_pos", "sum_neg", "max" or "min". Defaults to "mean".
43
87
  interval (None or list of two dates): List with the start and end dates of the period to be included in the dataframe, if the value is None all values are included.
44
88
  pos_neg_columns (list of str, optional): List of variables that will be included in separate columns positive and negative values. Defaults to [].
45
89
 
46
90
  Returns:
47
- pandas DataFrame: Returns all the variables
91
+ pandas.DataFrame: column "date" and one column per variable
48
92
  """
49
93
  series = {}
50
94
  series["date"] = self.project().dates()
@@ -92,7 +136,7 @@ class Component(Parameter_container):
92
136
  been the walk follows it until the stack runs out.
93
137
 
94
138
  Returns:
95
- component_list (component[])
139
+ list of Component: referenced components and, last, the component itself
96
140
  """
97
141
  if _seen is None:
98
142
  _seen = set()
@@ -125,8 +169,12 @@ class Component(Parameter_container):
125
169
  def check(self):
126
170
  """Check if all is correct
127
171
 
172
+ Checks every parameter and creates the variables of the `Parameter_variable` and
173
+ `Parameter_variable_list` parameters. Components that override it call this one
174
+ first and add their own checks.
175
+
128
176
  Returns:
129
- errors (string list): List of errors
177
+ list of Message: errors found
130
178
  """
131
179
  errors = []
132
180
  # Parameter errors
@@ -152,6 +200,16 @@ class Component(Parameter_container):
152
200
  return errors
153
201
 
154
202
  def get_parameter_variable_dictionary(self,time_index):
203
+ """Values of the variables taken from `Parameter_variable` parameters at a time step
204
+
205
+ Used to evaluate `Parameter_math_exp` expressions.
206
+
207
+ Args:
208
+ time_index (int): index of the time step
209
+
210
+ Returns:
211
+ dict: {symbol: value}
212
+ """
155
213
  # variables dictonary
156
214
  var_dic = {}
157
215
  for i in range(len(self._var_from_parameter_symbol)):
@@ -159,6 +217,15 @@ class Component(Parameter_container):
159
217
  return var_dic
160
218
 
161
219
  def pre_simulation(self, n_time_steps, delta_t):
220
+ """Prepare the component before the time loop of the simulation
221
+
222
+ The base method sets up the variables of the `Parameter_variable` parameters and
223
+ initialises every variable to zeros. Overriding methods call it first.
224
+
225
+ Args:
226
+ n_time_steps (int): number of time steps of the simulation
227
+ delta_t (int): time step (s)
228
+ """
162
229
  # Create variables from paramater "Parameter_variable" and "Parameter_variable_list"
163
230
  self._var_from_parameter_symbol = []
164
231
  self._var_from_parameter_variable = []
@@ -176,9 +243,20 @@ class Component(Parameter_container):
176
243
  var.initialise(n_time_steps)
177
244
 
178
245
  def post_simulation(self):
246
+ """Finish the component after the time loop of the simulation"""
179
247
  pass
180
248
 
181
249
  def pre_iteration(self, time_index, date, daylight_saving):
250
+ """Prepare the time step, before its iterations
251
+
252
+ The base method copies the values of the `Parameter_variable` parameters at the
253
+ time step. Overriding methods call it first.
254
+
255
+ Args:
256
+ time_index (int): index of the time step
257
+ date (datetime): date of the time step (center of the interval)
258
+ daylight_saving (bool): daylight saving time is in effect
259
+ """
182
260
  # Initilise all variables to 0
183
261
  for key, value in self.parameter_dict().items():
184
262
  # Copy variables in paramater_variable
@@ -193,9 +271,31 @@ class Component(Parameter_container):
193
271
  value.symbol[i]).values[time_index] = value.variable[i].values[time_index]
194
272
 
195
273
  def iteration(self, time_index, date, daylight_saving, n_iter):
274
+ """Calculate one iteration of the time step
275
+
276
+ The project repeats the iterations of every component until all of them return
277
+ True or the maximum number of iterations is reached.
278
+
279
+ Args:
280
+ time_index (int): index of the time step
281
+ date (datetime): date of the time step (center of the interval)
282
+ daylight_saving (bool): daylight saving time is in effect
283
+ n_iter (int): number of the iteration in the time step, from 0
284
+
285
+ Returns:
286
+ bool: the component has converged
287
+ """
196
288
  return True
197
289
 
198
290
  def post_iteration(self, time_index, date, daylight_saving, converged):
291
+ """Finish the time step, after its iterations
292
+
293
+ Args:
294
+ time_index (int): index of the time step
295
+ date (datetime): date of the time step (center of the interval)
296
+ daylight_saving (bool): daylight saving time is in effect
297
+ converged (bool): every component converged in the time step
298
+ """
199
299
  pass
200
300
 
201
301
  def _repr_html_(self):
@@ -208,6 +308,11 @@ class Component(Parameter_container):
208
308
  return html
209
309
 
210
310
  def variable_html(self):
311
+ """Key, description and unit of the variables as an HTML table
312
+
313
+ Returns:
314
+ str: HTML table
315
+ """
211
316
  keys = []
212
317
  descriptions = []
213
318
  units = []
@@ -222,5 +327,10 @@ class Component(Parameter_container):
222
327
  return data.to_html()
223
328
 
224
329
  def function_html(self):
330
+ """Short HTML help of the component's table methods
331
+
332
+ Returns:
333
+ str: HTML text
334
+ """
225
335
  html = "<p><strong>parameter_dataframe():</strong> Return pandas DataFrame with the component parametes.</p>"
226
336
  html += "<p><strong>variable_dataframe():</strong> Return pandas DataFrame with the component variables.</p>"
@@ -0,0 +1,85 @@
1
+ import math
2
+
3
+ class Iterative_process:
4
+ """Iterative process using the fixed-point method with adaptive relaxation coefficient
5
+
6
+ Used by the components to converge a value coupled with other components (e.g. the
7
+ temperature or humidity of a space) within the iterations of a time step:
8
+
9
+ ```python
10
+ it = Iterative_process(x_0, tol=0.01)
11
+ # in each iteration, with the value proposed by the component's equations
12
+ x = it.estimate_next_x(proposed_x)
13
+ converged = it.converged()
14
+ ```
15
+ """
16
+
17
+ def __init__(self, x_0, tol = 1e-5, lambda_min=0.1, lambda_max=1.0, n_ini_relax=2,rel_vel = 0.9):
18
+ """Create new iterative process
19
+
20
+ Args:
21
+ x_0 (float): Initial value
22
+ tol (float, optional): convergence tolerance of the residual. Defaults to 1e-5.
23
+ lambda_min (float, optional): minimum relaxation coefficient. Defaults to 0.1.
24
+ lambda_max (float, optional): maximum (and initial) relaxation coefficient.
25
+ Defaults to 1.0.
26
+ n_ini_relax (int, optional): Number of iterations in which adaptive relaxation
27
+ is initiated, must be greater than 1. Defaults to 2.
28
+ rel_vel (float, optional): factor that reduces (or, divided, recovers) the
29
+ relaxation coefficient. Defaults to 0.9.
30
+ """
31
+ self.x = [x_0]
32
+ self.tol = tol
33
+ self.lambda_min = lambda_min
34
+ self.lambda_max = lambda_max
35
+ self.lambda_i = lambda_max
36
+ self.n_ini_relax = n_ini_relax
37
+ self.rel_vel = rel_vel
38
+ self.residual = None # |proposed_x - x| of the last iteration
39
+
40
+ def converged(self):
41
+ """The residual of the last iteration is below the tolerance
42
+
43
+ Returns:
44
+ bool: converged
45
+ """
46
+ # Fixed-point residual, not the relaxed step: with relaxation lambda the step is only
47
+ # lambda * residual, so testing the step stopped with residuals up to tol / lambda_min
48
+ # (10 x tol), e.g. zones far from their moisture balance in steady state
49
+ return self.residual is not None and self.residual < self.tol
50
+
51
+ def estimate_next_x(self, proposed_x):
52
+ """Relaxed next value from the value proposed by the fixed-point equation
53
+
54
+ Args:
55
+ proposed_x (float): value given by the equations from the last value
56
+
57
+ Returns:
58
+ float: next value, `(1 - lambda) * x + lambda * proposed_x`
59
+ """
60
+ residual = proposed_x - self.x[-1]
61
+ x_next = (1 - self.lambda_i) * self.x[-1] + self.lambda_i * proposed_x
62
+
63
+ # Adaptive relaxation: reduce lambda when the iteration oscillates (the residual
64
+ # changes sign) or does not contract (the residual grows), and recover it while it
65
+ # contracts; reducing it unconditionally made well-behaved iterations crawl
66
+ # (lambda_min after ~10 iterations)
67
+ if len(self.x) > self.n_ini_relax and self.residual is not None:
68
+ if residual * self._last_residual < 0 or abs(residual) > self.residual:
69
+ self.lambda_i = max(self.lambda_min, self.lambda_i * self.rel_vel)
70
+ else:
71
+ self.lambda_i = min(self.lambda_max, self.lambda_i / self.rel_vel)
72
+ self._last_residual = residual
73
+ self.residual = abs(residual)
74
+
75
+ self.x.append(x_next)
76
+ return x_next
77
+
78
+ def set_next_x(self, next_x):
79
+ """Set the next value directly, without relaxation
80
+
81
+ Args:
82
+ next_x (float): next value
83
+ """
84
+ self.x.append(next_x)
85
+
@@ -0,0 +1,35 @@
1
+ class Message:
2
+ """Message of the simulation environment (error, warning or information)
3
+
4
+ Messages are added with `Simulation.message()` and listed with
5
+ `Simulation.message_list()`.
6
+ """
7
+
8
+ def __init__(self, text, level="ERROR"):
9
+ """Create new message
10
+
11
+ Args:
12
+ text (str): text of the message
13
+ level (str, optional): "ERROR", "WARNING", "INFO" or "CONSOLE". Defaults to
14
+ "ERROR".
15
+ """
16
+ self._text_ = text
17
+ self._level_ = level # ERROR, WARNING, INFO, CONSOLE
18
+
19
+ @property
20
+ def text(self):
21
+ """str: text of the message"""
22
+ return self._text_
23
+
24
+ @property
25
+ def level(self):
26
+ """str: "ERROR", "WARNING", "INFO" or "CONSOLE" """
27
+ return self._level_
28
+
29
+ def print(self):
30
+ """Print the message, preceded by its level unless it is "CONSOLE" """
31
+ if self.level == "CONSOLE":
32
+ print(self.text)
33
+ else:
34
+ print(self.level + ": " + self.text)
35
+
@@ -3,40 +3,71 @@ from opensimula.Parameters import Parameter_string
3
3
  from opensimula.Message import Message
4
4
 
5
5
  class Parameter_container:
6
- """Class to manage a list of Paramaters
6
+ """Class to manage a list of Parameters
7
7
 
8
8
  Superclass for Projects and Components
9
9
 
10
10
  Default parameters included:
11
+
11
12
  - name (string)
12
13
  - description (string)
13
-
14
14
  """
15
15
 
16
16
  def __init__(self, sim):
17
+ """Create the container with the parameters name and description
18
+
19
+ Args:
20
+ sim (Simulation): simulation environment, used to report messages
21
+ """
17
22
  self._sim_ = sim
18
23
  self._parameters_ = {}
19
24
  self.add_parameter(Parameter_string("name", "Name"))
20
25
  self.add_parameter(Parameter_string("description", "Description"))
21
26
 
22
27
  def add_parameter(self, param):
23
- """add Parameter"""
28
+ """Add a parameter
29
+
30
+ Args:
31
+ param (Parameter): parameter to add, replaces any parameter with the same key
32
+ """
24
33
  param.parent = self
25
34
  param._sim_ = self._sim_
26
35
  self._parameters_[param.key] = param
27
36
 
28
37
  def del_parameter(self, param):
29
- """Deletet parameter"""
30
- self._parameters_.remove(param)
38
+ """Delete a parameter
39
+
40
+ Args:
41
+ param (Parameter): parameter to delete
42
+ """
43
+ self._parameters_.pop(param.key, None)
31
44
 
32
45
  def parameter(self, key):
46
+ """Find and return a parameter using its key
47
+
48
+ Args:
49
+ key (str): key of the parameter, e.g. "name"
50
+
51
+ Returns:
52
+ Parameter: the parameter (KeyError if it does not exist); read or change its
53
+ value with `.value`
54
+ """
33
55
  return self._parameters_[key]
34
56
 
35
57
  def parameter_dict(self):
58
+ """Parameters of the container
59
+
60
+ Returns:
61
+ dict: {key: Parameter}
62
+ """
36
63
  return self._parameters_
37
64
 
38
65
  def set_parameters(self, dictonary):
39
- """Read parameters from dictonary"""
66
+ """Set parameter values from a dictionary
67
+
68
+ Args:
69
+ dictonary (dict): {key: value}; unknown keys are reported as errors
70
+ """
40
71
  for key, value in dictonary.items():
41
72
  if key in self._parameters_:
42
73
  self.parameter(key).value = value
@@ -44,6 +75,14 @@ class Parameter_container:
44
75
  self._sim_.message(Message("Component parameter " + key + " does not exist","ERROR"))
45
76
 
46
77
  def parameter_dataframe(self, string_format=False):
78
+ """Parameters as a table
79
+
80
+ Args:
81
+ string_format (bool, optional): Convert every value to string. Defaults to False.
82
+
83
+ Returns:
84
+ pandas.DataFrame: key, type, value and unit of each parameter
85
+ """
47
86
  keys = []
48
87
  values = []
49
88
  types = []
@@ -69,7 +108,7 @@ class Parameter_container:
69
108
  """Check if all is correct
70
109
 
71
110
  Returns:
72
- errors (string list): List of errors
111
+ list of Message: errors found
73
112
  """
74
113
  errors = []
75
114
  for key, value in self._parameters_.items():