-
Notifications
You must be signed in to change notification settings - Fork 2
/
test_sample_problem.py
122 lines (92 loc) · 3.46 KB
/
test_sample_problem.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"""Run a sample problem to test full system."""
# pylint: disable=invalid-name,missing-docstring
import unittest
from collections import namedtuple
import math
import os
from physprog import classfunctions
from physprog import optimize
THIS_DIR = os.path.dirname(__file__)
SAMPLE_INPUT = os.path.join(THIS_DIR, 'sample-input.yaml')
class TestInput(unittest.TestCase):
"""Test that input can be read."""
def test_read_class_functions(self):
functions = classfunctions.from_input(SAMPLE_INPUT)
self.assertTrue('frequency' in functions)
class Test_Sample_Problem(unittest.TestCase):
"""Test by optimizing a beam problem from the literature."""
def test_optimization(self):
beam = SampleProblemBeam()
# check initial conditions
self.assertAlmostEqual(beam.frequency(), 113.0, delta=0.5)
self.assertAlmostEqual(beam.cost(), 1060.0)
self.assertAlmostEqual(beam.mass(), 2230.0)
prefs = classfunctions.from_input(SAMPLE_INPUT)
optimize.optimize(beam, prefs, plot=False)
# not rigorous, but happens in this problem
self.assertLess(beam.cost(), 1060.0)
SampleDesign = namedtuple('SampleDesign', ['d1', 'd2', 'd3', 'b', 'L'])
class SampleProblemBeam(object):
"""Sample beam design problem from Messac, 1996."""
E1 = 1.6e9
C1 = 500.0
RHO1 = 100.0
E2 = 70e9
C2 = 1500.0
RHO2 = 2770.0
E3 = 200e9
C3 = 800.0
RHO3 = 7780.0
def __init__(self):
self._design = SampleDesign(0.3, 0.35, 0.40, 0.40, 5.0) # initial
def evaluate(self, x=None):
"""Convert input design into output design parameters."""
if x is not None:
self.design = x
return [self.frequency(), self.cost(), self.width(), self.length(),
self.mass(), self.semiheight(), self.width_layer1(),
self.width_layer2(), self.width_layer3()]
@property
def design(self):
return self._design
@design.setter
def design(self, val):
self._design = SampleDesign(*val)
@property
def ei(self):
ds = self.design
return 2.0 / 3.0 * ds.b * (self.E1 * ds.d1 ** 3 +
self.E2 * (ds.d2 ** 3 - ds.d1 ** 3) +
self.E3 * (ds.d3 ** 3 - ds.d2 ** 3))
@property
def mu(self):
ds = self.design
return 2 * ds.b * (self.RHO1 * ds.d1 +
self.RHO2 * (ds.d2 - ds.d1) +
self.RHO3 * (ds.d3 - ds.d2))
def frequency(self):
return math.pi / (2 * self.design.L ** 2) * math.sqrt(self.ei / self.mu)
def cost(self):
ds = self.design
# cost in the paper says 1060 but I'm getting 212, exactly a
# factor of 5 off. But why?? Ah, because cost should have L in it!
# That's a typo in the paper.
return 2 * ds.b * ds.L * (self.C1 * ds.d1 +
self.C2 * (ds.d2 - ds.d1) +
self.C3 * (ds.d3 - ds.d2))
def width(self):
return self.design.b
def length(self):
return self.design.L
def mass(self):
return self.mu * self.design.L
def semiheight(self):
return self.design.d3
def width_layer1(self):
return self.design.d1
def width_layer2(self):
return self.design.d2 - self.design.d1
def width_layer3(self):
return self.design.d3 - self.design.d2
if __name__ == '__main__':
unittest.main()