engforge 0.3.0__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.
- engforge-0.3.0/LICENSE +7 -0
- engforge-0.3.0/PKG-INFO +392 -0
- engforge-0.3.0/README.md +316 -0
- engforge-0.3.0/engforge/__init__.py +26 -0
- engforge-0.3.0/engforge/_testing_components.py +864 -0
- engforge-0.3.0/engforge/analysis.py +257 -0
- engforge-0.3.0/engforge/attr_dynamics.py +222 -0
- engforge-0.3.0/engforge/attr_plotting.py +811 -0
- engforge-0.3.0/engforge/attr_signals.py +116 -0
- engforge-0.3.0/engforge/attr_slots.py +211 -0
- engforge-0.3.0/engforge/attr_solver.py +443 -0
- engforge-0.3.0/engforge/attributes.py +326 -0
- engforge-0.3.0/engforge/common.py +76 -0
- engforge-0.3.0/engforge/component_collections.py +276 -0
- engforge-0.3.0/engforge/components.py +55 -0
- engforge-0.3.0/engforge/configuration.py +673 -0
- engforge-0.3.0/engforge/dataframe.py +185 -0
- engforge-0.3.0/engforge/datastores/__init__.py +116 -0
- engforge-0.3.0/engforge/datastores/data.py +519 -0
- engforge-0.3.0/engforge/datastores/gdocs.py +2650 -0
- engforge-0.3.0/engforge/datastores/reporting.py +935 -0
- engforge-0.3.0/engforge/datastores/secrets.py +549 -0
- engforge-0.3.0/engforge/dynamics.py +662 -0
- engforge-0.3.0/engforge/eng/__init__.py +0 -0
- engforge-0.3.0/engforge/eng/costs.py +1459 -0
- engforge-0.3.0/engforge/eng/fluid_material.py +279 -0
- engforge-0.3.0/engforge/eng/geometry.py +1060 -0
- engforge-0.3.0/engforge/eng/pipes.py +1211 -0
- engforge-0.3.0/engforge/eng/prediction.py +366 -0
- engforge-0.3.0/engforge/eng/solid_materials.py +445 -0
- engforge-0.3.0/engforge/eng/structure.py +2228 -0
- engforge-0.3.0/engforge/eng/structure_beams.py +821 -0
- engforge-0.3.0/engforge/eng/thermodynamics.py +271 -0
- engforge-0.3.0/engforge/engforge_attributes.py +380 -0
- engforge-0.3.0/engforge/env_var.py +214 -0
- engforge-0.3.0/engforge/locations.py +18 -0
- engforge-0.3.0/engforge/logging.py +290 -0
- engforge-0.3.0/engforge/patterns.py +449 -0
- engforge-0.3.0/engforge/problem_context.py +2251 -0
- engforge-0.3.0/engforge/properties.py +501 -0
- engforge-0.3.0/engforge/reporting.py +595 -0
- engforge-0.3.0/engforge/solveable.py +964 -0
- engforge-0.3.0/engforge/solver.py +316 -0
- engforge-0.3.0/engforge/solver_utils.py +726 -0
- engforge-0.3.0/engforge/system.py +143 -0
- engforge-0.3.0/engforge/system_reference.py +299 -0
- engforge-0.3.0/engforge/tabulation.py +288 -0
- engforge-0.3.0/engforge/test/__init__.py +2 -0
- engforge-0.3.0/engforge/test/_pre_test_structures.py +221 -0
- engforge-0.3.0/engforge/test/report_testing.py +158 -0
- engforge-0.3.0/engforge/test/test_airfilter.py +91 -0
- engforge-0.3.0/engforge/test/test_analysis.py +3 -0
- engforge-0.3.0/engforge/test/test_comp_iter.py +196 -0
- engforge-0.3.0/engforge/test/test_composition.py +139 -0
- engforge-0.3.0/engforge/test/test_costs.py +338 -0
- engforge-0.3.0/engforge/test/test_dynamics.py +109 -0
- engforge-0.3.0/engforge/test/test_dynamics_spaces.py +39 -0
- engforge-0.3.0/engforge/test/test_four_bar.py +97 -0
- engforge-0.3.0/engforge/test/test_modules.py +72 -0
- engforge-0.3.0/engforge/test/test_performance.py +93 -0
- engforge-0.3.0/engforge/test/test_pipes.py +49 -0
- engforge-0.3.0/engforge/test/test_problem.py +411 -0
- engforge-0.3.0/engforge/test/test_problem_deepscoping.py +68 -0
- engforge-0.3.0/engforge/test/test_slider_crank.py +51 -0
- engforge-0.3.0/engforge/test/test_solver.py +343 -0
- engforge-0.3.0/engforge/test/test_tabulation.py +233 -0
- engforge-0.3.0/engforge/typing.py +92 -0
- engforge-0.3.0/engforge.egg-info/PKG-INFO +392 -0
- engforge-0.3.0/engforge.egg-info/SOURCES.txt +74 -0
- engforge-0.3.0/engforge.egg-info/dependency_links.txt +1 -0
- engforge-0.3.0/engforge.egg-info/not-zip-safe +1 -0
- engforge-0.3.0/engforge.egg-info/requires.txt +65 -0
- engforge-0.3.0/engforge.egg-info/top_level.txt +1 -0
- engforge-0.3.0/pyproject.toml +123 -0
- engforge-0.3.0/setup.cfg +9 -0
engforge-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2023 Ottermatics LLC
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
engforge-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: engforge
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: The Engineer's Framework
|
|
5
|
+
Author-email: Kevin Russell <olly@ottermatics.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Ottermatics/engforge
|
|
8
|
+
Project-URL: Repository, https://github.com/Ottermatics/engforge
|
|
9
|
+
Project-URL: Documentation, https://ottermatics.github.io/engforge/
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: attrs~=23.2.0
|
|
20
|
+
Requires-Dist: arrow
|
|
21
|
+
Requires-Dist: deepdiff>=6.3.1
|
|
22
|
+
Requires-Dist: numpy==1.24.3
|
|
23
|
+
Requires-Dist: scipy
|
|
24
|
+
Requires-Dist: matplotlib~=3.8.1
|
|
25
|
+
Requires-Dist: jupyter
|
|
26
|
+
Requires-Dist: pandas
|
|
27
|
+
Requires-Dist: scikit-learn~=1.3.2
|
|
28
|
+
Requires-Dist: seaborn
|
|
29
|
+
Requires-Dist: tabulate
|
|
30
|
+
Requires-Dist: networkx-query==1.0.1
|
|
31
|
+
Requires-Dist: networkx>=2.5.1
|
|
32
|
+
Requires-Dist: black~=24.8.0
|
|
33
|
+
Requires-Dist: randomname~=0.2.1
|
|
34
|
+
Requires-Dist: termcolor
|
|
35
|
+
Requires-Dist: pyee
|
|
36
|
+
Requires-Dist: methodtools~=0.4.7
|
|
37
|
+
Requires-Dist: tomli>=1.2.0; python_version < "3.11"
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: wheel; extra == "dev"
|
|
40
|
+
Requires-Dist: jinja2>=2.11.3; extra == "dev"
|
|
41
|
+
Requires-Dist: sphinx>=3.2.1; extra == "dev"
|
|
42
|
+
Requires-Dist: recommonmark>=0.6.0; extra == "dev"
|
|
43
|
+
Requires-Dist: sphinx-rtd-theme>=1.0.0; extra == "dev"
|
|
44
|
+
Provides-Extra: eng
|
|
45
|
+
Requires-Dist: control; extra == "eng"
|
|
46
|
+
Requires-Dist: fluids; extra == "eng"
|
|
47
|
+
Requires-Dist: CoolProp; extra == "eng"
|
|
48
|
+
Requires-Dist: sectionproperties~=3.1.2; extra == "eng"
|
|
49
|
+
Requires-Dist: PyniteFEA>=1.2.0; extra == "eng"
|
|
50
|
+
Provides-Extra: database
|
|
51
|
+
Requires-Dist: SQLAlchemy~=1.3.17; extra == "database"
|
|
52
|
+
Requires-Dist: SQLAlchemy-Utils; extra == "database"
|
|
53
|
+
Requires-Dist: psycopg2-binary; extra == "database"
|
|
54
|
+
Requires-Dist: diskcache>=5.6.1; extra == "database"
|
|
55
|
+
Requires-Dist: sqlalchemy-batch-inserts; extra == "database"
|
|
56
|
+
Provides-Extra: google
|
|
57
|
+
Requires-Dist: expiringdict~=1.2.2; extra == "google"
|
|
58
|
+
Requires-Dist: pygsheets==2.0.4; extra == "google"
|
|
59
|
+
Requires-Dist: pydrive2==1.8.1; extra == "google"
|
|
60
|
+
Provides-Extra: cloud
|
|
61
|
+
Requires-Dist: boto3; extra == "cloud"
|
|
62
|
+
Provides-Extra: distributed
|
|
63
|
+
Requires-Dist: ray[default]~=2.35.0; extra == "distributed"
|
|
64
|
+
Requires-Dist: ray[tune]~=2.35.0; extra == "distributed"
|
|
65
|
+
Provides-Extra: docs
|
|
66
|
+
Requires-Dist: sphinx>=7.0.0; extra == "docs"
|
|
67
|
+
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
68
|
+
Requires-Dist: pydata-sphinx-theme; extra == "docs"
|
|
69
|
+
Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
|
|
70
|
+
Requires-Dist: myst-parser; extra == "docs"
|
|
71
|
+
Requires-Dist: sphinx_autodoc_typehints; extra == "docs"
|
|
72
|
+
Requires-Dist: toml~=0.10.2; extra == "docs"
|
|
73
|
+
Provides-Extra: all
|
|
74
|
+
Requires-Dist: engforge[cloud,database,dev,distributed,docs,eng,google]; extra == "all"
|
|
75
|
+
Dynamic: license-file
|
|
76
|
+
|
|
77
|
+
[](https://github.com/Ottermatics/engforge/actions/workflows/build.yml)
|
|
78
|
+
[](https://github.com/Ottermatics/engforge/actions/workflows/docs.yml)
|
|
79
|
+
# EngForge
|
|
80
|
+
A library to tabulate information from complex systems with various ways to store data and act as glue code for complex systems & engineering problems.
|
|
81
|
+
|
|
82
|
+
### Installation
|
|
83
|
+
```bash
|
|
84
|
+
pip install git+https://github.com/Ottermatics/engforge.git
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Core Functions
|
|
88
|
+
1. Tabulation Of Complex Systems
|
|
89
|
+
2. Modular Post Processing (dataframes)
|
|
90
|
+
3. Exploratory Analysis (ipython + functions / docs)
|
|
91
|
+
4. Workflows for core engineering problemes (structures + cost, thermal+fluids solve)
|
|
92
|
+
|
|
93
|
+
### MVP Features (WIP)
|
|
94
|
+
1. Tabulation, use `attrs.field` and `system_property` to capture `y=f(x)` where `fields` are the state from which `system_property` derives results [Done]
|
|
95
|
+
2. Dynamic Programing ensures work is only done when new data is available with `cached_system_property`. [Done]
|
|
96
|
+
3. Quick Calculation provided by direct cached references to attribues and properties [Done]
|
|
97
|
+
4. Solver based on `NPSS` strategy of balances and integrators [Done]
|
|
98
|
+
5. Reporting to google sheets, csv and excel.
|
|
99
|
+
|
|
100
|
+
### Systems & Analysis
|
|
101
|
+
Systems record data from components, and can execute a solver via the `run(**parameter_iterables)` command. Via a system's run command its state and internal component's & systems state can be altered in an outer product fashion, ie all combinations of inputs will be run. At the start of a run the systems & its components state is recorded and reset by default using `Ref` instances so that way multiple systems can use the same component. Its possible reference loops may occcur so its generally preferred to create components per system, however for coupled systems this is often desireable to converge on a solution.
|
|
102
|
+
|
|
103
|
+
By default the system calls a `default_solver()` method in its `execute()` function. A solver aims to drive its dependent parameter to zero by changing the independent parameters to zero, however it may adjust multiple parameters to meet multiple targets in more complex applications. For custom System behavior or to invoke custom solvers this method may be overriden.
|
|
104
|
+
|
|
105
|
+
To use the default solver & constraints
|
|
106
|
+
```python
|
|
107
|
+
@forge
|
|
108
|
+
SolverSystem(System):
|
|
109
|
+
sol2 = Solver.define("dep", "indep")
|
|
110
|
+
sol2.add_constraint("max", limit_max) #indep should never go above this value (or function)
|
|
111
|
+
sol2.add_constraint("min", 0) #indep should never go below zero
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`Analysis` is a pluggable way to provide different output and calculation from the same system and interacts with plot and table reporters.
|
|
115
|
+
|
|
116
|
+
### Components, Signals & Slots
|
|
117
|
+
Component are able to be mounted into multiple Systems via `SLOTS.define( ComponentType )`. A Component's properties can be updated via `SIGNALS` in the Systems's solver in the `pre_execute` and/or the `post_execute` functions via `SIGNAL.define(target, source, mode)` where mode can be `pre`,`post` or `both` to update before the `System.execute()` method.
|
|
118
|
+
|
|
119
|
+
Iterable Components may be defined on a System via `SLOT.define_iterable( <ComponentIter>, wide=True/False)` to choose how the system should iterate over the component, `wide` mode provides all the component `attributes` and `properties` in the same row whereas the `narrow` mode will iterate over each combination of component as though it was input into `system.run()`
|
|
120
|
+
|
|
121
|
+
### Example Engineering Problems:
|
|
122
|
+
These problems demonstrate functionality
|
|
123
|
+
|
|
124
|
+
#### Air Filter
|
|
125
|
+
run a throttle sweep with filter loss characteristic and fan afinity law based pressure based off of a design point.
|
|
126
|
+
```python
|
|
127
|
+
from engforge.analysis import Analysis
|
|
128
|
+
from engforge.reporting import CSVReporter,DiskPlotReporter
|
|
129
|
+
from engforge.properties import system_property
|
|
130
|
+
from engforge import *
|
|
131
|
+
import numpy as np
|
|
132
|
+
import os,pathlib
|
|
133
|
+
import attrs
|
|
134
|
+
|
|
135
|
+
@forge
|
|
136
|
+
class Fan(Component):
|
|
137
|
+
|
|
138
|
+
n_frac:float = field(default=1)
|
|
139
|
+
dp_design:float= field(default=100)
|
|
140
|
+
w_design:float = field(default=2)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@system_property
|
|
144
|
+
def dP_fan(self) -> float:
|
|
145
|
+
return self.dp_design*(self.n_frac*self.w_design)**2.0
|
|
146
|
+
|
|
147
|
+
@forge
|
|
148
|
+
class Filter(Component):
|
|
149
|
+
|
|
150
|
+
w:float = field(default=0)
|
|
151
|
+
k_loss:float = field(default=50)
|
|
152
|
+
|
|
153
|
+
@system_property
|
|
154
|
+
def dP_filter(self) -> float:
|
|
155
|
+
return self.k_loss*self.w
|
|
156
|
+
|
|
157
|
+
@forge
|
|
158
|
+
class Airfilter(System):
|
|
159
|
+
|
|
160
|
+
throttle:float = field(default=1)
|
|
161
|
+
w:float = field(default=1)
|
|
162
|
+
k_parasitic:float = field(default=0.1)
|
|
163
|
+
|
|
164
|
+
fan: Fan = Slot.define(Fan)
|
|
165
|
+
filt: Filter = Slot.define(Filter)
|
|
166
|
+
|
|
167
|
+
set_fan_n = Signal.define('fan.n_frac','throttle',mode='both')
|
|
168
|
+
set_filter_w = Signal.define('filt.w','w',mode='both')
|
|
169
|
+
|
|
170
|
+
flow_var = Solver.declare_var('w',combos='flow')
|
|
171
|
+
flow_var.add_var_constraint(0,'min',combos='flow')
|
|
172
|
+
|
|
173
|
+
pr_eq = Solver.constraint_equality('sum_dP',0,combos='flow')
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
flow_curve = Plot.define(
|
|
177
|
+
"throttle", "w", kind="lineplot", title="Flow Curve"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
@system_property
|
|
181
|
+
def dP_parasitic(self) -> float:
|
|
182
|
+
return self.k_parasitic * self.w**2.0
|
|
183
|
+
|
|
184
|
+
@system_property
|
|
185
|
+
def sum_dP(self) -> float:
|
|
186
|
+
return self.fan.dP_fan - self.dP_parasitic - self.filt.dP_filter
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
#Run the system
|
|
190
|
+
from matplotlib.pylab import *
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
fan = Fan()
|
|
195
|
+
filt = Filter()
|
|
196
|
+
af = Airfilter(fan=fan,filt=filt)
|
|
197
|
+
|
|
198
|
+
change_all_log_levels(af,20) #info
|
|
199
|
+
|
|
200
|
+
af.run(throttle=list(np.arange(0.1,1.1,0.1)),combos='*')
|
|
201
|
+
|
|
202
|
+
df = af.dataframe
|
|
203
|
+
|
|
204
|
+
fig,(ax,ax2) = subplots(2,1)
|
|
205
|
+
ax.plot(df.throttle*100,df.w,'k--',label='flow')
|
|
206
|
+
ax2.plot(df.throttle*100,df.filt_dp_filter,label='filter')
|
|
207
|
+
ax2.plot(df.throttle*100,df.dp_parasitic,label='parasitic')
|
|
208
|
+
ax2.plot(df.throttle*100,df.fan_dp_fan,label='fan')
|
|
209
|
+
ax.legend(loc='upper right')
|
|
210
|
+
ax.set_title('flow')
|
|
211
|
+
ax.grid()
|
|
212
|
+
ax2.legend()
|
|
213
|
+
ax2.grid()
|
|
214
|
+
ax2.set_title(f'pressure')
|
|
215
|
+
ax2.set_xlabel(f'throttle%')
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
##### Results
|
|
219
|
+

|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
#### Spring Mass Damper
|
|
223
|
+
##### Overview
|
|
224
|
+
Test case results in accurate resonance frequency calculation
|
|
225
|
+
```python
|
|
226
|
+
|
|
227
|
+
@forge
|
|
228
|
+
class SpringMass(System):
|
|
229
|
+
|
|
230
|
+
k: float = attrs.field(default=50)
|
|
231
|
+
m: float = attrs.field(default=1)
|
|
232
|
+
g: float = attrs.field(default=9.81)
|
|
233
|
+
u: float = attrs.field(default=0.3)
|
|
234
|
+
|
|
235
|
+
a: float = attrs.field(default=0)
|
|
236
|
+
x: float = attrs.field(default=0.0)
|
|
237
|
+
v: float = attrs.field(default=0.0)
|
|
238
|
+
|
|
239
|
+
wo_f: float = attrs.field(default=1.0)
|
|
240
|
+
Fa: float = attrs.field(default=10.0)
|
|
241
|
+
|
|
242
|
+
x_neutral: float = attrs.field(default=0.5)
|
|
243
|
+
|
|
244
|
+
res =Solver.constraint_equality("sumF")
|
|
245
|
+
var_a = Solver.declare_var("a",combos='a',active=False)
|
|
246
|
+
var_b = Solver.declare_var("u",combos='u',active=False)
|
|
247
|
+
var_b.add_var_constraint(0.0,kind="min")
|
|
248
|
+
var_b.add_var_constraint(1.0,kind="max")
|
|
249
|
+
|
|
250
|
+
vtx = Time.integrate("v", "accl")
|
|
251
|
+
xtx = Time.integrate("x", "v")
|
|
252
|
+
xtx.add_var_constraint(0,kind="min")
|
|
253
|
+
|
|
254
|
+
#FIXME: implement trace testing
|
|
255
|
+
#pos = Trace.define(y="x", y2=["v", "a"])
|
|
256
|
+
|
|
257
|
+
@system_property
|
|
258
|
+
def dx(self) -> float:
|
|
259
|
+
return self.x_neutral - self.x
|
|
260
|
+
|
|
261
|
+
@system_property
|
|
262
|
+
def Fspring(self) -> float:
|
|
263
|
+
return self.k * self.dx
|
|
264
|
+
|
|
265
|
+
@system_property
|
|
266
|
+
def Fgrav(self) -> float:
|
|
267
|
+
return self.g * self.m
|
|
268
|
+
|
|
269
|
+
@system_property
|
|
270
|
+
def Faccel(self) -> float:
|
|
271
|
+
return self.a * self.m
|
|
272
|
+
|
|
273
|
+
@system_property
|
|
274
|
+
def Ffric(self) -> float:
|
|
275
|
+
return self.u * self.v
|
|
276
|
+
|
|
277
|
+
@system_property
|
|
278
|
+
def sumF(self) -> float:
|
|
279
|
+
return self.Fspring - self.Fgrav - self.Faccel - self.Ffric + self.Fext
|
|
280
|
+
|
|
281
|
+
@system_property
|
|
282
|
+
def Fext(self) -> float:
|
|
283
|
+
return self.Fa * np.cos( self.time * self.wo_f )
|
|
284
|
+
|
|
285
|
+
@system_property
|
|
286
|
+
def accl(self) -> float:
|
|
287
|
+
return self.sumF / self.m
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
#Run The System, Compare damping `u`=0 & 0.1
|
|
291
|
+
sm = SpringMass(x=0.0)
|
|
292
|
+
sm.sim(dt=0.01,endtime=10,u=[0.0,0.1],combos='*',slv_vars='*')
|
|
293
|
+
|
|
294
|
+
df = sm.dataframe
|
|
295
|
+
df.groupby('run_id').plot('time','x')
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
##### Results Damping Off
|
|
299
|
+

|
|
300
|
+
|
|
301
|
+
##### Results - Damping On
|
|
302
|
+
<img src="media/olib_spring_mass_clac_damp 1.png" />
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
## Reporting & Analysis
|
|
306
|
+
`Analysis` is capable of tabulation as a `Component` or `System` and wraps a top level `System` and will save data for each system interval. `Analysis` stores several reporters for tables and plots that may be used to store results in multiple locations.
|
|
307
|
+
|
|
308
|
+
Reporting is supported for tables via dataframes in CSV,Excel and Gsheets (WIP).
|
|
309
|
+
|
|
310
|
+
For plots reporting is supported in disk storage.
|
|
311
|
+
|
|
312
|
+
```python
|
|
313
|
+
|
|
314
|
+
from engforge.analysis import Analysis
|
|
315
|
+
from engforge.reporting import CSVReporter,DiskPlotReporter
|
|
316
|
+
from engforge.properties import system_property
|
|
317
|
+
import numpy as np
|
|
318
|
+
import os,pathlib
|
|
319
|
+
|
|
320
|
+
this_dir = str(pathlib.Path(__file__).parent)
|
|
321
|
+
this_dir = os.path.join(this_dir,'airfilter_report')
|
|
322
|
+
if not os.path.exists(this_dir):
|
|
323
|
+
os.path.mkdir(this_dir)
|
|
324
|
+
|
|
325
|
+
csv = CSVReporter(path=this_dir,report_mode='daily')
|
|
326
|
+
csv_latest = CSVReporter(path=this_dir,report_mode='single')
|
|
327
|
+
|
|
328
|
+
plots = DiskPlotReporter(path=this_dir,report_mode='monthly')
|
|
329
|
+
plots_latest = DiskPlotReporter(path=this_dir,report_mode='single')
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
@forge
|
|
333
|
+
class AirfilterAnalysis(Analysis):
|
|
334
|
+
"""Does post processing on a system"""
|
|
335
|
+
|
|
336
|
+
efficiency = attrs.field(defualt=0.95)
|
|
337
|
+
|
|
338
|
+
@system_property
|
|
339
|
+
def clean_air_delivery_rate(self) -> float:
|
|
340
|
+
return self.system.w*self.efficiency
|
|
341
|
+
|
|
342
|
+
def post_process(self,*run_args,**run_kwargs):
|
|
343
|
+
pass
|
|
344
|
+
#TODO: something custom!
|
|
345
|
+
|
|
346
|
+
#Air Filter as before
|
|
347
|
+
fan = Fan()
|
|
348
|
+
filt = Filter()
|
|
349
|
+
af = Airfilter(fan=fan,filt=filt)
|
|
350
|
+
|
|
351
|
+
#Make The Analysis
|
|
352
|
+
sa = AirfilterAnalysis(
|
|
353
|
+
system = af,
|
|
354
|
+
table_reporters = [csv,csv_latest],
|
|
355
|
+
plot_reporters = [plots,plots_latest]
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
#Run the analysis! Input passed to system
|
|
359
|
+
sa.run(throttle=list(np.arange(0.1,1.1,0.1)),combos='*')
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
#CSV's & Plots available in ./airfilter_report!
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
## Documentation:
|
|
369
|
+
https://ottermatics.github.io/engforge/
|
|
370
|
+
|
|
371
|
+
### DataStores
|
|
372
|
+
Datastores are a work in progress feature to provide a zero configuration library for storage of tabulated data and report generated artifacts. No garuntee is provided as to their stability yet.
|
|
373
|
+
Requirements for datasources are attempted upon access of `engforge.datastores` and entering of a `CONFIRM` prompt.
|
|
374
|
+
|
|
375
|
+
### Environmental Variables
|
|
376
|
+
To allow a write-once implement anywhere interface `EnvVariable` is provided for both open (the default) and secret variables. Allowance for type conversion, and defaults are provided.
|
|
377
|
+
|
|
378
|
+
The current variable slots in memory are listed by `EnvVariable.print_env_vars()`
|
|
379
|
+
```bash
|
|
380
|
+
FORGE_DB_HOST |SECRETS[FORGE_DB_HOST] = localhost
|
|
381
|
+
FORGE_DB_NAME |SECRETS[FORGE_DB_NAME] =
|
|
382
|
+
FORGE_DB_PASS |SECRETS[FORGE_DB_PASS] = postgres
|
|
383
|
+
FORGE_DB_PORT |SECRETS[FORGE_DB_PORT] = 5432
|
|
384
|
+
FORGE_DB_USER |SECRETS[FORGE_DB_USER] = postgres
|
|
385
|
+
FORGE_HOSTNAME |SECRETS[FORGE_HOSTNAME] = <your-machine>
|
|
386
|
+
FORGE_REPORT_PATH |SECRETS[FORGE_REPORT_PATH] =
|
|
387
|
+
FORGE_SLACK_LOG_WEBHOOK |SECRETS[FORGE_SLACK_LOG_WEBHOOK] =
|
|
388
|
+
SEABORN_CONTEXT |SECRETS[SEABORN_CONTEXT] = paper
|
|
389
|
+
SEABORN_PALETTE |SECRETS[SEABORN_PALETTE] = deep
|
|
390
|
+
SEABORN_THEME |SECRETS[SEABORN_THEME] = darkgrid
|
|
391
|
+
```
|
|
392
|
+
|