Skip to content

Commit ab8acbe

Browse files
Merge pull request #41 from RocketPy-Team/develop
Fix: Systemic extraction bugs and reliability improvements
2 parents 2ac30a6 + 9bc336c commit ab8acbe

15 files changed

Lines changed: 166 additions & 110 deletions

rocketserializer/_helpers.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,14 @@ def parse_ork_file(ork_path: Path):
8888
return bs, datapoints
8989
except UnicodeDecodeError as exc:
9090
error_msg = (
91-
"The .ork file is not in UTF-8."
91+
"The .ork file is not in UTF-8. "
9292
+ "Please open the .ork file in a text editor and save it as UTF-8."
9393
)
9494
logger.error(error_msg)
95-
raise UnicodeDecodeError(error_msg) from exc
95+
raise ValueError(error_msg) from exc
9696
except Exception as e:
9797
logger.error("Error while parsing the file '%s': %s", ork_path.as_posix(), e)
98-
raise e
98+
raise
9999

100100

101101
def _dict_to_string(dictionary, indent=0):

rocketserializer/cli.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def cli():
7171
help="The path to the OpenRocket .jar file.",
7272
)
7373
@click.option("--encoding", type=str, default="utf-8", required=False)
74-
@click.option("--verbose", type=bool, default=False, required=False)
74+
@click.option("--verbose", is_flag=True, default=False, help="Enable verbose logging")
7575
def ork2json(filepath, output=None, ork_jar=None, encoding="utf-8", verbose=False):
7676
"""Generates a .json file from the .ork file.
7777
The .json file will be generated in the output folder using the information
@@ -216,8 +216,8 @@ def ork2json(filepath, output=None, ork_jar=None, encoding="utf-8", verbose=Fals
216216
@click.option("--output", type=str, required=False)
217217
@click.option("--ork_jar", type=str, default=None, required=False)
218218
@click.option("--encoding", type=str, default="utf-8", required=False)
219-
@click.option("--verbose", type=bool, default=False, required=False)
220-
def ork2notebook(filepath, output, ork_jar=None, encoding="utf-8", verbose=False):
219+
@click.option("--verbose", is_flag=True, default=False, help="Enable verbose logging")
220+
def ork2notebook(filepath, output, ork_jar=None, encoding="utf-8", verbose=False): # pylint: disable=unused-argument
221221
"""Generates a .ipynb file from the .ork file.
222222
223223
Notes
@@ -239,10 +239,9 @@ def ork2notebook(filepath, output, ork_jar=None, encoding="utf-8", verbose=False
239239
"--output",
240240
str(output),
241241
"--encoding",
242-
str(encoding),
243-
"--verbose",
244-
str(verbose),
245242
]
243+
if verbose:
244+
args.append("--verbose")
246245
if ork_jar:
247246
args.extend(["--ork_jar", str(ork_jar)])
248247

rocketserializer/components/environment.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@ def search_environment(bs):
2323
"""
2424
settings = {}
2525

26-
latitude = float(bs.find("launchlatitude").text)
27-
longitude = float(bs.find("launchlongitude").text)
28-
elevation = float(bs.find("launchaltitude").text)
29-
wind_average = float(bs.find("windaverage").text)
30-
wind_turbulence = float(bs.find("windturbulence").text)
31-
geodetic_method = bs.find("geodeticmethod").text
26+
latitude = float(getattr(bs.find("launchlatitude"), "text", "0"))
27+
longitude = float(getattr(bs.find("launchlongitude"), "text", "0"))
28+
elevation = float(getattr(bs.find("launchaltitude"), "text", "0"))
29+
wind_average = float(getattr(bs.find("windaverage"), "text", "0"))
30+
wind_turbulence = float(getattr(bs.find("windturbulence"), "text", "0"))
31+
geodetic_method = getattr(bs.find("geodeticmethod"), "text", "")
3232
logger.info(
3333
"Collected first environment settings: latitude, "
3434
+ "longitude, elevation, wind_average, wind_turbulence, geodetic_method"
3535
)
3636
try:
37-
base_temperature = float(bs.find("basetemperature").text)
37+
base_temperature = float(getattr(bs.find("basetemperature"), "text", "0"))
3838
logger.info(
3939
"The base temperature was found in the .ork file. It is %f °C.",
4040
base_temperature,
@@ -46,7 +46,7 @@ def search_environment(bs):
4646
)
4747
base_temperature = None
4848
try:
49-
base_pressure = float(bs.find("basepressure").text)
49+
base_pressure = float(getattr(bs.find("basepressure"), "text", "0"))
5050
logger.info(
5151
"The base pressure was found in the .ork file. It is %f Pa.",
5252
base_pressure,

rocketserializer/components/fins.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def search_trapezoidal_fins(bs, elements):
3838
"Starting collecting the settings for the trapezoidal fin set number '%d'",
3939
idx,
4040
)
41-
label = fin.find("name").text
41+
label = getattr(fin.find("name"), "text", "")
4242
try:
4343

4444
def get_element_by_name(name):
@@ -57,32 +57,36 @@ def get_element_by_name(name):
5757
logger.error(message)
5858
raise KeyError(message)
5959

60-
n_fin = int(fin.find("fincount").text)
60+
n_fin = int(getattr(fin.find("fincount"), "text", "0"))
6161
logger.info("Number of fins retrieved: %d", n_fin)
6262

63-
root_chord = float(fin.find("rootchord").text)
63+
root_chord = float(getattr(fin.find("rootchord"), "text", "0"))
6464
logger.info("Root chord retrieved: %f", root_chord)
6565

66-
tip_chord = float(fin.find("tipchord").text)
66+
tip_chord = float(getattr(fin.find("tipchord"), "text", "0"))
6767
logger.info("Tip chord retrieved: %f", tip_chord)
6868

69-
span = float(fin.find("height").text)
69+
span = float(getattr(fin.find("height"), "text", "0"))
7070
logger.info("Span retrieved: %f", span)
7171

7272
sweep_length = (
73-
float(fin.find("sweeplength").text) if fin.find("sweeplength") else None
73+
float(getattr(fin.find("sweeplength"), "text", "0"))
74+
if fin.find("sweeplength")
75+
else None
7476
)
7577
sweep_angle = (
76-
float(fin.find("sweepangle").text) if fin.find("sweepangle") else None
78+
float(getattr(fin.find("sweepangle"), "text", "0"))
79+
if fin.find("sweepangle")
80+
else None
7781
)
7882
logger.info(
7983
"Sweep length and angle retrieved: %s, %s", sweep_length, sweep_angle
8084
)
8185

82-
cant_angle = float(fin.find("cant").text)
86+
cant_angle = float(getattr(fin.find("cant"), "text", "0"))
8387
logger.info("Cant angle retrieved: %f", cant_angle)
8488

85-
section = fin.find("crosssection").text
89+
section = getattr(fin.find("crosssection"), "text", "")
8690
logger.info("Crosssection format retrieved")
8791

8892
fin_settings = {
@@ -145,7 +149,7 @@ def search_elliptical_fins(bs, elements):
145149
"Starting collecting the settings for the elliptical fin set number '%d'",
146150
idx,
147151
)
148-
label = fin.find("name").text
152+
label = getattr(fin.find("name"), "text", "")
149153
try:
150154

151155
def get_element_by_name(name):
@@ -164,19 +168,19 @@ def get_element_by_name(name):
164168
logger.error(message)
165169
raise KeyError(message)
166170

167-
n_fin = int(fin.find("fincount").text)
171+
n_fin = int(getattr(fin.find("fincount"), "text", "0"))
168172
logger.info("Number of fins retrieved: %d", n_fin)
169173

170-
root_chord = float(fin.find("rootchord").text)
174+
root_chord = float(getattr(fin.find("rootchord"), "text", "0"))
171175
logger.info("Root chord retrieved: %f", root_chord)
172176

173-
span = float(fin.find("height").text)
177+
span = float(getattr(fin.find("height"), "text", "0"))
174178
logger.info("Span retrieved: %f", span)
175179

176-
cant_angle = float(fin.find("cant").text)
180+
cant_angle = float(getattr(fin.find("cant"), "text", "0"))
177181
logger.info("Cant angle retrieved: %f", cant_angle)
178182

179-
section = fin.find("crosssection").text
183+
section = getattr(fin.find("crosssection"), "text", "")
180184
logger.info("Crosssection format retrieved")
181185

182186
fin_settings = {

rocketserializer/components/flight.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ def search_launch_conditions(bs):
2121
"""
2222
settings = {}
2323

24-
launch_rod_length = float(bs.find("launchrodlength").text)
25-
launch_rod_angle = float(bs.find("launchrodangle").text)
26-
launch_rod_direction = float(bs.find("launchroddirection").text)
24+
launch_rod_length = float(getattr(bs.find("launchrodlength"), "text", "0"))
25+
launch_rod_angle = float(getattr(bs.find("launchrodangle"), "text", "0"))
26+
launch_rod_direction = float(getattr(bs.find("launchroddirection"), "text", "0"))
2727
logger.info(
2828
"Collected launch conditions: launch rod length, launch rod angle, "
2929
"launch rod direction."

rocketserializer/components/id.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,31 @@ def search_id_info(bs, filepath):
2424
"filepath".
2525
"""
2626
settings = {}
27-
settings["rocket_name"] = bs.find("rocket").find("name").text
28-
logger.info("Collected the rocket name: '%s'", settings["rocket_name"])
29-
30-
try:
31-
settings["comment"] = bs.find("rocket").find("comment").text.replace("\n", "")
32-
logger.info("Collected the comment saved in the file: %s", settings["comment"])
33-
except AttributeError:
34-
logger.warning("No auxiliary comment was found in the file.")
27+
rocket_tag = bs.find("rocket")
28+
if rocket_tag:
29+
settings["rocket_name"] = getattr(rocket_tag.find("name"), "text", "")
30+
logger.info("Collected the rocket name: '%s'", settings["rocket_name"])
31+
32+
comment_tag = rocket_tag.find("comment")
33+
if comment_tag and comment_tag.text:
34+
settings["comment"] = comment_tag.text.replace("\n", "")
35+
logger.info(
36+
"Collected the comment saved in the file: %s", settings["comment"]
37+
)
38+
else:
39+
logger.warning("No auxiliary comment was found in the file.")
40+
settings["comment"] = None
41+
42+
designer_tag = rocket_tag.find("designer")
43+
if designer_tag and designer_tag.text:
44+
settings["designer"] = designer_tag.text
45+
logger.info("Collected the designer name: %s", settings["designer"])
46+
else:
47+
logger.warning("No designer name was found in the file.")
48+
settings["designer"] = None
49+
else:
50+
settings["rocket_name"] = ""
3551
settings["comment"] = None
36-
try:
37-
settings["designer"] = bs.find("rocket").find("designer").text
38-
logger.info("Collected the designer name: %s", settings["designer"])
39-
except AttributeError:
40-
logger.warning("No designer name was found in the file.")
4152
settings["designer"] = None
4253
# settings["ork_version"] = bs.attrs["creator"]
4354
settings["filepath"] = Path(filepath).as_posix()

rocketserializer/components/motor.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,18 @@ def search_motor(bs, datapoints, data_labels):
3939
settings = {}
4040

4141
# retrieve motor geometry
42-
motor_length = float(bs.find("motormount").find("length").text)
43-
motor_radius = float(bs.find("motormount").find("diameter").text) / 2
42+
motormount = bs.find("motormount")
43+
if motormount is not None:
44+
motor_length = float(getattr(motormount.find("length"), "text", "") or "0")
45+
diam = getattr(motormount.find("diameter"), "text", "") or "0"
46+
motor_radius = float(diam) / 2
47+
else:
48+
motor_length = 0.0
49+
motor_radius = 0.0
4450
logger.info("Collected motor geometry: motor length and motor radius.")
4551

4652
# get motor mass properties
4753
total_propellant_mass, motor_dry_mass, _ = __get_motor_mass(datapoints, data_labels)
48-
motor_dry_mass = 0 # If NOTE: dry inertia is 0, this should ALWAYS be 0 too.
4954
center_of_dry_mass = 0
5055
dry_inertia = (0, 0, 0) # impossible to retrieve from .ork file
5156

@@ -183,6 +188,10 @@ def __get_motor_mass(datapoints, data_labels):
183188
prop_mass_vector = motor_mass - motor_dry_mass
184189
prop_mass_vector = list(prop_mass_vector)
185190
logger.info("The motor dry mass is %.3f kg.", motor_dry_mass)
191+
else:
192+
raise ValueError(
193+
"Neither 'Propellant mass' nor 'Motor mass' found in data_labels."
194+
)
186195

187196
normalize = np.array(prop_mass_vector)
188197
normalize = normalize - normalize[np.argmin(normalize)]

rocketserializer/components/nose_cone.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ def search_nosecone(bs, elements=None, rocket_radius=None, just_radius=False):
2626
"""
2727
settings = {}
2828
nosecone = bs.find("nosecone") # TODO: allow for multiple nosecones
29-
name = nosecone.find("name").text if nosecone else "nosecone"
29+
name = getattr(nosecone.find("name"), "text", "") if nosecone else "nosecone"
3030

3131
if not nosecone:
3232
nosecones = list(
3333
filter(
34-
lambda x: x.find("name").text == "Nosecone", bs.find_all("transition")
34+
lambda x: getattr(x.find("name"), "text", "") == "Nosecone",
35+
bs.find_all("transition"),
3536
)
3637
)
3738
if len(nosecones) == 0:
@@ -41,9 +42,9 @@ def search_nosecone(bs, elements=None, rocket_radius=None, just_radius=False):
4142
logger.info("Multiple nosecones found, using only the first one")
4243
nosecone = nosecones[0] # only the first nosecone is considered
4344

44-
length = float(nosecone.find("length").text)
45-
kind = nosecone.find("shape").text
46-
base_radius = nosecone.find("aftradius").text
45+
length = float(getattr(nosecone.find("length"), "text", "0"))
46+
kind = getattr(nosecone.find("shape"), "text", "")
47+
base_radius = getattr(nosecone.find("aftradius"), "text", "")
4748
try:
4849
base_radius = float(base_radius)
4950
except ValueError:
@@ -83,10 +84,11 @@ def get_position(name, length):
8384
if kind == "haack":
8485
logger.info("Nosecone is a haack nosecone, searching for the shape parameter")
8586

86-
shape_parameter = float(nosecone.find("shapeparameter").text)
87+
shape_parameter = float(getattr(nosecone.find("shapeparameter"), "text", "0"))
8788
kind = "Von Karman" if shape_parameter == 0.0 else "lvhaack"
88-
settings.update({"noseShapeParameter": shape_parameter})
8989
logger.info("Shape parameter of the nosecone: %s", shape_parameter)
90+
else:
91+
shape_parameter = None
9092

9193
settings = {
9294
"name": name,
@@ -95,5 +97,8 @@ def get_position(name, length):
9597
"base_radius": base_radius,
9698
"position": get_position(name, length),
9799
}
100+
if shape_parameter is not None:
101+
settings["noseShapeParameter"] = shape_parameter
102+
98103
logger.info("Nosecone setting defined:\n %s", _dict_to_string(settings, indent=23))
99104
return settings

rocketserializer/components/parachute.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,24 @@ def search_parachutes(bs):
3030

3131
for idx, chute in enumerate(chutes):
3232
logger.info("Starting to collect the settings of the parachute number %d", idx)
33-
name = chute.find("name").text
33+
name = getattr(chute.find("name"), "text", "")
3434

3535
# parachute settings
36-
cd = "auto" if "auto" in chute.find("cd").text else float(chute.find("cd").text)
36+
cd = (
37+
"auto"
38+
if "auto" in getattr(chute.find("cd"), "text", "")
39+
else float(getattr(chute.find("cd"), "text", "0"))
40+
)
3741
cd = search_cd_chute_if_auto(chute) if cd == "auto" else cd
38-
area = np.pi * float(chute.find("diameter").text) ** 2 / 4
42+
area = np.pi * float(getattr(chute.find("diameter"), "text", "0")) ** 2 / 4
3943
cds = cd * area
4044
logger.info("Parachute '%s' has a drag coefficient of %f", name, cd)
4145

4246
# deployment settings
43-
deploy_event = chute.find("deployevent").text
44-
deploy_delay = float(chute.find("deploydelay").text)
47+
deploy_event = getattr(chute.find("deployevent"), "text", "")
48+
deploy_delay = float(getattr(chute.find("deploydelay"), "text", "0"))
4549
deploy_altitude = (
46-
float(chute.find("deployaltitude").text)
50+
float(getattr(chute.find("deployaltitude"), "text", "0"))
4751
if deploy_event == "altitude"
4852
else None
4953
)
@@ -70,17 +74,11 @@ def search_parachutes(bs):
7074

7175

7276
def search_cd_chute_if_auto(bs):
73-
# if the parachute cd is st to "auto", then look for the cd in the next tag
74-
# return float(
75-
# next(
76-
# filter(lambda x: x.text.replace(".", "").isnumeric(), bs.findAll("cd"))
77-
# ).text
78-
# )
79-
80-
# TODO: for the future, we need to check if the ork object has a drag coefficient
81-
82-
# simply return 1.0
77+
# if the parachute cd is set to "auto", OpenRocket defaults to 0.75 (flat)
78+
# or 1.5 (dome). Since we cannot easily deduce the type, 0.75 is the
79+
# most common standard parachute CD in OR.
8380
logger.warning(
84-
"cd auto: the cd is set to 1.0 for parachute %s", bs.find("name").text
81+
"cd auto: the cd is set to 0.75 for parachute %s",
82+
getattr(bs.find("name"), "text", "Unknown"),
8583
)
86-
return 1.0
84+
return 0.75

rocketserializer/components/rail_buttons.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ def search_rail_buttons(bs, elements: dict) -> dict:
2525
angular_position = 0.0
2626
lugs = bs.find_all("launchlug")
2727
for lug in lugs:
28-
if lug.find("name").text == name:
29-
angular_position = float(lug.find("radialdirection").text)
28+
if getattr(lug.find("name"), "text", "") == name:
29+
angular_position = float(getattr(lug.find("radialdirection"), "text", "0"))
3030
break
3131

3232
return {

0 commit comments

Comments
 (0)