docs: def NTU_from_P_G(P1, R1, Ntp, optimal=True):
      r'''Returns the number of transfer units of a TEMA G type heat exchanger
      with a specified (for side 1) thermal effectiveness `P1`, heat capacity 
      ratio `R1`, the number of tube passes `Ntp`, and for the two-pass case
      whether or not the inlets are arranged optimally. The supported cases are 
      as follows:
          
      * One tube pass (tube fluid split into two streams individually mixed,  
        shell fluid mixed)
      * Two tube passes (shell and tube exchanger with shell and tube fluids  
        mixed in each pass at the cross section), counterflow arrangement
      * Two tube passes (shell and tube exchanger with shell and tube fluids  
        mixed in each pass at the cross section), parallelflow arrangement
                  
      Parameters
      ----------
      P1 : float
          Thermal effectiveness of the heat exchanger in the P-NTU method,
          calculated with respect to stream 1 [-]
      R1 : float
          Heat capacity ratio of the heat exchanger in the P-NTU method,
          calculated with respect to stream 1 (shell side = 1, tube side = 2) [-]
      Ntp : int
          Number of tube passes, 1 or 2 [-]
      optimal : bool, optional
          Whether or not the arrangement is configured to give more of a
          countercurrent and efficient (True) case or an inefficient parallel
          case (only applies for two passes), [-]
  
      Returns
      -------
      NTU1 : float
          Thermal number of transfer units of the heat exchanger in the P-NTU 
          method, calculated with respect to stream 1 (shell side = 1, tube side
          = 2) [-]
  
      Notes
      -----
      For numbers of tube passes greater than 1 or 2, an exception is raised.
      
      Although this function allows the thermal effectiveness desired to be
      specified, it does not mean such a high value can be obtained. An exception
      is raised which shows the maximum possible effectiveness obtainable at the
      specified `R1` and configuration.
      
      >>> NTU_from_P_G(P1=1, R1=1/3., Ntp=2)
      Traceback (most recent call last):
      ValueError: No solution possible gives such a high P1; maximum P1=0.954545 at NTU1=10000.000000
      
      Of the three configurations, 1 pass and the optimal 2 pass have monotonic 
      functions which allow for a bounded solver to work smoothly. In both cases
      a solution is searched for between NTU1 values of 1E-11 and 1E-4.
      
      For the 2 pass unoptimal solution, a bounded solver is first use, but
      the upper bound on P1 and the upper NTU1 limit is calculated from a pade
      approximation performed with mpmath. 
  
      Examples
      --------
      >>> NTU_from_P_G(P1=.573, R1=1/3., Ntp=1)
      0.9999513707769526
      '''
      NTU_min = 1E-11
      function = temperature_effectiveness_TEMA_G
      if Ntp == 1 or (Ntp == 2 and optimal):
          NTU_max = 1E4
          # We could fit a curve to determine the NTU where the floating point
          # does not allow NTU to increase though, but that would be another
          # binary bisection process, different from the current pipeline
      elif Ntp == 2 and not optimal:
          NTU_max = _NTU_max_for_P_solver(NTU_from_G_2_unoptimal, R1)
      else:
          raise Exception('Supported numbers of tube passes are 1 or 2.')
      return _NTU_from_P_solver(P1, R1, NTU_min, NTU_max, function, Ntp=Ntp, optimal=optimal)