Skip to content

Commit 7eef17a

Browse files
author
Michael Burton
authored
use relaxed constants to solve pod equations (#31)
* testing * clean shear equations and solve with relaxed constants * fix sens_chart and update solar for fixes in gplibrary
1 parent 34ef868 commit 7eef17a

File tree

4 files changed

+165
-51
lines changed

4 files changed

+165
-51
lines changed

solar/npod_trade.py

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,58 @@
11
" number of pods trade study "
2-
from solar import Mission, Aircraft
2+
# from solar import Mission, Aircraft
33
import matplotlib.pyplot as plt
44
import pandas as pd
55
import numpy as np
66
import sys
7+
from relaxed_constants import relaxed_constants, post_process
78

8-
def pods(N=[1, 3, 5, 7, 9, 0]):
9+
def pods(N=[1, 3, 5, 7, 9, 0], Nplot=5):
910
"trade number of pods"
1011
SP = True
1112
data = {}
1213
for i in N:
14+
from solar import Mission, Aircraft
1315
Vehicle = Aircraft(Npod=i, sp=SP)
1416
M = Mission(Vehicle, latitude=[20])
1517
M.cost = M[M.aircraft.Wtotal]
16-
sol = M.localsolve("mosek")
17-
data[i] = sol("Wtotal").magnitude
18+
try:
19+
sol = M.localsolve("mosek")
20+
data[i] = sol("Wtotal").magnitude
21+
except RuntimeWarning:
22+
V2 = Aircraft(Npod=i, sp=SP)
23+
M2 = Mission(V2, latitude=[20])
24+
M2.cost = M2[M2.aircraft.Wtotal]
25+
feas = relaxed_constants(M2)
26+
sol2 = feas.localsolve("mosek")
27+
vks = post_process(sol2)
28+
data[i] = np.NaN if vks else sol2("Wtotal").magnitude
29+
M, sol = M2, sol2
30+
31+
if Nplot == i:
32+
plot_shear(M, sol)
1833

1934
df = pd.DataFrame(data, index=[0])
2035
return df
2136

37+
def plot_shear(model, result):
38+
" plot shear and moment diagrams "
39+
40+
S = result(model.mission[1].winggust.S)
41+
m = result(model.mission[1].winggust.M)
42+
fig, ax = plt.subplots(2)
43+
ax[0].plot(range(20), S)
44+
ax[1].plot(range(20), m)
45+
ax[0].grid(); ax[1].grid()
46+
fig.savefig("shearandmoment.pdf")
47+
48+
S = result(model.mission[1].wingg.S)
49+
m = result(model.mission[1].wingg.M)
50+
fig, ax = plt.subplots(2)
51+
ax[0].plot(range(20), S)
52+
ax[1].plot(range(20), m)
53+
ax[0].grid(); ax[1].grid()
54+
fig.savefig("shearandmoment2.pdf")
55+
2256
def plot_pods(df):
2357
" plot pod trade "
2458

@@ -44,15 +78,15 @@ def plot_pods(df):
4478

4579
def test():
4680
" for unit testing "
47-
pods(N=[0])
81+
pods(Nplot=100)
4882

4983
if __name__ == "__main__":
5084
if len(sys.argv) > 1:
5185
path = sys.argv[1]
5286
else:
5387
path = ""
5488

55-
GENERATE = False
89+
GENERATE = True
5690

5791
if GENERATE:
5892
DF = pods()

solar/relaxed_constants.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from gpkit.constraints.relax import ConstantsRelaxed
2+
from gpkit.constraints.bounded import Bounded
3+
from gpkit import Model
4+
5+
"""
6+
Methods to precondition an SP so that it solves with a relaxed constants algorithim
7+
and postcondition an SP to ensure all relax values are 1
8+
"""
9+
10+
def relaxed_constants(model, include_only=None, exclude=None):
11+
"""
12+
Method to precondition an SP so it solves with a relaxed constants
13+
algorithim
14+
15+
ARGUMENTS
16+
---------
17+
model: the model to solve with relaxed constants
18+
19+
RETURNS
20+
-------
21+
feas: the input model but with relaxed constants and a new objective
22+
"""
23+
24+
if model.substitutions:
25+
constsrelaxed = ConstantsRelaxed(Bounded(model))
26+
feas = Model(constsrelaxed.relaxvars.prod()**20 * model.cost,
27+
constsrelaxed)
28+
# NOTE: It hasn't yet been seen but might be possible that
29+
# the model.cost component above could cause infeasibility
30+
else:
31+
feas = Model(model.cost, model)
32+
33+
return feas
34+
35+
def post_process(sol):
36+
"""
37+
Model to print relevant info for a solved model with relaxed constants
38+
39+
ARGUMENTS
40+
--------
41+
sol: the solution to the solved model
42+
"""
43+
44+
bdvars = [d for d in sol.program.varkeys if "Relax" in str(d)
45+
and "before" not in str(d) and sol(d).magnitude >= 1.001]
46+
if bdvars:
47+
print "GP iteration has relaxed constants"
48+
print sol.program.result.table(varkeys)
49+
50+
return bdvars
51+

solar/sens_chart.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,10 @@ def test():
108108
else:
109109
path = ""
110110

111-
V = Aircraft(Npod=3, sp=True)
112-
M = Mission(V, latitude=[15])
111+
V = Aircraft(Npod=0, sp=False)
112+
M = Mission(V, latitude=[20])
113113
M.cost = M[M.aircraft.Wtotal]
114-
sol = M.localsolve("mosek")
114+
sol = M.solve("mosek")
115115

116116
vns = {M.aircraft.Wpay: "$W_{\\mathrm{pay}}$",
117117
M.aircraft.battery.etacharge: "$\\eta_{\\mathrm{charge}}$",
@@ -121,6 +121,6 @@ def test():
121121
"Nmax": "$N_{\\mathrm{max}}$",
122122
"e": "$e$", "etaprop": "$\\eta_{\\mathrm{prop}}$"}
123123

124-
sd = get_highestsens(M, sol, N=15)
124+
sd = get_highestsens(M, sol, N=10)
125125
f, a = plot_chart(sd)
126126
f.savefig(path + "sensbar.pdf", bbox_inches="tight")

solar/solar.py

Lines changed: 70 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55
from os import sep
66
from numpy import hstack
77
import pandas as pd
8-
import numpy as np
98
import gassolar.environment
109
from ad.admath import exp
1110
from gassolar.environment.solar_irradiance import get_Eirr, twi_fits
1211
from gassolar.environment.wind_speeds import get_month
13-
from gpkit import Model, parse_variables, Vectorize, Variable
12+
from gpkit import Model, parse_variables, Vectorize, SignomialsEnabled
1413
from gpkit.tests.helpers import StdoutCaptured
1514
from gpkitmodels.GP.aircraft.wing.wing import Wing as WingGP
1615
from gpkitmodels.SP.aircraft.wing.wing import Wing as WingSP
17-
from gpkitmodels.GP.aircraft.wing.boxspar import BoxSpar
16+
from gpkitmodels.GP.aircraft.wing.boxspar import BoxSpar as BoxSparGP
17+
from gpkitmodels.SP.aircraft.wing.boxspar import BoxSpar as BoxSparSP
1818
from gpkitmodels.GP.aircraft.wing.wing_skin import WingSecondStruct
1919
from gpkitmodels.GP.aircraft.tail.empennage import Empennage
2020
from gpkitmodels.GP.aircraft.tail.horizontal_tail import HorizontalTail
@@ -28,6 +28,7 @@
2828
from gpkitmodels.GP.aircraft.motor.motor import Motor
2929
from gpkitmodels import g
3030
from gpfit.fit_constraintset import FitCS as FCS
31+
from relaxed_constants import relaxed_constants, post_process
3132

3233
path = dirname(gassolar.environment.__file__)
3334

@@ -122,7 +123,7 @@ def setup(self, static, state, onDesign = False):
122123

123124
self.wing.substitutions[e] = 0.95
124125
self.wing.substitutions[self.wing.CLstall] = 4
125-
126+
126127
self.wing.substitutions[e] = 0.95
127128
dvars = [cdht*Sh/Sw, cdvt*Sv/Sw, cftb*Stb/Sw]
128129

@@ -163,8 +164,8 @@ class Aircraft(Model):
163164
minvttau 0.09 [-] minimum vertical tail tau ratio
164165
minhttau 0.06 [-] minimum horizontal tail tau ratio
165166
maxtau 0.144 [-] maximum wing tau ratio
166-
167-
SKIP VERIFICATION
167+
168+
SKIP VERIFICATION
168169
169170
Upper Unbounded
170171
---------------
@@ -210,27 +211,27 @@ def setup(self, Npod=0, sp=False):
210211
foamhd.substitutions.update({foamhd.rho: 0.03})
211212
materials = [cfrpud, cfrpfabric, foamhd]
212213

213-
HorizontalTail.sparModel = BoxSpar
214+
HorizontalTail.sparModel = BoxSparGP
214215
HorizontalTail.fillModel = None
215216
HorizontalTail.skinModel = WingSecondStruct
216-
VerticalTail.sparModel = BoxSpar
217+
VerticalTail.sparModel = BoxSparGP
217218
VerticalTail.fillModel = None
218219
VerticalTail.skinModel = WingSecondStruct
219-
TailBoom.__bases__ = (BoxSpar,)
220+
TailBoom.__bases__ = (BoxSparGP,)
220221
TailBoom.secondaryWeight = True
221222
self.emp = Empennage(N=5)
222223
self.solarcells = SolarCells()
223224
self.battery = Battery()
224225
if sp:
225-
WingSP.sparModel = BoxSpar
226+
WingSP.sparModel = BoxSparSP
226227
WingSP.fillModel = None
227228
WingSP.skinModel = WingSecondStruct
228-
self.wing = WingSP(N=10)
229+
self.wing = WingSP(N=20)
229230
else:
230-
WingGP.sparModel = BoxSpar
231+
WingGP.sparModel = BoxSparGP
231232
WingGP.fillModel = None
232233
WingGP.skinModel = WingSecondStruct
233-
self.wing = WingGP(N=10)
234+
self.wing = WingGP(N=20)
234235
self.motor = Motor()
235236
Propeller.flight_model = ActuatorProp
236237
self.propeller = Propeller()
@@ -462,23 +463,20 @@ def setup(self, aircraft, latitude=35, day=355):
462463

463464
self.aircraft = aircraft
464465
self.fs = FlightState(latitude=latitude, day=day)
465-
self.aircraftPerf = self.aircraft.flight_model(aircraft, self.fs, True)
466+
self.aircraftPerf = self.aircraft.flight_model(aircraft, self.fs, False)
466467
self.slf = SteadyLevelFlight(self.fs, self.aircraft,
467468
self.aircraftPerf)
468469

469-
if aircraft.Npod is not 0:
470-
if aircraft.Npod is not 1:
471-
assert self.aircraft.sp
472-
loadsp = self.aircraft.sp
473-
else:
474-
loadsp = False
470+
if aircraft.Npod is not 0 and aircraft.Npod is not 1:
471+
assert self.aircraft.sp
472+
loadsp = self.aircraft.sp
475473
else:
476474
loadsp = False
477475

478476
self.wingg = self.aircraft.wing.spar.loading(
479-
self.aircraft.wing, self.fs, sp=loadsp)
477+
self.aircraft.wing, self.fs, out=loadsp)
480478
self.winggust = self.aircraft.wing.spar.gustloading(
481-
self.aircraft.wing, self.fs, sp=loadsp)
479+
self.aircraft.wing, self.fs, out=loadsp)
482480
self.htailg = self.aircraft.emp.htail.spar.loading(
483481
self.aircraft.emp.htail, self.fs)
484482
self.vtailg = self.aircraft.emp.vtail.spar.loading(
@@ -524,17 +522,38 @@ def setup(self, aircraft, latitude=35, day=355):
524522
self.vtailg.W == qne*Sv*CLvmax,
525523
]
526524

527-
if self.aircraft.Npod is not 0:
528-
if self.aircraft.Npod is not 1:
529-
z0 = Variable("z0", 1e-10, "N", "placeholder zero value")
530-
Nwing, Npod = self.aircraft.wing.N, self.aircraft.Npod
531-
ypod = Nwing/((Npod-1)/2 + 1)
532-
y0len = ypod-1
533-
weight = self.aircraft.battery.W/Npod*self.wingg.Nsafety
534-
sout = np.hstack([[z0]*y0len + [weight]]*(Npod/2))
535-
sout = list(sout) + [z0]*(Nwing - len(sout) - 1)
536-
constraints.extend([sout == self.wingg.Sout,
537-
sout == self.winggust.Sout])
525+
if self.aircraft.Npod is not 0 and self.aircraft.Npod is not 1:
526+
Nwing, Npod = self.aircraft.wing.N, self.aircraft.Npod
527+
ypod = Nwing/((Npod-1)/2 + 1)
528+
ypods = [ypod*n for n in range(1, (Npod-1)/2+1)]
529+
Sgust, Mgust = self.winggust.S, self.winggust.M
530+
qgust, Sg, Mg = self.winggust.q, self.wingg.S, self.wingg.M
531+
qg = self.wingg.q
532+
deta = self.aircraft.wing.planform.deta
533+
b = self.aircraft.wing.planform.b
534+
weight = self.aircraft.battery.W/Npod*self.wingg.N
535+
for i in range(Nwing-1):
536+
if i in ypods:
537+
with SignomialsEnabled():
538+
constraints.extend([
539+
Sgust[i] >= (Sgust[i+1] + 0.5*deta[i]*(b/2)
540+
* (qgust[i] + qgust[i+1]) - weight),
541+
Sg[i] >= (Sg[i+1] + 0.5*deta[i]*(b/2)
542+
* (qg[i] + qg[i+1]) - weight),
543+
Mgust[i] >= (Mgust[i+1] + 0.5*deta[i]*(b/2)
544+
* (Sgust[i] + Sgust[i+1])),
545+
Mg[i] >= (Mg[i+1] + 0.5*deta[i]*(b/2)
546+
* (Sg[i] + Sg[i+1]))
547+
])
548+
else:
549+
constraints.extend([
550+
Sgust[i] >= (Sgust[i+1] + 0.5*deta[i]*(b/2)
551+
* (qgust[i] + qgust[i+1])),
552+
Sg[i] >= Sg[i+1] + 0.5*deta[i]*(b/2)*(qg[i] + qg[i+1]),
553+
Mgust[i] >= (Mgust[i+1] + 0.5*deta[i]*(b/2)
554+
* (Sgust[i] + Sgust[i+1])),
555+
Mg[i] >= Mg[i+1] + 0.5*deta[i]*(b/2)*(Sg[i] + Sg[i+1])
556+
])
538557

539558
self.submodels = [self.fs, self.aircraftPerf, self.slf, self.loading]
540559

@@ -643,21 +662,31 @@ def setup(self, aircraft, latitude=range(1, 21, 1), day=355):
643662
def test():
644663
" test model for continuous integration "
645664
v = Aircraft(sp=False)
646-
m = Mission(v, latitude=[15])
665+
m = Mission(v, latitude=[20])
647666
m.cost = m[m.aircraft.Wtotal]
648667
m.solve()
649668
v = Aircraft(sp=True)
650-
m = Mission(v, latitude=[15])
669+
m = Mission(v, latitude=[20])
651670
m.cost = m[m.aircraft.Wtotal]
652671
m.localsolve()
653-
v = Aircraft(Npod=5, sp=True)
654-
m = Mission(v, latitude=[15])
672+
v = Aircraft(Npod=3, sp=True)
673+
m = Mission(v, latitude=[20])
655674
m.cost = m[m.aircraft.Wtotal]
656-
m.localsolve()
675+
f = relaxed_constants(M)
676+
s = f.localsolve("mosek")
677+
post_process(s)
657678

658679
if __name__ == "__main__":
659680
SP = True
660-
Vehicle = Aircraft(Npod=5, sp=SP)
661-
M = Mission(Vehicle, latitude=[15])
681+
Vehicle = Aircraft(Npod=3, sp=SP)
682+
M = Mission(Vehicle, latitude=[20])
662683
M.cost = M[M.aircraft.Wtotal]
663-
sol = (M.localsolve("mosek") if SP else M.solve("mosek"))
684+
try:
685+
sol = (M.localsolve("mosek") if SP else M.solve("mosek"))
686+
except RuntimeWarning:
687+
V2 = Aircraft(Npod=3, sp=SP)
688+
M2 = Mission(V2, latitude=[20])
689+
M2.cost = M2[M2.aircraft.Wtotal]
690+
feas = relaxed_constants(M2)
691+
sol = feas.localsolve("mosek")
692+
vks = post_process(sol)

0 commit comments

Comments
 (0)