Skip to content

Instantly share code, notes, and snippets.

@bgnori
Created March 14, 2018 16:38
Show Gist options
  • Save bgnori/258d8bc34ee51bb279f39168b091e82d to your computer and use it in GitHub Desktop.
Save bgnori/258d8bc34ee51bb279f39168b091e82d to your computer and use it in GitHub Desktop.
import math
import json
from itertools import starmap
def tonne(x):
return x*1000.0
def deltaV(Isp, m0, mt, gravitational_acc=9.80665):
"""
>>> deltaV(440.0, tonne(374.8), tonne(60))
7905.151497282325
"""
return Isp * gravitational_acc * math.log(m0/mt)
def compositeIsp(*IspThrustPair):
z = zip(*starmap(lambda Isp, th: (th, th/Isp), IspThrustPair))
th, ff = map(sum, z)
return th/ff
class Stage:
def __init__(self, _parts, **kw):
self._parts = _parts
self._data = dict(kw)
def __getattr__(self, name):
if name.startswith("_calc_"):
return None
v = self._data.get(name, None)
if v is not None:
return v
f = getattr(self, "_calc_" + name, None)
if f is not None:
return f()
raise AttributeError(name)
def _calc_Wet(self):
if hasattr(self, "overhead"):
try:
return self.fuel / (1.0 - self.overhead)
except Exception as e:
raise AttributeError("Failed to calc: Wet") from e
if hasattr(self, "Dry"):
return self.Dry + self.fuel
def _calc_Dry(self):
try:
return self.Wet - self.fuel
except Exception as e:
raise AttributeError("Failed to calc: Dry") from e
def _calc_fuel(self):
return self.Wet - self.Dry
def _calc_Isp(self):
if hasattr(self, "parts"):
xs = []
for name in self.parts:
part = self._parts[name]
Isp = part["atmosphereCurve"]["0"] #FIXME
thrust = part["maxThrust"]
xs.append((Isp, thrust))
return compositeIsp(*xs)
else:
return 0
def hasSomeThrust(self):
return self.fuel > 0 #FIXME
def compoisiteDeltaV(rocket, parts):
total_weight = 0.0
total_deltaV = 0.0
xs = []
for s in rocket["stages"]:
stage = Stage(parts, **s)
v = deltaV(stage.Isp, total_weight + stage.Wet, total_weight + stage.Dry)
v_per_fuel = v / stage.fuel if stage.hasSomeThrust() else "n/a"
x = dict(s)
x.update({
"Isp": stage.Isp,
"fuel":stage.fuel,
"mt": total_weight + stage.Wet,
"m0": total_weight + stage.Dry,
"Delta V":v,
"Delta V per fuel":v_per_fuel,
})
total_weight += stage.Wet
total_deltaV += v
x["Subtotal Weight"] = total_weight
x["Subtotal Delta V"] = total_deltaV
xs.append(x)
result = dict(rocket)
result.update({"stages":xs, "Total Weight":total_weight, "Total DeltaV":total_deltaV})
return result
if __name__ == "__main__":
import sys
rocket = json.loads(sys.stdin.read())
with open("parts.json") as f:
parts = json.loads(f.read())
"""
cd = compoisiteDeltaV(
Stage(name="Payload", Wet=10.0, Dry=10.0, Isp=0),
Stage(name="Alpha", overhead=0.3, fuel=7.0, Isp=300),
Stage(name="Beta", overhead=0.1, fuel=9.0, Isp=300),
)
"""
print(json.dumps(compoisiteDeltaV(rocket, parts)))
import json
import glob
import sys
parts = json.loads(sys.stdin.read())
for path in glob.iglob("Engine/*.json"):
with open(path, "r") as g:
codename = path[7:-5]
engine = json.loads(g.read())
parts[codename] = engine
print(json.dumps(parts))
"""
parse and generete a json file from single .cfg in Squad/Parts
"""
import re
AND = "|"
pattern = re.compile(
r"category = (?P<category>\s+)" + AND +\
r"cost = (?P<cost>\d+)" + AND +\
r"mass = (?P<mass>\d+\.\d+)" + AND +\
r"title = (?P<title>.+)" + AND +\
r"maxThrust = (?P<maxThrust>\d+)" + AND +\
r"minThrust = (?P<minThrust>\d+)" + AND +\
r"(?P<atmosphereCurve>atmosphereCurve)")
keyvalues = re.compile(
r"key = (?P<key>\d+) (?P<value>(\d+)(\.(\d+))?)"
)
class Reader:
def __init__(self):
self.result = {}
pass
def read(self, lines):
self.lines = lines
for lno, line in enumerate(self.lines):
m = pattern.search(line)
if m:
self.handle(lno, m)
def handle(self, lno, m):
name = m.lastgroup
if name is not None:
handler = getattr(self, "handle_"+name, None)
if handler is not None:
handler(name, lno, m)
def do_int(self, name, m):
self.result[name] = int(m.group(name))
def do_float(self, name, m):
self.result[name] = float(m.group(name))
def do_str(self, name, m):
self.result[name] = m.group(name)
def handle_cost(self, name, lno, m):
self.do_int(name, m)
def handle_minThrust(self, name, lno, m):
self.do_int(name, m)
def handle_maxThrust(self, name, lno, m):
self.do_int(name, m)
def handle_mass(self, name, lno, m):
self.do_float(name, m)
def handle_title(self, name, lno, m):
self.do_str(name, m)
def handle_atmosphereCurve(self, name, lno, m):
kv = {}
for line in self.lines[lno+2:]:
m = keyvalues.search(line)
if m is None:
break
else:
d = m.groupdict()
kv[int(d["key"])] = float(d["value"])
self.result[name] = kv
if __name__ == "__main__":
import sys
import json
r = Reader()
with open(sys.argv[1], encoding='utf-8-sig', mode='r') as f:
r.read(f.readlines())
print(json.dumps(r.result))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment