Skip to content

waterrocketpy.rocket.materials

Material properties and calculations for water rocket components.

MaterialDatabase

Database of material properties for rocket components.

Source code in waterrocketpy/rocket/materials.py
class MaterialDatabase:
    """Database of material properties for rocket components."""

    def __init__(self):
        self._materials = self._load_default_materials()

    def _load_default_materials(self) -> Dict[str, MaterialProperties]:
        """Load default material properties."""
        materials = {}

        # PET (Polyethylene Terephthalate) - Common bottle material
        materials["PET"] = MaterialProperties(
            name="PET",
            density=1380,  # kg/m³
            yield_strength=55e6,  # Pa
            ultimate_strength=75e6,  # Pa
            elastic_modulus=2.8e9,  # Pa
            poisson_ratio=0.37,
            thermal_expansion=70e-6,  # 1/K
            thermal_conductivity=0.24,  # W/(m·K)
            specific_heat=1200,  # J/(kg·K)
            max_temperature=343,  # K (70°C)
            cost_per_kg=1.5,
        )

        # HDPE (High-Density Polyethylene)
        materials["HDPE"] = MaterialProperties(
            name="HDPE",
            density=960,  # kg/m³
            yield_strength=30e6,  # Pa
            ultimate_strength=40e6,  # Pa
            elastic_modulus=1.1e9,  # Pa
            poisson_ratio=0.42,
            thermal_expansion=120e-6,  # 1/K
            thermal_conductivity=0.48,  # W/(m·K)
            specific_heat=1900,  # J/(kg·K)
            max_temperature=393,  # K (120°C)
            cost_per_kg=1.2,
        )

        # Aluminum (for nozzles, fins)
        materials["Aluminum"] = MaterialProperties(
            name="Aluminum",
            density=2700,  # kg/m³
            yield_strength=276e6,  # Pa
            ultimate_strength=310e6,  # Pa
            elastic_modulus=69e9,  # Pa
            poisson_ratio=0.33,
            thermal_expansion=23e-6,  # 1/K
            thermal_conductivity=237,  # W/(m·K)
            specific_heat=900,  # J/(kg·K)
            max_temperature=933,  # K (660°C)
            cost_per_kg=2.5,
        )

        # Carbon Fiber (for advanced rockets)
        materials["Carbon_Fiber"] = MaterialProperties(
            name="Carbon Fiber",
            density=1600,  # kg/m³
            yield_strength=3500e6,  # Pa
            ultimate_strength=4000e6,  # Pa
            elastic_modulus=230e9,  # Pa
            poisson_ratio=0.22,
            thermal_expansion=-0.5e-6,  # 1/K
            thermal_conductivity=100,  # W/(m·K)
            specific_heat=700,  # J/(kg·K)
            max_temperature=673,  # K (400°C)
            cost_per_kg=50.0,
        )

        # Fiberglass
        materials["Fiberglass"] = MaterialProperties(
            name="Fiberglass",
            density=1800,  # kg/m³
            yield_strength=400e6,  # Pa
            ultimate_strength=500e6,  # Pa
            elastic_modulus=35e9,  # Pa
            poisson_ratio=0.25,
            thermal_expansion=8e-6,  # 1/K
            thermal_conductivity=0.35,  # W/(m·K)
            specific_heat=800,  # J/(kg·K)
            max_temperature=573,  # K (300°C)
            cost_per_kg=8.0,
        )

        # Stainless Steel (for high-pressure applications)
        materials["Stainless_Steel"] = MaterialProperties(
            name="Stainless Steel",
            density=8000,  # kg/m³
            yield_strength=520e6,  # Pa
            ultimate_strength=720e6,  # Pa
            elastic_modulus=200e9,  # Pa
            poisson_ratio=0.29,
            thermal_expansion=17e-6,  # 1/K
            thermal_conductivity=16,  # W/(m·K)
            specific_heat=500,  # J/(kg·K)
            max_temperature=1673,  # K (1400°C)
            cost_per_kg=5.0,
        )

        return materials

    def get_material(self, name: str) -> Optional[MaterialProperties]:
        """Get material properties by name."""
        return self._materials.get(name)

    def add_material(self, material: MaterialProperties) -> None:
        """Add a new material to the database."""
        self._materials[material.name] = material

    def list_materials(self) -> list:
        """List all available materials."""
        return list(self._materials.keys())

    def load_from_json(self, file_path: str) -> None:
        """Load materials from JSON file."""
        path = Path(file_path)
        if not path.exists():
            raise FileNotFoundError(
                f"Material database file not found: {file_path}"
            )

        with open(path, "r") as f:
            data = json.load(f)

        for name, props in data.items():
            material = MaterialProperties(name=name, **props)
            self.add_material(material)

    def save_to_json(self, file_path: str) -> None:
        """Save materials to JSON file."""
        path = Path(file_path)
        path.parent.mkdir(parents=True, exist_ok=True)

        data = {}
        for name, material in self._materials.items():
            data[name] = {
                "density": material.density,
                "yield_strength": material.yield_strength,
                "ultimate_strength": material.ultimate_strength,
                "elastic_modulus": material.elastic_modulus,
                "poisson_ratio": material.poisson_ratio,
                "thermal_expansion": material.thermal_expansion,
                "thermal_conductivity": material.thermal_conductivity,
                "specific_heat": material.specific_heat,
                "max_temperature": material.max_temperature,
                "cost_per_kg": material.cost_per_kg,
            }

        with open(path, "w") as f:
            json.dump(data, f, indent=2)

add_material(self, material)

Add a new material to the database.

Source code in waterrocketpy/rocket/materials.py
def add_material(self, material: MaterialProperties) -> None:
    """Add a new material to the database."""
    self._materials[material.name] = material

get_material(self, name)

Get material properties by name.

Source code in waterrocketpy/rocket/materials.py
def get_material(self, name: str) -> Optional[MaterialProperties]:
    """Get material properties by name."""
    return self._materials.get(name)

list_materials(self)

List all available materials.

Source code in waterrocketpy/rocket/materials.py
def list_materials(self) -> list:
    """List all available materials."""
    return list(self._materials.keys())

load_from_json(self, file_path)

Load materials from JSON file.

Source code in waterrocketpy/rocket/materials.py
def load_from_json(self, file_path: str) -> None:
    """Load materials from JSON file."""
    path = Path(file_path)
    if not path.exists():
        raise FileNotFoundError(
            f"Material database file not found: {file_path}"
        )

    with open(path, "r") as f:
        data = json.load(f)

    for name, props in data.items():
        material = MaterialProperties(name=name, **props)
        self.add_material(material)

save_to_json(self, file_path)

Save materials to JSON file.

Source code in waterrocketpy/rocket/materials.py
def save_to_json(self, file_path: str) -> None:
    """Save materials to JSON file."""
    path = Path(file_path)
    path.parent.mkdir(parents=True, exist_ok=True)

    data = {}
    for name, material in self._materials.items():
        data[name] = {
            "density": material.density,
            "yield_strength": material.yield_strength,
            "ultimate_strength": material.ultimate_strength,
            "elastic_modulus": material.elastic_modulus,
            "poisson_ratio": material.poisson_ratio,
            "thermal_expansion": material.thermal_expansion,
            "thermal_conductivity": material.thermal_conductivity,
            "specific_heat": material.specific_heat,
            "max_temperature": material.max_temperature,
            "cost_per_kg": material.cost_per_kg,
        }

    with open(path, "w") as f:
        json.dump(data, f, indent=2)

MaterialProperties dataclass

Container for material properties.

Source code in waterrocketpy/rocket/materials.py
@dataclass
class MaterialProperties:
    """Container for material properties."""

    name: str
    density: float  # kg/m³
    yield_strength: float  # Pa
    ultimate_strength: float  # Pa
    elastic_modulus: float  # Pa
    poisson_ratio: float
    thermal_expansion: float  # 1/K
    thermal_conductivity: float  # W/(m·K)
    specific_heat: float  # J/(kg·K)
    max_temperature: float  # K
    cost_per_kg: float = 0.0  # Optional cost information

StructuralAnalysis

Structural analysis calculations for rocket components.

Source code in waterrocketpy/rocket/materials.py
class StructuralAnalysis:
    """Structural analysis calculations for rocket components."""

    @staticmethod
    def calculate_wall_thickness(
        internal_pressure: float,
        diameter: float,
        material: MaterialProperties,
        safety_factor: float = 2.0,
    ) -> float:
        """
        Calculate minimum wall thickness for pressure vessel.

        Args:
            internal_pressure: Internal pressure (Pa)
            diameter: Vessel diameter (m)
            material: Material properties
            safety_factor: Safety factor

        Returns:
            Minimum wall thickness (m)
        """
        # Using thin-wall pressure vessel formula: σ = p*d/(2*t)
        # Rearranging: t = p*d/(2*σ_allow)

        allowable_stress = material.yield_strength / safety_factor
        radius = diameter / 2

        # Hoop stress formula for thin-walled cylinder
        thickness = internal_pressure * radius / allowable_stress

        return thickness

    @staticmethod
    def calculate_burst_pressure(
        diameter: float, wall_thickness: float, material: MaterialProperties
    ) -> float:
        """
        Calculate burst pressure for a cylindrical vessel.

        Args:
            diameter: Vessel diameter (m)
            wall_thickness: Wall thickness (m)
            material: Material properties

        Returns:
            Burst pressure (Pa)
        """
        radius = diameter / 2

        # Using ultimate strength for burst calculation
        burst_pressure = (
            2 * material.ultimate_strength * wall_thickness / radius
        )

        return burst_pressure

    @staticmethod
    def calculate_mass(volume: float, material: MaterialProperties) -> float:
        """
        Calculate mass of component.

        Args:
            volume: Component volume (m³)
            material: Material properties

        Returns:
            Mass (kg)
        """
        return volume * material.density

    @staticmethod
    def check_temperature_limits(
        operating_temperature: float, material: MaterialProperties
    ) -> bool:
        """
        Check if operating temperature is within material limits.

        Args:
            operating_temperature: Operating temperature (K)
            material: Material properties

        Returns:
            True if temperature is acceptable
        """
        return operating_temperature <= material.max_temperature

    @staticmethod
    def calculate_thermal_stress(
        temperature_change: float, length: float, material: MaterialProperties
    ) -> float:
        """
        Calculate thermal stress due to temperature change.

        Args:
            temperature_change: Temperature change (K)
            length: Component length (m)
            material: Material properties

        Returns:
            Thermal stress (Pa)
        """
        # Thermal strain = α * ΔT
        # Thermal stress = E * α * ΔT (if constrained)

        thermal_strain = material.thermal_expansion * temperature_change
        thermal_stress = material.elastic_modulus * thermal_strain

        return thermal_stress

    @staticmethod
    def calculate_cost(volume: float, material: MaterialProperties) -> float:
        """
        Calculate material cost.

        Args:
            volume: Component volume (m³)
            material: Material properties

        Returns:
            Cost (currency units)
        """
        mass = StructuralAnalysis.calculate_mass(volume, material)
        return mass * material.cost_per_kg

calculate_burst_pressure(diameter, wall_thickness, material) staticmethod

Calculate burst pressure for a cylindrical vessel.

Parameters:

Name Type Description Default
diameter float

Vessel diameter (m)

required
wall_thickness float

Wall thickness (m)

required
material MaterialProperties

Material properties

required

Returns:

Type Description
float

Burst pressure (Pa)

Source code in waterrocketpy/rocket/materials.py
@staticmethod
def calculate_burst_pressure(
    diameter: float, wall_thickness: float, material: MaterialProperties
) -> float:
    """
    Calculate burst pressure for a cylindrical vessel.

    Args:
        diameter: Vessel diameter (m)
        wall_thickness: Wall thickness (m)
        material: Material properties

    Returns:
        Burst pressure (Pa)
    """
    radius = diameter / 2

    # Using ultimate strength for burst calculation
    burst_pressure = (
        2 * material.ultimate_strength * wall_thickness / radius
    )

    return burst_pressure

calculate_cost(volume, material) staticmethod

Calculate material cost.

Parameters:

Name Type Description Default
volume float

Component volume (m³)

required
material MaterialProperties

Material properties

required

Returns:

Type Description
float

Cost (currency units)

Source code in waterrocketpy/rocket/materials.py
@staticmethod
def calculate_cost(volume: float, material: MaterialProperties) -> float:
    """
    Calculate material cost.

    Args:
        volume: Component volume (m³)
        material: Material properties

    Returns:
        Cost (currency units)
    """
    mass = StructuralAnalysis.calculate_mass(volume, material)
    return mass * material.cost_per_kg

calculate_mass(volume, material) staticmethod

Calculate mass of component.

Parameters:

Name Type Description Default
volume float

Component volume (m³)

required
material MaterialProperties

Material properties

required

Returns:

Type Description
float

Mass (kg)

Source code in waterrocketpy/rocket/materials.py
@staticmethod
def calculate_mass(volume: float, material: MaterialProperties) -> float:
    """
    Calculate mass of component.

    Args:
        volume: Component volume (m³)
        material: Material properties

    Returns:
        Mass (kg)
    """
    return volume * material.density

calculate_thermal_stress(temperature_change, length, material) staticmethod

Calculate thermal stress due to temperature change.

Parameters:

Name Type Description Default
temperature_change float

Temperature change (K)

required
length float

Component length (m)

required
material MaterialProperties

Material properties

required

Returns:

Type Description
float

Thermal stress (Pa)

Source code in waterrocketpy/rocket/materials.py
@staticmethod
def calculate_thermal_stress(
    temperature_change: float, length: float, material: MaterialProperties
) -> float:
    """
    Calculate thermal stress due to temperature change.

    Args:
        temperature_change: Temperature change (K)
        length: Component length (m)
        material: Material properties

    Returns:
        Thermal stress (Pa)
    """
    # Thermal strain = α * ΔT
    # Thermal stress = E * α * ΔT (if constrained)

    thermal_strain = material.thermal_expansion * temperature_change
    thermal_stress = material.elastic_modulus * thermal_strain

    return thermal_stress

calculate_wall_thickness(internal_pressure, diameter, material, safety_factor=2.0) staticmethod

Calculate minimum wall thickness for pressure vessel.

Parameters:

Name Type Description Default
internal_pressure float

Internal pressure (Pa)

required
diameter float

Vessel diameter (m)

required
material MaterialProperties

Material properties

required
safety_factor float

Safety factor

2.0

Returns:

Type Description
float

Minimum wall thickness (m)

Source code in waterrocketpy/rocket/materials.py
@staticmethod
def calculate_wall_thickness(
    internal_pressure: float,
    diameter: float,
    material: MaterialProperties,
    safety_factor: float = 2.0,
) -> float:
    """
    Calculate minimum wall thickness for pressure vessel.

    Args:
        internal_pressure: Internal pressure (Pa)
        diameter: Vessel diameter (m)
        material: Material properties
        safety_factor: Safety factor

    Returns:
        Minimum wall thickness (m)
    """
    # Using thin-wall pressure vessel formula: σ = p*d/(2*t)
    # Rearranging: t = p*d/(2*σ_allow)

    allowable_stress = material.yield_strength / safety_factor
    radius = diameter / 2

    # Hoop stress formula for thin-walled cylinder
    thickness = internal_pressure * radius / allowable_stress

    return thickness

check_temperature_limits(operating_temperature, material) staticmethod

Check if operating temperature is within material limits.

Parameters:

Name Type Description Default
operating_temperature float

Operating temperature (K)

required
material MaterialProperties

Material properties

required

Returns:

Type Description
bool

True if temperature is acceptable

Source code in waterrocketpy/rocket/materials.py
@staticmethod
def check_temperature_limits(
    operating_temperature: float, material: MaterialProperties
) -> bool:
    """
    Check if operating temperature is within material limits.

    Args:
        operating_temperature: Operating temperature (K)
        material: Material properties

    Returns:
        True if temperature is acceptable
    """
    return operating_temperature <= material.max_temperature

calculate_bottle_mass(diameter, length, wall_thickness, material_name='PET')

Calculate mass of a bottle.

Parameters:

Name Type Description Default
diameter float

Bottle diameter (m)

required
length float

Bottle length (m)

required
wall_thickness float

Wall thickness (m)

required
material_name str

Material name

'PET'

Returns:

Type Description
float

Bottle mass (kg)

Source code in waterrocketpy/rocket/materials.py
def calculate_bottle_mass(
    diameter: float,
    length: float,
    wall_thickness: float,
    material_name: str = "PET",
) -> float:
    """
    Calculate mass of a bottle.

    Args:
        diameter: Bottle diameter (m)
        length: Bottle length (m)
        wall_thickness: Wall thickness (m)
        material_name: Material name

    Returns:
        Bottle mass (kg)
    """
    material = get_material_properties(material_name)
    if not material:
        raise ValueError(f"Unknown material: {material_name}")

    # Calculate volume of material (approximation for thin walls)
    outer_radius = diameter / 2
    inner_radius = outer_radius - wall_thickness

    # Volume of cylindrical shell
    volume = np.pi * length * (outer_radius**2 - inner_radius**2)

    # Add volume for bottle ends (approximate as flat discs)
    end_volume = (
        2 * np.pi * wall_thickness * (outer_radius**2 - inner_radius**2)
    )

    total_volume = volume + end_volume

    return StructuralAnalysis.calculate_mass(total_volume, material)

get_material_properties(name)

Convenience function to get material properties.

Source code in waterrocketpy/rocket/materials.py
def get_material_properties(name: str) -> Optional[MaterialProperties]:
    """Convenience function to get material properties."""
    return material_db.get_material(name)