Debug: Database connection successful
You are not logged in.
If u want i could write say, class planet,
and u could tell me what its attributes are:
Radius, mass, density ..
And which member functions it needs to have. Maybe:
get_diameter()
get_surface_area()
..
something like that.
Could be as much about learning as it is about doing the programming.
Last edited by offtherock (2025-08-27 04:11:02)
Offline
Like button can go here
For offtherock ... Thank you for your interest in converting the Python program to object style!
Everything needed should be available in the existing program. The equations may have to be changed to account for the new style.
At present, the mass of the Earth is stored in the form of a variable that is then employed in the equations as needed.
If object style is used, then the property of mass must be delivered to the question in a compact form.
***
For all... Version 15 is in a development phase. The process to model Flow of thermal energy from hot gas to cold metal is not yet working. Today I'm planning to work with Gemini to improve the flow. My guess is that we do not yet have a material defined for the container wall, so we do not have properties of that material to work with, such as thermal conductivity.
In the course of this investigation I am hoping to learn about thermal energy transfer by direct contact (conduction).
(th)
Offline
Like button can go here
I downloaded the program and ran it.
You can add
###
from modules.planet import Planet
earth = Planet('Earth');
earth.g_constant = 6.67430e-11
earth.mass = 5.972e24
earth.radius = 6.371e6
earth.sea_level_density = 1.225
# Gravitational constant (N * m^2 / kg^2)
# Default units are kg and meters.
###
right beneath the first 3 import lines.
But u need to make a folder called modules.
and in that folder, place file planet.py and put in that file:
class Planet:
def __init__(self, name):
self.name = name
def set_mass(self,new_mass):
self.mass = new_mass
Offline
Like button can go here
For offtherock ... re #78
It is good to have someone else taking an interest in this study, and specifically in design of the software.
You are welcome to make the changes you recommend and upload the amended version. Please test it first, to be sure it replicates the performance of the version you are replacing.
My focus is upon solving the physics problems, so that is where I'm working at the moment.
In the quote below, for anyone who might be interested in the physics and engineering of the model, I've captured today's discussion about the current inability to accurately model heat flows between gas and metal in the air capture device. The hypothesis we are pursuing is that cooling the air capture container will allow it to capture more air molecules. However, in the early stages of creating the software model, we have omitted details.
Hi Again! and thanks (again) for staying with me in this quest! In our effort to add a new feature to our program to simulate air capture, we have begun the process of figure out how to transfer thermal energy from hot gas to cold metal. At this point, I think we do not yet have the metal defined. Please confirm that. I think we identified a metal alloy that is at the upper range of temperature tolerance, but that alloy may not yet be encoded in the program? We need to select a metal for the air capture container, and we need to know how well that metal will absorb thermal energy of the hot gas that arrives as the projectile ascends. Attempting to model this process may be difficult for Python. I think it would be difficult for OpenFOAM. Here is a transcript of the latest run, along with a difference listing between Version 14 and 15. Do you think Python can solve this problem? In thinking about the problem, I realized that the surface area of metal exposed to the hot gas makes a big difference. We discussed using pipes of small diameter for the air capture device. Such pipes would be useful in construction of large objects in LEO. By using many such pipes for the air capture device, we maximize the surface area that is available for cooling. Let's use pipe that has ID of 4 cm and OD of 5 cm. This is a strong pipe suitable for on-orbit applications. Here is the transcript:
<< duplicate text removed >>
That's an excellent question, and thank you for the feedback. The results from Version 15 are definitely a problem, but they confirm we're still grappling with how to properly model the heat transfer. Let's address your points directly.
1. Python and the Thermal Problem ?
Yes, Python can solve this problem. While the previous attempts were flawed, it wasn't a limitation of the language itself, but rather the physical model being implemented. The current approach is more sophisticated than the "instantaneous equilibrium" model of Version 14, but it still seems to be missing a key piece of the physics.The issue is that our current model assumes a perfect, instantaneous heat exchange between the incoming air and the entire mass of the pipe. In reality, heat transfer is governed by rates. The heat must first transfer from the hot gas to the surface of the cold pipe, and then conduct inward. We can't model this fully with our current approach, but we can do a better job with an improved, simplified model.
2. A Corrected Thermal Model (The Next Step) ?️
The core problem in the Version 15 code (based on the diff report) is that heat_transferred_to_pipe is calculated using an energy balance that still seems to lead to an over-estimation of the thermal energy exchange, causing the temperature to rise to an absurd level. The massive temperature jump from 1535 K to 214,939 K is a clear sign that the model is still broken.The physics that needs to be modeled is more like this:
Work of Compression: For each time step, the incoming air's kinetic energy is converted into a corresponding rise in the gas's internal energy and pressure.
Heat Transfer: Heat then flows from the hot gas to the cold pipe's inner surface. The rate of this transfer depends on the surface area, the temperature difference, and the thermal properties of the gas and pipe.
Our current model is still skipping these crucial steps. It's essentially calculating a "final state" temperature, but that final state is physically impossible because it ignores the dynamics of the system.
3. Material Selection and Surface Area
You've made a brilliant point about the surface area. The design using many small-diameter pipes is a perfect engineering solution for this problem. Maximizing the surface area is the most effective way to improve the rate of heat transfer. Our current model uses a single pipe_mass_kg parameter but doesn't account for the surface area that mass represents.Here's how we'll fix this in the next version:
Define Pipe Properties: We'll define the specific properties of the pipes you suggested:
Inner Diameter (pipe_ID_m): 4 cm (0.04 m)
Outer Diameter (pipe_OD_m): 5 cm (0.05 m)
Calculate Number of Pipes: We can then calculate the volume and mass of a single pipe, and from the total pipe_mass_kg, determine the number of pipes required.
Calculate Total Surface Area: Using the number of pipes and the inner diameter, we can get the total internal surface area available for cooling.
Incorporate Heat Transfer Coefficient: We'll use a simplified heat transfer coefficient (h) to model the rate of heat flow from the gas to the pipe. This coefficient depends on the gas flow conditions and the material properties. While we don't have a specific metal defined yet, we can start with a general assumption and then add a material_properties dictionary to the code in the future. We've used a specific heat for steel so far, so let's stick with that for now.
The next version will include these changes to create a much more realistic thermal model that accounts for the physics of heat transfer over time and with surface area.
Summary of Next Steps
Model the new pipe geometry to calculate total cooling surface area.Implement a heat transfer coefficient to model the rate of heat flow from the air to the pipe.
Correct the thermal energy balance to properly calculate the temperatures of the air and the pipe in each time step.
I'm confident we can create a model that provides a more realistic and useful simulation of the system's performance. The "doors" are a problem for a later time; for now, let's focus on getting the physics of the core process correct. I am ready to implement these changes.
****
Thank you for your enlightening discussion of the problem at hand. I've decided to publish today's conversation because we have a couple of engineers in the group, and they may find the analysis interesting, and they might even have suggestions. Please do proceed to Version 16. I'm confident we will learn something, and the program will probably work better as we make adjustments.
***Thank you. It's great that you're sharing this with the wider group; their input will be invaluable. I'm ready to proceed with Version 16, which incorporates a more realistic thermal model based on heat transfer principles.
The Program (Version 16)
This version corrects the thermal model by incorporating your suggestion to use a collection of small pipes, which increases the cooling surface area. We'll now calculate the number of pipes required to hold the pipe_mass_kg and pipe_volume_m3 and use that to determine the total surface area available for cooling.The new approach for the thermal model is as follows:
Incoming Air Temperature: For each time step, the incoming air's temperature is calculated based on the work done to compress it.
Heat Transfer: The heat energy is then transferred from the air to the pipe based on a simplified heat transfer equation. The rate of heat transfer depends on the surface area, the temperature difference between the air and the pipe, and a heat transfer coefficient.
Pipe and Air Temperature Update: The energy transferred is used to update both the air's temperature (it cools down) and the pipe's temperature (it heats up).
This new model is a more accurate representation of the physics and should provide a much more realistic simulation of the cooling effect.
After rereading the discussion above, I realized that the temperature of the air capture equipment will rise as thermal energy flows in from the hot gas. I wonder if Gemini is taking that into account. If Gemini is assuming the metal is always 100 K, then the computed energy absorption will be greater than reality.
Version 15 was stored in another topic so that this post has a longer lifetime in the Active list.
(th)
Offline
Like button can go here
This is Version 16 with changes to address cooling...
import math
import json
import os
# --- Constants for Earth and Atmosphere ---
G = 6.67430e-11 # Gravitational constant (N * m^2 / kg^2)
M_EARTH = 5.972e24 # Mass of Earth (kg)
R_EARTH = 6.371e6 # Radius of Earth (m)
RHO_0 = 1.225 # Sea-level air density (kg/m^3)
H = 8500.0 # Atmospheric scale height (m)
CD = 0.2 # Drag coefficient for a streamlined body (assumed)
V_EXHAUST_ASSUMED = 1000.0 # Assumed exhaust velocity for outflow (m/s)
# --- Constants for Thermodynamic Calculations ---
TEMP_0_K = 288.0 # Sea-level standard temperature (Kelvin)
PRESS_0_PA = 101325.0 # Sea-level standard pressure (Pascals)
GAMMA = 1.4 # Heat capacity ratio for air
SPECIFIC_HEAT_AIR_J_KG_K = 1005.0 # Specific heat of air at constant pressure
SPECIFIC_HEAT_PIPE_J_KG_K = 450.0 # Specific heat of steel (J/kg*K)
PIPE_DENSITY_KG_M3 = 7850.0 # Density of steel (kg/m^3)
HEAT_TRANSFER_COEFFICIENT = 50.0 # W/(m^2*K) - A simplified assumption for internal forced convection
# Molar masses (kg/mol)
MOLAR_MASS_DRY_AIR = 0.028965
MOLAR_MASS_WATER = 0.018015
# Mass fractions of dry air
MASS_FRACTION_NITROGEN = 0.755
MASS_FRACTION_OXYGEN = 0.232
# --- File for saving parameters ---
PARAMS_FILE = "simulation_params.json"
VERSION = 16
def get_gravity(altitude_meters):
"""Calculates the acceleration due to gravity at a given altitude."""
r = R_EARTH + altitude_meters
return G * M_EARTH / r**2
def get_vapor_pressure(temp_celsius):
"""Calculates saturation vapor pressure in Pa using the Arden Buck equation."""
es = 0.61121 * math.exp((18.678 - (temp_celsius / 234.5)) * (temp_celsius / (257.14 + temp_celsius)))
return es * 1000.0
def get_air_density(altitude_meters, relative_humidity_percent=0.0):
"""
Calculates moist air density using a simplified exponential model and humidity.
Relative humidity is a percentage from 0 to 100.
"""
temp_celsius = TEMP_0_K - 273.15
es_pa = get_vapor_pressure(temp_celsius)
e_pa = es_pa * (relative_humidity_percent / 100.0)
rho_moist_0 = (PRESS_0_PA / (287.058 * TEMP_0_K)) * (1 - e_pa / PRESS_0_PA * (1 - MOLAR_MASS_WATER / MOLAR_MASS_DRY_AIR))
return rho_moist_0 * math.exp(-altitude_meters / H)
def get_gas_pressure(mass_kg, volume_m3, temp_K, relative_humidity_percent=0.0):
"""
Estimates pressure of collected gas using Ideal Gas Law, adjusted for molar mass.
"""
temp_celsius = TEMP_0_K - 273.15
es_pa = get_vapor_pressure(temp_celsius)
e_pa = es_pa * (relative_humidity_percent / 100.0)
mole_fraction_water = e_pa / PRESS_0_PA
mole_fraction_dry_air = 1.0 - mole_fraction_water
avg_molar_mass = (mole_fraction_dry_air * MOLAR_MASS_DRY_AIR) + (mole_fraction_water * MOLAR_MASS_WATER)
R = 8.314
n = mass_kg / avg_molar_mass
if volume_m3 <= 0:
return float('inf')
return (n * R * temp_K) / volume_m3
def simulate_air_harvesting_launch(
projectile_diameter_m,
pipe_mass_kg,
payload_mass_kg,
rocket_mass_kg,
initial_velocity_mps,
launch_altitude_meters_above_sea_level,
final_altitude_meters_above_sea_level,
pipe_volume_m3,
pipe_ID_m,
pipe_OD_m,
time_step_s,
use_door_closing,
outflow_rate_factor,
relative_humidity_percent,
initial_pipe_temp_K,
version
):
"""
Simulates a projectile launch with subsystem mass inputs and pre-cooling.
"""
initial_projectile_mass_kg = pipe_mass_kg + payload_mass_kg + rocket_mass_kg
if initial_velocity_mps <= 0 or projectile_diameter_m <= 0 or initial_projectile_mass_kg <= 0:
print("Error: All initial values must be positive.")
return
# Calculate pipe properties based on mass and volume
pipe_cross_sectional_area = math.pi * ((pipe_OD_m / 2)**2 - (pipe_ID_m / 2)**2)
pipe_length_for_mass = pipe_mass_kg / (pipe_cross_sectional_area * PIPE_DENSITY_KG_M3)
# Calculate number of pipes needed to achieve the specified volume
pipe_internal_volume_single = math.pi * (pipe_ID_m / 2)**2 * pipe_length_for_mass
number_of_pipes = pipe_volume_m3 / pipe_internal_volume_single if pipe_internal_volume_single > 0 else 0
total_cooling_surface_area_sqm = number_of_pipes * math.pi * pipe_ID_m * pipe_length_for_mass
current_mass_kg = initial_projectile_mass_kg
current_velocity_mps = initial_velocity_mps
current_altitude_m = launch_altitude_meters_above_sea_level
current_time_s = 0.0
cross_sectional_area_sqm = math.pi * (projectile_diameter_m / 2)**2
total_work_done_on_air_J = 0.0
total_work_done_against_gravity_J = 0.0
doors_closed = False
pipe_is_full = False
pipe_is_empty = False
collected_air_mass = 0.0
gas_temperature_K = TEMP_0_K
pipe_temperature_K = initial_pipe_temp_K
print(f"--- Gas Gun Air Harvesting Simulation V{version} ---")
print(f"Projectile Diameter: {projectile_diameter_m} m")
print(f"Initial Mass: {initial_projectile_mass_kg} kg")
print(f"Pipe Mass: {pipe_mass_kg} kg")
print(f"Payload Mass: {payload_mass_kg} kg")
print(f"Rocket Mass: {rocket_mass_kg} kg")
print(f"Initial Velocity: {initial_velocity_mps} m/s ({initial_velocity_mps/1000:.2f} km/s)")
print(f"Target Altitude: {final_altitude_meters_above_sea_level / 1000:.0f} km")
print(f"Pipe Volume: {pipe_volume_m3} m^3")
print(f"Pipe ID/OD: {pipe_ID_m*100:.2f} cm / {pipe_OD_m*100:.2f} cm")
print(f"Calculated Number of Pipes: {number_of_pipes:.0f}")
print(f"Total Cooling Surface Area: {total_cooling_surface_area_sqm:.2f} m^2")
print(f"Relative Humidity: {relative_humidity_percent:.1f}%")
print(f"Initial Pipe Temp: {initial_pipe_temp_K:.1f} K")
print(f"Use Door Closing: {use_door_closing}")
print("------------------------------------------")
while current_altitude_m < final_altitude_meters_above_sea_level:
if current_velocity_mps <= 0:
print(f"Projectile stalled at {current_altitude_m / 1000:.2f} km. Velocity is zero or negative.")
break
g = get_gravity(current_altitude_m)
rho = get_air_density(current_altitude_m, relative_humidity_percent)
force_gravity = current_mass_kg * g
net_force = -force_gravity
dynamic_pressure = 0.5 * rho * current_velocity_mps**2
if not doors_closed and not pipe_is_full:
mass_collected_in_step = rho * cross_sectional_area_sqm * current_velocity_mps * time_step_s
# Simplified thermal model with heat transfer
if mass_collected_in_step > 0:
# Energy added to air from compression
work_air_step = 0.5 * mass_collected_in_step * current_velocity_mps**2
# New temperature of the collected air before mixing
temp_new_air = TEMP_0_K + (work_air_step / (mass_collected_in_step * SPECIFIC_HEAT_AIR_J_KG_K))
# Calculate the energy of the combined air mass (old + new)
total_energy_air = (collected_air_mass * SPECIFIC_HEAT_AIR_J_KG_K * gas_temperature_K) + \
(mass_collected_in_step * SPECIFIC_HEAT_AIR_J_KG_K * temp_new_air)
total_mass_in_pipe = collected_air_mass + mass_collected_in_step
# Update the air temperature to reflect mixing
gas_temperature_K = total_energy_air / (total_mass_in_pipe * SPECIFIC_HEAT_AIR_J_KG_K)
# Calculate heat transfer between air and pipe
temp_diff = gas_temperature_K - pipe_temperature_K
heat_transferred = HEAT_TRANSFER_COEFFICIENT * total_cooling_surface_area_sqm * temp_diff * time_step_s
# Cap heat transfer at the energy available in the air
heat_transferred = min(heat_transferred, total_energy_air)
# Update temperatures based on heat transfer
gas_temperature_K -= heat_transferred / (total_mass_in_pipe * SPECIFIC_HEAT_AIR_J_KG_K)
pipe_temperature_K += heat_transferred / (pipe_mass_kg * SPECIFIC_HEAT_PIPE_J_KG_K)
else:
total_mass_in_pipe = collected_air_mass
internal_pressure = get_gas_pressure(total_mass_in_pipe, pipe_volume_m3, gas_temperature_K, relative_humidity_percent)
if use_door_closing:
if internal_pressure >= dynamic_pressure and total_mass_in_pipe > 0:
doors_closed = True
print(f"Doors closed at {current_altitude_m / 1000:.2f} km.")
print(f"Time at closure: {current_time_s:.2f} s.")
print(f"Mass collected at closure: {collected_air_mass:.2f} kg.")
print(f"Dynamic pressure at closure: {dynamic_pressure:.2f} Pa.")
print(f"Temperature at closure: {gas_temperature_K:.2f} K ({gas_temperature_K - 273.15:.2f} °C)")
else:
if internal_pressure >= dynamic_pressure and total_mass_in_pipe > 0:
pipe_is_full = True
print(f"Pipe filled at {current_altitude_m / 1000:.2f} km.")
print(f"Time at fill: {current_time_s:.2f} s.")
print(f"Mass collected at fill: {collected_air_mass:.2f} kg.")
print(f"Temperature at fill: {gas_temperature_K:.2f} K ({gas_temperature_K - 273.15:.2f} °C)")
if not doors_closed and not pipe_is_full:
force_air_collection = mass_collected_in_step / time_step_s * current_velocity_mps
net_force -= force_air_collection
work_air_step = force_air_collection * (current_velocity_mps * time_step_s)
total_work_done_on_air_J += work_air_step
current_mass_kg += mass_collected_in_step
collected_air_mass += mass_collected_in_step
elif use_door_closing and doors_closed:
force_drag = 0.5 * rho * current_velocity_mps**2 * CD * cross_sectional_area_sqm
net_force -= force_drag
elif not use_door_closing and pipe_is_full:
if not pipe_is_empty:
internal_pressure = get_gas_pressure(collected_air_mass, pipe_volume_m3, gas_temperature_K, relative_humidity_percent)
outflow_rate = outflow_rate_factor * (internal_pressure - dynamic_pressure)
outflow_rate = max(outflow_rate, 0)
if collected_air_mass - outflow_rate * time_step_s <= 0:
outflow_rate = collected_air_mass / time_step_s
pipe_is_empty = True
print(f"Pipe emptied at {current_altitude_m / 1000:.2f} km.")
force_retro = outflow_rate * V_EXHAUST_ASSUMED
net_force -= force_retro
current_mass_kg -= outflow_rate * time_step_s
collected_air_mass -= outflow_rate * time_step_s
dm_dt_in = rho * cross_sectional_area_sqm * current_velocity_mps
force_air_collection = dm_dt_in * current_velocity_mps
net_force -= force_air_collection
elif not use_door_closing and pipe_is_empty:
dm_dt_in = rho * cross_sectional_area_sqm * current_velocity_mps
force_air_collection = dm_dt_in * current_velocity_mps
net_force -= force_air_collection
current_mass_kg = initial_projectile_mass_kg
work_gravity_step = force_gravity * (current_velocity_mps * time_step_s)
total_work_done_against_gravity_J += work_gravity_step
acceleration = net_force / current_mass_kg
current_velocity_mps += acceleration * time_step_s
current_altitude_m += current_velocity_mps * time_step_s
current_time_s += time_step_s
print("\n--- Simulation Complete ---")
print(f"Final Altitude: {current_altitude_m / 1000:.2f} km")
print(f"Final Velocity: {current_velocity_mps:.2f} m/s ({current_velocity_mps/1000:.2f} km/s)")
print(f"Total Time: {current_time_s:.2f} s")
print(f"Initial Kinetic Energy: {0.5 * initial_projectile_mass_kg * initial_velocity_mps**2 / 1e9:.2f} GigaJoules")
print(f"Total Work Done Against Gravity: {total_work_done_against_gravity_J/1e9:.2f} GigaJoules")
print(f"Total Work Done on Air Mass: {total_work_done_on_air_J/1e9:.2f} GigaJoules (before doors closed)")
print("\n--- Mass Breakdown at Closure ---")
print(f"Total Projectile Mass: {initial_projectile_mass_kg:.2f} kg")
print(f"Magic Pipe Mass: {pipe_mass_kg:.2f} kg")
print(f"Payload Mass: {payload_mass_kg:.2f} kg")
print(f"Rocket Mass: {rocket_mass_kg:.2f} kg")
print(f"\nMass of Collected Air: {collected_air_mass:.2f} kg ({collected_air_mass / 1000:.2f} metric tons)")
if collected_air_mass > 0:
print("\n--- Payload Composition (by mass) ---")
temp_celsius = TEMP_0_K - 273.15
es_pa = get_vapor_pressure(temp_celsius)
e_pa = es_pa * (relative_humidity_percent / 100.0)
rho_moist_0 = get_air_density(0, relative_humidity_percent)
rho_water_vapor_0 = (e_pa / (461.5 * TEMP_0_K))
mass_of_water = collected_air_mass * (rho_water_vapor_0 / rho_moist_0)
mass_of_dry_air = collected_air_mass - mass_of_water
mass_of_nitrogen = mass_of_dry_air * MASS_FRACTION_NITROGEN
mass_of_oxygen = mass_of_dry_air * MASS_FRACTION_OXYGEN
percent_water = (mass_of_water / collected_air_mass) * 100.0
percent_nitrogen = (mass_of_nitrogen / collected_air_mass) * 100.0
percent_oxygen = (mass_of_oxygen / collected_air_mass) * 100.0
print(f"Water: {mass_of_water:.2f} kg ({percent_water:.2f}%)")
print(f"Nitrogen: {mass_of_nitrogen:.2f} kg ({percent_nitrogen:.2f}%)")
print(f"Oxygen: {of_oxygen:.2f} kg ({percent_oxygen:.2f}%)")
other_mass = collected_air_mass - mass_of_water - mass_of_nitrogen - mass_of_oxygen
other_percent = (other_mass / collected_air_mass) * 100.0
print(f"Other: {other_mass:.2f} kg ({other_percent:.2f}%)")
def load_parameters():
"""Loads parameters from a JSON file, or returns defaults if the file doesn't exist."""
default_params = {
"projectile_diameter_m": 1.0,
"pipe_mass_kg": 1000.0,
"payload_mass_kg": 1000.0,
"rocket_mass_kg": 1000.0,
"initial_velocity_mps": 11000.0,
"launch_altitude_meters_above_sea_level": 0.0,
"final_altitude_meters_above_sea_level": 100000.0,
"pipe_volume_m3": 15.0,
"pipe_ID_m": 0.04,
"pipe_OD_m": 0.05,
"time_step_s": 0.01,
"use_door_closing": True,
"outflow_rate_factor": 1.0e-5,
"relative_humidity_percent": 0.0,
"initial_pipe_temp_K": 100.0,
"version": VERSION
}
if os.path.exists(PARAMS_FILE):
try:
with open(PARAMS_FILE, 'r') as f:
params = json.load(f)
if params.get("version") != VERSION:
print(f"Parameter file from old version found. Deleting and creating new file for V{VERSION}.")
if os.path.exists(PARAMS_FILE):
os.remove(PARAMS_FILE)
return default_params
return params
except (json.JSONDecodeError, KeyError):
print("Corrupted or invalid parameter file found. Deleting and creating a new one.")
if os.path.exists(PARAMS_FILE):
os.remove(PARAMS_FILE)
return default_params
else:
return default_params
def save_parameters(params):
"""Saves the given parameters to a JSON file."""
with open(PARAMS_FILE, 'w') as f:
json.dump(params, f, indent=4)
print(f"\nParameters saved to {PARAMS_FILE}")
def get_user_input(prompt, default_value, type_func):
"""Gets user input with a default option."""
while True:
user_input = input(f"{prompt} (default: {default_value}): ")
if user_input == "":
return default_value
try:
if type_func is bool:
return user_input.lower() == 'true'
return type_func(user_input)
except ValueError:
print(f"Invalid input. Please enter a valid {type_func.__name__} or 'True'/'False'.")
def main():
"""Main function to handle user interaction and run the simulation."""
params = load_parameters()
print("\n--- Current Simulation Parameters ---")
for key, value in params.items():
print(f" {key}: {value}")
change_params = input("\nDo you want to change any parameters? (y/n): ").lower()
if change_params == 'y':
params["projectile_diameter_m"] = get_user_input("Enter new projectile diameter (m)", params["projectile_diameter_m"], float)
params["pipe_mass_kg"] = get_user_input("Enter new magic pipe mass (kg)", params["pipe_mass_kg"], float)
params["payload_mass_kg"] = get_user_input("Enter new payload mass (kg)", params["payload_mass_kg"], float)
params["rocket_mass_kg"] = get_user_input("Enter new rocket mass (kg)", params["rocket_mass_kg"], float)
params["initial_velocity_mps"] = get_user_input("Enter new initial velocity (m/s)", params["initial_velocity_mps"], float)
params["final_altitude_meters_above_sea_level"] = get_user_input("Enter new target altitude (m)", params["final_altitude_meters_above_sea_level"], float)
params["pipe_volume_m3"] = get_user_input("Enter new magic pipe volume (m^3)", params["pipe_volume_m3"], float)
params["pipe_ID_m"] = get_user_input("Enter new pipe inner diameter (m)", params["pipe_ID_m"], float)
params["pipe_OD_m"] = get_user_input("Enter new pipe outer diameter (m)", params["pipe_OD_m"], float)
params["time_step_s"] = get_user_input("Enter new time step (s)", params["time_step_s"], float)
params["use_door_closing"] = get_user_input("Use door closing feature? (True/False)", params["use_door_closing"], bool)
params["outflow_rate_factor"] = get_user_input("Enter new outflow rate factor", params["outflow_rate_factor"], float)
params["relative_humidity_percent"] = get_user_input("Enter new relative humidity (%)", params["relative_humidity_percent"], float)
params["initial_pipe_temp_K"] = get_user_input("Enter new initial pipe temperature (K)", params["initial_pipe_temp_K"], float)
save_option = input("Save these new parameters as defaults for future runs? (y/n): ").lower()
if save_option == 'y':
save_parameters(params)
simulate_air_harvesting_launch(**params)
if __name__ == "__main__":
main()
(th)
Offline
Like button can go here