Skip to content

Commit

Permalink
ENH: prevent out of bounds Tanks from construction.
Browse files Browse the repository at this point in the history
  • Loading branch information
phmbressan committed Nov 23, 2023
1 parent 6894dd4 commit 0b28b2c
Showing 1 changed file with 84 additions and 22 deletions.
106 changes: 84 additions & 22 deletions rocketpy/motors/tank.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ def __init__(self, name, geometry, flux_time, liquid, gas, discretize=100):
# Initialize plots and prints object
self.prints = _TankPrints(self)
self.plots = _TankPlots(self)
return None

@property
def flux_time(self):
Expand Down Expand Up @@ -410,6 +409,73 @@ def inertia(self):
"""
return self.liquid_inertia + self.gas_inertia

def _check_volume_bounds(self):
"""Checks if the tank is overfilled or underfilled. Raises a ValueError
if the tank is overfilled or underfilled.
"""
if (self.fluid_volume > self.geometry.total_volume + 1e-6).any():
raise ValueError(
f"The tank '{self.name}' is overfilled. The fluid volume is "
+ "greater than the total volume of the tank.\n\t\t"
+ "Try increasing the tank height and check out the fluid density"
+ " values.\n\t\t"
+ f"The fluid volume is {np.max(self.fluid_volume.y_array):.3f} m³ at "
+ f"{self.fluid_volume.x_array[np.argmax(self.fluid_volume.y_array)]:.3f} s."
)
elif (self.fluid_volume < -1e-6).any():
raise ValueError(
f"The tank '{self.name}' is underfilled. The fluid volume is "
+ "negative.\n\t\t"
+ "Try increasing input fluid quantities and check out the fluid density"
+ " values.\n\t\t"
+ f"The fluid volume is {np.min(self.fluid_volume.y_array):.3f} m³ at "
+ f"{self.fluid_volume.x_array[np.argmin(self.fluid_volume.y_array)]:.3f} s."
)

def _check_height_bounds(self):
"""Checks if the tank is overfilled or underfilled. Raises a ValueError
if the tank is overfilled or underfilled.
"""
top_tolerance = self.geometry.top + 1e-4
bottom_tolerance = self.geometry.bottom - 1e-4

if (self.liquid_height > top_tolerance).any():
raise ValueError(
f"The tank '{self.name}' is overfilled. "
+ f"The liquid height is above the tank top.\n\t\t"
+ "Try increasing the tank height and check out the fluid density"
+ " values.\n\t\t"
+ f"The liquid height is {np.max(self.liquid_height.y_array):.3f} m above "
+ f"the tank top at {self.liquid_height.x_array[np.argmax(self.liquid_height.y_array)]:.3f} s."
)
elif (self.liquid_height < bottom_tolerance).any():
raise ValueError(
f"The tank '{self.name}' is underfilled. "
+ "The liquid height is below the tank bottom.\n\t\t"
+ "Try increasing input fluid quantities and check out the fluid density"
+ " values.\n\t\t"
+ f"The liquid height is {np.min(self.liquid_height.y_array):.3f} m below "
+ f"the tank bottom at {self.liquid_height.x_array[np.argmin(self.liquid_height.y_array)]:.3f} s."
)
elif (self.gas_height > top_tolerance).any():
raise ValueError(
f"The tank '{self.name}' is overfilled. "
+ "The gas height is above the tank top.\n\t\t"
+ "Try increasing the tank height and check out the fluid density"
+ " values.\n\t\t"
+ f"The gas height is {np.max(self.gas_height.y_array):.3f} m above "
+ f"the tank top at {self.gas_height.x_array[np.argmax(self.gas_height.y_array)]:.3f} s."
)
elif (self.gas_height < bottom_tolerance).any():
raise ValueError(
f"The tank '{self.name}' is underfilled. "
+ "The gas height is below the tank bottom.\n\t\t"
+ "Try increasing input fluid quantities and check out the fluid density"
+ " values.\n\t\t"
+ f"The gas height is {np.min(self.gas_height.y_array):.3f} m below "
+ f"the tank bottom at {self.gas_height.x_array[np.argmin(self.gas_height.y_array)]:.3f} s."
)

def draw(self):
"""Draws the tank geometry."""
self.plots.draw()
Expand Down Expand Up @@ -535,7 +601,10 @@ def __init__(

# Discretize input flow if needed
self.discretize_flow() if discretize else None
return None

# Check if the tank is overfilled or underfilled
self._check_volume_bounds()
self._check_height_bounds()

@funcify_method("Time (s)", "Mass (kg)")
def fluid_mass(self):
Expand Down Expand Up @@ -814,15 +883,9 @@ def __init__(
# Discretize input if needed
self.discretize_ullage() if discretize else None

# Check if the ullage is within bounds
if (self.ullage > self.geometry.total_volume).any():
raise ValueError(
"The ullage volume is out of bounds. It is greater than the "
+ "total volume of the tank."
)
if (self.ullage < 0).any():
raise ValueError("The ullage volume is out of bounds. It is negative.")
return None
# Check if the tank is overfilled or underfilled
self._check_volume_bounds()
self._check_height_bounds()

@funcify_method("Time (s)", "Mass (kg)")
def fluid_mass(self):
Expand Down Expand Up @@ -862,7 +925,7 @@ def fluid_volume(self):
Function
Volume of the fluid as a function of time.
"""
return self.geometry.total_volume
return Function(self.geometry.total_volume).set_discrete_based_on_model(self.gas_volume)

@funcify_method("Time (s)", "Volume (m³)")
def liquid_volume(self):
Expand Down Expand Up @@ -1012,13 +1075,9 @@ def __init__(
# Discretize input if needed
self.discretize_liquid_height() if discretize else None

# Check if the liquid level is within bounds
if (self.liquid_level > self.geometry.top).any():
raise ValueError(
"The liquid level is out of bounds. It is greater than the tank top."
)
if (self.liquid_level < self.geometry.bottom).any():
raise ValueError("The liquid level is out of bounds. It is negative.")
# Check if the tank is overfilled or underfilled
self._check_volume_bounds()
self._check_height_bounds()

@funcify_method("Time (s)", "Mass (kg)")
def fluid_mass(self):
Expand Down Expand Up @@ -1062,7 +1121,7 @@ def fluid_volume(self):
Volume of the fluid as a function of time.
"""
volume = self.gas_volume + self.liquid_volume
diff = abs(volume - self.geometry.total_volume)
diff = volume - self.geometry.total_volume
if (diff > 1e-6).any():
raise ValueError(
"The `fluid_volume`, defined as the sum of `gas_volume` and "
Expand Down Expand Up @@ -1096,9 +1155,8 @@ def gas_volume(self):
Volume of the gas as a function of time.
"""
# TODO: there's a bug on the gas_center_of_mass is I don't discretize here
func = Function(self.geometry.total_volume)
func = Function(self.geometry.total_volume).set_discrete_based_on_model(self.liquid_volume)
func -= self.liquid_volume
func.set_discrete_based_on_model(self.liquid_volume)
return func

@funcify_method("Time (s)", "Height (m)")
Expand Down Expand Up @@ -1230,6 +1288,10 @@ def __init__(
# Discretize input if needed
self.discretize_masses() if discretize else None

# Check if the tank is overfilled or underfilled
self._check_volume_bounds()
self._check_height_bounds()

@funcify_method("Time (s)", "Mass (kg)")
def fluid_mass(self):
"""
Expand Down

0 comments on commit 0b28b2c

Please sign in to comment.