docs: def V_from_h(h, D, L, horizontal=True, sideA=None, sideB=None, sideA_a=0,
               sideB_a=0, sideA_f=None, sideA_k=None, sideB_f=None, sideB_k=None):
      r'''Calculates partially full volume of a vertical or horizontal tank with
      different head types according to [1]_.
  
      Parameters
      ----------
      h : float
          Height of the liquid in the tank, [m]
      D : float
          Diameter of the cylindrical section of the tank, [m]
      L : float
          Length of the main cylindrical section of the tank, [m]
      horizontal : bool, optional
          Whether or not the tank is a horizontal or vertical tank
      sideA : string, optional
          The left (or bottom for vertical) head of the tank's type; one of
          [None, 'conical', 'ellipsoidal', 'torispherical', 'guppy', 'spherical'].
      sideB : string, optional
          The right (or top for vertical) head of the tank's type; one of
          [None, 'conical', 'ellipsoidal', 'torispherical', 'guppy', 'spherical'].
      sideA_a : float, optional
          The distance the head as specified by sideA extends down or to the left
          from the main cylindrical section, [m]
      sideB_a : float, optional
          The distance the head as specified by sideB extends up or to the right
          from the main cylindrical section, [m]
      sideA_f : float, optional
          Dish-radius parameter for side A; fD  = dish radius [1/m]
      sideA_k : float, optional
          knuckle-radius parameter for side A; kD = knuckle radius [1/m]
      sideB_f : float, optional
          Dish-radius parameter for side B; fD  = dish radius [1/m]
      sideB_k : float, optional
          knuckle-radius parameter for side B; kD = knuckle radius [1/m]
  
      Returns
      -------
      V : float
          Volume up to h [m^3]
  
      Examples
      --------
      >>> V_from_h(h=7, D=1.5, L=5., horizontal=False, sideA='conical',
      ... sideB='conical', sideA_a=2., sideB_a=1.)
      10.013826583317465
  
      References
      ----------
      .. [1] Jones, D. "Compute Fluid Volumes in Vertical Tanks." Chemical
         Processing. December 18, 2003.
         http://www.chemicalprocessing.com/articles/2003/193/
      '''
      if sideA not in [None, 'conical', 'ellipsoidal', 'torispherical', 'spherical', 'guppy']:
          raise Exception('Unspoorted head type for side A')
      if sideB not in [None, 'conical', 'ellipsoidal', 'torispherical', 'spherical', 'guppy']:
          raise Exception('Unspoorted head type for side B')
      R = D/2.
      V = 0
      if horizontal:
          # Conical case
          if sideA == 'conical':
              V += V_horiz_conical(D, L, sideA_a, h, headonly=True)
          if sideB == 'conical':
              V += V_horiz_conical(D, L, sideB_a, h, headonly=True)
          # Elliosoidal case
          if sideA == 'ellipsoidal':
              V += V_horiz_ellipsoidal(D, L, sideA_a, h, headonly=True)
          if sideB == 'ellipsoidal':
              V += V_horiz_ellipsoidal(D, L, sideB_a, h, headonly=True)
          # Guppy case
          if sideA == 'guppy':
              V += V_horiz_guppy(D, L, sideA_a, h, headonly=True)
          if sideB == 'guppy':
              V += V_horiz_guppy(D, L, sideB_a, h, headonly=True)
          # Spherical case
          if sideA == 'spherical':
              V += V_horiz_spherical(D, L, sideA_a, h, headonly=True)
          if sideB == 'spherical':
              V += V_horiz_spherical(D, L, sideB_a, h, headonly=True)
          # Torispherical case
          if sideA == 'torispherical':
              V += V_horiz_torispherical(D, L, sideA_f, sideA_k, h, headonly=True)
          if sideB == 'torispherical':
              V += V_horiz_torispherical(D, L, sideB_f, sideB_k, h, headonly=True)
          if h > D: # Must be before Af, which will raise a domain error
              raise Exception('Input height is above top of tank')
          Af = R**2*acos((R-h)/R) - (R-h)*(2*R*h - h**2)**0.5
          V += L*Af
      else:
          # Bottom head
          if sideA in ['conical', 'ellipsoidal', 'torispherical', 'spherical']:
              if sideA == 'conical':
                  V += V_vertical_conical(D, sideA_a, h=min(sideA_a, h))
              if sideA == 'ellipsoidal':
                  V += V_vertical_ellipsoidal(D, sideA_a, h=min(sideA_a, h))
              if sideA == 'spherical':
                  V += V_vertical_spherical(D, sideA_a, h=min(sideA_a, h))
              if sideA == 'torispherical':
                  V += V_vertical_torispherical(D, sideA_f, sideA_k, h=min(sideA_a, h))
          # Cylindrical section
          if h >= sideA_a + L:
              V += pi/4*D**2*L # All middle
          elif h > sideA_a:
              V += pi/4*D**2*(h - sideA_a) # Partial middle
          # Top head
          if h > sideA_a + L:
              h2 = sideB_a - (h - sideA_a - L)
              if sideB == 'conical':
                  V += V_vertical_conical(D, sideB_a, h=sideB_a)
                  V -= V_vertical_conical(D, sideB_a, h=h2)
              if sideB == 'ellipsoidal':
                  V += V_vertical_ellipsoidal(D, sideB_a, h=sideB_a)
                  V -= V_vertical_ellipsoidal(D, sideB_a, h=h2)
              if sideB == 'spherical':
                  V += V_vertical_spherical(D, sideB_a, h=sideB_a)
                  V -= V_vertical_spherical(D, sideB_a, h=h2)
              if sideB == 'torispherical':
                  V += V_vertical_torispherical(D, sideB_f, sideB_k, h=sideB_a)
                  V -= V_vertical_torispherical(D, sideB_f, sideB_k, h=h2)
          if h > L + sideA_a + sideB_a:
              raise Exception('Input height is above top of tank')
      return V