# 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