August 3, 2017

Linking together GPkit and ESP

When working on an engineering idea or conceptual design, it's important to have a design that is grounded in physics in terms of things like mass, power, lift, drag and stress. Though very quickly in the process of figuring out something like an aircraft or car it becomes necessary to know the shape of things to make sure everything can fit together, balance and look good. It's tricky to wrap your head around a design idea without a drawing, and a drawing alone isn't really a complete idea. You need to have both physics modelling and geometry rendering. And for things to go fast, it's ideal to have those two linked together.

One drawing package that isn't particularly well known at the moment, but is super useful for the conceptual design of aircraft and other aerodynamic bodies, is Engineering Sketch Pad. It can help a designer produce and render beautiful 3D models of a design in a browser-based interface. To learn more about it, check out this slide deck.

Screenshot of lander rendered in ESP

Screenshots from the ESP documentation

GPkit, a Python package for writing geometric programs to model designs, can be really helpful in the conceptual stage, but it isn't clear how to easily render its results into a geometric model. For example, if you were working on a racecar wing in GPkit, you would only get a terminal read out of the wing's dimensions from an optimization run, not a drawing which you could use to see how the wing looks. A terminal based output is great for quick debugging, but makes tweaking the design laborious, as the data must be manually transferred to the drawing program.

Let's look at how to link together a GPkit model and an ESP drawing to make displaying results quick and labor-free. If you're not familiar with either GPkit or ESP, reading through their documentation and having a look at some of the examples/tutorials would be a good idea before joining them up.

First, a GPkit model:

from gpkit import Model, Variable

#We want a skinny bottle for some reason
width = Variable('width','-','the width of the bottle')

constraints = [width >= 20.0]  
objective = width

m = Model(objective,constraints)  
sol = m.solve()

print sol.table()

This is a very simple model, a rip-off of the 'Hello World' for GPkit, where you're just constraining one variable and optimizing that.

The ESP drawing that we're going to look at is the bottle.csm example included in the /EngSketchPad/data folder for OpenESP.

Screenshot of the bottle example

The part of the bottle.csm file we want is the design parameters:

# default design parameters
despmtr   width               10.00  
despmtr   depth                4.00  
despmtr   height              15.00  
despmtr   neckDiam             2.50  
despmtr   neckHeight           3.00  
despmtr   wall                 0.20     wall thickness (in neck)  
despmtr   filRad1              0.25     fillet radius on body of bottle  
despmtr   filRad2              0.10     fillet radius between bottle and neck

We want to update this width parameter with the result from the GPkit model each time the model is run, in order to redraw the bottle. To do this, we're going to add a simple class to update the .csm file with a results dictionary after the model is solved.

from gpkit import Model, Variable

class ESPfile():  
    def __init__(self,filepath=""):
        self.filepath = filepath
        self.contents = ""
        if filepath != "":
            with open(filepath, 'r') as file:
                self.contents=file.read()
    def saveDesignParameters(self,paramdict):
        lines = self.contents.splitlines()
        for i,line in enumerate(lines):
            if line[0:7] == 'despmtr':
                key = line[10:25].strip()
                if key in paramdict:
                    line = line[:25] + str(paramdict[key])
                    lines[i] = line
        output = ""
        for line in lines:
            output = output + line + '\n'
        self.contents = output
        with open(self.filepath, "w") as file:
            file.write(self.contents)
            print 'successfully updated ESP file'

#We want a skinny bottle for some reason
width = Variable('width','-','the width of the bottle')

constraints = [width >= 20.0]  
objective = width

m = Model(objective,constraints)  
sol = m.solve()

print sol.table()

f = ESPfile('bottle.csm')  
f.saveDesignParameters({"width" : float(sol(width))})  

As long as the GPkit model is in the /data folder with bottle.csm, you should be able to execute it and see a change in the bottle.csm file. To see a change in the ESP drawing, just re-open it with the 'File' button.

There's definitely ways to improve this to make the Python script modify the .csm more cleanly and there might be a way to automatically refresh the ESP render, but this should be enough to get someone working with both tools iterating much more quickly.

Please let me know if you have any comments or criticisms!

  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket
Comments powered by Disqus