engforge 0.3.0__py3-none-any.whl
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/__init__.py +26 -0
- engforge/_testing_components.py +864 -0
- engforge/analysis.py +257 -0
- engforge/attr_dynamics.py +222 -0
- engforge/attr_plotting.py +811 -0
- engforge/attr_signals.py +116 -0
- engforge/attr_slots.py +211 -0
- engforge/attr_solver.py +443 -0
- engforge/attributes.py +326 -0
- engforge/common.py +76 -0
- engforge/component_collections.py +276 -0
- engforge/components.py +55 -0
- engforge/configuration.py +673 -0
- engforge/dataframe.py +185 -0
- engforge/datastores/__init__.py +116 -0
- engforge/datastores/data.py +519 -0
- engforge/datastores/gdocs.py +2650 -0
- engforge/datastores/reporting.py +935 -0
- engforge/datastores/secrets.py +549 -0
- engforge/dynamics.py +662 -0
- engforge/eng/__init__.py +0 -0
- engforge/eng/costs.py +1459 -0
- engforge/eng/fluid_material.py +279 -0
- engforge/eng/geometry.py +1060 -0
- engforge/eng/pipes.py +1211 -0
- engforge/eng/prediction.py +366 -0
- engforge/eng/solid_materials.py +445 -0
- engforge/eng/structure.py +2228 -0
- engforge/eng/structure_beams.py +821 -0
- engforge/eng/thermodynamics.py +271 -0
- engforge/engforge_attributes.py +380 -0
- engforge/env_var.py +214 -0
- engforge/locations.py +18 -0
- engforge/logging.py +290 -0
- engforge/patterns.py +449 -0
- engforge/problem_context.py +2251 -0
- engforge/properties.py +501 -0
- engforge/reporting.py +595 -0
- engforge/solveable.py +964 -0
- engforge/solver.py +316 -0
- engforge/solver_utils.py +726 -0
- engforge/system.py +143 -0
- engforge/system_reference.py +299 -0
- engforge/tabulation.py +288 -0
- engforge/test/__init__.py +2 -0
- engforge/test/_pre_test_structures.py +221 -0
- engforge/test/report_testing.py +158 -0
- engforge/test/test_airfilter.py +91 -0
- engforge/test/test_analysis.py +3 -0
- engforge/test/test_comp_iter.py +196 -0
- engforge/test/test_composition.py +139 -0
- engforge/test/test_costs.py +338 -0
- engforge/test/test_dynamics.py +109 -0
- engforge/test/test_dynamics_spaces.py +39 -0
- engforge/test/test_four_bar.py +97 -0
- engforge/test/test_modules.py +72 -0
- engforge/test/test_performance.py +93 -0
- engforge/test/test_pipes.py +49 -0
- engforge/test/test_problem.py +411 -0
- engforge/test/test_problem_deepscoping.py +68 -0
- engforge/test/test_slider_crank.py +51 -0
- engforge/test/test_solver.py +343 -0
- engforge/test/test_tabulation.py +233 -0
- engforge/typing.py +92 -0
- engforge-0.3.0.dist-info/METADATA +392 -0
- engforge-0.3.0.dist-info/RECORD +69 -0
- engforge-0.3.0.dist-info/WHEEL +5 -0
- engforge-0.3.0.dist-info/licenses/LICENSE +7 -0
- engforge-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from engforge._testing_components import *
|
|
3
|
+
from engforge.problem_context import ProblemExec
|
|
4
|
+
import itertools
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
indep = "*x,*y,*z"
|
|
8
|
+
indep_l = indep.split(",")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SolverRefSelection(unittest.TestCase):
|
|
12
|
+
def setUp(self) -> None:
|
|
13
|
+
self.sc = CubeSystem()
|
|
14
|
+
|
|
15
|
+
def test_comps_solver_act(self):
|
|
16
|
+
inv = "ineq_cost,ineq_length,min_len" + "," + indep
|
|
17
|
+
acts = ["*costA", "*lenA"]
|
|
18
|
+
for act in [True, False]:
|
|
19
|
+
for cmb in [inv, inv.split(",")]:
|
|
20
|
+
extra = dict(
|
|
21
|
+
combos=cmb,
|
|
22
|
+
slv_vars="*",
|
|
23
|
+
activate=acts if act else None,
|
|
24
|
+
only_active=act,
|
|
25
|
+
)
|
|
26
|
+
info = self.sc.solver_vars(**extra)["attrs"]
|
|
27
|
+
ans = {"x", "y", "z", "comp.x", "comp.y", "comp.z"}
|
|
28
|
+
self.assertEqual(set(info["solver.var"]), ans)
|
|
29
|
+
self.assertEqual(set(info["dynamics.state"]), ans)
|
|
30
|
+
self.assertEqual(set(info["dynamics.rate"]), ans)
|
|
31
|
+
|
|
32
|
+
empt = ["solver.eq", "solver.obj", "time", "slot", "signal"]
|
|
33
|
+
for emp in empt:
|
|
34
|
+
self.assertEqual(info[emp], {})
|
|
35
|
+
|
|
36
|
+
if act:
|
|
37
|
+
ineq = {"comp.lenA", "comp.costA", "costA", "lenA"}
|
|
38
|
+
self.assertEqual(set(info["solver.ineq"]), ineq)
|
|
39
|
+
|
|
40
|
+
def test_comps_solver_obj(self):
|
|
41
|
+
inv = "obj_size,ineq_cost,ineq_length,min_len" + "," + indep
|
|
42
|
+
acts = ["*costA", "*lenA"]
|
|
43
|
+
aacts = ["*costA", "*lenA", "*size"]
|
|
44
|
+
for act in [True, False]:
|
|
45
|
+
for cmb in [inv, inv.split(",")]:
|
|
46
|
+
actv = acts if act else aacts
|
|
47
|
+
extra = dict(combos=cmb, slv_vars="*", activate=actv, only_active=True)
|
|
48
|
+
info = self.sc.solver_vars(**extra)["attrs"]
|
|
49
|
+
ans = {"x", "y", "z", "comp.x", "comp.y", "comp.z"}
|
|
50
|
+
self.assertEqual(set(info["solver.var"]), ans)
|
|
51
|
+
self.assertEqual(set(info["dynamics.state"]), ans)
|
|
52
|
+
self.assertEqual(set(info["dynamics.rate"]), ans)
|
|
53
|
+
|
|
54
|
+
ineq = {"comp.lenA", "comp.costA", "costA", "lenA"}
|
|
55
|
+
self.assertEqual(set(info["solver.ineq"]), ineq)
|
|
56
|
+
|
|
57
|
+
empt = ["solver.eq", "time", "slot", "signal"]
|
|
58
|
+
for emp in empt:
|
|
59
|
+
self.assertEqual(info[emp], {})
|
|
60
|
+
|
|
61
|
+
if not act:
|
|
62
|
+
obj = {"size", "comp.size"}
|
|
63
|
+
self.assertEqual(set(info["solver.obj"]), obj)
|
|
64
|
+
else:
|
|
65
|
+
self.assertEqual(set(info["solver.obj"]), set())
|
|
66
|
+
|
|
67
|
+
def test_sys_solver(self):
|
|
68
|
+
# test combos
|
|
69
|
+
inv = "volume,height,min_len,total_*" + "," + indep
|
|
70
|
+
for act in [True, False]:
|
|
71
|
+
for cmb in [inv, inv.split(",")]:
|
|
72
|
+
extra = dict(
|
|
73
|
+
combos=cmb,
|
|
74
|
+
slv_vars=indep + ",hght,obj,*sys*",
|
|
75
|
+
activate=[],
|
|
76
|
+
only_active=act,
|
|
77
|
+
)
|
|
78
|
+
info = self.sc.solver_vars(**extra)["attrs"]
|
|
79
|
+
ans = {"x", "y", "z", "comp.x", "comp.y", "comp.z"}
|
|
80
|
+
self.assertEqual(set(info["solver.var"]), ans)
|
|
81
|
+
self.assertEqual(set(info["dynamics.state"]), ans)
|
|
82
|
+
self.assertEqual(set(info["dynamics.rate"]), ans)
|
|
83
|
+
|
|
84
|
+
obj = {"hght", "obj"}
|
|
85
|
+
self.assertEqual(set(info["solver.obj"]), obj)
|
|
86
|
+
ineq = {"sys_budget", "sys_length"}
|
|
87
|
+
self.assertEqual(set(info["solver.ineq"]), ineq)
|
|
88
|
+
|
|
89
|
+
empt = ["solver.eq", "time", "slot", "signal"]
|
|
90
|
+
for emp in empt:
|
|
91
|
+
self.assertEqual(info[emp], {})
|
|
92
|
+
|
|
93
|
+
def test_xyz_var_only(self):
|
|
94
|
+
"""only xyz via vars"""
|
|
95
|
+
inv = indep
|
|
96
|
+
for act in [True, False]:
|
|
97
|
+
for cmb in [inv, inv.split(",")]:
|
|
98
|
+
extra = dict(combos=None, slv_vars=cmb, only_active=act)
|
|
99
|
+
info = self.sc.solver_vars(**extra)["attrs"]
|
|
100
|
+
ans = {"x", "y", "z", "comp.x", "comp.y", "comp.z"}
|
|
101
|
+
self.assertEqual(set(info["solver.var"]), ans)
|
|
102
|
+
self.assertEqual(set(info["dynamics.state"]), ans)
|
|
103
|
+
self.assertEqual(set(info["dynamics.rate"]), ans)
|
|
104
|
+
|
|
105
|
+
empt = [
|
|
106
|
+
"solver.eq",
|
|
107
|
+
"solver.ineq",
|
|
108
|
+
"solver.obj",
|
|
109
|
+
"time",
|
|
110
|
+
"slot",
|
|
111
|
+
"signal",
|
|
112
|
+
]
|
|
113
|
+
for emp in empt:
|
|
114
|
+
self.assertEqual(info[emp], {})
|
|
115
|
+
|
|
116
|
+
def test_xyz_combo_only(self):
|
|
117
|
+
"""only xyz via combos"""
|
|
118
|
+
inv = "x,y,z"
|
|
119
|
+
for act in [True, False]:
|
|
120
|
+
for cmb in [inv, inv.split(",")]:
|
|
121
|
+
extra = dict(combos=None, slv_vars=indep, only_active=act)
|
|
122
|
+
info = self.sc.solver_vars(**extra)["attrs"]
|
|
123
|
+
ans = {"x", "y", "z", "comp.x", "comp.y", "comp.z"}
|
|
124
|
+
self.assertEqual(set(info["solver.var"]), ans)
|
|
125
|
+
self.assertEqual(set(info["dynamics.state"]), ans)
|
|
126
|
+
self.assertEqual(set(info["dynamics.rate"]), ans)
|
|
127
|
+
|
|
128
|
+
empt = [
|
|
129
|
+
"solver.eq",
|
|
130
|
+
"solver.ineq",
|
|
131
|
+
"solver.obj",
|
|
132
|
+
"time",
|
|
133
|
+
"slot",
|
|
134
|
+
"signal",
|
|
135
|
+
]
|
|
136
|
+
for emp in empt:
|
|
137
|
+
self.assertEqual(info[emp], {})
|
|
138
|
+
|
|
139
|
+
def test_xyz_act_nocombo(self):
|
|
140
|
+
"""activated aren't included because no combos are given"""
|
|
141
|
+
extra = dict(
|
|
142
|
+
combos=None,
|
|
143
|
+
slv_vars=indep,
|
|
144
|
+
activate=["*costA", "*lenA", "*size"],
|
|
145
|
+
only_active=True,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
info = self.sc.solver_vars(**extra)["attrs"]
|
|
149
|
+
ans = {"x", "y", "z", "comp.x", "comp.y", "comp.z"}
|
|
150
|
+
self.assertEqual(set(info["solver.var"]), ans)
|
|
151
|
+
self.assertEqual(set(info["dynamics.state"]), ans)
|
|
152
|
+
self.assertEqual(set(info["dynamics.rate"]), ans)
|
|
153
|
+
|
|
154
|
+
empt = [
|
|
155
|
+
"solver.eq",
|
|
156
|
+
"solver.ineq",
|
|
157
|
+
"solver.obj",
|
|
158
|
+
"time",
|
|
159
|
+
"slot",
|
|
160
|
+
"signal",
|
|
161
|
+
]
|
|
162
|
+
for emp in empt:
|
|
163
|
+
self.assertEqual(info[emp], {})
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
import pprint
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class SingleCompSolverTest(unittest.TestCase):
|
|
170
|
+
inequality_min = -1e-6
|
|
171
|
+
|
|
172
|
+
def setUp(self) -> None:
|
|
173
|
+
self.sc = CubeSystem(comp=CubeComp())
|
|
174
|
+
|
|
175
|
+
def test_exec_results(self):
|
|
176
|
+
extra = dict(combos=indep_l, slv_vars=indep, activate=[], only_active=True)
|
|
177
|
+
with ProblemExec(self.sc, extra) as pb:
|
|
178
|
+
o = self.sc.execute(**extra)
|
|
179
|
+
self.assertDictEqual(o["Xstart"], o["Xans"])
|
|
180
|
+
|
|
181
|
+
def test_run_results(self):
|
|
182
|
+
"""test that inputs stay the same when no objecives present"""
|
|
183
|
+
extra = dict(combos=indep, slv_vars=indep_l, activate=[], only_active=True)
|
|
184
|
+
|
|
185
|
+
scx, scy, scz = self.sc.x, self.sc.y, self.sc.z
|
|
186
|
+
sccx, sccy, sccz = self.sc.comp.x, self.sc.comp.y, self.sc.comp.z
|
|
187
|
+
vray = [scx, scy, scz, sccx, sccy, sccz]
|
|
188
|
+
|
|
189
|
+
o = self.sc.run(**extra)
|
|
190
|
+
|
|
191
|
+
# dfray = self.sc.dataframe[['x','y','z','comp_x','comp_y','comp_z']].iloc[0].values
|
|
192
|
+
# self.assertFalse(np.all(dfray==vray),msg=f'{dfray}\n{vray}')
|
|
193
|
+
|
|
194
|
+
scx, scy, scz = self.sc.x, self.sc.y, self.sc.z
|
|
195
|
+
sccx, sccy, sccz = self.sc.comp.x, self.sc.comp.y, self.sc.comp.z
|
|
196
|
+
v2ray = [scx, scy, scz, sccx, sccy, sccz]
|
|
197
|
+
|
|
198
|
+
self.assertTrue(np.all(vray == v2ray), msg="revert values changed!")
|
|
199
|
+
|
|
200
|
+
def test_comp_method_equivalence(self):
|
|
201
|
+
objs = {"obj_eff": ["eff", "effF"], "obj_size": ["size", "sizeF"]}
|
|
202
|
+
cons = {
|
|
203
|
+
"ineq_cost": ["costA", "costF", "costP"],
|
|
204
|
+
"ineq_length": ["lenA", "lenF", "lenP"],
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
for ok, ck in itertools.product(objs, cons):
|
|
208
|
+
attempts = []
|
|
209
|
+
for var in objs[ok]:
|
|
210
|
+
for con in cons[ck]:
|
|
211
|
+
extra = dict(
|
|
212
|
+
combos=[ok, ck, "min_len"],
|
|
213
|
+
slv_vars=indep,
|
|
214
|
+
activate=[var, con],
|
|
215
|
+
only_active=True,
|
|
216
|
+
both_match=False,
|
|
217
|
+
)
|
|
218
|
+
o = self.sc.execute(**extra)
|
|
219
|
+
attempts.append(o)
|
|
220
|
+
|
|
221
|
+
# check for equivalence
|
|
222
|
+
a0 = attempts[0]
|
|
223
|
+
for atmpt in attempts[1:]:
|
|
224
|
+
ak1 = a0["Xans"]
|
|
225
|
+
ak2 = atmpt["Xans"]
|
|
226
|
+
self.assertEqual(set(ak1), set(ak2))
|
|
227
|
+
for k in ak1:
|
|
228
|
+
self.assertAlmostEqual(ak1[k], ak2[k], places=4)
|
|
229
|
+
|
|
230
|
+
def test_system_execute(self):
|
|
231
|
+
"""check the system solver methods work as expected (objectives are optimized)"""
|
|
232
|
+
extra = dict(
|
|
233
|
+
combos="volume,height,min_len,total_*",
|
|
234
|
+
slv_vars=indep,
|
|
235
|
+
activate=[],
|
|
236
|
+
only_active=True,
|
|
237
|
+
both_match=False,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
H = self.sc.execute(**extra, weights={"hght": 1, "obj": 0})
|
|
241
|
+
V = self.sc.execute(**extra, weights={"hght": 0, "obj": 1})
|
|
242
|
+
|
|
243
|
+
self.assertGreater(H["Yobj"]["hght"], V["Yobj"]["hght"])
|
|
244
|
+
self.assertGreater(V["Yobj"]["obj"], H["Yobj"]["obj"])
|
|
245
|
+
|
|
246
|
+
def test_system_run(self):
|
|
247
|
+
"""check the system solver methods work as expected (objectives are optimized)"""
|
|
248
|
+
extra = dict(
|
|
249
|
+
combos="volume,height,min_len,total_*",
|
|
250
|
+
slv_vars=indep,
|
|
251
|
+
activate=[],
|
|
252
|
+
only_active=True,
|
|
253
|
+
both_match=False,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
H = self.sc.run(**extra, weights={"hght": 1, "obj": 0})["output"][0]
|
|
257
|
+
V = self.sc.run(**extra, weights={"hght": 0, "obj": 1})["output"][0]
|
|
258
|
+
|
|
259
|
+
self.assertGreater(H["Yobj"]["hght"], V["Yobj"]["hght"])
|
|
260
|
+
self.assertGreater(V["Yobj"]["obj"], H["Yobj"]["obj"])
|
|
261
|
+
|
|
262
|
+
def test_system_solver(self):
|
|
263
|
+
"""check the system solver methods work as expected (objectives are optimized)"""
|
|
264
|
+
extra = dict(
|
|
265
|
+
combos="volume,height,min_len,total_*",
|
|
266
|
+
slv_vars=indep,
|
|
267
|
+
activate=[],
|
|
268
|
+
only_active=True,
|
|
269
|
+
both_match=False,
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
H = self.sc.solver(**extra, weights={"hght": 1, "obj": 0})
|
|
273
|
+
V = self.sc.solver(**extra, weights={"hght": 0, "obj": 1})
|
|
274
|
+
|
|
275
|
+
self.assertGreater(H["Yobj"]["hght"], V["Yobj"]["hght"])
|
|
276
|
+
self.assertGreater(V["Yobj"]["obj"], H["Yobj"]["obj"])
|
|
277
|
+
|
|
278
|
+
def test_system_eval(self):
|
|
279
|
+
"""check the system solver methods work as expected (objectives are optimized)"""
|
|
280
|
+
extra = dict(
|
|
281
|
+
combos="volume,height,min_len,total_*",
|
|
282
|
+
slv_vars=indep,
|
|
283
|
+
activate=[],
|
|
284
|
+
only_active=True,
|
|
285
|
+
both_match=False,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
H = self.sc.eval(**extra, weights={"hght": 1, "obj": 0})
|
|
289
|
+
V = self.sc.eval(**extra, weights={"hght": 0, "obj": 1})
|
|
290
|
+
|
|
291
|
+
self.assertGreater(H["Yobj"]["hght"], V["Yobj"]["hght"])
|
|
292
|
+
self.assertGreater(V["Yobj"]["obj"], H["Yobj"]["obj"])
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
# TODO: rewrite these tests
|
|
296
|
+
# def test_selective_exec(self):
|
|
297
|
+
# extra = dict(combos='*fun*,goal',ign_combos=['z_sym_eq','*size*','*eff*'])
|
|
298
|
+
# o = self.sc.execute(**extra)
|
|
299
|
+
# res = self.test_results(o)
|
|
300
|
+
# self.test_selection(o,res,extra)
|
|
301
|
+
#
|
|
302
|
+
# def test_runmtx(self):
|
|
303
|
+
# extra = dict(budget=[100,500,1000],max_length=[50,100,200])
|
|
304
|
+
# o = self.sc.run(**extra)
|
|
305
|
+
# res = self.test_results(o)
|
|
306
|
+
# df = self.test_dataframe(o)
|
|
307
|
+
# self.test_selection(o,res,extra)
|
|
308
|
+
#
|
|
309
|
+
# def test_selective_runmtx(self):
|
|
310
|
+
# extra = dict(budget=[100,500,1000],max_length=[50,100,200],combos='*fun*,goal',ign_combos=['z_sym_eq','*size*','*eff*'])
|
|
311
|
+
# o = self.sc.run(**extra)
|
|
312
|
+
# res = self.test_results(o)
|
|
313
|
+
# df = self.test_dataframe(o)
|
|
314
|
+
# self.test_selection(o,res,extra)
|
|
315
|
+
#
|
|
316
|
+
# def test_run_wildcard(self):
|
|
317
|
+
# extra = dict(combos='*fun*,goal',ign_combos='*',budget=[100,500,1000],max_length=[50,100,200])
|
|
318
|
+
# o = self.sc.run(**extra)
|
|
319
|
+
# res = self.test_results(o)
|
|
320
|
+
# df = self.test_dataframe(o)
|
|
321
|
+
# self.test_selection(o,res,extra)
|
|
322
|
+
#
|
|
323
|
+
# #Checks
|
|
324
|
+
# def test_dataframe(self,results)->dict:
|
|
325
|
+
# #print(results)
|
|
326
|
+
# print(NotImplementedError("#FIXME!"))
|
|
327
|
+
#
|
|
328
|
+
# def test_selection(self,results,df_res,extra):
|
|
329
|
+
# #print(results,df_res,extra)
|
|
330
|
+
# print(NotImplementedError("#FIXME!"))
|
|
331
|
+
#
|
|
332
|
+
# def test_results(self,results):
|
|
333
|
+
# Ycon = results['Ycon']
|
|
334
|
+
# costmg = {k:v for k,v in Ycon.items() if 'cost' in k}
|
|
335
|
+
# lenmg = {k:v for k,v in Ycon.items() if 'len' in k}
|
|
336
|
+
#
|
|
337
|
+
# #Test input equivalence of methods
|
|
338
|
+
# self.assertEqual(len(set(costmg.values())),1)
|
|
339
|
+
# self.assertEqual(len(set(lenmg.values())),1)
|
|
340
|
+
#
|
|
341
|
+
# #Test inequality constraints
|
|
342
|
+
# yvals = (v >= self.inequality_min for v in Ycon.values())
|
|
343
|
+
# self.assertTrue(all(yvals))
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import io
|
|
3
|
+
import tempfile
|
|
4
|
+
|
|
5
|
+
from engforge.configuration import forge
|
|
6
|
+
from engforge.tabulation import system_property
|
|
7
|
+
from engforge.components import Component
|
|
8
|
+
from engforge.system import System
|
|
9
|
+
from engforge.component_collections import ComponentIterator, ComponentDict
|
|
10
|
+
from engforge.problem_context import ProblemExec
|
|
11
|
+
import attr
|
|
12
|
+
import os
|
|
13
|
+
import numpy
|
|
14
|
+
import random
|
|
15
|
+
|
|
16
|
+
from pprint import pprint
|
|
17
|
+
|
|
18
|
+
# from engforge.logging import LoggingMixin, change_all_log_levels
|
|
19
|
+
# change_all_log_levels(10)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@forge
|
|
23
|
+
class TestConfig(System):
|
|
24
|
+
attrs_prop: float = attr.ib(1.0)
|
|
25
|
+
attrs_str: str = attr.ib("hey now")
|
|
26
|
+
|
|
27
|
+
@system_property
|
|
28
|
+
def test_one(self) -> int:
|
|
29
|
+
return 1
|
|
30
|
+
|
|
31
|
+
@system_property(stochastic=True)
|
|
32
|
+
def test_two(self) -> float:
|
|
33
|
+
return random.random()
|
|
34
|
+
|
|
35
|
+
@system_property(label="three", desc="some words")
|
|
36
|
+
def test_three(self) -> int:
|
|
37
|
+
return 2
|
|
38
|
+
|
|
39
|
+
@system_property(label="four", desc="would make sense", stochastic=True)
|
|
40
|
+
def test_four(self) -> float:
|
|
41
|
+
return random.random()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class Test(unittest.TestCase):
|
|
45
|
+
test_file_name = "test_dataframe_file"
|
|
46
|
+
test_dir = "~/"
|
|
47
|
+
|
|
48
|
+
def setUp(self):
|
|
49
|
+
self.test_config = TestConfig(name="testconfig")
|
|
50
|
+
|
|
51
|
+
# self.test_dir = tempfile.mkdtemp()
|
|
52
|
+
#
|
|
53
|
+
# def tearDown(self):
|
|
54
|
+
# contents_local = os.listdir(self.test_dir)
|
|
55
|
+
# for fil in contents_local:
|
|
56
|
+
# if self.test_file_name in fil:
|
|
57
|
+
# rfil = os.path.join(self.test_dir, fil)
|
|
58
|
+
|
|
59
|
+
def test_property_labels(self):
|
|
60
|
+
ans = set(["four", "test_two", "test_one", "three", "converged", "run_id"])
|
|
61
|
+
self.assertEqual(set(self.test_config.system_properties_labels), ans)
|
|
62
|
+
|
|
63
|
+
def test_property_types(self):
|
|
64
|
+
ans = [int, float, int, float, int, int]
|
|
65
|
+
self.assertEqual(self.test_config.system_properties_types, ans)
|
|
66
|
+
|
|
67
|
+
def test_property_desc(self):
|
|
68
|
+
ans = ["", "", "some words", "would make sense", "", ""]
|
|
69
|
+
self.assertEqual(self.test_config.system_properties_description, ans)
|
|
70
|
+
|
|
71
|
+
def test_table_vals(self):
|
|
72
|
+
vals_ans = (1, 2)
|
|
73
|
+
for val in vals_ans:
|
|
74
|
+
self.assertTrue(
|
|
75
|
+
any(
|
|
76
|
+
[
|
|
77
|
+
val == valcan if type(valcan) is int else False
|
|
78
|
+
for valcan in self.test_config.system_properties
|
|
79
|
+
]
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def test_assemble_data_always_save(self):
|
|
84
|
+
self.test_config.info(
|
|
85
|
+
f"testing data assembly {self.test_config.always_save_data}"
|
|
86
|
+
)
|
|
87
|
+
self.test_config._always_save_data = True
|
|
88
|
+
# Run before test_table_to...
|
|
89
|
+
self.assertFalse(self.test_config.dataframe.shape[0])
|
|
90
|
+
with ProblemExec(self.test_config, {}) as px:
|
|
91
|
+
px.save_data()
|
|
92
|
+
|
|
93
|
+
self.assertTrue(px.dataframe.shape[0])
|
|
94
|
+
self.assertTrue(1 == px.dataframe.shape[0])
|
|
95
|
+
|
|
96
|
+
# Stochastic Props so this will work without input change.
|
|
97
|
+
px.save_data()
|
|
98
|
+
self.assertTrue(2 == px.dataframe.shape[0])
|
|
99
|
+
|
|
100
|
+
def test_assemble_data_on_input(self):
|
|
101
|
+
# change this to check behavior to adjust stochastic behavior
|
|
102
|
+
# print(f"testing data assembly {self.test_config.always_save_data}")
|
|
103
|
+
# Run before test_table_to...
|
|
104
|
+
self.assertFalse(self.test_config.dataframe.shape[0])
|
|
105
|
+
self.test_config._always_save_data = False
|
|
106
|
+
self.test_config.info(
|
|
107
|
+
f"testing data assembly {self.test_config.always_save_data}"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
with ProblemExec(self.test_config, {}) as px:
|
|
111
|
+
px.save_data()
|
|
112
|
+
|
|
113
|
+
# print(px.dataframe,len(px.dataframe))
|
|
114
|
+
self.assertTrue(px.dataframe.shape[0])
|
|
115
|
+
self.assertTrue(1 == px.dataframe.shape[0])
|
|
116
|
+
|
|
117
|
+
# No Update So This Wont Save
|
|
118
|
+
px.save_data()
|
|
119
|
+
self.assertFalse(2 == px.dataframe.shape[0])
|
|
120
|
+
|
|
121
|
+
# Change Something
|
|
122
|
+
cur_val = self.test_config.attrs_prop
|
|
123
|
+
new_val = 6 + cur_val
|
|
124
|
+
self.test_config.info(f"setting attrs prop on in {cur_val } => {new_val}")
|
|
125
|
+
|
|
126
|
+
self.test_config.attrs_prop = new_val
|
|
127
|
+
px.save_data()
|
|
128
|
+
self.assertTrue(2 == px.dataframe.shape[0])
|
|
129
|
+
|
|
130
|
+
def test_dataframe(self, iter=5):
|
|
131
|
+
attr_in = {}
|
|
132
|
+
cur_dict = self.test_config.data_dict
|
|
133
|
+
with ProblemExec(self.test_config, {}) as px:
|
|
134
|
+
for i in range(iter):
|
|
135
|
+
with ProblemExec(self.test_config, {}) as px:
|
|
136
|
+
cur_val = self.test_config.attrs_prop
|
|
137
|
+
attr_in[i] = val = cur_val + i**2.0
|
|
138
|
+
self.test_config.info(f"setting attrs prop df {cur_val } => {val}")
|
|
139
|
+
self.test_config.attrs_prop = val
|
|
140
|
+
px.save_data()
|
|
141
|
+
px.exit_with_state()
|
|
142
|
+
postdict = self.test_config.data_dict
|
|
143
|
+
self.assertDictEqual(cur_dict, postdict)
|
|
144
|
+
px.exit_with_state()
|
|
145
|
+
|
|
146
|
+
postdict = self.test_config.data_dict
|
|
147
|
+
# self.test_config.info(f'cur_dict {cur_dict} postdict {postdict}')
|
|
148
|
+
self.assertDictEqual(cur_dict, postdict)
|
|
149
|
+
|
|
150
|
+
df = self.test_config.dataframe
|
|
151
|
+
pprint(df)
|
|
152
|
+
|
|
153
|
+
self.assertEqual(len(df.index), iter)
|
|
154
|
+
|
|
155
|
+
self.assertEqual(df["test_one"].max(), 1)
|
|
156
|
+
self.assertEqual(df["test_one"].min(), 1)
|
|
157
|
+
|
|
158
|
+
self.assertEqual(df["test_three"].max(), 2)
|
|
159
|
+
self.assertEqual(df["test_three"].min(), 2)
|
|
160
|
+
|
|
161
|
+
l1 = list(df["attrs_prop"])
|
|
162
|
+
l2 = [attr_in[i] for i in range(iter)]
|
|
163
|
+
self.assertListEqual(l1, l2)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# TODO: move these to reporting
|
|
167
|
+
# def file_in_format(self, fileextension, path=True):
|
|
168
|
+
# fille = "{}.{}".format(self.test_file_name, fileextension)
|
|
169
|
+
# if path:
|
|
170
|
+
# path = os.path.join(self.test_dir, fille)
|
|
171
|
+
# return path
|
|
172
|
+
# else:
|
|
173
|
+
# return fille
|
|
174
|
+
# def test_table_to_csv(self):
|
|
175
|
+
# pass
|
|
176
|
+
# print('saving '+self.file_in_format('xlsx'))
|
|
177
|
+
# self.test_config.save_csv(self.file_in_format('csv'))
|
|
178
|
+
# self.assertIn(self.file_in_format('csv',False), os.listdir(self.test_dir))
|
|
179
|
+
|
|
180
|
+
#
|
|
181
|
+
# def test_table_to_excel(self):
|
|
182
|
+
# pass
|
|
183
|
+
# #print('saving '+self.file_in_format('xlsx'))
|
|
184
|
+
# #self.test_config.save_excel(self.file_in_format('xlsx'))
|
|
185
|
+
# #self.assertIn(self.file_in_format('xlsx',False),os.listdir(self.test_dir))
|
|
186
|
+
#
|
|
187
|
+
# def test_table_to_gsheets(self):
|
|
188
|
+
# pass
|
|
189
|
+
#
|
|
190
|
+
# def test_table_to_db(self):
|
|
191
|
+
# pass
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@forge
|
|
195
|
+
class Static(System):
|
|
196
|
+
attrs_prop: float = attr.ib(1.0)
|
|
197
|
+
attrs_str: str = attr.ib("hey now")
|
|
198
|
+
|
|
199
|
+
@system_property
|
|
200
|
+
def test_one(self) -> int:
|
|
201
|
+
return 1
|
|
202
|
+
|
|
203
|
+
@system_property()
|
|
204
|
+
def test_two(self) -> int:
|
|
205
|
+
return 2
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class TestStatic(unittest.TestCase):
|
|
209
|
+
def setUp(self):
|
|
210
|
+
self.test_config = Static()
|
|
211
|
+
|
|
212
|
+
def test_static(self, num=10):
|
|
213
|
+
cur_dict = self.test_config.data_dict
|
|
214
|
+
with ProblemExec(self.test_config, {}) as px:
|
|
215
|
+
for i in range(num):
|
|
216
|
+
with ProblemExec(self.test_config, {}) as px:
|
|
217
|
+
px.save_data()
|
|
218
|
+
postdict = self.test_config.data_dict
|
|
219
|
+
self.assertDictEqual(cur_dict, postdict)
|
|
220
|
+
|
|
221
|
+
self.assertEqual(len(self.test_config.dataframe), 1)
|
|
222
|
+
|
|
223
|
+
def test_input(self, num=10):
|
|
224
|
+
cur_dict = self.test_config.data_dict
|
|
225
|
+
with ProblemExec(self.test_config, {}) as px:
|
|
226
|
+
for i in range(num):
|
|
227
|
+
with ProblemExec(self.test_config, {}) as px:
|
|
228
|
+
self.test_config.attrs_prop = i + self.test_config.attrs_prop
|
|
229
|
+
px.save_data()
|
|
230
|
+
postdict = self.test_config.data_dict
|
|
231
|
+
self.assertDictEqual(cur_dict, postdict)
|
|
232
|
+
|
|
233
|
+
self.assertEqual(len(self.test_config.dataframe), num)
|
engforge/typing.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
""" """
|
|
2
|
+
|
|
3
|
+
import pandas, attr, numpy
|
|
4
|
+
from engforge.properties import *
|
|
5
|
+
import attrs
|
|
6
|
+
|
|
7
|
+
# import matplotlib.pyplot as plt
|
|
8
|
+
pandas.set_option("use_inf_as_na", True)
|
|
9
|
+
|
|
10
|
+
# Type Checking
|
|
11
|
+
NUMERIC_TYPES = (float, int, numpy.int64, numpy.float64)
|
|
12
|
+
NUMERIC_NAN_TYPES = (float, int, type(None), numpy.int64, numpy.float64)
|
|
13
|
+
STR_TYPES = (str, numpy.string_)
|
|
14
|
+
TABLE_TYPES = (int, float, str, type(None), numpy.int64, numpy.float64)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# TODO: add min / max args & attrs boilerplate
|
|
18
|
+
def NUMERIC_VALIDATOR():
|
|
19
|
+
return attr.validators.instance_of(NUMERIC_TYPES)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def NUMERIC_NAN_VALIDATOR():
|
|
23
|
+
return attr.validators.instance_of(NUMERIC_NAN_TYPES)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def STR_VALIDATOR():
|
|
27
|
+
return attr.validators.instance_of(STR_TYPES)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
ATTR_VALIDATOR_TYPES = (
|
|
31
|
+
attr.validators._AndValidator,
|
|
32
|
+
attr.validators._InstanceOfValidator,
|
|
33
|
+
attr.validators._MatchesReValidator,
|
|
34
|
+
attr.validators._ProvidesValidator,
|
|
35
|
+
attr.validators._OptionalValidator,
|
|
36
|
+
attr.validators._InValidator,
|
|
37
|
+
attr.validators._IsCallableValidator,
|
|
38
|
+
attr.validators._DeepIterable,
|
|
39
|
+
attr.validators._DeepMapping,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
TAB_VALIDATOR_TYPE = (
|
|
43
|
+
attr.validators._InstanceOfValidator
|
|
44
|
+
) # our validators should require a type i think, at least for tabulation
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# Improved Attrs Creation Fields
|
|
48
|
+
def Options(*choices, **kwargs):
|
|
49
|
+
"""creates an attrs field with validated choices on init and setattr
|
|
50
|
+
:param choices: a list of choices that are validated on input, the first becoming the default unless it is passed in kwargs
|
|
51
|
+
:param kwargs: keyword args passed to attrs field"""
|
|
52
|
+
assert choices, f"must have some choices!"
|
|
53
|
+
assert "type" not in kwargs, "options type set is str"
|
|
54
|
+
valids = set((str, int, float, bool, type(None)))
|
|
55
|
+
assert set([type(c) for c in choices]).issubset(
|
|
56
|
+
valids
|
|
57
|
+
), f"choices must be in {valids}"
|
|
58
|
+
assert "on_setattr" not in kwargs
|
|
59
|
+
|
|
60
|
+
validators = [attrs.validators.in_(choices)]
|
|
61
|
+
|
|
62
|
+
# Merge Validators
|
|
63
|
+
if "validators" in kwargs:
|
|
64
|
+
in_validators = kwargs.pop("validators")
|
|
65
|
+
if isinstance(in_validators, list):
|
|
66
|
+
validators.extend(in_validators)
|
|
67
|
+
elif isinstance(in_validators, attr.validators._ValidatorType):
|
|
68
|
+
validators.append(in_validators)
|
|
69
|
+
else:
|
|
70
|
+
raise ValueError(f"bad validator {in_validators}")
|
|
71
|
+
|
|
72
|
+
# Default
|
|
73
|
+
if "default" in kwargs:
|
|
74
|
+
default = kwargs.pop("default")
|
|
75
|
+
assert type(default) is str
|
|
76
|
+
else:
|
|
77
|
+
default = choices[0]
|
|
78
|
+
|
|
79
|
+
on_setattr = [attrs.setters.validate]
|
|
80
|
+
|
|
81
|
+
# Create The Attr!
|
|
82
|
+
a = attrs.field(
|
|
83
|
+
default=default,
|
|
84
|
+
type=str,
|
|
85
|
+
validator=validators,
|
|
86
|
+
on_setattr=on_setattr,
|
|
87
|
+
**kwargs,
|
|
88
|
+
)
|
|
89
|
+
return a
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# def Numeric #TODO with min/max that is enforced in solver!
|