{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "83344e81",
   "metadata": {},
   "source": [
    "## Sample Program:\n",
    "\n",
    "Function to automatically create a representative horizontal vessel in the process industry given a volume."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "652e3512",
   "metadata": {},
   "outputs": [],
   "source": [
    "from fluids import TANK\n",
    "\n",
    "\n",
    "def create_horizontal_vessel(volume, L_over_D_ratio=3, head_type='ASME F&D'):\n",
    "    \"\"\"\n",
    "    Create a representative horizontal vessel for a given volume, allowing\n",
    "    customization of the head type with predefined options.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    volume : float\n",
    "        The desired total volume of the vessel in cubic meters.\n",
    "    L_over_D_ratio : float, optional\n",
    "        The desired length-to-diameter ratio of the vessel. Defaults to 3,\n",
    "        typical for the process industry.\n",
    "    head_type : str, optional\n",
    "        The type of head for both ends of the vessel. Allows for custom strings\n",
    "        corresponding to different torispherical options, alongside other allowed\n",
    "        types by the fluids TANK class. Defaults to 'ASME F&D'.\n",
    "        One of '2:1 semi-elliptical', 'ASME F&D', 'ASME 80/6', 'ASME 80/10 F&D', \n",
    "        'DIN 28011', 'DIN 28013', None, 'conical', 'ellipsoidal', 'guppy', 'spherical'\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    fluids.geometry.TANK\n",
    "        An object representing the designed vessel, including its dimensions and\n",
    "        other relevant information.\n",
    "\n",
    "    Examples\n",
    "    --------\n",
    "    >>> designed_vessel = create_horizontal_vessel(100)\n",
    "\n",
    "    Notes\n",
    "    -----\n",
    "    The function uses the TANK class from the fluids library to calculate the\n",
    "    necessary dimensions for the given volume. The head type is customizable with\n",
    "    predefined strings for different standard torispherical options.\n",
    "    \"\"\"\n",
    "    # Mapping custom strings to torispherical head parameters\n",
    "    head_params = {\n",
    "        '2:1 semi-elliptical': {'f': 0.9, 'k': 0.17},\n",
    "        'ASME F&D': {'f': 1.0, 'k': 0.06},\n",
    "        'ASME 80/6': {'f': 0.8, 'k': 0.06},\n",
    "        'ASME 80/10 F&D': {'f': 0.8, 'k': 0.1},\n",
    "        'DIN 28011': {'f': 1.0, 'k': 0.1},\n",
    "        'DIN 28013': {'f': 0.8, 'k': 0.154}\n",
    "    }\n",
    "    head_a_ratios = {\n",
    "        'conical': 0.2,\n",
    "        'ellipsoidal': 0.2,\n",
    "        'guppy': 0.5,\n",
    "        'spherical': 0.5,\n",
    "        'None': 0\n",
    "    }\n",
    "    if head_type in head_params:\n",
    "        # Use custom torispherical head parameters\n",
    "        f = head_params[head_type]['f']\n",
    "        k = head_params[head_type]['k']\n",
    "        sideA_f, sideA_k, sideB_f, sideB_k = f, k, f, k\n",
    "        sideA, sideB = 'torispherical', 'torispherical'\n",
    "        sideA_a_ratio = sideB_a_ratio = None\n",
    "    else:\n",
    "        # Use the head type as specified (non-torispherical or default parameters)\n",
    "        sideA, sideB = head_type, head_type\n",
    "        sideA_f = sideA_k = sideB_f = sideB_k = None\n",
    "        sideA_a_ratio = sideB_a_ratio = head_a_ratios[head_type]\n",
    "\n",
    "    # Create a TANK object with the specified parameters\n",
    "    vessel = TANK(V=volume, L_over_D=L_over_D_ratio, horizontal=True, \n",
    "                  sideA=sideA, sideB=sideB, \n",
    "                  sideA_f=sideA_f, sideA_k=sideA_k,\n",
    "                  sideB_f=sideB_f, sideB_k=sideB_k,\n",
    "                  sideA_a_ratio=sideA_a_ratio, sideB_a_ratio=sideB_a_ratio)\n",
    "    return vessel\n",
    "\n",
    "vessel = create_horizontal_vessel(100)\n",
    "vessel = create_horizontal_vessel(100, L_over_D_ratio=5, head_type='spherical')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f2127464",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6397.683587435168"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def estimate_tank_weight_basic(tank, density=7850, thickness=0.005):\n",
    "    \"\"\"\n",
    "    Estimate the weight of a tank based on its volume and material properties.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    tank : TANK\n",
    "        The TANK object representing the tank whose weight is to be estimated.\n",
    "    density : float, optional\n",
    "        The density of the material used for the tank, in kilograms per cubic meter.\n",
    "        Default is 7850 kg/m^3, typical of steel.\n",
    "    thickness : float, optional\n",
    "        The thickness of the tank's wall, in meters. Default is 0.005 m (5 mm).\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    float\n",
    "        The estimated weight of the tank, in kilograms.\n",
    "\n",
    "    Notes\n",
    "    -----\n",
    "    The function calculates the difference in volume between the original tank\n",
    "    and an enlarged version of the tank created by adding the specified thickness\n",
    "    to its walls. This volume difference, representing the volume of material used,\n",
    "    is then multiplied by the material's density to estimate the tank's weight.\n",
    "    \"\"\"\n",
    "    # Create a new tank object with added thickness to represent the outer shell\n",
    "    outer_tank = tank.add_thickness(thickness)\n",
    "    \n",
    "    # Calculate the volume of the material used for the shell\n",
    "    material_volume = outer_tank.V_total - tank.V_total\n",
    "    \n",
    "    # Estimate the weight of the tank\n",
    "    weight = material_volume * density\n",
    "    \n",
    "    return weight\n",
    "\n",
    "estimate_tank_weight_basic(vessel)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "896c5f27",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Estimated weight of the coated tank: 6593.20 kg\n"
     ]
    }
   ],
   "source": [
    "def estimate_tank_weight(tank, density_body=7850, thickness_body=0.005, density_heads=7850,\n",
    "                         thickness_heads=0.005, coating_density=0, coating_thickness=0):\n",
    "    \"\"\"\n",
    "    Estimate the weight of a tank with options for different materials and thicknesses \n",
    "    for the body and heads, and coatings.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    tank : TANK\n",
    "        The TANK object representing the tank whose weight is to be estimated.\n",
    "    density_body : float, optional\n",
    "        The density of the material used for the tank's body, in kg/m^3. Default is 7850 kg/m^3 for steel.\n",
    "    thickness_body : float, optional\n",
    "        The thickness of the tank's body walls, in meters. Default is 0.005 m (5 mm).\n",
    "    density_heads : float, optional\n",
    "        The density of the material used for the tank's heads, in kg/m^3. Allows for different materials for the body and heads.\n",
    "    thickness_heads : float, optional\n",
    "        The thickness of the tank's heads, in meters. Allows for different thicknesses for the body and heads.\n",
    "    coating_density : float, optional\n",
    "        The density of any coating applied to the tank, in kg/m^3. Default is 0, assuming no coating.\n",
    "    coating_thickness : float, optional\n",
    "        The thickness of the coating, in meters. Default is 0, assuming no coating.\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    float\n",
    "        The estimated total weight of the tank, in kilograms, including the body, heads, any internal structures, and coatings.\n",
    "\n",
    "    \"\"\"\n",
    "    # Create an outer tank to represent the body with added thickness\n",
    "    outer_tank_body = tank.add_thickness(thickness_body)\n",
    "    body_volume = outer_tank_body.V_lateral - tank.V_lateral\n",
    "    body_weight = body_volume * density_body\n",
    "\n",
    "    # Estimate heads weight by creating two new TANK objects with a length of 0 and added thickness for heads\n",
    "    head_tank_original = TANK(D=tank.D, L=0, horizontal=tank.horizontal, \n",
    "                              sideA=tank.sideA, sideB=tank.sideB, \n",
    "                              sideA_f=tank.sideA_f, sideA_k=tank.sideA_k,\n",
    "                              sideB_f=tank.sideB_f, sideB_k=tank.sideB_k,)\n",
    "    head_tank_with_thickness = head_tank_original.add_thickness(thickness_heads)\n",
    "    heads_volume = head_tank_with_thickness.V_total - head_tank_original.V_total\n",
    "    heads_weight = heads_volume * density_heads\n",
    "    \n",
    "    \n",
    "    # Calculate the weight of the coating, if applicable\n",
    "    tank_minus_coating = tank.add_thickness(thickness_body, sideA_thickness=thickness_heads, sideB_thickness=thickness_heads)\n",
    "        \n",
    "    coated_tank = tank_minus_coating.add_thickness(coating_thickness)\n",
    "    coating_volume = coated_tank.V_total - tank_minus_coating.V_total\n",
    "    coating_weight = coating_volume * coating_density\n",
    "\n",
    "    # Sum up the weights to get the total\n",
    "    total_weight = body_weight + heads_weight + coating_weight\n",
    "\n",
    "    return total_weight\n",
    "\n",
    "# Assuming the create_horizontal_vessel function has been defined as per previous examples\n",
    "tank = create_horizontal_vessel(volume=100, L_over_D_ratio=3, head_type='ASME F&D')\n",
    "\n",
    "# Estimate the weight of the tank including the coating\n",
    "tank_weight = estimate_tank_weight(tank=tank, \n",
    "                                   density_body=7850, \n",
    "                                   thickness_body=0.005, \n",
    "                                   density_heads=7850, \n",
    "                                   thickness_heads=0.005, \n",
    "                                   coating_density=1400, \n",
    "                                   coating_thickness=0.002)\n",
    "\n",
    "print(f\"Estimated weight of the coated tank: {tank_weight:.2f} kg\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "6e17ea2c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "
\n",
       "\n",
       "
\n",
       "  
\n",
       "    \n",
       "       \n",
       "       Fill Level (%)\n",
       "       Volume (m^3)\n",
       "    
\n",
       "  
\n",
       "  
\n",
       "    \n",
       "       0\n",
       "       0.000000\n",
       "       0.000000\n",
       "    
\n",
       "    \n",
       "       1\n",
       "       7.142857\n",
       "       3.058448\n",
       "    
\n",
       "    \n",
       "       2\n",
       "       14.285714\n",
       "       8.537083\n",
       "    
\n",
       "    \n",
       "       3\n",
       "       21.428571\n",
       "       15.425298\n",
       "    
\n",
       "    \n",
       "       4\n",
       "       28.571429\n",
       "       23.292010\n",
       "    
\n",
       "    \n",
       "       5\n",
       "       35.714286\n",
       "       31.836766\n",
       "    
\n",
       "    \n",
       "       6\n",
       "       42.857143\n",
       "       40.813114\n",
       "    
\n",
       "    \n",
       "       7\n",
       "       50.000000\n",
       "       50.000000\n",
       "    
\n",
       "    \n",
       "       8\n",
       "       57.142857\n",
       "       59.186886\n",
       "    
\n",
       "    \n",
       "       9\n",
       "       64.285714\n",
       "       68.163234\n",
       "    
\n",
       "    \n",
       "       10\n",
       "       71.428571\n",
       "       76.707990\n",
       "    
\n",
       "    \n",
       "       11\n",
       "       78.571429\n",
       "       84.574702\n",
       "    
\n",
       "    \n",
       "       12\n",
       "       85.714286\n",
       "       91.462917\n",
       "    
\n",
       "    \n",
       "       13\n",
       "       92.857143\n",
       "       96.941552\n",
       "    
\n",
       "    \n",
       "       14\n",
       "       100.000000\n",
       "       100.000000\n",
       "    
\n",
       "  
\n",
       "
\n",
       "
"
      ],
      "text/plain": [
       "    Fill Level (%)  Volume (m^3)\n",
       "0         0.000000      0.000000\n",
       "1         7.142857      3.058448\n",
       "2        14.285714      8.537083\n",
       "3        21.428571     15.425298\n",
       "4        28.571429     23.292010\n",
       "5        35.714286     31.836766\n",
       "6        42.857143     40.813114\n",
       "7        50.000000     50.000000\n",
       "8        57.142857     59.186886\n",
       "9        64.285714     68.163234\n",
       "10       71.428571     76.707990\n",
       "11       78.571429     84.574702\n",
       "12       85.714286     91.462917\n",
       "13       92.857143     96.941552\n",
       "14      100.000000    100.000000"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "from numpy import linspace\n",
    "\n",
    "def tank_strapping_chart(tank, intervals=100):\n",
    "    \"\"\"\n",
    "    Computes a pandas DataFrame of fill levels and volumes for a given tank object.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    tank : TANK\n",
    "        The tank object from the fluids library for which fill levels and volumes are calculated.\n",
    "    intervals : int, optional\n",
    "        The number of intervals between empty (0%) and full (100%) to calculate volumes for. Default is 100.\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    pd.DataFrame\n",
    "        A DataFrame with two columns: 'Fill Level (%)' and 'Volume (m^3)', \n",
    "        representing the fill level of the tank and the corresponding volume.\n",
    "    \"\"\"\n",
    "    # Generate fill levels from 0% to 100% at the specified intervals\n",
    "    fill_levels = linspace(0, 100, intervals)\n",
    "    \n",
    "    # Calculate the corresponding volume for each fill level\n",
    "    volumes = [tank.V_from_h(tank.h_max * level/100) for level in fill_levels]\n",
    "    \n",
    "    # Create a DataFrame\n",
    "    df = pd.DataFrame({\n",
    "        'Fill Level (%)': fill_levels,\n",
    "        'Volume (m^3)': volumes\n",
    "    })\n",
    "    \n",
    "    return df\n",
    "\n",
    "tank_strapping_chart(tank, 15)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "17fe7585",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "
\n",
       "\n",
       "
\n",
       "  
\n",
       "    \n",
       "       \n",
       "       Fill Level (%)\n",
       "       Height (m)\n",
       "       Volume (m^3)\n",
       "       Liquid Weight (kg)\n",
       "       Total Weight (kg)\n",
       "       Wetted Surface Area (m^2)\n",
       "       Dry Surface Area (m^2)\n",
       "       Exposed Liquid Surface Area (m^2)\n",
       "    
\n",
       "  
\n",
       "  
\n",
       "    \n",
       "       0\n",
       "       0.000000\n",
       "       0.000000\n",
       "       0.000000\n",
       "       0.000000\n",
       "       5000.000000\n",
       "       0.000000\n",
       "       131.364674\n",
       "       0.000000\n",
       "    
\n",
       "    \n",
       "       1\n",
       "       0.111111\n",
       "       0.379077\n",
       "       5.893393\n",
       "       5893.392635\n",
       "       10893.392635\n",
       "       25.421906\n",
       "       105.942768\n",
       "       22.991978\n",
       "    
\n",
       "    \n",
       "       2\n",
       "       0.222222\n",
       "       0.758155\n",
       "       16.257248\n",
       "       16257.247829\n",
       "       21257.247829\n",
       "       38.260995\n",
       "       93.103679\n",
       "       30.940749\n",
       "    
\n",
       "    \n",
       "       3\n",
       "       0.333333\n",
       "       1.137232\n",
       "       28.929098\n",
       "       28929.097826\n",
       "       33929.097826\n",
       "       49.590488\n",
       "       81.774186\n",
       "       35.466005\n",
       "    
\n",
       "    \n",
       "       4\n",
       "       0.444444\n",
       "       1.516309\n",
       "       42.843948\n",
       "       42843.947653\n",
       "       47843.947653\n",
       "       60.368404\n",
       "       70.996270\n",
       "       37.582422\n",
       "    
\n",
       "    \n",
       "       5\n",
       "       0.555556\n",
       "       1.895387\n",
       "       57.156052\n",
       "       57156.052347\n",
       "       62156.052347\n",
       "       70.996270\n",
       "       60.368404\n",
       "       37.582422\n",
       "    
\n",
       "    \n",
       "       6\n",
       "       0.666667\n",
       "       2.274464\n",
       "       71.070902\n",
       "       71070.902174\n",
       "       76070.902174\n",
       "       81.774186\n",
       "       49.590488\n",
       "       35.466005\n",
       "    
\n",
       "    \n",
       "       7\n",
       "       0.777778\n",
       "       2.653542\n",
       "       83.742752\n",
       "       83742.752171\n",
       "       88742.752171\n",
       "       93.103679\n",
       "       38.260995\n",
       "       30.940749\n",
       "    
\n",
       "    \n",
       "       8\n",
       "       0.888889\n",
       "       3.032619\n",
       "       94.106607\n",
       "       94106.607365\n",
       "       99106.607365\n",
       "       105.942768\n",
       "       25.421906\n",
       "       22.991978\n",
       "    
\n",
       "    \n",
       "       9\n",
       "       1.000000\n",
       "       3.411696\n",
       "       100.000000\n",
       "       100000.000000\n",
       "       105000.000000\n",
       "       131.364674\n",
       "       0.000000\n",
       "       0.000000\n",
       "    
\n",
       "  
\n",
       "
\n",
       "
"
      ],
      "text/plain": [
       "   Fill Level (%)  Height (m)  Volume (m^3)  Liquid Weight (kg)  \\\n",
       "0        0.000000    0.000000      0.000000            0.000000   \n",
       "1        0.111111    0.379077      5.893393         5893.392635   \n",
       "2        0.222222    0.758155     16.257248        16257.247829   \n",
       "3        0.333333    1.137232     28.929098        28929.097826   \n",
       "4        0.444444    1.516309     42.843948        42843.947653   \n",
       "5        0.555556    1.895387     57.156052        57156.052347   \n",
       "6        0.666667    2.274464     71.070902        71070.902174   \n",
       "7        0.777778    2.653542     83.742752        83742.752171   \n",
       "8        0.888889    3.032619     94.106607        94106.607365   \n",
       "9        1.000000    3.411696    100.000000       100000.000000   \n",
       "\n",
       "   Total Weight (kg)  Wetted Surface Area (m^2)  Dry Surface Area (m^2)  \\\n",
       "0        5000.000000                   0.000000              131.364674   \n",
       "1       10893.392635                  25.421906              105.942768   \n",
       "2       21257.247829                  38.260995               93.103679   \n",
       "3       33929.097826                  49.590488               81.774186   \n",
       "4       47843.947653                  60.368404               70.996270   \n",
       "5       62156.052347                  70.996270               60.368404   \n",
       "6       76070.902174                  81.774186               49.590488   \n",
       "7       88742.752171                  93.103679               38.260995   \n",
       "8       99106.607365                 105.942768               25.421906   \n",
       "9      105000.000000                 131.364674                0.000000   \n",
       "\n",
       "   Exposed Liquid Surface Area (m^2)  \n",
       "0                           0.000000  \n",
       "1                          22.991978  \n",
       "2                          30.940749  \n",
       "3                          35.466005  \n",
       "4                          37.582422  \n",
       "5                          37.582422  \n",
       "6                          35.466005  \n",
       "7                          30.940749  \n",
       "8                          22.991978  \n",
       "9                           0.000000  "
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "from numpy import linspace\n",
    "\n",
    "def tank_strapping_chart_detailed(tank, dry_weight, liquid_density=1000, intervals=100):\n",
    "    \"\"\"\n",
    "    Computes a pandas DataFrame of fill levels, volumes, heights, weights, and surface areas for a given tank object,\n",
    "    including the total weight of the tank at each fill level and the surface areas of interest.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    tank : TANK\n",
    "        The tank object from the fluids library for which fill levels, volumes, heights, weights, and surface areas are calculated.\n",
    "    dry_weight : float\n",
    "        The dry weight of the tank in kilograms.\n",
    "    liquid_density : float, optional\n",
    "        The density of the liquid in kg/m^3. Default is 1000 (density of water).\n",
    "    intervals : int, optional\n",
    "        The number of intervals between empty (0%) and full (100%) to calculate volumes for. Default is 100.\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    pd.DataFrame\n",
    "        A DataFrame with columns: 'Fill Level (%)', 'Height (m)', 'Volume (m^3)', 'Liquid Weight (kg)', \n",
    "        'Total Weight (kg)', 'Wetted Surface Area (m^2)', 'Dry Surface Area (m^2)', 'Exposed Liquid Surface Area (m^2)',\n",
    "        representing the fill level of the tank, the corresponding height, volume, weight of the liquid,\n",
    "        total weight including the tank, and the surface areas of interest.\n",
    "    \"\"\"\n",
    "    # Pre-compute the dry (total) surface area of the tank\n",
    "    dry_surface_area = tank.A\n",
    "    \n",
    "    # Generate fill levels from 0% to 100% at the specified intervals\n",
    "    fill_levels = linspace(0, 1, intervals)\n",
    "    \n",
    "    # Initialize lists to store computed values\n",
    "    heights, volumes, liquid_weights, total_weights, wetted_areas, dry_areas, cross_sectional_areas = [], [], [], [], [], [], []\n",
    "\n",
    "    for level in fill_levels:\n",
    "        height = tank.h_max * level\n",
    "        volume = tank.V_from_h(height)\n",
    "        liquid_weight = volume * liquid_density\n",
    "        total_weight = dry_weight + liquid_weight\n",
    "        wetted_area = tank.SA_from_h(height)\n",
    "        dry_area = dry_surface_area - wetted_area\n",
    "        cross_sectional_area = tank.A_cross_sectional(height)\n",
    "\n",
    "        # Append computed values to lists\n",
    "        heights.append(height)\n",
    "        volumes.append(volume)\n",
    "        liquid_weights.append(liquid_weight)\n",
    "        total_weights.append(total_weight)\n",
    "        wetted_areas.append(wetted_area)\n",
    "        dry_areas.append(dry_area)\n",
    "        cross_sectional_areas.append(cross_sectional_area)\n",
    "    \n",
    "    # Create a DataFrame\n",
    "    df = pd.DataFrame({\n",
    "        'Fill Level (%)': fill_levels,\n",
    "        'Height (m)': heights,\n",
    "        'Volume (m^3)': volumes,\n",
    "        'Liquid Weight (kg)': liquid_weights,\n",
    "        'Total Weight (kg)': total_weights,\n",
    "        'Wetted Surface Area (m^2)': wetted_areas,\n",
    "        'Dry Surface Area (m^2)': dry_areas,\n",
    "        'Exposed Liquid Surface Area (m^2)': cross_sectional_areas\n",
    "    })\n",
    "    \n",
    "    return df\n",
    "\n",
    "\n",
    "df = tank_strapping_chart_detailed(tank, intervals=10, dry_weight=5000) # for a dry weight of 5000 kg\n",
    "df\n"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
