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,93 @@
|
|
|
1
|
+
# TODO:
|
|
2
|
+
# 1. ensure total evaluation time is not in Refs
|
|
3
|
+
# 2. minimize call redundancy (how)
|
|
4
|
+
# 3. validate caching performance and safe reset of values
|
|
5
|
+
|
|
6
|
+
from engforge._testing_components import *
|
|
7
|
+
from engforge.logging import LoggingMixin
|
|
8
|
+
from cProfile import Profile
|
|
9
|
+
from pstats import Stats
|
|
10
|
+
import unittest
|
|
11
|
+
import time
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PerfTest(LoggingMixin):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
log = PerfTest()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def eval_steady_state(dxdt=0):
|
|
22
|
+
"""test that the ss answer is equal to the result with damping"""
|
|
23
|
+
sm = SpringMass()
|
|
24
|
+
sm.run(dxdt=dxdt, combos="time")
|
|
25
|
+
df = sm.dataframe
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def eval_transient(endtime=10, dt=0.001, run_solver=False):
|
|
29
|
+
"""test that the ss answer is equal to the result with damping"""
|
|
30
|
+
sm = SpringMass()
|
|
31
|
+
df = sm.simulate(dt=dt, endtime=endtime, run_solver=run_solver)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class TestPerformance(unittest.TestCase):
|
|
35
|
+
def test_steady_state(self):
|
|
36
|
+
with Profile() as pr:
|
|
37
|
+
start = time.time()
|
|
38
|
+
eval_steady_state()
|
|
39
|
+
|
|
40
|
+
stats = Stats(pr)
|
|
41
|
+
stats.sort_stats("tottime").print_stats(10)
|
|
42
|
+
|
|
43
|
+
end = time.time()
|
|
44
|
+
self.assertLessEqual((end - start), 1.0)
|
|
45
|
+
|
|
46
|
+
def test_transient(self):
|
|
47
|
+
endtime = 10
|
|
48
|
+
with Profile() as pr:
|
|
49
|
+
start = time.time()
|
|
50
|
+
eval_transient(endtime=endtime, dt=0.001, run_solver=False)
|
|
51
|
+
|
|
52
|
+
stats = Stats(pr)
|
|
53
|
+
stats.sort_stats("tottime").print_stats(10)
|
|
54
|
+
end = time.time()
|
|
55
|
+
self.assertLessEqual((end - start), endtime)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
import sys
|
|
60
|
+
import argparse
|
|
61
|
+
|
|
62
|
+
parser = argparse.ArgumentParser()
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"-ss",
|
|
65
|
+
"--steady-state",
|
|
66
|
+
action="store_true",
|
|
67
|
+
dest="steady_state",
|
|
68
|
+
help="run the steady state test",
|
|
69
|
+
)
|
|
70
|
+
parser.add_argument(
|
|
71
|
+
"-tr",
|
|
72
|
+
"--transient",
|
|
73
|
+
action="store_true",
|
|
74
|
+
dest="transient",
|
|
75
|
+
help="run the transient test",
|
|
76
|
+
)
|
|
77
|
+
parser.add_argument(
|
|
78
|
+
"-a", "--all", action="store_true", dest="all", help="run all tests"
|
|
79
|
+
)
|
|
80
|
+
parser.add_argument("-b", "--base", action="store_true", help="run all tests")
|
|
81
|
+
|
|
82
|
+
args = parser.parse_args()
|
|
83
|
+
|
|
84
|
+
run_all = True if not sys.argv else args.all
|
|
85
|
+
|
|
86
|
+
if not args.base:
|
|
87
|
+
log.info(f"running all: {run_all} | {sys.argv}")
|
|
88
|
+
if args.steady_state or run_all:
|
|
89
|
+
log.info(f"running steady state test")
|
|
90
|
+
eval_steady_state()
|
|
91
|
+
if args.transient or run_all:
|
|
92
|
+
log.info(f"running transient integration test")
|
|
93
|
+
eval_transient()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from engforge.eng.pipes import *
|
|
2
|
+
from engforge.eng.fluid_material import *
|
|
3
|
+
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestPipes(unittest.TestCase):
|
|
8
|
+
def test_pipe_analysis(self):
|
|
9
|
+
n1 = FlowInput(x=0, y=0, z=0, flow_in=-0.1)
|
|
10
|
+
n2 = PipeNode(x=10, y=0, z=0)
|
|
11
|
+
n3 = PipeNode(x=0, y=10, z=0)
|
|
12
|
+
n4 = PipeNode(x=10, y=10, z=0)
|
|
13
|
+
n5 = FlowInput(x=20, y=10, z=0, flow_in=0.1)
|
|
14
|
+
|
|
15
|
+
n2z = PipeNode(x=10, y=0, z=5, name="n2z")
|
|
16
|
+
n3z = PipeNode(x=0, y=10, z=5, name="n3z")
|
|
17
|
+
n4z = PipeNode(x=10, y=10, z=5, name="n4z")
|
|
18
|
+
n4zo = FlowInput(x=0, y=0, z=0, flow_in=-0.5)
|
|
19
|
+
|
|
20
|
+
n2za = PipeNode(x=10, y=0, z=10)
|
|
21
|
+
n3za = PipeNode(x=0, y=10, z=10)
|
|
22
|
+
n4za = PipeNode(x=10, y=10, z=10)
|
|
23
|
+
n2zoa = FlowInput(x=10, y=5, z=15, flow_in=0.6)
|
|
24
|
+
|
|
25
|
+
pipe1 = Pipe(v=random.random(), D=0.1 * random.random(), node_s=n1, node_e=n2)
|
|
26
|
+
pipe2 = Pipe(v=random.random(), D=0.1 * random.random(), node_s=n1, node_e=n3)
|
|
27
|
+
pipe3 = Pipe(v=random.random(), D=0.1, node_s=n2, node_e=n4)
|
|
28
|
+
pipe4 = Pipe(v=random.random(), D=0.1 * random.random(), node_s=n3, node_e=n4)
|
|
29
|
+
pipe5 = Pipe(v=random.random(), D=0.1 * random.random(), node_s=n4, node_e=n5)
|
|
30
|
+
|
|
31
|
+
pipe5 = Pipe(v=random.random(), D=0.1 * random.random(), node_s=n2z, node_e=n2)
|
|
32
|
+
pipe6 = Pipe(v=random.random(), D=0.1 * random.random(), node_s=n3, node_e=n3z)
|
|
33
|
+
pipe7 = Pipe(v=random.random(), D=0.1 * random.random(), node_s=n4, node_e=n4z)
|
|
34
|
+
pipe8 = Pipe(v=random.random(), D=0.1 * random.random(), node_s=n2, node_e=n4z)
|
|
35
|
+
pipe9 = Pipe(
|
|
36
|
+
v=random.random(), D=0.1 * random.random(), node_s=n4zo, node_e=n4z
|
|
37
|
+
)
|
|
38
|
+
pipe10 = Pipe(
|
|
39
|
+
v=random.random(), D=0.1 * random.random(), node_s=n3z, node_e=n2z
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# pipe10 = Pipe(v=random.random(),D=0.1*random.random(),node_s=n3za,node_e=n4)
|
|
43
|
+
# pipe11 = Pipe(v=random.random(),D=0.1*random.random(),node_s=n2za,node_e=n2zoa)
|
|
44
|
+
# pipe12 = Pipe(v=random.random(),D=0.1*random.random(),node_s=n4za,node_e=n3z)
|
|
45
|
+
# pipe13 = Pipe(v=random.random(),D=0.1*random.random(),node_s=n3,node_e=n2za)
|
|
46
|
+
# pipe13 = Pipe(v=random.random(),D=0.1*random.random(),node_s=n1,node_e=n4z)
|
|
47
|
+
|
|
48
|
+
ps = PipeSystem(in_node=n1)
|
|
49
|
+
ps.draw()
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from engforge.problem_context import *
|
|
3
|
+
from engforge.system import System, forge
|
|
4
|
+
from engforge._testing_components import *
|
|
5
|
+
import random
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@forge(auto_attribs=True)
|
|
9
|
+
class SimpleContext(System):
|
|
10
|
+
one: int = 1
|
|
11
|
+
two: int = 2
|
|
12
|
+
|
|
13
|
+
def set_rand(self):
|
|
14
|
+
self.one = random.random()
|
|
15
|
+
self.two = random.random()
|
|
16
|
+
|
|
17
|
+
def __str__(self):
|
|
18
|
+
return f"{self.one}_{self.two}"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
chk = lambda d, k: set(d.get(k)) if k in d else set()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestSession(unittest.TestCase):
|
|
25
|
+
"""Test lifecycle of a problem and IO of the context"""
|
|
26
|
+
|
|
27
|
+
def test_system_last_context(self):
|
|
28
|
+
sm = SpringMass(Fa=0, u=5)
|
|
29
|
+
sm.run(dxdt=0, combos="time")
|
|
30
|
+
ssid = sm.last_context.session_id
|
|
31
|
+
sm.run(dxdt=0, combos="time")
|
|
32
|
+
trid = sm.last_context.session_id
|
|
33
|
+
self.assertNotEqual(ssid, trid, "Session ID should change after a run")
|
|
34
|
+
|
|
35
|
+
def test_system_change_context(self):
|
|
36
|
+
sm = SpringMass(Fa=0, u=5)
|
|
37
|
+
sm.run(dxdt=0, combos="time")
|
|
38
|
+
ssid = sm.last_context.session_id
|
|
39
|
+
trsm, df = sm.simulate(dt=0.01, endtime=0.1, return_all=True)
|
|
40
|
+
trid = trsm.last_context.session_id
|
|
41
|
+
self.assertNotEqual(ssid, trid, "Session ID should change after a run")
|
|
42
|
+
|
|
43
|
+
def test_slide_crank_empty(self):
|
|
44
|
+
sm = SliderCrank(Tg=0)
|
|
45
|
+
pbx = ProblemExec(sm, {"combos": "", "slv_vars": "", "dxdt": None})
|
|
46
|
+
atx = pbx.ref_attrs
|
|
47
|
+
self.assertEqual(chk(atx, "solver.var"), set())
|
|
48
|
+
self.assertEqual(chk(atx, "solver.obj"), set())
|
|
49
|
+
self.assertEqual(chk(atx, "solver.ineq"), set())
|
|
50
|
+
self.assertEqual(chk(atx, "solver.eq"), set())
|
|
51
|
+
self.assertEqual(chk(atx, "dynamics.output"), set())
|
|
52
|
+
self.assertEqual(chk(atx, "dynamics.rate"), set())
|
|
53
|
+
self.assertEqual(chk(atx, "dynamics.state"), set())
|
|
54
|
+
self.assertEqual(chk(atx, "dynamics.input"), set())
|
|
55
|
+
|
|
56
|
+
cons = pbx.constraints
|
|
57
|
+
self.assertEqual(cons["constraints"], [])
|
|
58
|
+
self.assertEqual(len(cons["bounds"]), len(atx["solver.var"]))
|
|
59
|
+
|
|
60
|
+
def test_slide_crank_dflt(self):
|
|
61
|
+
sm = SliderCrank(Tg=0)
|
|
62
|
+
pbx = ProblemExec(sm, {"dxdt": None})
|
|
63
|
+
atx = pbx.ref_attrs
|
|
64
|
+
self.assertEqual(chk(atx, "solver.var"), set())
|
|
65
|
+
self.assertEqual(chk(atx, "solver.obj"), set())
|
|
66
|
+
self.assertEqual(chk(atx, "solver.ineq"), set())
|
|
67
|
+
self.assertEqual(chk(atx, "solver.eq"), set())
|
|
68
|
+
self.assertEqual(chk(atx, "dynamics.output"), set())
|
|
69
|
+
self.assertEqual(chk(atx, "dynamics.rate"), set())
|
|
70
|
+
self.assertEqual(chk(atx, "dynamics.state"), set())
|
|
71
|
+
self.assertEqual(chk(atx, "dynamics.input"), set())
|
|
72
|
+
|
|
73
|
+
cons = pbx.constraints
|
|
74
|
+
self.assertEqual(len(cons["constraints"]), 0)
|
|
75
|
+
self.assertEqual(len(cons["bounds"]), 0)
|
|
76
|
+
|
|
77
|
+
def test_slide_crank_dxdt_true(self):
|
|
78
|
+
sm = SliderCrank(Tg=0)
|
|
79
|
+
pbx = ProblemExec(sm, {"dxdt": True})
|
|
80
|
+
atx = pbx.ref_attrs
|
|
81
|
+
self.assertEqual(chk(atx, "solver.var"), set())
|
|
82
|
+
self.assertEqual(chk(atx, "solver.obj"), set())
|
|
83
|
+
self.assertEqual(chk(atx, "solver.ineq"), set())
|
|
84
|
+
self.assertEqual(chk(atx, "solver.eq"), set())
|
|
85
|
+
self.assertEqual(chk(atx, "dynamics.output"), set())
|
|
86
|
+
self.assertEqual(chk(atx, "dynamics.rate"), set(("omega", "theta")))
|
|
87
|
+
self.assertEqual(chk(atx, "dynamics.state"), set(("omega", "theta")))
|
|
88
|
+
self.assertEqual(chk(atx, "dynamics.input"), set(("Tg",)))
|
|
89
|
+
|
|
90
|
+
cons = pbx.constraints
|
|
91
|
+
self.assertEqual(cons["constraints"], [])
|
|
92
|
+
self.assertEqual(len(cons["bounds"]), len(atx["solver.var"]))
|
|
93
|
+
|
|
94
|
+
def test_slide_crank_dxdt_zero(self):
|
|
95
|
+
sm = SliderCrank(Tg=0)
|
|
96
|
+
pbx = ProblemExec(sm, {"dxdt": 0})
|
|
97
|
+
atx = pbx.ref_attrs
|
|
98
|
+
self.assertEqual(chk(atx, "solver.var"), set())
|
|
99
|
+
self.assertEqual(chk(atx, "solver.obj"), set())
|
|
100
|
+
self.assertEqual(chk(atx, "solver.ineq"), set())
|
|
101
|
+
self.assertEqual(chk(atx, "solver.eq"), set())
|
|
102
|
+
self.assertEqual(chk(atx, "dynamics.output"), set())
|
|
103
|
+
self.assertEqual(chk(atx, "dynamics.rate"), set(("omega", "theta")))
|
|
104
|
+
self.assertEqual(chk(atx, "dynamics.state"), set(("omega", "theta")))
|
|
105
|
+
self.assertEqual(chk(atx, "dynamics.input"), set(("Tg",)))
|
|
106
|
+
|
|
107
|
+
cons = pbx.constraints
|
|
108
|
+
self.assertEqual(len(cons["constraints"]), 2)
|
|
109
|
+
self.assertEqual(len(cons["bounds"]), 2)
|
|
110
|
+
|
|
111
|
+
def test_slide_crank_design(self):
|
|
112
|
+
sm = SliderCrank(Tg=0)
|
|
113
|
+
pbx = ProblemExec(sm, {"combos": "design,cost", "dxdt": None})
|
|
114
|
+
atx = pbx.ref_attrs
|
|
115
|
+
self.assertEqual(
|
|
116
|
+
chk(atx, "solver.var"),
|
|
117
|
+
set(("Lo", "Rc", "Ro", "x_offset", "y_offset")),
|
|
118
|
+
)
|
|
119
|
+
self.assertEqual(chk(atx, "solver.obj"), set(("cost_slv",)))
|
|
120
|
+
self.assertEqual(
|
|
121
|
+
chk(atx, "solver.ineq"),
|
|
122
|
+
set(("crank_pos_slv", "gear_pos_slv", "motor_pos_slv")),
|
|
123
|
+
)
|
|
124
|
+
self.assertEqual(chk(atx, "solver.eq"), set(()))
|
|
125
|
+
self.assertEqual(chk(atx, "dynamics.output"), set())
|
|
126
|
+
self.assertEqual(chk(atx, "dynamics.rate"), set())
|
|
127
|
+
self.assertEqual(chk(atx, "dynamics.state"), set())
|
|
128
|
+
self.assertEqual(chk(atx, "dynamics.input"), set())
|
|
129
|
+
|
|
130
|
+
cons = pbx.constraints
|
|
131
|
+
self.assertEqual(len(cons["constraints"]), 4)
|
|
132
|
+
self.assertEqual(len(cons["bounds"]), 5)
|
|
133
|
+
|
|
134
|
+
def test_slide_crank_design_one_match(self):
|
|
135
|
+
sm = SliderCrank(Tg=0)
|
|
136
|
+
pbx = ProblemExec(sm, {"combos": "design", "dxdt": None, "both_match": False})
|
|
137
|
+
atx = pbx.ref_attrs
|
|
138
|
+
self.assertEqual(
|
|
139
|
+
chk(atx, "solver.var"),
|
|
140
|
+
set(("Lo", "Rc", "Ro", "x_offset", "y_offset", "X_spring_center")),
|
|
141
|
+
)
|
|
142
|
+
self.assertEqual(chk(atx, "solver.obj"), set(("cost_slv", "sym_slv")))
|
|
143
|
+
self.assertEqual(
|
|
144
|
+
chk(atx, "solver.ineq"),
|
|
145
|
+
set(("crank_pos_slv", "gear_pos_slv", "motor_pos_slv", "size")),
|
|
146
|
+
)
|
|
147
|
+
self.assertEqual(chk(atx, "solver.eq"), set(("gear_speed_slv", "range_slv")))
|
|
148
|
+
self.assertEqual(chk(atx, "dynamics.output"), set())
|
|
149
|
+
self.assertEqual(chk(atx, "dynamics.rate"), set())
|
|
150
|
+
self.assertEqual(chk(atx, "dynamics.state"), set())
|
|
151
|
+
self.assertEqual(chk(atx, "dynamics.input"), set())
|
|
152
|
+
|
|
153
|
+
cons = pbx.constraints
|
|
154
|
+
self.assertEqual(len(cons["constraints"]), 7)
|
|
155
|
+
self.assertEqual(len(cons["bounds"]), 6)
|
|
156
|
+
|
|
157
|
+
def test_slide_crank_design_slv_design(self):
|
|
158
|
+
sm = SliderCrank(Tg=0)
|
|
159
|
+
pbx = ProblemExec(sm, {"combos": "design", "slv_vars": "*slv", "dxdt": None})
|
|
160
|
+
atx = pbx.ref_attrs
|
|
161
|
+
self.assertEqual(chk(atx, "solver.var"), set())
|
|
162
|
+
self.assertEqual(chk(atx, "solver.obj"), set(()))
|
|
163
|
+
self.assertEqual(
|
|
164
|
+
chk(atx, "solver.ineq"),
|
|
165
|
+
set(("crank_pos_slv", "gear_pos_slv", "motor_pos_slv")),
|
|
166
|
+
)
|
|
167
|
+
self.assertEqual(chk(atx, "solver.eq"), set(()))
|
|
168
|
+
self.assertEqual(chk(atx, "dynamics.output"), set())
|
|
169
|
+
self.assertEqual(chk(atx, "dynamics.rate"), set())
|
|
170
|
+
self.assertEqual(chk(atx, "dynamics.state"), set())
|
|
171
|
+
self.assertEqual(chk(atx, "dynamics.input"), set())
|
|
172
|
+
|
|
173
|
+
cons = pbx.constraints
|
|
174
|
+
self.assertEqual(len(cons["constraints"]), 3)
|
|
175
|
+
self.assertEqual(len(cons["bounds"]), 0)
|
|
176
|
+
|
|
177
|
+
def test_slide_crank_design_slv(self):
|
|
178
|
+
sm = SliderCrank(Tg=0)
|
|
179
|
+
pbx = ProblemExec(
|
|
180
|
+
sm,
|
|
181
|
+
{
|
|
182
|
+
"combos": "design,cost,speed_goal,range_goal",
|
|
183
|
+
"ign_combos": "max*",
|
|
184
|
+
"slv_vars": "*slv",
|
|
185
|
+
"dxdt": None,
|
|
186
|
+
},
|
|
187
|
+
)
|
|
188
|
+
atx = pbx.ref_attrs
|
|
189
|
+
self.assertEqual(chk(atx, "solver.var"), set())
|
|
190
|
+
self.assertEqual(chk(atx, "solver.obj"), set(("cost_slv",)))
|
|
191
|
+
self.assertEqual(
|
|
192
|
+
chk(atx, "solver.ineq"),
|
|
193
|
+
set(("crank_pos_slv", "gear_pos_slv", "motor_pos_slv")),
|
|
194
|
+
)
|
|
195
|
+
self.assertEqual(chk(atx, "solver.eq"), set(("gear_speed_slv", "range_slv")))
|
|
196
|
+
self.assertEqual(chk(atx, "dynamics.output"), set())
|
|
197
|
+
self.assertEqual(chk(atx, "dynamics.rate"), set())
|
|
198
|
+
self.assertEqual(chk(atx, "dynamics.state"), set())
|
|
199
|
+
self.assertEqual(chk(atx, "dynamics.input"), set())
|
|
200
|
+
|
|
201
|
+
cons = pbx.constraints
|
|
202
|
+
self.assertEqual(len(cons["constraints"]), 5)
|
|
203
|
+
self.assertEqual(len(cons["bounds"]), len(atx["solver.var"]))
|
|
204
|
+
|
|
205
|
+
def test_slide_crank_design_slv_one_match(self):
|
|
206
|
+
sm = SliderCrank(Tg=0)
|
|
207
|
+
pbx = ProblemExec(
|
|
208
|
+
sm,
|
|
209
|
+
{
|
|
210
|
+
"combos": "design",
|
|
211
|
+
"ign_combos": "max*",
|
|
212
|
+
"slv_vars": "*slv",
|
|
213
|
+
"dxdt": None,
|
|
214
|
+
"both_match": False,
|
|
215
|
+
},
|
|
216
|
+
)
|
|
217
|
+
atx = pbx.ref_attrs
|
|
218
|
+
self.assertEqual(
|
|
219
|
+
chk(atx, "solver.var"),
|
|
220
|
+
set(("Lo", "Rc", "Ro", "x_offset", "y_offset")),
|
|
221
|
+
)
|
|
222
|
+
self.assertEqual(chk(atx, "solver.obj"), set(("cost_slv", "sym_slv")))
|
|
223
|
+
self.assertEqual(
|
|
224
|
+
chk(atx, "solver.ineq"),
|
|
225
|
+
set(("crank_pos_slv", "gear_pos_slv", "motor_pos_slv")),
|
|
226
|
+
)
|
|
227
|
+
self.assertEqual(chk(atx, "solver.eq"), set(("gear_speed_slv", "range_slv")))
|
|
228
|
+
self.assertEqual(chk(atx, "dynamics.output"), set())
|
|
229
|
+
self.assertEqual(chk(atx, "dynamics.rate"), set())
|
|
230
|
+
self.assertEqual(chk(atx, "dynamics.state"), set())
|
|
231
|
+
self.assertEqual(chk(atx, "dynamics.input"), set())
|
|
232
|
+
|
|
233
|
+
cons = pbx.constraints
|
|
234
|
+
self.assertEqual(len(cons["constraints"]), 6)
|
|
235
|
+
self.assertEqual(len(cons["bounds"]), len(atx["solver.var"]))
|
|
236
|
+
|
|
237
|
+
def test_slide_crank_add_var(self):
|
|
238
|
+
sc = SliderCrank()
|
|
239
|
+
out = sc.run(
|
|
240
|
+
combos="design,speed_goal,range_goal",
|
|
241
|
+
slv_vars="*",
|
|
242
|
+
revert_last=False,
|
|
243
|
+
add_vars="*gear*",
|
|
244
|
+
both_match=False,
|
|
245
|
+
)
|
|
246
|
+
# self.assertEqual(len(out['gear_speed_slv']),0)
|
|
247
|
+
print(out)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class TestContextExits(unittest.TestCase):
|
|
251
|
+
def tearDown(self) -> None:
|
|
252
|
+
self.assertFalse(
|
|
253
|
+
hasattr(ProblemExec.class_cache, "session"), msg="not cleaned!"
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
def test_error_exit(self):
|
|
257
|
+
tst = SimpleContext()
|
|
258
|
+
|
|
259
|
+
class TestError(Exception):
|
|
260
|
+
pass
|
|
261
|
+
|
|
262
|
+
with self.assertRaises(TestError): # we should get an error
|
|
263
|
+
with ProblemExec(tst) as pb1:
|
|
264
|
+
tst.set_rand()
|
|
265
|
+
with ProblemExec(tst, level_name="2") as pb2:
|
|
266
|
+
tst.set_rand()
|
|
267
|
+
with ProblemExec(tst) as pb3:
|
|
268
|
+
tst.set_rand()
|
|
269
|
+
raise TestError(
|
|
270
|
+
"pocket-sand"
|
|
271
|
+
) # TODO: INSERT KING OF THE HILL REFERENCE
|
|
272
|
+
self.assertFalse(hasattr(ProblemExec.class_cache, "session"))
|
|
273
|
+
|
|
274
|
+
def test_context_singularity(self):
|
|
275
|
+
tst = SimpleContext()
|
|
276
|
+
|
|
277
|
+
with ProblemExec(tst) as pb1:
|
|
278
|
+
self.assertEqual(pb1, tst.last_context)
|
|
279
|
+
self.assertTrue(pb1.entered)
|
|
280
|
+
self.assertFalse(pb1.exited)
|
|
281
|
+
with ProblemExec(tst, level_name="2") as pb2:
|
|
282
|
+
self.assertIs(pb1, pb2)
|
|
283
|
+
self.assertTrue(pb1.entered)
|
|
284
|
+
self.assertFalse(pb1.exited)
|
|
285
|
+
with ProblemExec(tst) as pb3:
|
|
286
|
+
self.assertIs(pb1, pb3)
|
|
287
|
+
self.assertTrue(pb3.entered)
|
|
288
|
+
self.assertFalse(pb3.exited)
|
|
289
|
+
pb3.exit_to_level("top", revert=True)
|
|
290
|
+
raise Exception("Wrong Level")
|
|
291
|
+
raise Exception("Wrong Level")
|
|
292
|
+
raise Exception("Wrong Level")
|
|
293
|
+
self.assertEqual(pb1, tst.last_context)
|
|
294
|
+
self.assertTrue(pb1.entered)
|
|
295
|
+
self.assertTrue(pb1.exited)
|
|
296
|
+
|
|
297
|
+
def test_exit_top(self):
|
|
298
|
+
tst = SimpleContext()
|
|
299
|
+
|
|
300
|
+
with ProblemExec(tst) as pb1:
|
|
301
|
+
tst.set_rand()
|
|
302
|
+
with ProblemExec(tst, level_name="2") as pb2:
|
|
303
|
+
tst.set_rand()
|
|
304
|
+
with ProblemExec(tst) as pb3:
|
|
305
|
+
tst.set_rand()
|
|
306
|
+
pb3.exit_to_level("top", revert=True)
|
|
307
|
+
raise Exception("Wrong Level")
|
|
308
|
+
raise Exception("Wrong Level")
|
|
309
|
+
raise Exception("Wrong Level")
|
|
310
|
+
self.assertEqual(tst.one, 1)
|
|
311
|
+
self.assertEqual(tst.two, 2)
|
|
312
|
+
|
|
313
|
+
def test_exit_top_with_state(self):
|
|
314
|
+
tst = SimpleContext()
|
|
315
|
+
|
|
316
|
+
with ProblemExec(tst, level_name="super") as pb1:
|
|
317
|
+
tst.set_rand()
|
|
318
|
+
with ProblemExec(tst, level_name="2") as pb2:
|
|
319
|
+
tst.set_rand()
|
|
320
|
+
with ProblemExec(tst) as pb3:
|
|
321
|
+
tst.set_rand()
|
|
322
|
+
final_one = tst.one
|
|
323
|
+
final_two = tst.two
|
|
324
|
+
pb3.exit_to_level("top", revert=False)
|
|
325
|
+
raise Exception("Wrong Level")
|
|
326
|
+
raise Exception("Wrong Level")
|
|
327
|
+
raise Exception("Wrong Level")
|
|
328
|
+
self.assertEqual(tst.one, final_one)
|
|
329
|
+
self.assertEqual(tst.two, final_two)
|
|
330
|
+
|
|
331
|
+
def test_exit_2_with_state(self):
|
|
332
|
+
tst = SimpleContext()
|
|
333
|
+
|
|
334
|
+
with ProblemExec(tst) as pb1:
|
|
335
|
+
tst.set_rand()
|
|
336
|
+
with ProblemExec(tst, level_name="2") as pb2:
|
|
337
|
+
tst.set_rand()
|
|
338
|
+
with ProblemExec(tst) as pb3:
|
|
339
|
+
tst.set_rand()
|
|
340
|
+
final_one = tst.one
|
|
341
|
+
final_two = tst.two
|
|
342
|
+
pb3.exit_to_level("2", revert=False)
|
|
343
|
+
raise Exception("Wrong Level")
|
|
344
|
+
self.assertEqual(tst.one, final_one)
|
|
345
|
+
self.assertEqual(tst.two, final_two)
|
|
346
|
+
self.assertEqual(tst.one, 1)
|
|
347
|
+
self.assertEqual(tst.two, 2)
|
|
348
|
+
|
|
349
|
+
def test_exit_2_wo_state(self):
|
|
350
|
+
tst = SimpleContext()
|
|
351
|
+
with ProblemExec(tst) as pb1:
|
|
352
|
+
tst.set_rand()
|
|
353
|
+
final_one = tst.one
|
|
354
|
+
final_two = tst.two
|
|
355
|
+
with ProblemExec(tst, level_name="2") as pb2:
|
|
356
|
+
tst.set_rand()
|
|
357
|
+
with ProblemExec(tst) as pb3:
|
|
358
|
+
tst.set_rand()
|
|
359
|
+
pb3.exit_to_level("2", revert=True)
|
|
360
|
+
raise Exception("Wrong Level")
|
|
361
|
+
self.assertEqual(tst.one, final_one)
|
|
362
|
+
self.assertEqual(tst.two, final_two)
|
|
363
|
+
self.assertEqual(tst.one, 1)
|
|
364
|
+
self.assertEqual(tst.two, 2)
|
|
365
|
+
|
|
366
|
+
def test_exit_with_state(self):
|
|
367
|
+
tst = SimpleContext()
|
|
368
|
+
|
|
369
|
+
with ProblemExec(tst) as pb1:
|
|
370
|
+
tst.set_rand()
|
|
371
|
+
mid_one = tst.one
|
|
372
|
+
mid_two = tst.two
|
|
373
|
+
with ProblemExec(tst, level_name="2") as pb2:
|
|
374
|
+
tst.set_rand()
|
|
375
|
+
final_one = tst.one
|
|
376
|
+
final_two = tst.two
|
|
377
|
+
with ProblemExec(tst) as pb3:
|
|
378
|
+
tst.set_rand()
|
|
379
|
+
final_one = tst.one
|
|
380
|
+
final_two = tst.two
|
|
381
|
+
pb3.exit_with_state()
|
|
382
|
+
raise Exception("Wrong Level")
|
|
383
|
+
self.assertEqual(tst.one, final_one)
|
|
384
|
+
self.assertEqual(tst.two, final_two)
|
|
385
|
+
self.assertEqual(tst.one, mid_one)
|
|
386
|
+
self.assertEqual(tst.two, mid_two)
|
|
387
|
+
self.assertEqual(tst.one, 1)
|
|
388
|
+
self.assertEqual(tst.two, 2)
|
|
389
|
+
|
|
390
|
+
def test_exit_and_revert(self):
|
|
391
|
+
tst = SimpleContext()
|
|
392
|
+
|
|
393
|
+
with ProblemExec(tst) as pb1:
|
|
394
|
+
tst.set_rand()
|
|
395
|
+
mid_one = tst.one
|
|
396
|
+
mid_two = tst.two
|
|
397
|
+
with ProblemExec(tst, level_name="2") as pb2:
|
|
398
|
+
tst.set_rand()
|
|
399
|
+
final_one = tst.one
|
|
400
|
+
final_two = tst.two
|
|
401
|
+
with ProblemExec(tst) as pb3:
|
|
402
|
+
tst.set_rand()
|
|
403
|
+
|
|
404
|
+
pb3.exit_and_revert()
|
|
405
|
+
raise Exception("Wrong Level")
|
|
406
|
+
self.assertEqual(tst.one, final_one)
|
|
407
|
+
self.assertEqual(tst.two, final_two)
|
|
408
|
+
self.assertEqual(tst.one, mid_one)
|
|
409
|
+
self.assertEqual(tst.two, mid_two)
|
|
410
|
+
self.assertEqual(tst.one, 1)
|
|
411
|
+
self.assertEqual(tst.two, 2)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from engforge import *
|
|
2
|
+
|
|
3
|
+
import unittest
|
|
4
|
+
import attrs
|
|
5
|
+
import random
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_obj(sys, prob):
|
|
9
|
+
# print('obj',sys, prob)
|
|
10
|
+
comp = sys
|
|
11
|
+
assert comp is not prob.system, f"{comp} is problems system, in sub comp"
|
|
12
|
+
return comp.val - comp.comp_val
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_con(sys, prob):
|
|
16
|
+
# print('con',sys, prob)
|
|
17
|
+
comp = sys
|
|
18
|
+
assert comp is not prob.system, f"{comp} is problems system, in sub comp"
|
|
19
|
+
return -1
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_zero(sys, prob):
|
|
23
|
+
# print('zero',sys, prob)
|
|
24
|
+
comp = sys
|
|
25
|
+
assert comp is not prob.system, f"{comp} is problems system, in sub comp"
|
|
26
|
+
return 0
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@forge
|
|
30
|
+
class TestComp(Component):
|
|
31
|
+
val = attrs.field(factory=random.random, type=float)
|
|
32
|
+
val_var = Solver.declare_var("val")
|
|
33
|
+
|
|
34
|
+
comp_val = attrs.field(default=0, type=float)
|
|
35
|
+
slv_var = Solver.declare_var("comp_val")
|
|
36
|
+
slv_var.add_var_constraint(1.0, kind="max")
|
|
37
|
+
slv_var.add_var_constraint(test_con, kind="min")
|
|
38
|
+
|
|
39
|
+
var_obj = Solver.objective(test_obj)
|
|
40
|
+
var_ineq = Solver.con_ineq(test_zero)
|
|
41
|
+
var_2ineq = Solver.con_ineq(test_zero, test_zero)
|
|
42
|
+
var_eq = Solver.con_eq(test_zero)
|
|
43
|
+
var_2eq = Solver.con_eq(test_zero, test_zero)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@forge
|
|
47
|
+
class DeepComp(TestComp):
|
|
48
|
+
comp = Slot.define(TestComp, default_ok=False, none_ok=True)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@forge
|
|
52
|
+
class DeepSys(System):
|
|
53
|
+
comp = Slot.define(DeepComp)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class TestDeep(unittest.TestCase):
|
|
57
|
+
def test_one_deep(self):
|
|
58
|
+
comp = DeepComp(comp=None)
|
|
59
|
+
sys = DeepSys(comp=comp)
|
|
60
|
+
|
|
61
|
+
sys.run(combos="default", slv_vars="*")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
comp = DeepComp(comp=None)
|
|
66
|
+
sys = DeepSys(comp=comp)
|
|
67
|
+
# sys.change_all_log_lvl(1)
|
|
68
|
+
sys.run(combos="default", slv_vars="*")
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from engforge._testing_components import *
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestSliderCrank(unittest.TestCase):
|
|
8
|
+
def test_optimization(self):
|
|
9
|
+
sc = SliderCrank()
|
|
10
|
+
|
|
11
|
+
out = sc.run(combos="design", slv_vars="*")
|
|
12
|
+
|
|
13
|
+
def test_design_multiobj(self):
|
|
14
|
+
sc = SliderCrank()
|
|
15
|
+
|
|
16
|
+
out = sc.run(
|
|
17
|
+
combos="design,*goal,*sym",
|
|
18
|
+
slv_vars="*",
|
|
19
|
+
k_spring=10,
|
|
20
|
+
revert_last=False,
|
|
21
|
+
revert_every=False,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
out = out["output"][0]
|
|
25
|
+
Yobj = set(out["Yobj"])
|
|
26
|
+
self.assertEqual(set(("sym_slv",)), Yobj)
|
|
27
|
+
|
|
28
|
+
self.assertAlmostEqual(sc.dx_goal, 0.0, places=3)
|
|
29
|
+
self.assertAlmostEqual(sc.ds_goal, 0.0, places=3)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# BUG:
|
|
33
|
+
# ======================================================================
|
|
34
|
+
# FAIL: test_design_objs (test_slider_crank.TestSliderCrank)
|
|
35
|
+
# ----------------------------------------------------------------------
|
|
36
|
+
# Traceback (most recent call last):
|
|
37
|
+
# File "/mnt/c/Users/Sup/Ottermatics Dropbox/Ottermatics/engforge/engforge/test/test_slider_crank.py", line 34, in test_design_objs
|
|
38
|
+
# self.assertEqual(set(('sym_slv',)),Yobj)
|
|
39
|
+
# AssertionError: Items in the second set but not the first:
|
|
40
|
+
# 'cost_slv'
|
|
41
|
+
# def test_design_objs(self):
|
|
42
|
+
# sc = SliderCrank()
|
|
43
|
+
#
|
|
44
|
+
# out = sc.run(combos='design,*goal,*sym,*cost',slv_vars='*',k_spring=10,revert_last=False,revert_every=False)
|
|
45
|
+
#
|
|
46
|
+
# out = out['output'][0]
|
|
47
|
+
# Yobj = set(out['Yobj'])
|
|
48
|
+
# self.assertEqual(set(('sym_slv',)),Yobj)
|
|
49
|
+
#
|
|
50
|
+
# self.assertAlmostEqual(sc.dx_goal,0.0,places=3)
|
|
51
|
+
# self.assertAlmostEqual(sc.ds_goal,0.0,places=3)
|