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.
Files changed (69) hide show
  1. engforge/__init__.py +26 -0
  2. engforge/_testing_components.py +864 -0
  3. engforge/analysis.py +257 -0
  4. engforge/attr_dynamics.py +222 -0
  5. engforge/attr_plotting.py +811 -0
  6. engforge/attr_signals.py +116 -0
  7. engforge/attr_slots.py +211 -0
  8. engforge/attr_solver.py +443 -0
  9. engforge/attributes.py +326 -0
  10. engforge/common.py +76 -0
  11. engforge/component_collections.py +276 -0
  12. engforge/components.py +55 -0
  13. engforge/configuration.py +673 -0
  14. engforge/dataframe.py +185 -0
  15. engforge/datastores/__init__.py +116 -0
  16. engforge/datastores/data.py +519 -0
  17. engforge/datastores/gdocs.py +2650 -0
  18. engforge/datastores/reporting.py +935 -0
  19. engforge/datastores/secrets.py +549 -0
  20. engforge/dynamics.py +662 -0
  21. engforge/eng/__init__.py +0 -0
  22. engforge/eng/costs.py +1459 -0
  23. engforge/eng/fluid_material.py +279 -0
  24. engforge/eng/geometry.py +1060 -0
  25. engforge/eng/pipes.py +1211 -0
  26. engforge/eng/prediction.py +366 -0
  27. engforge/eng/solid_materials.py +445 -0
  28. engforge/eng/structure.py +2228 -0
  29. engforge/eng/structure_beams.py +821 -0
  30. engforge/eng/thermodynamics.py +271 -0
  31. engforge/engforge_attributes.py +380 -0
  32. engforge/env_var.py +214 -0
  33. engforge/locations.py +18 -0
  34. engforge/logging.py +290 -0
  35. engforge/patterns.py +449 -0
  36. engforge/problem_context.py +2251 -0
  37. engforge/properties.py +501 -0
  38. engforge/reporting.py +595 -0
  39. engforge/solveable.py +964 -0
  40. engforge/solver.py +316 -0
  41. engforge/solver_utils.py +726 -0
  42. engforge/system.py +143 -0
  43. engforge/system_reference.py +299 -0
  44. engforge/tabulation.py +288 -0
  45. engforge/test/__init__.py +2 -0
  46. engforge/test/_pre_test_structures.py +221 -0
  47. engforge/test/report_testing.py +158 -0
  48. engforge/test/test_airfilter.py +91 -0
  49. engforge/test/test_analysis.py +3 -0
  50. engforge/test/test_comp_iter.py +196 -0
  51. engforge/test/test_composition.py +139 -0
  52. engforge/test/test_costs.py +338 -0
  53. engforge/test/test_dynamics.py +109 -0
  54. engforge/test/test_dynamics_spaces.py +39 -0
  55. engforge/test/test_four_bar.py +97 -0
  56. engforge/test/test_modules.py +72 -0
  57. engforge/test/test_performance.py +93 -0
  58. engforge/test/test_pipes.py +49 -0
  59. engforge/test/test_problem.py +411 -0
  60. engforge/test/test_problem_deepscoping.py +68 -0
  61. engforge/test/test_slider_crank.py +51 -0
  62. engforge/test/test_solver.py +343 -0
  63. engforge/test/test_tabulation.py +233 -0
  64. engforge/typing.py +92 -0
  65. engforge-0.3.0.dist-info/METADATA +392 -0
  66. engforge-0.3.0.dist-info/RECORD +69 -0
  67. engforge-0.3.0.dist-info/WHEEL +5 -0
  68. engforge-0.3.0.dist-info/licenses/LICENSE +7 -0
  69. engforge-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,91 @@
1
+ """tests airfilter system operation by solving for airflow between filter and and fan"""
2
+
3
+ import unittest
4
+
5
+ from engforge.configuration import forge
6
+ from engforge.system import System
7
+ from engforge.components import Component
8
+ from engforge.attr_dynamics import Time
9
+ from engforge.attr_solver import Solver
10
+ from engforge.attr_signals import Signal
11
+ from engforge.attr_slots import Slot
12
+ from engforge.properties import *
13
+ from engforge.attr_plotting import *
14
+ from engforge.analysis import Analysis
15
+
16
+ from engforge._testing_components import *
17
+
18
+ from scipy.optimize import curve_fit, least_squares
19
+ import numpy as np
20
+ from matplotlib.pyplot import *
21
+
22
+ import attrs
23
+
24
+
25
+ class TestFilterSystem(unittest.TestCase):
26
+ def setUp(self):
27
+ self.af = Airfilter()
28
+
29
+ def test_plot(self):
30
+ N = 10
31
+ self.af.run(throttle=np.linspace(0, 1, N), combos="*", slv_vars="*")
32
+ fig = self.af.flow_curve()
33
+ self.assertIsNotNone(fig)
34
+
35
+ df = self.af.dataframe
36
+ self.assertEqual(df.shape[0], N)
37
+
38
+ dfv = self.af.dataframe_variants
39
+ self.assertEqual(dfv.shape[0], N)
40
+ self.assertIn("w", dfv.columns)
41
+ self.assertIn("throttle", dfv.columns)
42
+
43
+ dfc = self.af.dataframe_constants
44
+ self.assertIsInstance(dfc, dict)
45
+
46
+ self.assertEqual(df.shape[1], len(dfc) + dfv.shape[1])
47
+
48
+
49
+ class TestAnalysis(unittest.TestCase):
50
+ def setUp(self):
51
+ self.af = AirFilterAnalysis()
52
+
53
+ def test_plot(self):
54
+ self.af.run(throttle=np.linspace(0, 1, 10), combos="*", slv_vars="*")
55
+ fig = self.af.system.flow_curve()
56
+ ofig = self.af._stored_plots["airfilteranalysis.airfilter.flow_curve"]
57
+ print(fig)
58
+ print(ofig)
59
+
60
+ self.assertIsNotNone(fig)
61
+ self.assertIsNotNone(ofig)
62
+
63
+
64
+ # #Run the system
65
+ # from matplotlib.pylab import *
66
+ #
67
+ #
68
+ #
69
+ # fan = Fan()
70
+ # filt = Filter()
71
+ # af = Airfilter(fan=fan,filt=filt)
72
+ #
73
+ # change_all_log_levels(af,20) #info
74
+ #
75
+ # af.run(throttle=list(np.arange(0.1,1.1,0.1)),combos='*')
76
+ #
77
+ # df = af.dataframe
78
+ #
79
+ # fig,(ax,ax2) = subplots(2,1)
80
+ # ax.plot(df.throttle*100,df.w,'k--',label='flow')
81
+ # ax2.plot(df.throttle*100,df.filt_dp_filter,label='filter')
82
+ # ax2.plot(df.throttle*100,df.dp_parasitic,label='parasitic')
83
+ # ax2.plot(df.throttle*100,df.fan_dp_fan,label='fan')
84
+ # ax.legend(loc='upper right')
85
+ # ax.set_title('flow')
86
+ # ax.grid()
87
+ # ax2.legend()
88
+ # ax2.grid()
89
+ # ax2.set_title(f'pressure')
90
+ # ax2.set_xlabel(f'throttle%') dfv = self.af.dataframe_variants
91
+ # self.assertEqual(dfv.shape[0],N)
@@ -0,0 +1,3 @@
1
+ from engforge.test.test_airfilter import *
2
+ from engforge.analysis import Analysis
3
+ from engforge.attr_slots import Slot
@@ -0,0 +1,196 @@
1
+ from engforge.components import Component
2
+ from engforge.component_collections import ComponentDict, ComponentIter
3
+ from engforge.system import System
4
+ from engforge.attr_slots import Slot
5
+ from engforge.configuration import forge
6
+ from engforge.tabulation import system_property
7
+
8
+ import attrs, attr
9
+
10
+ import random
11
+ import unittest
12
+ import itertools
13
+
14
+ # from engforge.logging import LoggingMixin, change_all_log_levels
15
+ # change_all_log_levels(10)
16
+
17
+
18
+ @forge
19
+ class TestConfig(Component):
20
+ attrs_prop: float = attr.ib(1.0)
21
+ attrs_str: str = attr.ib("hey now")
22
+
23
+ @system_property
24
+ def test_one(self) -> int:
25
+ return 1
26
+
27
+ @system_property(stochastic=True)
28
+ def test_two(self) -> float:
29
+ return random.random()
30
+
31
+ @system_property
32
+ def test_three(self) -> int:
33
+ return 2
34
+
35
+ @system_property(stochastic=True)
36
+ def test_four(self) -> float:
37
+ return random.random()
38
+
39
+
40
+ @forge
41
+ class DictComp(ComponentDict):
42
+ component_type = TestConfig
43
+
44
+
45
+ @forge
46
+ class ListComp(ComponentDict):
47
+ component_type = TestConfig
48
+
49
+
50
+ @forge
51
+ class WideSystem(System):
52
+ cdict = Slot.define_iterator(DictComp)
53
+ citer = Slot.define_iterator(ComponentIter)
54
+
55
+
56
+ @forge
57
+ class NarrowSystem(System):
58
+ cdict = Slot.define_iterator(DictComp, wide=False)
59
+ citer = Slot.define_iterator(ComponentIter, wide=False)
60
+
61
+
62
+ class TestWide(unittest.TestCase):
63
+ def setUp(self):
64
+ self.item_in = {i: "hey" * (i + 1) for i in range(5)}
65
+
66
+ lc = ListComp(component_type=TestConfig)
67
+ for i, v in self.item_in.items():
68
+ lc[i] = TestConfig(name=f"citer_{i}", attrs_prop=i, attrs_str=v)
69
+
70
+ dc = DictComp(component_type=TestConfig)
71
+ for i, v in self.item_in.items():
72
+ dc[v] = TestConfig(name=f"cdict_{i}", attrs_prop=i, attrs_str=v)
73
+
74
+ self.system = WideSystem(cdict=dc, citer=lc)
75
+
76
+ def test_keys(self):
77
+ self.assertFalse(len(self.system.dataframe))
78
+
79
+ dat = self.system.data_dict
80
+
81
+ all_keys = set(dat.keys())
82
+
83
+ comps = {
84
+ "cdict": ["hey" * (i + 1) for i in range(5)],
85
+ "citer": list(range(5)),
86
+ }
87
+
88
+ props = [
89
+ "test_one",
90
+ "test_two",
91
+ "test_three",
92
+ "test_four",
93
+ "name",
94
+ "attrs_prop",
95
+ "attrs_str",
96
+ ]
97
+
98
+ should_keys = set()
99
+ dataframe_keys = set()
100
+ for ck, vlist in comps.items():
101
+ for v in vlist:
102
+ for p in props:
103
+ tkn = f"{ck}.{v}.{p}"
104
+ should_keys.add(tkn)
105
+ dataframe_keys.add(tkn)
106
+
107
+ sys_key = set(self.system.data_dict.keys())
108
+ mtch = should_keys.issubset(sys_key)
109
+ self.system.debug(f"keys: {should_keys} vs {sys_key}")
110
+ self.assertTrue(mtch, msg=f"missing keys: {should_keys - sys_key}")
111
+
112
+ # save the data to table
113
+ self.system.run(revert_last=False, revert_every=False, save_on_exit=True)
114
+
115
+ df = self.system.last_context.dataframe
116
+ self.assertTrue(len(df) == 1, msg=f"len: {len(df)}|\n{str(df)}")
117
+ self.assertTrue(dataframe_keys.issubset(set(df.iloc[0].keys())))
118
+ self.assertTrue(dataframe_keys.issubset(set(df.keys())))
119
+
120
+
121
+ class TestNarrow(unittest.TestCase):
122
+ def setUp(self):
123
+ self.item_in = {i: "hey" * (i + 1) for i in range(5)}
124
+
125
+ lc = ListComp(component_type=TestConfig)
126
+ for i, v in self.item_in.items():
127
+ lc[i] = TestConfig(name=f"citer_{i}", attrs_prop=i, attrs_str=v)
128
+
129
+ dc = DictComp(component_type=TestConfig)
130
+ for i, v in self.item_in.items():
131
+ dc[v] = TestConfig(name=f"cdict_{i}", attrs_prop=i, attrs_str=v)
132
+
133
+ self.system = NarrowSystem(cdict=dc, citer=lc)
134
+
135
+ def test_keys(self):
136
+ self.assertFalse(len(self.system.dataframe) > 0)
137
+
138
+ dat = self.system.data_dict
139
+
140
+ all_keys = set(dat.keys())
141
+
142
+ comps = {
143
+ "cdict": ["hey" * (i + 1) for i in range(5)],
144
+ "citer": list(range(5)),
145
+ }
146
+
147
+ props = [
148
+ "test_one",
149
+ "test_two",
150
+ "test_three",
151
+ "test_four",
152
+ "name",
153
+ "attrs_prop",
154
+ "attrs_str",
155
+ ]
156
+
157
+ should_keys = set()
158
+ dataframe_keys = set()
159
+ for ck, vlist in comps.items():
160
+ # for v in vlist:
161
+ for p in props:
162
+ tkn = f"{ck}.{p}"
163
+ should_keys.add(tkn)
164
+ dataframe_keys.add(tkn)
165
+
166
+ sys_key = set(self.system.data_dict.keys())
167
+ mtch = should_keys.issubset(sys_key)
168
+ self.system.info(f"keys: {should_keys} vs {sys_key}")
169
+ self.assertTrue(mtch, msg=f"missing keys: {should_keys - sys_key}")
170
+
171
+ # save the data to table
172
+ self.system.run()
173
+
174
+ df = self.system.last_context.dataframe
175
+ self.assertTrue(len(df) == 5 ** len(comps))
176
+ self.assertTrue(dataframe_keys.issubset(set(df.iloc[0].keys())))
177
+ self.assertTrue(dataframe_keys.issubset(set(df.keys())))
178
+
179
+ # test item existence
180
+ v1 = set(self.system.dataframe["cdict.current_item"])
181
+ v2 = set(comps["cdict"])
182
+
183
+ self.assertEqual(v1, v2)
184
+
185
+ d1 = set(self.system.dataframe["citer.current_item"])
186
+ d2 = set(comps["citer"])
187
+
188
+ self.assertEqual(d1, d2)
189
+
190
+ dvs = self.system.dataframe["cdict.current_item"]
191
+ cvs = self.system.dataframe["citer.current_item"]
192
+
193
+ al = set(zip(dvs, cvs))
194
+ sh = set(itertools.product(v2, d2))
195
+
196
+ self.assertEqual(al, sh)
@@ -0,0 +1,139 @@
1
+ import unittest
2
+
3
+ from engforge.configuration import forge
4
+ from engforge.system import System
5
+ from engforge.components import Component
6
+ from engforge.attr_dynamics import Time
7
+ from engforge.attr_solver import Solver
8
+ from engforge.attr_signals import Signal
9
+ from engforge.attr_slots import Slot
10
+ from engforge.properties import *
11
+ from engforge.problem_context import ProblemExec
12
+
13
+ import attrs
14
+
15
+
16
+ @forge
17
+ class MockComponent(Component):
18
+ input: float = attrs.field(default=0)
19
+ # use to test input from system
20
+ aux: float = attrs.field(default=0)
21
+
22
+ comp = Slot.define(Component, none_ok=True)
23
+
24
+ @system_property
25
+ def output(self) -> float:
26
+ return self.input * self.input
27
+
28
+
29
+ def limit_max(system, prb):
30
+ return 4 - system.input
31
+
32
+
33
+ @forge
34
+ class MockSystem(System):
35
+ input: float = attrs.field(default=0)
36
+ output: float = attrs.field(default=0)
37
+
38
+ in2: float = attrs.field(default=1)
39
+
40
+ x: float = attrs.field(default=0)
41
+
42
+ # move system input to component
43
+ pre_sig = Signal.define("comp.input", "input", mode="pre")
44
+ # move component output to system
45
+ post_sig = Signal.define("output", "comp.output", mode="both")
46
+
47
+ Solver.constraint_equality("in_out_diff")
48
+ Solver.constraint_equality("in2out2")
49
+
50
+ var_in = Solver.declare_var("input")
51
+ var_in.add_var_constraint(kind="min", value=0)
52
+ var_in.add_var_constraint(kind="max", value=1)
53
+
54
+ sol2 = Solver.declare_var("in2")
55
+ sol2.add_var_constraint(kind="max", value=limit_max)
56
+ sol2.add_var_constraint(kind="min", value=0)
57
+
58
+ comp = Slot.define(MockComponent)
59
+
60
+ @system_property
61
+ def in_out_diff(self) -> float:
62
+ # Should solve= 0 when in2=input^2
63
+ return self.input + 1 - self.output - self.in2 * 0.1
64
+
65
+ @system_property
66
+ def in2out2(self) -> float:
67
+ return self.in2 - self.input * 2 + self.comp.aux / 10
68
+
69
+ @system_property
70
+ def dxdt(self) -> float:
71
+ # dxdt = (in - in**2)/1000.0
72
+ # Should converge to 1,0,-1
73
+ ans = (self.input - self.in2) / 2
74
+ if ans < 0 and self.input < 0:
75
+ return -1 * ans
76
+ return ans
77
+
78
+
79
+ class TestComposition(unittest.TestCase):
80
+ def setUp(self) -> None:
81
+ self.comp2 = MockComponent()
82
+ self.comp = MockComponent(comp=self.comp2)
83
+ self.system = MockSystem(input=5, comp=self.comp)
84
+
85
+ def test_signals(self):
86
+ self.system.post_sig.signal.mode = "post" # usually its both
87
+
88
+ # Pre Signals Test
89
+ outsys = self.system.output
90
+ outcomp = self.system.comp.output
91
+ sysstart = self.system.input
92
+ compstart = self.system.comp.input
93
+ self.assertNotEqual(sysstart, compstart) # no signals transfering input
94
+
95
+ log.warning(f"test signals: {sysstart} {compstart}| {outsys} {outcomp}")
96
+ with ProblemExec(self.system, {}, post_exec=True, pre_exec=True) as pbx:
97
+ sysend = self.system.input
98
+ compend = self.system.comp.input
99
+ self.assertEqual(sysend, compend) # signals should work as defined
100
+ self.assertEqual(sysstart, sysend) # input should remain the same
101
+ self.assertNotEqual(compstart, compend) # input on comp changes
102
+
103
+ sysstart = self.system.output
104
+ compstart = self.system.comp.output
105
+ self.assertNotEqual(sysstart, compstart) # they aren't aligned
106
+ log.info(f"pre-vert: {sysstart} {compstart}")
107
+
108
+ # preserve changes
109
+ pbx.exit_with_state()
110
+
111
+ # now post signals should be applied
112
+ sysend = self.system.output
113
+ compend = self.system.comp.output
114
+
115
+ log.info(f"final: {sysstart} {compstart}")
116
+
117
+ self.assertEqual(sysend, compend) # signals should work
118
+ self.assertEqual(compstart, compend) # output should change
119
+ self.assertNotEqual(sysstart, sysend) # output should change
120
+
121
+ def test_input_and_run(self):
122
+ self.system.run(**{"comp.aux": 5, "comp.comp.aux": 6})
123
+ self.assertEqual(len(self.system.dataframe), 1, f"wrong run config")
124
+ self.assertEqual(set(self.system.dataframe["comp.aux"]), set([5]))
125
+ self.assertEqual(set(self.system.dataframe["comp.comp.aux"]), set([6]))
126
+
127
+ # internal storage
128
+ # self.assertEqual(set(self.system.comp.dataframe["aux"]), set([5]))
129
+ # self.assertEqual(set(self.system.comp.comp.dataframe["aux"]), set([6]))
130
+
131
+
132
+ # # solver constraints checking
133
+ # input = self.system.dataframe["input"][0]
134
+ # self.assertGreaterEqual(input, -1e3) # min protection
135
+ # self.assertLessEqual(input, 1) # max protection
136
+ #
137
+ # in2 = self.system.dataframe["in2"][0]
138
+ # self.assertGreaterEqual(in2, -1e3) # min protection
139
+ # self.assertLessEqual(in2, 4 - input) # max protection