Skip to content

Commit 82bd50f

Browse files
committed
TST: introduce testing to variable density tanks.
1 parent 4eacbad commit 82bd50f

File tree

14 files changed

+354
-20
lines changed

14 files changed

+354
-20
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
Temperature (K),Pressure (Pa),Density (kg/m³)
2+
193.150000,101325.000000,2.839688
3+
205.372222,101325.000000,2.659196
4+
217.594444,101325.000000,2.501930
5+
229.816667,101325.000000,2.363172
6+
242.038889,101325.000000,2.239591
7+
254.261111,101325.000000,2.128693
8+
266.483333,101325.000000,2.028539
9+
278.705556,101325.000000,1.937588
10+
290.927778,101325.000000,1.854594
11+
303.150000,101325.000000,1.778532
12+
193.150000,990733.333333,1206.532256
13+
205.372222,990733.333333,1168.931406
14+
217.594444,990733.333333,1129.335464
15+
229.816667,990733.333333,1087.042281
16+
242.038889,990733.333333,24.480299
17+
254.261111,990733.333333,22.807515
18+
266.483333,990733.333333,21.414919
19+
278.705556,990733.333333,20.221402
20+
290.927778,990733.333333,19.178742
21+
303.150000,990733.333333,18.255258
22+
193.150000,1880141.666667,1207.901606
23+
205.372222,1880141.666667,1170.560205
24+
217.594444,1880141.666667,1131.305292
25+
229.816667,1880141.666667,1089.479276
26+
242.038889,1880141.666667,1044.107836
27+
254.261111,1880141.666667,993.574261
28+
266.483333,1880141.666667,44.818526
29+
278.705556,1880141.666667,41.521255
30+
290.927778,1880141.666667,38.847302
31+
303.150000,1880141.666667,36.598433
32+
193.150000,2769550.000000,1209.256890
33+
205.372222,2769550.000000,1172.168610
34+
217.594444,2769550.000000,1133.244437
35+
229.816667,2769550.000000,1091.867709
36+
242.038889,2769550.000000,1047.140735
37+
254.261111,2769550.000000,997.611513
38+
266.483333,2769550.000000,940.542069
39+
278.705556,2769550.000000,67.699444
40+
290.927778,2769550.000000,61.910544
41+
303.150000,2769550.000000,57.447399
42+
193.150000,3658958.333333,1210.598454
43+
205.372222,3658958.333333,1173.757228
44+
217.594444,3658958.333333,1135.154031
45+
229.816667,3658958.333333,1094.209859
46+
242.038889,3658958.333333,1050.096018
47+
254.261111,3658958.333333,1001.503955
48+
266.483333,3658958.333333,946.059899
49+
278.705556,3658958.333333,878.329006
50+
290.927778,3658958.333333,90.504952
51+
303.150000,3658958.333333,81.893190
52+
193.150000,4548366.666667,1211.926631
53+
205.372222,4548366.666667,1175.326641
54+
217.594444,4548366.666667,1137.035143
55+
229.816667,4548366.666667,1096.507838
56+
242.038889,4548366.666667,1052.978332
57+
254.261111,4548366.666667,1005.263627
58+
266.483333,4548366.666667,951.292446
59+
278.705556,4548366.666667,886.629576
60+
290.927778,4548366.666667,130.554270
61+
303.150000,4548366.666667,112.079628
62+
193.150000,5437775.000000,1213.241741
63+
205.372222,5437775.000000,1176.877402
64+
217.594444,5437775.000000,1138.888779
65+
229.816667,5437775.000000,1098.763608
66+
242.038889,5437775.000000,1055.791888
67+
254.261111,5437775.000000,1008.901026
68+
266.483333,5437775.000000,956.273388
69+
278.705556,5437775.000000,894.237174
70+
290.927778,5437775.000000,812.409895
71+
303.150000,5437775.000000,153.463224
72+
193.150000,6327183.333333,1214.544092
73+
205.372222,6327183.333333,1178.410038
74+
217.594444,6327183.333333,1140.715888
75+
229.816667,6327183.333333,1100.978992
76+
242.038889,6327183.333333,1058.540519
77+
254.261111,6327183.333333,1012.425369
78+
266.483333,6327183.333333,961.030387
79+
278.705556,6327183.333333,901.279439
80+
290.927778,6327183.333333,825.421408
81+
303.150000,6327183.333333,689.418589
82+
193.150000,7216591.666667,1215.833981
83+
205.372222,7216591.666667,1179.925053
84+
217.594444,7216591.666667,1142.517369
85+
229.816667,7216591.666667,1103.155693
86+
242.038889,7216591.666667,1061.227727
87+
254.261111,7216591.666667,1015.844801
88+
266.483333,7216591.666667,965.586483
89+
278.705556,7216591.666667,907.849718
90+
290.927778,7216591.666667,836.658448
91+
303.150000,7216591.666667,729.094125
92+
193.150000,8106000.000000,1217.111692
93+
205.372222,8106000.000000,1181.422931
94+
217.594444,8106000.000000,1144.294074
95+
229.816667,8106000.000000,1105.295297
96+
242.038889,8106000.000000,1063.856717
97+
254.261111,8106000.000000,1019.166555
98+
266.483333,8106000.000000,969.961109
99+
278.705556,8106000.000000,914.018666
100+
290.927778,8106000.000000,846.619843
101+
303.150000,8106000.000000,753.272731

docs/user/motors/tanks.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ Fluid are then passed to tanks when they are defined.
8080
a dataset or external libraries.
8181
In this case, the fluid would be defined as such:
8282

83-
>>> Fluid(name="Liquid Nitrous Oxide", density=lambda t, p: 44 * p / (8.314 * t))
83+
>>> Fluid(name="N2O", density=lambda t, p: 44 * p / (8.314 * t))
84+
>>> from CoolProp.CoolProp import PropsSI # external library
85+
>>> Fluid(name="N2O", density=lambda t, p: PropsSI('D', 'T', t, 'P', p, 'N2O'))
8486

8587
In fact, the density parameter can be any ``Function`` source, such as a
8688
``callable``, csv file or an array of points. See more on

rocketpy/mathutils/function.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3695,8 +3695,9 @@ def savetxt(
36953695
+ " must be provided."
36963696
)
36973697
# Generate the data points using the callable
3698-
x = np.linspace(lower, upper, samples)
3699-
data_points = np.column_stack((x, self(x)))
3698+
data_points = self.set_discrete(
3699+
lower, upper, samples, mutate_self=False
3700+
).source
37003701
else:
37013702
# If the source is already an array, use it as is
37023703
data_points = self.source

rocketpy/motors/fluid.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import numpy as np
2+
from scipy.constants import atm, zero_Celsius
23

34
from ..mathutils.function import Function
45
from ..plots.fluid_plots import _FluidPlots
@@ -69,7 +70,7 @@ def density_function(temperature, pressure):
6970

7071
self._density_function = Function(
7172
density_function,
72-
interpolation="shepard",
73+
interpolation="linear",
7374
extrapolation="natural",
7475
inputs=["Temperature (K)", "Pressure (Pa)"],
7576
outputs="Density (kg/m³)",
@@ -90,7 +91,7 @@ def get_time_variable_density(self, temperature, pressure):
9091
Function
9192
Density of the fluid in kg/m³ as function of time.
9293
"""
93-
if callable(temperature.source):
94+
if callable(temperature.source) and callable(pressure.source):
9495
return Function(
9596
lambda time: self.density_function.get_value(
9697
temperature.source(time), pressure.source(time)
@@ -99,13 +100,16 @@ def get_time_variable_density(self, temperature, pressure):
99100
outputs="Density (kg/m³)",
100101
)
101102
else:
103+
time_scale = np.unique(
104+
np.concatenate((temperature.x_array, pressure.x_array))
105+
)
102106
density_time = self.density_function.get_value(
103-
temperature.y_array, pressure.y_array
107+
temperature.get_value(time_scale), pressure.get_value(time_scale)
104108
)
105109
return Function(
106110
np.column_stack(
107111
(
108-
temperature.x_array,
112+
time_scale,
109113
density_time,
110114
)
111115
),
@@ -138,7 +142,20 @@ def __str__(self):
138142
return f"Fluid: {self.name}"
139143

140144
def to_dict(self, **kwargs): # pylint: disable=unused-argument
141-
return {"name": self.name, "density": self.density}
145+
discretize = kwargs.get("discretize", False)
146+
if not isinstance(self.density, (int, float, np.number)):
147+
density = self.density_function
148+
else:
149+
density = self.density
150+
151+
if discretize and isinstance(density, Function):
152+
density = density.set_discrete(
153+
((100, atm * 0.9), (zero_Celsius + 30, atm * 100)),
154+
(25, 25),
155+
mutate_self=False,
156+
)
157+
158+
return {"name": self.name, "density": density}
142159

143160
@classmethod
144161
def from_dict(cls, data):

rocketpy/motors/tank.py

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,8 @@ def to_dict(self, **kwargs):
627627
"liquid": self.liquid,
628628
"gas": self.gas,
629629
"discretize": self.discretize,
630+
"temperature": self.temperature,
631+
"pressure": self.pressure,
630632
}
631633
if kwargs.get("include_outputs", False):
632634
data.update(
@@ -674,6 +676,8 @@ def __init__(
674676
liquid_mass_flow_rate_out,
675677
gas_mass_flow_rate_out,
676678
discretize=100,
679+
temperature=None,
680+
pressure=None,
677681
):
678682
"""Initializes the MassFlowRateBasedTank class.
679683
@@ -733,8 +737,26 @@ def __init__(
733737
this parameter may be set to None. Otherwise, an uniform
734738
discretization will be applied based on the discretize value.
735739
The default is 100.
740+
temperature : int, float, callable, string, array, Function
741+
Temperature inside the tank as a function of time in K. If a callable
742+
is given, it must be a function of time in seconds. An array of points
743+
can also be given as a list or a string with the path to a .csv file
744+
with two columns, the first one being the time in seconds and the
745+
second one being the temperature in K. The default is None. This
746+
parameter is only required if fluid (``liquid`` or ``gas`` parameters)
747+
densities are functions of temperature.
748+
pressure : int, float, callable, string, array, Function
749+
Pressure inside the tank as a function of time in Pa. If a callable
750+
is given, it must be a function of time in seconds. An array of points
751+
can also be given as a list or a string with the path to a .csv file
752+
with two columns, the first one being the time in seconds and the
753+
second one being the pressure in Pa. The default is None. This
754+
parameter is only required if fluid (``liquid`` or ``gas`` parameters)
755+
densities are functions of pressure.
736756
"""
737-
super().__init__(name, geometry, flux_time, liquid, gas, discretize)
757+
super().__init__(
758+
name, geometry, flux_time, liquid, gas, discretize, temperature, pressure
759+
)
738760
self.initial_liquid_mass = initial_liquid_mass
739761
self.initial_gas_mass = initial_gas_mass
740762

@@ -1032,6 +1054,8 @@ def from_dict(cls, data):
10321054
liquid_mass_flow_rate_out=data["liquid_mass_flow_rate_out"],
10331055
gas_mass_flow_rate_out=data["gas_mass_flow_rate_out"],
10341056
discretize=data["discretize"],
1057+
temperature=data.get("temperature"),
1058+
pressure=data.get("pressure"),
10351059
)
10361060

10371061

@@ -1056,6 +1080,8 @@ def __init__(
10561080
gas,
10571081
ullage,
10581082
discretize=100,
1083+
temperature=None,
1084+
pressure=None,
10591085
):
10601086
"""
10611087
Parameters
@@ -1089,8 +1115,26 @@ def __init__(
10891115
an uniform discretization will be applied based on the discretize
10901116
value.
10911117
The default is 100.
1118+
temperature : int, float, callable, string, array, Function
1119+
Temperature inside the tank as a function of time in K. If a callable
1120+
is given, it must be a function of time in seconds. An array of points
1121+
can also be given as a list or a string with the path to a .csv file
1122+
with two columns, the first one being the time in seconds and the
1123+
second one being the temperature in K. The default is None. This
1124+
parameter is only required if fluid (``liquid`` or ``gas`` parameters)
1125+
densities are functions of temperature.
1126+
pressure : int, float, callable, string, array, Function
1127+
Pressure inside the tank as a function of time in Pa. If a callable
1128+
is given, it must be a function of time in seconds. An array of points
1129+
can also be given as a list or a string with the path to a .csv file
1130+
with two columns, the first one being the time in seconds and the
1131+
second one being the pressure in Pa. The default is None. This
1132+
parameter is only required if fluid (``liquid`` or ``gas`` parameters)
1133+
densities are functions of pressure.
10921134
"""
1093-
super().__init__(name, geometry, flux_time, liquid, gas, discretize)
1135+
super().__init__(
1136+
name, geometry, flux_time, liquid, gas, discretize, temperature, pressure
1137+
)
10941138

10951139
# Define ullage
10961140
self.ullage = Function(ullage, "Time (s)", "Volume (m³)", "linear")
@@ -1248,6 +1292,8 @@ def from_dict(cls, data):
12481292
gas=data["gas"],
12491293
ullage=data["ullage"],
12501294
discretize=data["discretize"],
1295+
temperature=data.get("temperature"),
1296+
pressure=data.get("pressure"),
12511297
)
12521298

12531299

@@ -1272,6 +1318,8 @@ def __init__(
12721318
gas,
12731319
liquid_height,
12741320
discretize=100,
1321+
temperature=None,
1322+
pressure=None,
12751323
):
12761324
"""
12771325
Parameters
@@ -1305,8 +1353,26 @@ def __init__(
13051353
Otherwise, an uniform discretization will be applied based on the
13061354
discretize value.
13071355
The default is 100.
1356+
temperature : int, float, callable, string, array, Function
1357+
Temperature inside the tank as a function of time in K. If a callable
1358+
is given, it must be a function of time in seconds. An array of points
1359+
can also be given as a list or a string with the path to a .csv file
1360+
with two columns, the first one being the time in seconds and the
1361+
second one being the temperature in K. The default is None. This
1362+
parameter is only required if fluid (``liquid`` or ``gas`` parameters)
1363+
densities are functions of temperature.
1364+
pressure : int, float, callable, string, array, Function
1365+
Pressure inside the tank as a function of time in Pa. If a callable
1366+
is given, it must be a function of time in seconds. An array of points
1367+
can also be given as a list or a string with the path to a .csv file
1368+
with two columns, the first one being the time in seconds and the
1369+
second one being the pressure in Pa. The default is None. This
1370+
parameter is only required if fluid (``liquid`` or ``gas`` parameters)
1371+
densities are functions of pressure.
13081372
"""
1309-
super().__init__(name, geometry, flux_time, liquid, gas, discretize)
1373+
super().__init__(
1374+
name, geometry, flux_time, liquid, gas, discretize, temperature, pressure
1375+
)
13101376

13111377
# Define liquid level function
13121378
self.liquid_level = Function(liquid_height, "Time (s)", "height (m)", "linear")
@@ -1478,6 +1544,8 @@ def from_dict(cls, data):
14781544
gas=data["gas"],
14791545
liquid_height=data["liquid_height"],
14801546
discretize=data["discretize"],
1547+
temperature=data.get("temperature"),
1548+
pressure=data.get("pressure"),
14811549
)
14821550

14831551

@@ -1501,6 +1569,8 @@ def __init__(
15011569
liquid_mass,
15021570
gas_mass,
15031571
discretize=100,
1572+
temperature=None,
1573+
pressure=None,
15041574
):
15051575
"""
15061576
Parameters
@@ -1539,8 +1609,26 @@ def __init__(
15391609
may be set to None. Otherwise, an uniform discretization will be
15401610
applied based on the discretize value.
15411611
The default is 100.
1612+
temperature : int, float, callable, string, array, Function
1613+
Temperature inside the tank as a function of time in K. If a callable
1614+
is given, it must be a function of time in seconds. An array of points
1615+
can also be given as a list or a string with the path to a .csv file
1616+
with two columns, the first one being the time in seconds and the
1617+
second one being the temperature in K. The default is None. This
1618+
parameter is only required if fluid (``liquid`` or ``gas`` parameters)
1619+
densities are functions of temperature.
1620+
pressure : int, float, callable, string, array, Function
1621+
Pressure inside the tank as a function of time in Pa. If a callable
1622+
is given, it must be a function of time in seconds. An array of points
1623+
can also be given as a list or a string with the path to a .csv file
1624+
with two columns, the first one being the time in seconds and the
1625+
second one being the pressure in Pa. The default is None. This
1626+
parameter is only required if fluid (``liquid`` or ``gas`` parameters)
1627+
densities are functions of pressure.
15421628
"""
1543-
super().__init__(name, geometry, flux_time, liquid, gas, discretize)
1629+
super().__init__(
1630+
name, geometry, flux_time, liquid, gas, discretize, temperature, pressure
1631+
)
15441632

15451633
# Define fluid masses
15461634
self.liquid_mass = Function(liquid_mass, "Time (s)", "Mass (kg)", "linear")
@@ -1745,4 +1833,6 @@ def from_dict(cls, data):
17451833
liquid_mass=data["liquid_mass"],
17461834
gas_mass=data["gas_mass"],
17471835
discretize=data["discretize"],
1836+
temperature=data.get("temperature"),
1837+
pressure=data.get("pressure"),
17481838
)

0 commit comments

Comments
 (0)