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.
- opensimula-0.8.8/PKG-INFO +188 -0
- opensimula-0.8.8/README.md +166 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/pyproject.toml +2 -2
- opensimula-0.8.8/src/opensimula/Iterative_process.py +50 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Project.py +13 -6
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Building.py +17 -3
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Construction.py +9 -5
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/File_met.py +80 -58
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/HVAC_SZW_system.py +22 -22
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Space.py +4 -1
- opensimula-0.8.8/src/opensimula/editor/static/editor.js +8271 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/visual_3D/Environment_3D.py +107 -176
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/visual_3D/Polygon_3D.py +0 -8
- opensimula-0.8.8/src/opensimula.egg-info/PKG-INFO +188 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula.egg-info/requires.txt +1 -1
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Case_600FF.py +3 -3
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Case_610.py +20 -4
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Construction.py +35 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_File_met.py +19 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_HVAC_DX_system.py +12 -12
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_HVAC_FAN_COIL_water_system.py +10 -10
- opensimula-0.8.8/test/test_Iterative_process.py +30 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_editor_schema.py +15 -9
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_editor_widget.py +26 -6
- opensimula-0.8.6/PKG-INFO +0 -45
- opensimula-0.8.6/README.md +0 -23
- opensimula-0.8.6/src/opensimula/Iterative_process.py +0 -47
- opensimula-0.8.6/src/opensimula/editor/static/editor.js +0 -1047
- opensimula-0.8.6/src/opensimula.egg-info/PKG-INFO +0 -45
- opensimula-0.8.6/test/test_Iterative_process.py +0 -13
- {opensimula-0.8.6 → opensimula-0.8.8}/LICENSE +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/setup.cfg +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Child.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Component.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Message.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Parameter_container.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Parameters.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Simulation.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/Variable.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/__init__.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Building_surface.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Calculator.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Chiller_heat_pump.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/DX_unit.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Day_schedule.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Fan.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/File_data.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Frame.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Glazing.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/HVAC_DX_system.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/HVAC_MZW_system.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/HVAC_perfect_system.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/HVAC_water_system.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Material.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Opening.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Opening_type.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Pump.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Solar_surface.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Space_type.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Surface.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Test_component.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Water_coil.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Week_schedule.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/Year_schedule.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/components/__init__.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/editor/__init__.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/editor/schema.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/editor/static/editor.css +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/editor/validation.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula/editor/widget.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula.egg-info/SOURCES.txt +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula.egg-info/dependency_links.txt +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/src/opensimula.egg-info/top_level.txt +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Calculator.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_File_data.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_HVAC_DX_Equipment.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_HVAC_water_system_process.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Project.py +0 -0
- {opensimula-0.8.6 → opensimula-0.8.8}/test/test_Schedules.py +0 -0
- {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
|
+

|
|
24
|
+
|
|
25
|
+
# OpenSimula
|
|
26
|
+
|
|
27
|
+
[](https://github.com/jfCoronel/OpenSimula/actions/workflows/tests.yml)
|
|
28
|
+
[](https://pypi.org/project/opensimula/)
|
|
29
|
+
[](https://pypi.org/project/opensimula/)
|
|
30
|
+
[](https://doi.org/10.5281/zenodo.23210985)
|
|
31
|
+
[](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
|
+

|
|
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
|
+

|
|
2
|
+
|
|
3
|
+
# OpenSimula
|
|
4
|
+
|
|
5
|
+
[](https://github.com/jfCoronel/OpenSimula/actions/workflows/tests.yml)
|
|
6
|
+
[](https://pypi.org/project/opensimula/)
|
|
7
|
+
[](https://pypi.org/project/opensimula/)
|
|
8
|
+
[](https://doi.org/10.5281/zenodo.23210985)
|
|
9
|
+
[](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
|
+

|
|
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.
|
|
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
|
|
680
|
+
def show_3D(self):
|
|
681
681
|
env_3D = Environment_3D()
|
|
682
682
|
self.create_3D_environment(env_3D)
|
|
683
|
-
|
|
683
|
+
env_3D.show(polygons_type="initial")
|
|
684
684
|
|
|
685
|
-
def
|
|
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"
|
|
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
|
|
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"
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
#
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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 (
|