Sample Program:

Function to automatically create a representative horizontal vessel in the process industry given a volume.

[1]:
from fluids import TANK


def create_horizontal_vessel(volume, L_over_D_ratio=3, head_type='ASME F&D'):
    """
    Create a representative horizontal vessel for a given volume, allowing
    customization of the head type with predefined options.

    Parameters
    ----------
    volume : float
        The desired total volume of the vessel in cubic meters.
    L_over_D_ratio : float, optional
        The desired length-to-diameter ratio of the vessel. Defaults to 3,
        typical for the process industry.
    head_type : str, optional
        The type of head for both ends of the vessel. Allows for custom strings
        corresponding to different torispherical options, alongside other allowed
        types by the fluids TANK class. Defaults to 'ASME F&D'.
        One of '2:1 semi-elliptical', 'ASME F&D', 'ASME 80/6', 'ASME 80/10 F&D',
        'DIN 28011', 'DIN 28013', None, 'conical', 'ellipsoidal', 'guppy', 'spherical'

    Returns
    -------
    fluids.geometry.TANK
        An object representing the designed vessel, including its dimensions and
        other relevant information.

    Examples
    --------
    >>> designed_vessel = create_horizontal_vessel(100)

    Notes
    -----
    The function uses the TANK class from the fluids library to calculate the
    necessary dimensions for the given volume. The head type is customizable with
    predefined strings for different standard torispherical options.
    """
    # Mapping custom strings to torispherical head parameters
    head_params = {
        '2:1 semi-elliptical': {'f': 0.9, 'k': 0.17},
        'ASME F&D': {'f': 1.0, 'k': 0.06},
        'ASME 80/6': {'f': 0.8, 'k': 0.06},
        'ASME 80/10 F&D': {'f': 0.8, 'k': 0.1},
        'DIN 28011': {'f': 1.0, 'k': 0.1},
        'DIN 28013': {'f': 0.8, 'k': 0.154}
    }
    head_a_ratios = {
        'conical': 0.2,
        'ellipsoidal': 0.2,
        'guppy': 0.5,
        'spherical': 0.5,
        'None': 0
    }
    if head_type in head_params:
        # Use custom torispherical head parameters
        f = head_params[head_type]['f']
        k = head_params[head_type]['k']
        sideA_f, sideA_k, sideB_f, sideB_k = f, k, f, k
        sideA, sideB = 'torispherical', 'torispherical'
        sideA_a_ratio = sideB_a_ratio = None
    else:
        # Use the head type as specified (non-torispherical or default parameters)
        sideA, sideB = head_type, head_type
        sideA_f = sideA_k = sideB_f = sideB_k = None
        sideA_a_ratio = sideB_a_ratio = head_a_ratios[head_type]

    # Create a TANK object with the specified parameters
    vessel = TANK(V=volume, L_over_D=L_over_D_ratio, horizontal=True,
                  sideA=sideA, sideB=sideB,
                  sideA_f=sideA_f, sideA_k=sideA_k,
                  sideB_f=sideB_f, sideB_k=sideB_k,
                  sideA_a_ratio=sideA_a_ratio, sideB_a_ratio=sideB_a_ratio)
    return vessel

vessel = create_horizontal_vessel(100)
vessel = create_horizontal_vessel(100, L_over_D_ratio=5, head_type='spherical')
[2]:
def estimate_tank_weight_basic(tank, density=7850, thickness=0.005):
    """
    Estimate the weight of a tank based on its volume and material properties.

    Parameters
    ----------
    tank : TANK
        The TANK object representing the tank whose weight is to be estimated.
    density : float, optional
        The density of the material used for the tank, in kilograms per cubic meter.
        Default is 7850 kg/m^3, typical of steel.
    thickness : float, optional
        The thickness of the tank's wall, in meters. Default is 0.005 m (5 mm).

    Returns
    -------
    float
        The estimated weight of the tank, in kilograms.

    Notes
    -----
    The function calculates the difference in volume between the original tank
    and an enlarged version of the tank created by adding the specified thickness
    to its walls. This volume difference, representing the volume of material used,
    is then multiplied by the material's density to estimate the tank's weight.
    """
    # Create a new tank object with added thickness to represent the outer shell
    outer_tank = tank.add_thickness(thickness)

    # Calculate the volume of the material used for the shell
    material_volume = outer_tank.V_total - tank.V_total

    # Estimate the weight of the tank
    weight = material_volume * density

    return weight

estimate_tank_weight_basic(vessel)
[2]:
6397.683587435168
[3]:
def estimate_tank_weight(tank, density_body=7850, thickness_body=0.005, density_heads=7850,
                         thickness_heads=0.005, coating_density=0, coating_thickness=0):
    """
    Estimate the weight of a tank with options for different materials and thicknesses
    for the body and heads, and coatings.

    Parameters
    ----------
    tank : TANK
        The TANK object representing the tank whose weight is to be estimated.
    density_body : float, optional
        The density of the material used for the tank's body, in kg/m^3. Default is 7850 kg/m^3 for steel.
    thickness_body : float, optional
        The thickness of the tank's body walls, in meters. Default is 0.005 m (5 mm).
    density_heads : float, optional
        The density of the material used for the tank's heads, in kg/m^3. Allows for different materials for the body and heads.
    thickness_heads : float, optional
        The thickness of the tank's heads, in meters. Allows for different thicknesses for the body and heads.
    coating_density : float, optional
        The density of any coating applied to the tank, in kg/m^3. Default is 0, assuming no coating.
    coating_thickness : float, optional
        The thickness of the coating, in meters. Default is 0, assuming no coating.

    Returns
    -------
    float
        The estimated total weight of the tank, in kilograms, including the body, heads, any internal structures, and coatings.

    """
    # Create an outer tank to represent the body with added thickness
    outer_tank_body = tank.add_thickness(thickness_body)
    body_volume = outer_tank_body.V_lateral - tank.V_lateral
    body_weight = body_volume * density_body

    # Estimate heads weight by creating two new TANK objects with a length of 0 and added thickness for heads
    head_tank_original = TANK(D=tank.D, L=0, horizontal=tank.horizontal,
                              sideA=tank.sideA, sideB=tank.sideB,
                              sideA_f=tank.sideA_f, sideA_k=tank.sideA_k,
                              sideB_f=tank.sideB_f, sideB_k=tank.sideB_k,)
    head_tank_with_thickness = head_tank_original.add_thickness(thickness_heads)
    heads_volume = head_tank_with_thickness.V_total - head_tank_original.V_total
    heads_weight = heads_volume * density_heads


    # Calculate the weight of the coating, if applicable
    tank_minus_coating = tank.add_thickness(thickness_body, sideA_thickness=thickness_heads, sideB_thickness=thickness_heads)

    coated_tank = tank_minus_coating.add_thickness(coating_thickness)
    coating_volume = coated_tank.V_total - tank_minus_coating.V_total
    coating_weight = coating_volume * coating_density

    # Sum up the weights to get the total
    total_weight = body_weight + heads_weight + coating_weight

    return total_weight

# Assuming the create_horizontal_vessel function has been defined as per previous examples
tank = create_horizontal_vessel(volume=100, L_over_D_ratio=3, head_type='ASME F&D')

# Estimate the weight of the tank including the coating
tank_weight = estimate_tank_weight(tank=tank,
                                   density_body=7850,
                                   thickness_body=0.005,
                                   density_heads=7850,
                                   thickness_heads=0.005,
                                   coating_density=1400,
                                   coating_thickness=0.002)

print(f"Estimated weight of the coated tank: {tank_weight:.2f} kg")

Estimated weight of the coated tank: 6593.20 kg
[4]:
import pandas as pd
from numpy import linspace

def tank_strapping_chart(tank, intervals=100):
    """
    Computes a pandas DataFrame of fill levels and volumes for a given tank object.

    Parameters
    ----------
    tank : TANK
        The tank object from the fluids library for which fill levels and volumes are calculated.
    intervals : int, optional
        The number of intervals between empty (0%) and full (100%) to calculate volumes for. Default is 100.

    Returns
    -------
    pd.DataFrame
        A DataFrame with two columns: 'Fill Level (%)' and 'Volume (m^3)',
        representing the fill level of the tank and the corresponding volume.
    """
    # Generate fill levels from 0% to 100% at the specified intervals
    fill_levels = linspace(0, 100, intervals)

    # Calculate the corresponding volume for each fill level
    volumes = [tank.V_from_h(tank.h_max * level/100) for level in fill_levels]

    # Create a DataFrame
    df = pd.DataFrame({
        'Fill Level (%)': fill_levels,
        'Volume (m^3)': volumes
    })

    return df

tank_strapping_chart(tank, 15)
[4]:
Fill Level (%) Volume (m^3)
0 0.000000 0.000000
1 7.142857 3.058448
2 14.285714 8.537083
3 21.428571 15.425298
4 28.571429 23.292010
5 35.714286 31.836766
6 42.857143 40.813114
7 50.000000 50.000000
8 57.142857 59.186886
9 64.285714 68.163234
10 71.428571 76.707990
11 78.571429 84.574702
12 85.714286 91.462917
13 92.857143 96.941552
14 100.000000 100.000000
[5]:
import pandas as pd
from numpy import linspace

def tank_strapping_chart_detailed(tank, dry_weight, liquid_density=1000, intervals=100):
    """
    Computes a pandas DataFrame of fill levels, volumes, heights, weights, and surface areas for a given tank object,
    including the total weight of the tank at each fill level and the surface areas of interest.

    Parameters
    ----------
    tank : TANK
        The tank object from the fluids library for which fill levels, volumes, heights, weights, and surface areas are calculated.
    dry_weight : float
        The dry weight of the tank in kilograms.
    liquid_density : float, optional
        The density of the liquid in kg/m^3. Default is 1000 (density of water).
    intervals : int, optional
        The number of intervals between empty (0%) and full (100%) to calculate volumes for. Default is 100.

    Returns
    -------
    pd.DataFrame
        A DataFrame with columns: 'Fill Level (%)', 'Height (m)', 'Volume (m^3)', 'Liquid Weight (kg)',
        'Total Weight (kg)', 'Wetted Surface Area (m^2)', 'Dry Surface Area (m^2)', 'Exposed Liquid Surface Area (m^2)',
        representing the fill level of the tank, the corresponding height, volume, weight of the liquid,
        total weight including the tank, and the surface areas of interest.
    """
    # Pre-compute the dry (total) surface area of the tank
    dry_surface_area = tank.A

    # Generate fill levels from 0% to 100% at the specified intervals
    fill_levels = linspace(0, 1, intervals)

    # Initialize lists to store computed values
    heights, volumes, liquid_weights, total_weights, wetted_areas, dry_areas, cross_sectional_areas = [], [], [], [], [], [], []

    for level in fill_levels:
        height = tank.h_max * level
        volume = tank.V_from_h(height)
        liquid_weight = volume * liquid_density
        total_weight = dry_weight + liquid_weight
        wetted_area = tank.SA_from_h(height)
        dry_area = dry_surface_area - wetted_area
        cross_sectional_area = tank.A_cross_sectional(height)

        # Append computed values to lists
        heights.append(height)
        volumes.append(volume)
        liquid_weights.append(liquid_weight)
        total_weights.append(total_weight)
        wetted_areas.append(wetted_area)
        dry_areas.append(dry_area)
        cross_sectional_areas.append(cross_sectional_area)

    # Create a DataFrame
    df = pd.DataFrame({
        'Fill Level (%)': fill_levels,
        'Height (m)': heights,
        'Volume (m^3)': volumes,
        'Liquid Weight (kg)': liquid_weights,
        'Total Weight (kg)': total_weights,
        'Wetted Surface Area (m^2)': wetted_areas,
        'Dry Surface Area (m^2)': dry_areas,
        'Exposed Liquid Surface Area (m^2)': cross_sectional_areas
    })

    return df


df = tank_strapping_chart_detailed(tank, intervals=10, dry_weight=5000) # for a dry weight of 5000 kg
df

[5]:
Fill Level (%) Height (m) Volume (m^3) Liquid Weight (kg) Total Weight (kg) Wetted Surface Area (m^2) Dry Surface Area (m^2) Exposed Liquid Surface Area (m^2)
0 0.000000 0.000000 0.000000 0.000000 5000.000000 0.000000 131.364674 0.000000
1 0.111111 0.379077 5.893393 5893.392635 10893.392635 25.421906 105.942768 22.991978
2 0.222222 0.758155 16.257248 16257.247829 21257.247829 38.260995 93.103679 30.940749
3 0.333333 1.137232 28.929098 28929.097826 33929.097826 49.590488 81.774186 35.466005
4 0.444444 1.516309 42.843948 42843.947653 47843.947653 60.368404 70.996270 37.582422
5 0.555556 1.895387 57.156052 57156.052347 62156.052347 70.996270 60.368404 37.582422
6 0.666667 2.274464 71.070902 71070.902174 76070.902174 81.774186 49.590488 35.466005
7 0.777778 2.653542 83.742752 83742.752171 88742.752171 93.103679 38.260995 30.940749
8 0.888889 3.032619 94.106607 94106.607365 99106.607365 105.942768 25.421906 22.991978
9 1.000000 3.411696 100.000000 100000.000000 105000.000000 131.364674 0.000000 0.000000