Coverage for gpkit\tests\t_tools.py: 0%

83 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-03 16:57 -0500

1"""Tests for tools module""" 

2import unittest 

3import numpy as np 

4from numpy import log 

5from gpkit import Variable, VectorVariable, Model, NomialArray 

6from gpkit.tools.autosweep import BinarySweepTree 

7from gpkit.tools.tools import te_exp_minus1, te_secant, te_tangent 

8from gpkit.small_scripts import mag 

9from gpkit import parse_variables 

10 

11 

12def assert_logtol(first, second, logtol=1e-6): 

13 "Asserts that the logs of two arrays have a given abstol" 

14 np.testing.assert_allclose(log(mag(first)), log(mag(second)), 

15 atol=logtol, rtol=0) 

16 

17 

18class OnlyVectorParse(Model): 

19 """ 

20 Variables of length 3 

21 --------------------- 

22 x [-] just another variable 

23 """ 

24 @parse_variables(__doc__, globals()) 

25 def setup(self): 

26 pass 

27 

28 

29class Fuselage(Model): 

30 """The thing that carries the fuel, engine, and payload 

31 

32 Variables 

33 --------- 

34 f [-] Fineness 

35 g 9.81 [m/s^2] Standard gravity 

36 k [-] Form factor 

37 l [ft] Length 

38 mfac 2.0 [-] Weight margin factor 

39 R [ft] Radius 

40 rhocfrp 1.6 [g/cm^3] Density of CFRP 

41 rhofuel 6.01 [lbf/gallon] Density of 100LL fuel 

42 S [ft^2] Wetted area 

43 t 0.024 [in] Minimum skin thickness 

44 Vol [ft^3] Volume 

45 W [lbf] Weight 

46 

47 Upper Unbounded 

48 --------------- 

49 k, W 

50 

51 """ 

52 

53 # pylint: disable=undefined-variable, invalid-name 

54 @parse_variables(__doc__, globals()) 

55 def setup(self, Wfueltot): 

56 return [ 

57 f == l/R/2, 

58 k >= 1 + 60/f**3 + f/400, 

59 3*(S/np.pi)**1.6075 >= 2*(l*R*2)**1.6075 + (2*R)**(2*1.6075), 

60 Vol <= 4*np.pi/3*(l/2)*R**2, 

61 Vol >= Wfueltot/rhofuel, 

62 W/mfac >= S*rhocfrp*t*g, 

63 ] 

64 

65 

66class TestTools(unittest.TestCase): 

67 """TestCase for math models""" 

68 

69 def test_vector_only_parse(self): 

70 # pylint: disable=no-member 

71 m = OnlyVectorParse() 

72 self.assertTrue(hasattr(m, "x")) 

73 self.assertIsInstance(m.x, NomialArray) 

74 self.assertEqual(len(m.x), 3) 

75 

76 def test_parse_variables(self): 

77 Fuselage(Variable("Wfueltot", 5, "lbf")) 

78 

79 def test_binary_sweep_tree(self): 

80 bst0 = BinarySweepTree([1, 2], [{"cost": 1}, {"cost": 8}], None, None) 

81 assert_logtol(bst0.sample_at([1, 1.5, 2])["cost"], [1, 3.375, 8], 1e-3) 

82 bst0.add_split(1.5, {"cost": 4}) 

83 assert_logtol(bst0.sample_at([1, 1.25, 1.5, 1.75, 2])["cost"], 

84 [1, 2.144, 4, 5.799, 8], 1e-3) 

85 

86 def test_dual_objective(self): 

87 L = Variable("L") 

88 W = Variable("W") 

89 eqns = [L >= 1, W >= 1, 

90 L*W == 10] 

91 N = 4 

92 ws = Variable("w_{CO}", ("sweep", np.linspace(1/N, 1-1/N, N)), "-") 

93 w_s = Variable("v_{CO}", lambda c: 1-c[ws], "-") 

94 obj = ws*(L+W) + w_s*(W**-1 * L**-3) 

95 m = Model(obj, eqns) 

96 sol = m.solve(verbosity=0) 

97 a = sol["cost"] 

98 b = np.array([1.58856898, 2.6410391, 3.69348122, 4.74591386]) 

99 self.assertTrue((abs(a-b)/(a+b+1e-7) < 1e-7).all()) 

100 

101 def test_te_exp_minus1(self): 

102 """Test Taylor expansion of e^x - 1""" 

103 x = Variable('x') 

104 self.assertEqual(te_exp_minus1(x, 1), x) 

105 self.assertEqual(te_exp_minus1(x, 3), x + x**2/2 + x**3/6) 

106 self.assertEqual(te_exp_minus1(x, 0), 0) 

107 # make sure x was not modified 

108 self.assertEqual(x, Variable('x')) 

109 # try for VectorVariable too 

110 y = VectorVariable(3, 'y') 

111 self.assertEqual(te_exp_minus1(y, 1), y) 

112 self.assertEqual(te_exp_minus1(y, 3), y + y**2/2 + y**3/6) 

113 self.assertEqual(te_exp_minus1(y, 0), 0) 

114 # make sure y was not modified 

115 self.assertEqual(y, VectorVariable(3, 'y')) 

116 

117 def test_te_secant(self): 

118 "Test Taylor expansion of secant(var)" 

119 x = Variable('x') 

120 self.assertEqual(te_secant(x, 1), 1 + x**2/2) 

121 a = te_secant(x, 2) 

122 b = 1 + x**2/2 + 5*x**4/24 

123 self.assertTrue(all([abs(val) <= 1e-10 

124 for val in (a.hmap - b.hmap).values()])) # pylint:disable=no-member 

125 self.assertEqual(te_secant(x, 0), 1) 

126 # make sure x was not modified 

127 self.assertEqual(x, Variable('x')) 

128 # try for VectorVariable too 

129 y = VectorVariable(3, 'y') 

130 self.assertTrue(te_secant(y, 0) == 1) # truthy bc monomial constraint 

131 self.assertTrue(all(te_secant(y, 1) == 1 + y**2/2)) 

132 self.assertTrue(all(te_secant(y, 2) == 1 + y**2/2 + 5*y**4/24)) 

133 # make sure y was not modified 

134 self.assertEqual(y, VectorVariable(3, 'y')) 

135 _ = te_secant(x, 13) # to trigger the extension 

136 

137 def test_te_tangent(self): 

138 "Test Taylor expansion of tangent(var)" 

139 x = Variable('x') 

140 self.assertEqual(te_tangent(x, 1), x) 

141 self.assertEqual(te_tangent(x, 3), x + x**3/3 + 2*x**5/15) 

142 self.assertEqual(te_tangent(x, 0), 0) 

143 # make sure x was not modified 

144 self.assertEqual(x, Variable('x')) 

145 # try for VectorVariable too 

146 y = VectorVariable(3, 'y') 

147 self.assertEqual(te_tangent(y, 1), y) 

148 self.assertEqual(te_tangent(y, 3), y + y**3/3 + 2*y**5/15) 

149 self.assertEqual(te_tangent(y, 0), 0) 

150 # make sure y was not modified 

151 self.assertEqual(y, VectorVariable(3, 'y')) 

152 with self.assertRaises(NotImplementedError): 

153 _ = te_tangent(x, 16) 

154 

155 

156TESTS = [TestTools] 

157 

158 

159if __name__ == "__main__": # pragma: no cover 

160 # pylint: disable=wrong-import-position 

161 from gpkit.tests.helpers import run_tests 

162 run_tests(TESTS)