OpenSimula 0.8.6__tar.gz → 0.8.8__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 (80) hide show
  1. opensimula-0.8.8/PKG-INFO +188 -0
  2. opensimula-0.8.8/README.md +166 -0
  3. {opensimula-0.8.6 → opensimula-0.8.8}/pyproject.toml +2 -2
  4. opensimula-0.8.8/src/opensimula/Iterative_process.py +50 -0
  5. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Project.py +13 -6
  6. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Building.py +17 -3
  7. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Construction.py +9 -5
  8. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/File_met.py +80 -58
  9. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/HVAC_SZW_system.py +22 -22
  10. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Space.py +4 -1
  11. opensimula-0.8.8/src/opensimula/editor/static/editor.js +8271 -0
  12. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/visual_3D/Environment_3D.py +107 -176
  13. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/visual_3D/Polygon_3D.py +0 -8
  14. opensimula-0.8.8/src/opensimula.egg-info/PKG-INFO +188 -0
  15. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula.egg-info/requires.txt +1 -1
  16. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Case_600FF.py +3 -3
  17. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Case_610.py +20 -4
  18. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Construction.py +35 -0
  19. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_File_met.py +19 -0
  20. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_HVAC_DX_system.py +12 -12
  21. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_HVAC_FAN_COIL_water_system.py +10 -10
  22. opensimula-0.8.8/test/test_Iterative_process.py +30 -0
  23. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_editor_schema.py +15 -9
  24. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_editor_widget.py +26 -6
  25. opensimula-0.8.6/PKG-INFO +0 -45
  26. opensimula-0.8.6/README.md +0 -23
  27. opensimula-0.8.6/src/opensimula/Iterative_process.py +0 -47
  28. opensimula-0.8.6/src/opensimula/editor/static/editor.js +0 -1047
  29. opensimula-0.8.6/src/opensimula.egg-info/PKG-INFO +0 -45
  30. opensimula-0.8.6/test/test_Iterative_process.py +0 -13
  31. {opensimula-0.8.6 → opensimula-0.8.8}/LICENSE +0 -0
  32. {opensimula-0.8.6 → opensimula-0.8.8}/setup.cfg +0 -0
  33. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Child.py +0 -0
  34. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Component.py +0 -0
  35. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Message.py +0 -0
  36. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Parameter_container.py +0 -0
  37. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Parameters.py +0 -0
  38. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Simulation.py +0 -0
  39. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Variable.py +0 -0
  40. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/__init__.py +0 -0
  41. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Building_surface.py +0 -0
  42. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Calculator.py +0 -0
  43. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Chiller_heat_pump.py +0 -0
  44. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/DX_unit.py +0 -0
  45. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Day_schedule.py +0 -0
  46. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Fan.py +0 -0
  47. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/File_data.py +0 -0
  48. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Frame.py +0 -0
  49. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Glazing.py +0 -0
  50. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/HVAC_DX_system.py +0 -0
  51. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/HVAC_MZW_system.py +0 -0
  52. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/HVAC_perfect_system.py +0 -0
  53. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/HVAC_water_system.py +0 -0
  54. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Material.py +0 -0
  55. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Opening.py +0 -0
  56. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Opening_type.py +0 -0
  57. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Pump.py +0 -0
  58. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Solar_surface.py +0 -0
  59. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Space_type.py +0 -0
  60. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Surface.py +0 -0
  61. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Test_component.py +0 -0
  62. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Water_coil.py +0 -0
  63. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Week_schedule.py +0 -0
  64. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Year_schedule.py +0 -0
  65. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/__init__.py +0 -0
  66. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/editor/__init__.py +0 -0
  67. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/editor/schema.py +0 -0
  68. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/editor/static/editor.css +0 -0
  69. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/editor/validation.py +0 -0
  70. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/editor/widget.py +0 -0
  71. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula.egg-info/SOURCES.txt +0 -0
  72. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula.egg-info/dependency_links.txt +0 -0
  73. {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula.egg-info/top_level.txt +0 -0
  74. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Calculator.py +0 -0
  75. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_File_data.py +0 -0
  76. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_HVAC_DX_Equipment.py +0 -0
  77. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_HVAC_water_system_process.py +0 -0
  78. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Project.py +0 -0
  79. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Schedules.py +0 -0
  80. {opensimula-0.8.6 → opensimula-0.8.8}/test/test_underground_repeated_simulation.py +0 -0
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.4
2
+ Name: opensimula
3
+ Version: 0.8.8
4
+ Summary: Component-based time simulation environment in Python
5
+ Author-email: "Juan F. Coronel" <jfc@us.es>
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: anywidget>=0.11.0
10
+ Requires-Dist: jsonschema>=4.26.0
11
+ Requires-Dist: matplotlib>=3.10.0
12
+ Requires-Dist: nbformat>=5.10.4
13
+ Requires-Dist: numpy>=2.3.3
14
+ Requires-Dist: openpyxl>=3.1.5
15
+ Requires-Dist: pandas>=2.3.2
16
+ Requires-Dist: plotly>=6.3.0
17
+ Requires-Dist: psychrolib>=2.5.0
18
+ Requires-Dist: scipy>=1.16.2
19
+ Requires-Dist: shapely>=2.1.1
20
+ Requires-Dist: tqdm>=4.67.1
21
+ Dynamic: license-file
22
+
23
+ ![Logo](https://jfcoronel.github.io/OpenSimula/img/logo_opensimula.png)
24
+
25
+ # OpenSimula
26
+
27
+ [![Tests](https://github.com/jfCoronel/OpenSimula/actions/workflows/tests.yml/badge.svg)](https://github.com/jfCoronel/OpenSimula/actions/workflows/tests.yml)
28
+ [![PyPI version](https://img.shields.io/pypi/v/opensimula)](https://pypi.org/project/opensimula/)
29
+ [![Python versions](https://img.shields.io/pypi/pyversions/opensimula)](https://pypi.org/project/opensimula/)
30
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23210985.svg)](https://doi.org/10.5281/zenodo.23210985)
31
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
32
+
33
+ **OpenSimula** is a component-based time simulation environment in Python, focused on the
34
+ thermal and energy simulation of buildings and their HVAC installations — though it can be
35
+ used to simulate any system whose state evolves over time. It implements the [ASHRAE
36
+ 140](https://www.ashrae.org/technical-resources/bookstore/method-of-test-for-the-evaluation-of-building-energy-analysis-computer-programs)
37
+ standard test suite to validate its building load and HVAC calculations.
38
+
39
+ [**Documentation**](https://jfcoronel.github.io/OpenSimula/) · [Getting started](https://jfcoronel.github.io/OpenSimula/getting_started/) · [User guide](https://jfcoronel.github.io/OpenSimula/user_guide/) · [Component list](https://jfcoronel.github.io/OpenSimula/component_list/)
40
+
41
+ ## What it does
42
+
43
+ A project is built from **components** — spaces, walls, windows, constructions, schedules,
44
+ HVAC equipment, weather files — wired together and simulated hour by hour (or at any other
45
+ time step). OpenSimula takes care of:
46
+
47
+ - **Building thermal simulation**: multi-space heat balance, constructions with thermal mass,
48
+ windows and solar gains, ground-coupled surfaces, internal gains and schedules.
49
+ - **HVAC systems**: from an ideal loads system (`HVAC_perfect_system`) to direct-expansion and
50
+ water-based single- and multi-zone systems, coils, fans, pumps, chillers and heat pumps.
51
+ - **Solar geometry and shadows**: direct and diffuse shadow calculations between the surfaces
52
+ of a project, with an interactive 3D [Plotly](https://plotly.com/python/) view — including
53
+ an animated view of shadows changing throughout the day.
54
+ - **Everything else a simulation needs**: psychrometrics (via
55
+ [PsychroLib](https://github.com/psychrometrics/psychrolib)), day/week/year schedules,
56
+ arbitrary math expressions as inputs, and reading weather data (TMY3, MET) or generic data
57
+ files (CSV, Excel).
58
+ - **Validation against ASHRAE 140**: the `ASHRAE_140/` folder in this repository reproduces
59
+ the standard's load, heating, cooling, air-side HVAC and weather test cases as runnable
60
+ notebooks, comparing OpenSimula's results against the reference values.
61
+
62
+ Projects can be defined as plain Python dictionaries, JSON or Excel files, and results come
63
+ back as component `Variable` time series or pandas `DataFrame`s, ready to plot or export.
64
+
65
+ ## Installation
66
+
67
+ ```bash
68
+ pip install opensimula
69
+ ```
70
+
71
+ Requires Python 3.12 or later.
72
+
73
+ ## Quick example
74
+
75
+ ```python
76
+ import opensimula as osm
77
+
78
+ project_dict = {
79
+ "name": "First example",
80
+ "time_step": 3600,
81
+ "n_time_steps": 24 * 7,
82
+ "initial_time": "01/01/2001 00:00:00",
83
+ "components": [
84
+ {
85
+ "type": "Day_schedule",
86
+ "name": "working_day",
87
+ "time_steps": [8 * 3600, 5 * 3600, 2 * 3600, 4 * 3600],
88
+ "values": [0, 100, 0, 80, 0],
89
+ "interpolation": "STEP",
90
+ },
91
+ {
92
+ "type": "Day_schedule",
93
+ "name": "holiday_day",
94
+ "time_steps": [],
95
+ "values": [0],
96
+ "interpolation": "STEP",
97
+ },
98
+ {
99
+ "type": "Week_schedule",
100
+ "name": "office_week",
101
+ "days_schedules": ["working_day"] * 5 + ["holiday_day"] * 2,
102
+ },
103
+ ],
104
+ }
105
+
106
+ sim = osm.Simulation()
107
+ pro = sim.new_project("First example")
108
+ pro.read_dict(project_dict)
109
+ pro.simulate()
110
+
111
+ sim.plot(pro.dates(), [pro.component("office_week").variable("values")])
112
+ ```
113
+
114
+ This is deliberately minimal — the [Getting started](https://jfcoronel.github.io/OpenSimula/getting_started/)
115
+ guide walks through a full building, and the `jupyter_test/` and `ASHRAE_140/` folders in
116
+ this repository contain complete, runnable building and HVAC examples.
117
+
118
+ ## Working in Jupyter
119
+
120
+ OpenSimula ships an interactive project editor as a [Jupyter
121
+ widget](https://jfcoronel.github.io/OpenSimula/user_guide/#project-editor) (`pro.editor()`),
122
+ built on [anywidget](https://anywidget.dev/) so it works the same in Jupyter, JupyterLab, VS
123
+ Code notebooks and Marimo. It shows every component's parameters as a form generated from
124
+ each component's own schema, together with an interactive 3D view of the building.
125
+
126
+ ![Project editor example](https://jfcoronel.github.io/OpenSimula/img/editor_3d.png)
127
+
128
+ ## Component types
129
+
130
+ Components are grouped by what they define:
131
+
132
+ - **Building**: `Building`, `Space_type`, `Space`, `Building_surface`, `Opening`, `Solar_surface`.
133
+ - **Constructions**: `Material`, `Construction`, `Glazing`, `Frame`, `Opening_type`.
134
+ - **HVAC (air side)**: `HVAC_perfect_system`, `DX_unit`, `HVAC_DX_system`, `Water_coil`, `Fan`, `HVAC_SZW_system`, `HVAC_MZW_system`.
135
+ - **HVAC (water side)**: `Pump`, `Chiller_heat_pump`, `HVAC_water_system`.
136
+ - **Schedules**: `Day_schedule`, `Week_schedule`, `Year_schedule`.
137
+ - **Files**: `File_met`, `File_data`.
138
+ - **Utilities**: `Calculator`.
139
+
140
+ See the [Component list](https://jfcoronel.github.io/OpenSimula/component_list/) for every
141
+ parameter and variable of each one.
142
+
143
+ ## Package dependencies
144
+
145
+ - numpy
146
+ - pandas
147
+ - scipy
148
+ - shapely
149
+ - psychrolib
150
+ - plotly
151
+ - matplotlib
152
+ - anywidget
153
+ - jsonschema
154
+ - nbformat
155
+ - openpyxl
156
+ - tqdm
157
+
158
+ These are installed automatically with `pip install opensimula`.
159
+
160
+ ## Documentation and support
161
+
162
+ Full documentation, including the getting started guide, user guide and component
163
+ reference, is at [jfcoronel.github.io/OpenSimula](https://jfcoronel.github.io/OpenSimula/).
164
+ Bugs and feature requests are tracked on
165
+ [GitHub Issues](https://github.com/jfCoronel/OpenSimula/issues).
166
+
167
+ ## Contributing
168
+
169
+ Contributions are welcome: bug reports, fixes, new components, validation cases and examples.
170
+ See [CONTRIBUTING.md](https://github.com/jfCoronel/OpenSimula/blob/main/CONTRIBUTING.md) for how to set up a development environment, run the
171
+ tests and submit a pull request.
172
+
173
+ ## Citing OpenSimula
174
+
175
+ If you use OpenSimula in your research, please cite it with its DOI,
176
+ [10.5281/zenodo.23210985](https://doi.org/10.5281/zenodo.23210985), which always resolves to
177
+ the latest version (each version also has its own DOI, listed on
178
+ [Zenodo](https://doi.org/10.5281/zenodo.23210985)). The full metadata is in
179
+ [CITATION.cff](https://github.com/jfCoronel/OpenSimula/blob/main/CITATION.cff) (GitHub's "Cite this repository" button generates APA and BibTeX
180
+ entries from it).
181
+
182
+ ## Main Developers
183
+
184
+ * [Juan F. Coronel](http://jfc.us.es), Universidad de Sevilla
185
+
186
+ ## License
187
+
188
+ OpenSimula is released under the [MIT License](LICENSE).
@@ -0,0 +1,166 @@
1
+ ![Logo](https://jfcoronel.github.io/OpenSimula/img/logo_opensimula.png)
2
+
3
+ # OpenSimula
4
+
5
+ [![Tests](https://github.com/jfCoronel/OpenSimula/actions/workflows/tests.yml/badge.svg)](https://github.com/jfCoronel/OpenSimula/actions/workflows/tests.yml)
6
+ [![PyPI version](https://img.shields.io/pypi/v/opensimula)](https://pypi.org/project/opensimula/)
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)
9
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
10
+
11
+ **OpenSimula** is a component-based time simulation environment in Python, focused on the
12
+ thermal and energy simulation of buildings and their HVAC installations — though it can be
13
+ used to simulate any system whose state evolves over time. It implements the [ASHRAE
14
+ 140](https://www.ashrae.org/technical-resources/bookstore/method-of-test-for-the-evaluation-of-building-energy-analysis-computer-programs)
15
+ standard test suite to validate its building load and HVAC calculations.
16
+
17
+ [**Documentation**](https://jfcoronel.github.io/OpenSimula/) · [Getting started](https://jfcoronel.github.io/OpenSimula/getting_started/) · [User guide](https://jfcoronel.github.io/OpenSimula/user_guide/) · [Component list](https://jfcoronel.github.io/OpenSimula/component_list/)
18
+
19
+ ## What it does
20
+
21
+ A project is built from **components** — spaces, walls, windows, constructions, schedules,
22
+ HVAC equipment, weather files — wired together and simulated hour by hour (or at any other
23
+ time step). OpenSimula takes care of:
24
+
25
+ - **Building thermal simulation**: multi-space heat balance, constructions with thermal mass,
26
+ windows and solar gains, ground-coupled surfaces, internal gains and schedules.
27
+ - **HVAC systems**: from an ideal loads system (`HVAC_perfect_system`) to direct-expansion and
28
+ water-based single- and multi-zone systems, coils, fans, pumps, chillers and heat pumps.
29
+ - **Solar geometry and shadows**: direct and diffuse shadow calculations between the surfaces
30
+ of a project, with an interactive 3D [Plotly](https://plotly.com/python/) view — including
31
+ an animated view of shadows changing throughout the day.
32
+ - **Everything else a simulation needs**: psychrometrics (via
33
+ [PsychroLib](https://github.com/psychrometrics/psychrolib)), day/week/year schedules,
34
+ arbitrary math expressions as inputs, and reading weather data (TMY3, MET) or generic data
35
+ files (CSV, Excel).
36
+ - **Validation against ASHRAE 140**: the `ASHRAE_140/` folder in this repository reproduces
37
+ the standard's load, heating, cooling, air-side HVAC and weather test cases as runnable
38
+ notebooks, comparing OpenSimula's results against the reference values.
39
+
40
+ Projects can be defined as plain Python dictionaries, JSON or Excel files, and results come
41
+ back as component `Variable` time series or pandas `DataFrame`s, ready to plot or export.
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install opensimula
47
+ ```
48
+
49
+ Requires Python 3.12 or later.
50
+
51
+ ## Quick example
52
+
53
+ ```python
54
+ import opensimula as osm
55
+
56
+ project_dict = {
57
+ "name": "First example",
58
+ "time_step": 3600,
59
+ "n_time_steps": 24 * 7,
60
+ "initial_time": "01/01/2001 00:00:00",
61
+ "components": [
62
+ {
63
+ "type": "Day_schedule",
64
+ "name": "working_day",
65
+ "time_steps": [8 * 3600, 5 * 3600, 2 * 3600, 4 * 3600],
66
+ "values": [0, 100, 0, 80, 0],
67
+ "interpolation": "STEP",
68
+ },
69
+ {
70
+ "type": "Day_schedule",
71
+ "name": "holiday_day",
72
+ "time_steps": [],
73
+ "values": [0],
74
+ "interpolation": "STEP",
75
+ },
76
+ {
77
+ "type": "Week_schedule",
78
+ "name": "office_week",
79
+ "days_schedules": ["working_day"] * 5 + ["holiday_day"] * 2,
80
+ },
81
+ ],
82
+ }
83
+
84
+ sim = osm.Simulation()
85
+ pro = sim.new_project("First example")
86
+ pro.read_dict(project_dict)
87
+ pro.simulate()
88
+
89
+ sim.plot(pro.dates(), [pro.component("office_week").variable("values")])
90
+ ```
91
+
92
+ This is deliberately minimal — the [Getting started](https://jfcoronel.github.io/OpenSimula/getting_started/)
93
+ guide walks through a full building, and the `jupyter_test/` and `ASHRAE_140/` folders in
94
+ this repository contain complete, runnable building and HVAC examples.
95
+
96
+ ## Working in Jupyter
97
+
98
+ OpenSimula ships an interactive project editor as a [Jupyter
99
+ widget](https://jfcoronel.github.io/OpenSimula/user_guide/#project-editor) (`pro.editor()`),
100
+ built on [anywidget](https://anywidget.dev/) so it works the same in Jupyter, JupyterLab, VS
101
+ Code notebooks and Marimo. It shows every component's parameters as a form generated from
102
+ each component's own schema, together with an interactive 3D view of the building.
103
+
104
+ ![Project editor example](https://jfcoronel.github.io/OpenSimula/img/editor_3d.png)
105
+
106
+ ## Component types
107
+
108
+ Components are grouped by what they define:
109
+
110
+ - **Building**: `Building`, `Space_type`, `Space`, `Building_surface`, `Opening`, `Solar_surface`.
111
+ - **Constructions**: `Material`, `Construction`, `Glazing`, `Frame`, `Opening_type`.
112
+ - **HVAC (air side)**: `HVAC_perfect_system`, `DX_unit`, `HVAC_DX_system`, `Water_coil`, `Fan`, `HVAC_SZW_system`, `HVAC_MZW_system`.
113
+ - **HVAC (water side)**: `Pump`, `Chiller_heat_pump`, `HVAC_water_system`.
114
+ - **Schedules**: `Day_schedule`, `Week_schedule`, `Year_schedule`.
115
+ - **Files**: `File_met`, `File_data`.
116
+ - **Utilities**: `Calculator`.
117
+
118
+ See the [Component list](https://jfcoronel.github.io/OpenSimula/component_list/) for every
119
+ parameter and variable of each one.
120
+
121
+ ## Package dependencies
122
+
123
+ - numpy
124
+ - pandas
125
+ - scipy
126
+ - shapely
127
+ - psychrolib
128
+ - plotly
129
+ - matplotlib
130
+ - anywidget
131
+ - jsonschema
132
+ - nbformat
133
+ - openpyxl
134
+ - tqdm
135
+
136
+ These are installed automatically with `pip install opensimula`.
137
+
138
+ ## Documentation and support
139
+
140
+ Full documentation, including the getting started guide, user guide and component
141
+ reference, is at [jfcoronel.github.io/OpenSimula](https://jfcoronel.github.io/OpenSimula/).
142
+ Bugs and feature requests are tracked on
143
+ [GitHub Issues](https://github.com/jfCoronel/OpenSimula/issues).
144
+
145
+ ## Contributing
146
+
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
+ ## Main Developers
161
+
162
+ * [Juan F. Coronel](http://jfc.us.es), Universidad de Sevilla
163
+
164
+ ## License
165
+
166
+ OpenSimula is released under the [MIT License](LICENSE).
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "opensimula"
3
- version = "0.8.6"
3
+ version = "0.8.8"
4
4
  requires-python = ">=3.12"
5
5
  authors = [
6
6
  { name="Juan F. Coronel", email="jfc@us.es" },
@@ -10,6 +10,7 @@ readme = "README.md"
10
10
  dependencies = [
11
11
  "anywidget>=0.11.0",
12
12
  "jsonschema>=4.26.0",
13
+ "matplotlib>=3.10.0",
13
14
  "nbformat>=5.10.4",
14
15
  "numpy>=2.3.3",
15
16
  "openpyxl>=3.1.5",
@@ -19,7 +20,6 @@ dependencies = [
19
20
  "scipy>=1.16.2",
20
21
  "shapely>=2.1.1",
21
22
  "tqdm>=4.67.1",
22
- "vedo>=2025.5.4",
23
23
  ]
24
24
 
25
25
  [dependency-groups]
@@ -0,0 +1,50 @@
1
+ import math
2
+
3
+ class Iterative_process:
4
+ def __init__(self, x_0, tol = 1e-5, lambda_min=0.1, lambda_max=1.0, n_ini_relax=2,rel_vel = 0.9):
5
+ """
6
+ Iterative process using the fixed-point method with adaptive relaxation coefficient
7
+
8
+ Parameters:
9
+ x_0: Initial value
10
+ tol: convergence tolerance
11
+ lambda_min, lambda_max: relaxation coefficient range
12
+ n_ini_relax: Number of iterations in which adaptive relaxation is initiated, must be greater than 1
13
+ """
14
+ self.x = [x_0]
15
+ self.tol = tol
16
+ self.lambda_min = lambda_min
17
+ self.lambda_max = lambda_max
18
+ self.lambda_i = lambda_max
19
+ self.n_ini_relax = n_ini_relax
20
+ self.rel_vel = rel_vel
21
+ self.residual = None # |proposed_x - x| of the last iteration
22
+
23
+ def converged(self):
24
+ # Fixed-point residual, not the relaxed step: with relaxation lambda the step is only
25
+ # lambda * residual, so testing the step stopped with residuals up to tol / lambda_min
26
+ # (10 x tol), e.g. zones far from their moisture balance in steady state
27
+ return self.residual is not None and self.residual < self.tol
28
+
29
+ def estimate_next_x(self, proposed_x):
30
+ residual = proposed_x - self.x[-1]
31
+ x_next = (1 - self.lambda_i) * self.x[-1] + self.lambda_i * proposed_x
32
+
33
+ # Adaptive relaxation: reduce lambda when the iteration oscillates (the residual
34
+ # changes sign) or does not contract (the residual grows), and recover it while it
35
+ # contracts; reducing it unconditionally made well-behaved iterations crawl
36
+ # (lambda_min after ~10 iterations)
37
+ if len(self.x) > self.n_ini_relax and self.residual is not None:
38
+ if residual * self._last_residual < 0 or abs(residual) > self.residual:
39
+ self.lambda_i = max(self.lambda_min, self.lambda_i * self.rel_vel)
40
+ else:
41
+ self.lambda_i = min(self.lambda_max, self.lambda_i / self.rel_vel)
42
+ self._last_residual = residual
43
+ self.residual = abs(residual)
44
+
45
+ self.x.append(x_next)
46
+ return x_next
47
+
48
+ def set_next_x(self, next_x):
49
+ self.x.append(next_x)
50
+
@@ -677,23 +677,30 @@ class Project(Parameter_container):
677
677
  self.create_3D_environment(env_3D)
678
678
  return env_3D.geometry_dict()
679
679
 
680
- def show_3D(self, jupyter=False):
680
+ def show_3D(self):
681
681
  env_3D = Environment_3D()
682
682
  self.create_3D_environment(env_3D)
683
- return env_3D.show(polygons_type="initial", jupyter=jupyter)
683
+ env_3D.show(polygons_type="initial")
684
684
 
685
- def show_3D_shadows(self, date, jupyter=False):
685
+ def plotly_figure_3D(self):
686
+ """The Plotly figure of show_3D(), returned instead of shown, so it
687
+ can be composed, saved, or otherwise reused."""
688
+ env_3D = Environment_3D()
689
+ self.create_3D_environment(env_3D)
690
+ return env_3D.plotly_figure(polygons_type="initial")
691
+
692
+ def show_3D_shadows(self, date):
686
693
  env_3D = Environment_3D()
687
694
  self.create_3D_environment(env_3D)
688
695
  file_met = self.parameter("simulation_file_met").component
689
696
  cos = file_met.sun_cosines(date)
690
697
  if len(cos) == 3:
691
698
  env_3D.calculate_shadows(cos)
692
- env_3D.show(polygons_type="Building_shadows", jupyter=jupyter)
699
+ env_3D.show(polygons_type="Building_shadows")
693
700
  else:
694
701
  self._sim_.message(Message(date.strftime("%H:%M, %d/%m/%Y") + " is night", "WARNING"))
695
702
 
696
- def show_3D_shadows_animation(self, date, jupyter=False):
703
+ def show_3D_shadows_animation(self, date):
697
704
  env_3D = Environment_3D()
698
705
  self.create_3D_environment(env_3D)
699
706
  file_met = self.parameter("simulation_file_met").component
@@ -705,6 +712,6 @@ class Project(Parameter_container):
705
712
  if len(cos) == 3: # Day time
706
713
  texts.append(new_date.strftime("%H:%M, %d/%m/%Y"))
707
714
  cosines.append(cos)
708
- env_3D.show_animation(texts, cosines, polygons_type="Building_shadows", jupyter=jupyter)
715
+ env_3D.show_animation(texts, cosines, polygons_type="Building_shadows")
709
716
 
710
717
 
@@ -85,7 +85,7 @@ class Building(Component):
85
85
  SWR_matrix = (SWR_matrix - np.matmul(self.ff_matrix, rho_matrix)
86
86
  - np.matmul(self.ff_matrix, np.matmul(tau_matrix, self.B_matrix)))
87
87
 
88
- SWR_matrix = np.linalg.inv(SWR_matrix)
88
+ SWR_matrix = _radiosity_inverse_(SWR_matrix)
89
89
  aux_matrix = np.matmul(area_matrix, np.matmul(alpha_matrix, SWR_matrix))
90
90
  self.SWDIF_matrix = np.matmul(aux_matrix, np.matmul(self.ff_matrix, tau_matrix)) # SW Solar Diffuse
91
91
 
@@ -119,7 +119,7 @@ class Building(Component):
119
119
  LWR_matrix = (LWR_matrix - np.matmul(self.ff_matrix, rho_matrix)
120
120
  - np.matmul(self.ff_matrix, np.matmul(tau_matrix, self.B_matrix)))
121
121
 
122
- LWR_matrix = np.linalg.inv(LWR_matrix)
122
+ LWR_matrix = _radiosity_inverse_(LWR_matrix)
123
123
  aux_matrix = np.matmul(area_matrix, np.matmul(alpha_matrix,LWR_matrix))
124
124
 
125
125
  ig_dist_matrix = np.zeros((self._n_surfaces, self._n_spaces))
@@ -508,4 +508,18 @@ class Building(Component):
508
508
 
509
509
  # _______________ post_iteration _______________
510
510
  def post_iteration(self, time_index, date, daylight_saving, converged):
511
- super().post_iteration(time_index, date, daylight_saving, converged)
511
+ super().post_iteration(time_index, date, daylight_saving, converged)
512
+
513
+
514
+ def _radiosity_inverse_(matrix):
515
+ """Inverse of a radiosity matrix (I - F·rho - F·tau·B).
516
+
517
+ In a closed enclosure whose surfaces neither absorb nor transmit (rho = 1, e.g. surfaces
518
+ with solar absorptance or emissivity 0, as in the ASHRAE 140 ground-coupling cases) the
519
+ matrix is singular, since the rows of F sum to 1. Nothing is absorbed then, so any
520
+ generalised inverse gives the same (zero) absorbed radiation: use the pseudo-inverse.
521
+ """
522
+ try:
523
+ return np.linalg.inv(matrix)
524
+ except np.linalg.LinAlgError:
525
+ return np.linalg.pinv(matrix)
@@ -281,7 +281,10 @@ class Construction(Component):
281
281
  ox = []
282
282
  oy = []
283
283
  oz = []
284
- for i in range(1, n_coef):
284
+ # n_coef terms of the response series give n_coef valid a, b, c coefficients, as many
285
+ # as d has: with one fewer, the steady state (sum(a)/sum(d) = U) failed for light
286
+ # constructions with few roots, e.g. 6.59 instead of 5.05 W/m²K for a thin panel
287
+ for i in range(1, n_coef + 1):
285
288
  sum_exp_x = 0
286
289
  sum_exp_y = 0
287
290
  sum_exp_z = 0
@@ -304,10 +307,11 @@ class Construction(Component):
304
307
  if math.fabs(d[i]) < min_coef:
305
308
  d = d[0: i+1]
306
309
  break
307
- # Cut number of coeficients, se producen coeficientes extraños para muros ligeros a partir del n. de roots
308
- a = np.resize(a, n_coef-1)
309
- b = np.resize(b, n_coef-1)
310
- c = np.resize(c, n_coef-1)
310
+ # Only the first n_coef terms of the convolutions are valid (the response series
311
+ # above are truncated after n_coef terms)
312
+ a = np.resize(a, n_coef)
313
+ b = np.resize(b, n_coef)
314
+ c = np.resize(c, n_coef)
311
315
  # Cut a, b, c coefficients
312
316
  for i in range(len(a)):
313
317
  if (