diff --git a/docs/source/examples/performance_modeling.py b/docs/source/examples/performance_modeling.py index c0c3d59ef..6a184002e 100644 --- a/docs/source/examples/performance_modeling.py +++ b/docs/source/examples/performance_modeling.py @@ -1,7 +1,7 @@ """Modular aircraft concept""" import pickle import numpy as np -from gpkit import Model, Vectorize, parse_variables +from gpkit import Model, Vectorize, parse_variables, pv_decorater class AircraftP(Model): @@ -21,10 +21,10 @@ class AircraftP(Model): Wfuel, aircraft.W, state.mu """ + @pv_decorater(__doc__, globals()) def setup(self, aircraft, state): self.aircraft = aircraft self.state = state - exec(parse_variables(AircraftP.__doc__)) self.wing_aero = aircraft.wing.dynamic(aircraft.wing, state) self.perf_models = [self.wing_aero] @@ -62,8 +62,8 @@ class Aircraft(Model): --------------- wing.c, wing.S """ + @pv_decorater(__doc__, globals()) def setup(self): - exec(parse_variables(Aircraft.__doc__)) self.fuse = Fuselage() self.wing = Wing() self.components = [self.fuse, self.wing] @@ -87,8 +87,9 @@ class FlightState(Model): rho 0.74 [kg/m^3] air density """ + @pv_decorater(__doc__, globals()) def setup(self): - exec(parse_variables(FlightState.__doc__)) + pass class FlightSegment(Model): @@ -103,6 +104,7 @@ class FlightSegment(Model): Wfuel, aircraft.W """ + @pv_decorater(__doc__, globals()) def setup(self, aircraft): self.aircraft = aircraft @@ -165,10 +167,11 @@ class WingAero(Model): --------------- CL, wing.S, state.mu, state.rho, state.V """ + @pv_decorater(__doc__, globals()) def setup(self, wing, state): self.wing = wing self.state = state - exec(parse_variables(WingAero.__doc__)) + assert False c = wing.c A = wing.A @@ -205,8 +208,8 @@ class Wing(Model): --------------- c, S """ + @pv_decorater(__doc__, globals()) def setup(self): - exec(parse_variables(Wing.__doc__)) return {"parametrization of wing weight": W >= S*rho, "definition of mean chord": @@ -225,32 +228,33 @@ class Fuselage(Model): W 100 [lbf] weight """ + @pv_decorater(__doc__, globals()) def setup(self): - exec(parse_variables(Fuselage.__doc__)) + pass AC = Aircraft() MISSION = Mission(AC) M = Model(MISSION.takeoff_fuel, [MISSION, AC]) print(M) sol = M.solve(verbosity=0) -# save solution to some files -sol.savemat() -sol.savecsv() -sol.savetxt() -sol.save("solution.pkl") -# retrieve solution from a file -sol_loaded = pickle.load(open("solution.pkl")) - -vars_of_interest = set(AC.varkeys) -# note that there's two ways to access submodels -assert (MISSION["flight segment"]["aircraft performance"] - is MISSION.fs.aircraftp) -vars_of_interest.update(MISSION.fs.aircraftp.unique_varkeys) -vars_of_interest.add(M["D"]) -print(sol.summary(vars_of_interest)) -print(sol.table(tables=["loose constraints"])) - -MISSION["flight segment"]["aircraft performance"]["fuel burn rate"] = ( - MISSION.fs.aircraftp.Wburn >= 0.2*MISSION.fs.aircraftp.wing_aero.D) -sol = M.solve(verbosity=0) -print(sol.diff("solution.pkl", showvars=vars_of_interest, sortbymodel=False)) +# # save solution to some files +# sol.savemat() +# sol.savecsv() +# sol.savetxt() +# sol.save("solution.pkl") +# # retrieve solution from a file +# sol_loaded = pickle.load(open("solution.pkl")) +# +# vars_of_interest = set(AC.varkeys) +# # note that there's two ways to access submodels +# assert (MISSION["flight segment"]["aircraft performance"] +# is MISSION.fs.aircraftp) +# vars_of_interest.update(MISSION.fs.aircraftp.unique_varkeys) +# vars_of_interest.add(M["D"]) +# print(sol.summary(vars_of_interest)) +# print(sol.table(tables=["loose constraints"])) +# +# MISSION["flight segment"]["aircraft performance"]["fuel burn rate"] = ( +# MISSION.fs.aircraftp.Wburn >= 0.2*MISSION.fs.aircraftp.wing_aero.D) +# sol = M.solve(verbosity=0) +# print(sol.diff("solution.pkl", showvars=vars_of_interest, sortbymodel=False)) diff --git a/docs/source/examples/pm_test.py b/docs/source/examples/pm_test.py new file mode 100644 index 000000000..2950ba5bf --- /dev/null +++ b/docs/source/examples/pm_test.py @@ -0,0 +1,3 @@ +from performance_modeling import Wing + +print(Wing()) diff --git a/gpkit/__init__.py b/gpkit/__init__.py index 4f7e1e8dc..cfd7abc16 100644 --- a/gpkit/__init__.py +++ b/gpkit/__init__.py @@ -17,6 +17,41 @@ from .constraints.model import Model from .tools.docstring import parse_variables +import inspect +import ast + + +class pv_decorater(object): + + def __init__(self, string, globals): + self.string = string + self.globals = globals + + def __call__(self, f): + string = self.string + orig_source = inspect.getsource(f) + # print("os\n", orig_source) + orig_lines = orig_source.split("\n") + indent_length = 0 + while orig_lines[1][indent_length] in [" ", "\t"]: + indent_length += 1 + first_indent_length = indent_length + while orig_lines[2][indent_length] in [" ", "\t"]: + indent_length += 1 + second_indent = orig_lines[2][:indent_length] + parse_lines = [second_indent + line for line in parse_variables(string).split("\n")] + # make ast of these new lines, insert it into the original ast + new_lines = [orig_lines[1]] + parse_lines + orig_lines[2:] + new_src = "\n".join([line[first_indent_length:] for line in new_lines]) + # print("ns\n%s" % new_src) + new_ast = ast.parse(new_src, "") + ast.fix_missing_locations(new_ast) + code = compile(new_ast, "", "exec", dont_inherit=True) + out = {} + exec(code, self.globals, out) + return out[f.__name__] + + GPBLU = "#59ade4" GPCOLORS = ["#59ade4", "#FA3333"] diff --git a/gpkit/constraints/set.py b/gpkit/constraints/set.py index fa8e447aa..afcc5cf82 100644 --- a/gpkit/constraints/set.py +++ b/gpkit/constraints/set.py @@ -262,6 +262,8 @@ def process_result(self, result): def __repr__(self): "Returns namespaced string." + if not self: + return "" % self.__class__.__name__ return ("" % (self.__class__.__name__, len(self), len(self.varkeys))) diff --git a/gpkit/tools/docstring.py b/gpkit/tools/docstring.py index be0eac3c3..f60ef1a9f 100644 --- a/gpkit/tools/docstring.py +++ b/gpkit/tools/docstring.py @@ -1,6 +1,5 @@ "Docstring-parsing methods" import re -import sys import numpy as np @@ -59,8 +58,6 @@ def expected_unbounded(instance, doc): def parse_variables(string, errorcatch=True): "Parses a string to determine what variables to create from it" - if sys.version_info >= (3, 0): - raise FutureWarning("parse_variables is not yet supported in Python 3") out = "from gpkit import Variable, VectorVariable\n" out += check_and_parse_flag(string, "Constants\n", errorcatch, constant_declare) diff --git a/test.py b/test.py new file mode 100644 index 000000000..003ef9742 --- /dev/null +++ b/test.py @@ -0,0 +1,15 @@ +from gpkit import * +from gpkit.nomials.array import NomialArray +import numpy as np + +t = Variable("t") +u = Variable("u") +v = Variable("v") +w = Variable("w") +x = VectorVariable(3, "x") +y = VectorVariable(3, "y") +z = VectorVariable(3, "z") +a = VectorVariable((3, 2), "a") +b = VectorVariable((3, 2), "b") + +print w >= x