module bo_fl_types

   implicit none

   real(8), parameter, public :: OGlimit  = 100.0d0     ! bbl/MMSCF limit for gas enthalpy calc
   real(8), parameter, public :: t_basis  = 298.15      ! basis temperature for enthalpy, K
   real(8), parameter, public :: p_basis  = 101325.0    ! basis pressure for enthalpy, Pa
   real(8), parameter, public :: runset   = -1e31
   integer, parameter, public :: iunset   = -383838383
   integer, parameter, public :: s_names  = 256





      type, public :: t_meas
        sequence
        real(8)                       :: val          = runset        ! measured value, i.e. measurement supplied by the user
        real(8)                       :: wgt          = runset        ! weight
        real(8)                       :: calc         = runset        ! calculated value, i.e. result from the simulation
      end type

      type, public :: t_measurement
        sequence
        character(s_names)            :: name          = ' '          ! name of measurement point
        integer                       :: branch_num    = iunset       ! branch number where measurement is associated
        integer                       :: location      = iunset       ! location wrt the branch. can be:
                                                                      !   -1   start of branch
                                                                      !   -2   end of branch
                                                                      !   -3   in the upstream branch
                                                                      !   +ve  an element number of the pipe position arrays
        real(8)                       :: ref_temp      = runset       ! temperature reference for the measurement, used to correct the
                                                                      ! measured value from 288.73 K to the reference value
        type(t_meas)                  :: pressure                     ! measured value and weight
        type(t_meas)                  :: temperature                  ! measured value and weight

        type(t_meas)                  :: vfgas                        ! measured value and weight, Volume Fraction of Gas
        type(t_meas)                  :: vfoil                        ! measured value and weight
        type(t_meas)                  :: vfwat                        ! measured value and weight

        type(t_meas)                  :: mfgas                        ! measured value and weight, Mass Fraction of Gas
        type(t_meas)                  :: mfoil                        ! measured value and weight
        type(t_meas)                  :: mfwat                        ! measured value and weight

        type(t_meas)                  :: watcut                       ! measured value and weight
        type(t_meas)                  :: Qgas                         ! measured value and weight
        type(t_meas)                  :: Qoil                         ! measured value and weight
        type(t_meas)                  :: Qliq                         ! measured value and weight
        type(t_meas)                  :: Qwat                         ! measured value and weight

        type(t_meas)                  :: STGas                        ! measured value and weight
        type(t_meas)                  :: STOil                        ! measured value and weight
        type(t_meas)                  :: STLiq                        ! measured value and weight
        type(t_meas)                  :: STWat                        ! measured value and weight
        type(t_meas)                  :: STGOR                        ! measured value and weight
        type(t_meas)                  :: STWCUT                       ! measured value and weight

        type(t_meas)                  :: Velgas                       ! measured value and weight
        type(t_meas)                  :: Velliq                       ! measured value and weight
        type(t_meas)                  :: mixdensity                   ! measured value and weight
        type(t_meas)                  :: mass_rate                    ! calculated value and weight, see bo_fluids_mod for calculation
        integer(8)                    :: end_mark   = 54321           ! last element for checksum
        character(:),     allocatable :: pos_statement                ! text of position statement where measurement should be taken

      end type

      type, public :: t_multipoint_calib_1_result
        sequence
        real(8), allocatable :: calc(:)          ! individual calculated results
        real(8), allocatable :: errs(:)          ! individual measurement errors
        real(8)              :: errf = 0.        ! sum of squares of errors
      end type


      type, public :: t_multipoint_calib_results
        sequence
        type (t_multipoint_calib_1_result) :: Rs  ! error in each Rs measurement
        type (t_multipoint_calib_1_result) :: Rv  ! error in each Rv measurement
        type (t_multipoint_calib_1_result) :: sod ! error in each SOD/FVF measurement
        type (t_multipoint_calib_1_result) :: uod ! error in each UOD
        type (t_multipoint_calib_1_result) :: sov ! error in each SOV mesurement
        type (t_multipoint_calib_1_result) :: uov ! error in each SOV mesurement
        type (t_multipoint_calib_1_result) :: gz  ! error in each Gas Z mesurement
        type (t_multipoint_calib_1_result) :: gv  ! error in each Gas vis mesurement
      end type


!-----BLACK OIL fluids-------------------------------------------------------------------------------------------------
      type, public :: t_calib
        sequence
        character(12)             :: correlation   = ' '          ! name of corelation
        character(4)              :: padding       = 'abcd'       ! to make it all a multiple of 8 bytes
        real(8)                   :: pressure      = runset       ! pressure of this calibration point
        real(8)                   :: temperature   = runset       !
        real(8)                   :: bppressure    = runset       ! bubble point pressure for arrays below
        real(8)                   :: measurement   = runset       ! measured value of quantity at above P & T
        real(8)                   :: factor        = runset       ! correlation adjustment factor resulting from the tuning calc
        real(8)                   :: untuned_value = runset       ! untuned value of quantity
        character(4)              :: type          = ' '          ! additional info that distinguishes the type of quantity being
        logical                   :: fix_stocktank = .false.      ! for multipoint calibration, enables correction of stocktank
                                                                  ! value to match measured value
        logical            :: choose_best_fit_corr = .false.      ! if we need to reset the correlation to the best fitting one
        logical                   :: st_adjust     = .false.      ! for all calls, adjust the correlation so it goes through the
                                                                  ! "correct" value at stock-tank P & T. For Rs this is zero; for
                                                                  ! FVF this is 1; not sure any other quantities have such a
                                                                  ! "correct" value, but anyway, lets see...
        real(8), allocatable      :: apres(:)                     ! array or pressures for matching
        real(8), allocatable      :: ameas(:)                     ! array of measured values for matching
        real(8), allocatable      :: afac (:)                     ! array of factors calculated from matching
      end type

      type, public  :: t_bergsut_data
        sequence
        real(8) :: Blin   = runset
        real(8) :: Alin   = runset
      end type

      type, public   :: t_dovcalib
        sequence
        character(12)                      :: correlation  = 'GLASO' ! name of correlation
        character(4)                       :: padding      = 'abcd'  ! to make it all a multiple of 8 bytes
        real(8)              , allocatable :: temps(:)               ! temperature points (K)
        real(8)              , allocatable :: viscs(:)               ! viscosity points   (Pa.S)
        type (t_bergsut_data), allocatable :: bergsut_data           ! data for bergman & sutton DOV correlation
      end type



      type, public  :: t_bo_fluid


        sequence
        character(16)      :: preamble  = 'ABCDEFGHIJKLMNOP'
        type (t_calib)     :: rs_calib  = t_calib('STANDING') ! Rs  correlation and calibration point (vol/vol)
        type (t_calib)     :: rv_calib  = t_calib('NONE'    ) ! Rv  correlation and calibration point (vol/vol)
        type (t_calib)     :: sod_calib = t_calib('STANDING') ! Saturated Oil Density data            (kg/m3)
        type (t_calib)     :: uod_calib = t_calib('STANDING') ! Unsaturated oil density data          (kg/m3)
        type (t_calib)     :: sov_calib = t_calib('BEGROB'  ) ! Saturated Oil Viscosity data          (Pa.sec)
        type (t_calib)     :: uov_calib = t_calib('VAZBEG'  ) ! Unsaturated oil viscosity data        (Pa.sec)
        type (t_calib)     :: gz_calib  = t_calib('STANDING') ! Gas Z factor data                     (unitless)
        type (t_calib)     :: gv_calib  = t_calib('LEE'     ) ! Gas Viscosity data                    (Pa.sec)
        type (t_dovcalib)  :: dov_calib                       ! Dead oil Viscosity correlation and calib data, for temperature dependence
!!!     type (t_emulcalib) :: emul_calib                      ! Emulsion Viscosity correlation and calib data

        logical            :: valid     = .false.             ! only set true by finish_fluid_definition
        character(4)       :: padding   = 'abcd'       ! to make it all a multiple of 8 bytes
        real(8)            :: st_od     = runset ! 750.       ! stock-tank (dead) oil density         (kg/m3)
        real(8)            :: WatsonK   = runset              ! Watson K-factor of the oil, if known
        real(8)            :: st_wd     = runset  ! 1024.     ! stock-tank water density              (kg/m3)
        real(8)            :: st_gd     = runset  ! 0.8       ! stock-tank gas   density              (kg/m3)
        real(8)            :: st_vfg    = runset              ! stock-tank volume fraction gas
        real(8)            :: st_vfo    = runset              ! stock-tank volume fraction oil
        real(8)            :: st_vfw    = runset              ! stock-tank volume fraction water
        real(8)            :: st_mfg    = runset              ! stock-tank mass fraction of gas
        real(8)            :: st_mfo    = runset              ! stock-tank mass fraction of oil
        real(8)            :: st_mfw    = runset              ! stock-tank mass fraction of water
        character(8)       :: st_frac_type = 'volume'         ! 'mass' or 'volume' to specify which of the above are set by the user

        character(12)      :: sten_go_corr  = 'ABDULMAJEED'   ! correlation for gas-oil surface tension
        character(12)      :: sten_gw_corr  = 'ACF'           ! correlation for gas-water surface tension
        character(12)      :: sten_ow_corr  = 'xxx'           ! correlation for oil-water surface tension
        character(12)      :: gas_pcpt_corr = 'STANDING'      ! correlation for Gas Pseudo-Critical Pressure & Temperature
        character(12)      :: wd_corr       = 'MCCAIN'        ! correlation for water density, FVF, compressibility
        character(12)      :: wv_corr       = 'MCCAIN'        ! correlation for water viscosity

        ! Thermal data, for enthalpy calculation
        real(8)            :: gas_cp   = 0.7                  ! J/kg/K, == 0.7 BTU/lbF
        real(8)            :: oil_cp   = 0.5                  ! J/kg/k, == 0.5 BTU/lbF
        real(8)            :: wat_cp   = 1.0                  ! J/kg/K, == 1   BTU/lbF
        real(8)            :: gas_hvap = 140.                 ! J/Kg, == 140 BTU/lb
        real(8)            :: gas_jt   = 0.07                 ! K/Pa, == 0.07 F/psia, AGA approximation (www.aga.org/Kc/glossary/Pages/J.aspx, needs user login). also 4.655e-6.
        real(8)            :: oil_jt   = -5d-7                ! K/Pa, Q's guess
        real(8)            :: wat_jt   = -2.5d-7              ! K/Pa, Q's guess
        logical            :: taper_gas_hvap = .false.        ! apply reduction to HVAP based on ratio of gas & oil densities
        logical            :: taper_gas_jt   = .true.         ! apply reduction to gas JT as pressure increases
        character(12)      :: enth_model     = 'MAXEUR'       ! correlation for enthalpy
        integer            :: enth_model_sub = 0              ! "sub" corr for MAXEUR: 1='ACFGAS', 2='ACFOIL' or 3='BLEND'
 !!!    real(8)            :: illegality_fraction = 0.        ! assigned during a mix; represents the portion of this fluid, that
                                                              ! originated from an "illegal fluid" (i.e. one that was invented at
                                                              ! a sink acting as a source, or a junction with no feed branch)

        real(8)            :: mfCO2          = 0.0            ! mole fraction Carbon Dioxide; N.B. Was mass fraction !
        real(8)            :: mfH2S          = 0.0            ! mole fraction Hydrogen Sulphide
        real(8)            :: mfN2           = 0.0            ! mole fraction Nitrogen

        ! Corrosion data
        real(8)            :: pHact          = runset         ! fluid pH                         (-)

        character(12)      :: gtype          = '****'         ! type of gas ratio: GLR, GOR, OGR or LGR
        character(12)      :: wtype          = '****'         ! type of water ratio: WCUT, WGR, or GWR
        real(8)            :: gratio         = runset         ! value of gratio
        real(8)            :: wratio         = runset         ! value of wratio

                                                              ! following BP data provides an alternative to specifying the
                                                              ! GRATIO.
        real(8)            :: BPpressure     = runset         ! bubble poiont pressure  (Pa)
        real(8)            :: BPtemperature  = runset         ! bubble poiont temperature (K)
        logical          :: bubble_point_set = .false.        ! signals the need to convert these to a GOR
        logical   :: calibration_needs_doing = .false.        ! signals the need to call the calibration code.
                                                              ! This gets set when any calibration data is changed,
                                                              ! or correlations changed, or gassg or api changed.
        character(12)    :: calibration_type = 'NONE'         ! can be SINGLE, MULTI, or FACTORS, depending on input data supplied
        character(4)       :: more_padding   = 'abcd'         ! to make it all a multiple of 8 bytes

        ! Derived values... these are calculated in routine finish_bo_fluid_definition in bo_fluids_mod.f90:
        real(8)            :: st_glr       = runset           ! gas-liquid ratio, volume/volume
        real(8)            :: st_gor       = runset           ! .
        real(8)            :: st_ogr       = runset           ! .
        real(8)            :: st_lgr       = runset           ! .
        real(8)            :: st_wgr       = runset           ! .
        real(8)            :: st_gwr       = runset           ! .
        real(8)            :: st_vfwl      = runset           ! volume fraction of water in liquid, fraction 0 to 1
        real(8)            :: st_ovis      = runset           ! oil viscosity
        real(8)            :: st_wvis      = runset           ! water viscosity



        ! Derivatives of phase volume fractions wrt flowrate ... Adrian's crackuot idea, but worth a few beers if he gets it to work
        real(8)            :: dmgdr         = 0.              ! derivative of mass fraction stgas   vs rate
        real(8)            :: dmwdr         = 0.              ! derivative of mass fraction stwater vs rate

        type(t_measurement), allocatable :: measurement       ! measured values of P, T, VFG/O/W, plus some more things not directly applicable to fluids

        type(t_multipoint_calib_results), allocatable :: mcalib_res  ! results of multipoint calibration

        integer(8)                :: handle = 0              ! checksum/handle

      end type t_bo_fluid



      type, public :: t_calib_results  
        sequence
        real(8) :: pRsO           = runset       ! "potential" Rs: gas that would disolve in the oil phase              std.vol/std.vol
        real(8) :: upRsO          = runset       ! Unlimited "potential" Rs, can go negative, used for tuning calcs vol/vol
        real(8) :: p_sat_oil_dens = runset       ! saturated oil density assuming Rs == pRsO
        real(8) :: Bob            = runset       ! Oil Bo (FVF) at bubble point pressure
        real(8) :: dov            = runset       ! dead Oil viscosity at atmosp and flash temperature
        real(8) :: sov_at_pRs     = runset       ! Saturated Oil viscosity assuming Rs == pRso
        real(8) :: sov_at_gor     = runset       ! Saturated Oil viscosity assuming Rs == GOR
      end type

end module


program ivf_test 

   use bo_fl_types

   implicit none

   type t_fluid 
     real(8) :: bb(1000)
     type(t_bo_fluid) :: bo
     real(8) :: aa(2000)
   end type
   
   type(t_fluid) :: fl 
   type(t_fluid) afl ! , allocatable :: afl  

   fl%bo%rs_calib%apres = [1d0,2d0,3d0,4d0,5d0]  ! without this, it runs without error

!!   allocate(afl)  ! fails with or without this
   afl = fl       ! fails here. forrtl: severe (157): Program Exception - access violation

   print *, afl%bo%rs_calib%apres

end program
