hydrostatic_multi_phase.F90       coverage:  0.00 %func     0.00 %block


     1) module HydrostaticMultiPhase_module
     2)  
     3)   use PFLOTRAN_Constants_module
     4) 
     5)   implicit none
     6) 
     7)   private
     8) 
     9) #include "petsc/finclude/petscsys.h"
    10) 
    11)   !LIQ = water to be consistent with the remainder fo the code
    12)   PetscInt, parameter :: HYDRO_LIQ_PHASE = 1  
    13)   PetscInt, parameter :: HYDRO_GAS_PHASE = 2
    14)   PetscInt, parameter :: HYDRO_OIL_PHASE = 3 
    15) 
    16) 
    17)   type :: one_dim_grid_type
    18)     PetscReal :: delta_z
    19)     PetscReal :: min_z
    20)     PetscReal :: max_z
    21)     PetscReal, pointer :: z(:)
    22)     PetscInt :: idatum
    23)   contains 
    24)     procedure :: ElevationIdLoc
    25)   end type one_dim_grid_type
    26) 
    27) 
    28)   public :: TOIHydrostaticUpdateCoupler
    29)   !          HydrostaticTest 
    30)  
    31) contains
    32) 
    33) ! ************************************************************************** !
    34) subroutine TOIHydrostaticUpdateCoupler(coupler,option,grid, &
    35)               characteristic_curves_array,sat_func_id,imat)
    36) 
    37)   ! 
    38)   ! Computes the hydrostatic initial/boundary condition for oil/water systems
    39)   ! given the oil water contact (owc) elevation
    40)   !
    41)   ! Author: Paolo Orsini
    42)   ! Date: 12/21/15
    43)   ! 
    44)   ! Algorithm description (To add with a schematic drawing of OWC)
    45)   !- Identify location of datum and OWC within 1D domain
    46)   ! 
    47)   ! IF DATUM FALLS IN WATER REGION:
    48)   ! 1. COMPUTE WATER HYDROSTATIC PRESSURE from:
    49)   ! - istart (idatum),
    50)   ! - pressure_start (pressure_at_datum), this must be a water pressure
    51)   ! - temperature_at_datum, or temp_array(npressure)
    52)   !     
    53)   ! 2. COMPUTE OIL HYDROSTATIC PRESSURE profile passing:
    54)   ! - istart (OWC_loc_id)
    55)   ! - pressure_start (oil pressure_at_OWC), computed from pw at OWC and pc,  
    56)   !   which is an input or computed from a saturation function for So = Soir
    57)   ! - temperature_at_datum, or temp_array(npressure)
    58) 
    59)   ! IF DATUM FALLS in OIL REGION
    60)   ! 1. COMPUTE OIL HYDROSTATIC PRESSURE from:
    61)   ! - istart (idatum),
    62)   ! - pressure_start (pressure_at_datum), this must be an oil pressure
    63)   ! - temperature_at_datum, or temp_array(npressure) 
    64)   ! 2. COMPUTES WATER HYDROSTATIC PRESSURE profile passing:
    65)   ! - istart (OWC_loc_id)
    66)   ! - pressure_start (water pressure_at_OWC), computed from po at OWC and pc, 
    67)   !   which is an input or computed from a saturation function for So = Soir
    68)   ! - temperature_at_datum, or temp_array(npressure)
    69) 
    70)   !The oil and water pressure arrays on the 1D grid are used to interpolate
    71)   ! the pressure and copute the saturation on the 3D grid cells
    72)   ! - compute oil initial phase pressures
    73)   ! - compute equilibrating capillary pressure: pc = po - pw 
    74)   ! - compute saturation from inverse pc curve: sw = pc^(-1)(sw) 
    75) 
    76)   !PO note - this should be a member function of the coupler class!
    77) 
    78)   use EOS_Water_module
    79) 
    80)   use Option_module
    81)   use Grid_module
    82)   use Coupler_module
    83)   use Condition_module
    84)   use Connection_module
    85)   use Characteristic_Curves_module
    86)   use Region_module
    87)   !use Grid_Structured_module
    88)   !use Utility_module, only : DotProduct
    89)   use Utility_module
    90)   use Dataset_Gridded_HDF5_class
    91)   use Dataset_Ascii_class
    92)   
    93)   use TOilIms_Aux_module
    94)   
    95)   implicit none
    96) 
    97)   type(coupler_type) :: coupler
    98)   type(option_type) :: option
    99)   type(grid_type) :: grid
   100)   type(characteristic_curves_ptr_type) :: characteristic_curves_array(:)
   101)   PetscInt, pointer, intent(in) :: sat_func_id(:)
   102)   PetscInt, pointer, intent(in) :: imat(:)
   103) 
   104)   PetscReal :: xm_nacl
   105)   PetscInt :: local_id, ghosted_id, iconn, ghosted_id_min_dist
   106)   PetscReal :: oil_press_grad(3), wat_press_grad(3), temperature_grad(3)  
   107)   PetscReal :: datum(3), owc(3)
   108)   PetscReal :: pressure_at_datum, temperature_at_datum, press_start
   109)   PetscReal :: max_z, min_z
   110)   PetscReal :: gravity_magnitude
   111)   PetscReal :: pw_owc, po_owc, pc_owc, pw_cell, po_cell, temperature, temp_owc
   112)   PetscInt  :: i_owc, ipressure, ipress_start ! id_loc_owc 
   113)   PetscReal, pointer :: wat_pressure_array(:), wat_density_array(:)
   114)   PetscReal, pointer :: oil_pressure_array(:), oil_density_array(:)  
   115)   PetscReal, pointer :: temperature_array(:)
   116)   PetscReal :: dist_x, dist_y, dist_z, delta_z, dist_z_for_pressure
   117)   PetscReal :: dist_owc_start
   118)   PetscReal :: dist_z_owc, dx_conn, dy_conn, dz_conn
   119)   PetscBool :: datum_in_water, pw_hydrostatic, po_hydrostatic
   120)   PetscReal :: sat_liq_owc, pc_comp, sat_liq_comp, dsat_dpres
   121)   PetscReal :: sat_ir(2)
   122) 
   123)   class(one_dim_grid_type), pointer :: one_d_grid
   124)   type(flow_condition_type), pointer :: condition
   125)   class(characteristic_curves_type), pointer :: characteristic_curves
   126)   !class(characteristic_curves_type) :: characteristic_curves
   127) 
   128)   if (coupler%connection_set%num_connections == 0 ) return
   129) 
   130)   pw_hydrostatic = PETSC_TRUE
   131)   po_hydrostatic = PETSC_TRUE  
   132) 
   133)   condition => coupler%flow_condition
   134)   
   135)   nullify(wat_pressure_array)
   136)   nullify(wat_density_array)
   137)   nullify(oil_pressure_array)
   138)   nullify(oil_density_array)
   139) 
   140)   ! fix indices for map to flow_aux_real_var
   141)   coupler%flow_aux_mapping(TOIL_IMS_PRESSURE_INDEX) = 1
   142)   coupler%flow_aux_mapping(TOIL_IMS_OIL_SATURATION_INDEX) = 2
   143)   coupler%flow_aux_mapping(TOIL_IMS_TEMPERATURE_INDEX) = 3 
   144) 
   145)   xm_nacl = option%m_nacl * FMWNACL
   146)   xm_nacl = xm_nacl /(1.d3 + xm_nacl)
   147) 
   148)   !initialise datum
   149)   datum(:) = 0.0d0
   150)   oil_press_grad(:) = 0.0d0
   151)   wat_press_grad(:) = 0.0d0
   152)   temperature_grad(:) = 0.0d0
   153)    
   154)   if ( associated(condition%datum) ) then
   155)     datum(1:3) = condition%datum%rarray(1:3) 
   156)   end if   
   157)   pressure_at_datum = &
   158)       condition%toil_ims%pressure%dataset%rarray(1)
   159)   ! gradient is in m/m; needs conversion to Pa/m
   160)   if (associated(condition%toil_ims%pressure%gradient)) then
   161)     oil_press_grad(1:3) = &
   162)     condition%toil_ims%pressure%gradient%rarray(1:3)
   163)   endif
   164)   if (associated(condition%toil_ims%liq_press_grad)) then
   165)     wat_press_grad(1:3) = &
   166)       condition%toil_ims%liq_press_grad%dataset%rarray(1:3)
   167)   endif
   168) 
   169)   temperature_at_datum = &
   170)     condition%toil_ims%temperature%dataset%rarray(1)
   171)   if (associated(condition%toil_ims%temperature%gradient)) then
   172)      temperature_grad(1:3) = &
   173)        condition%toil_ims%temperature%gradient%rarray(1:3)
   174)   endif
   175) 
   176)   max_z = max(grid%z_max_global,datum(Z_DIRECTION))+1.d0 ! add 1m buffer
   177)   min_z = min(grid%z_min_global,datum(Z_DIRECTION))-1.d0
   178) 
   179)   if (associated(condition%toil_ims%owc)) then
   180)     owc(1:3) = condition%toil_ims%owc%dataset%rarray(1:3)
   181)   else ! default condition assumes owc above domain and datum: water domain
   182)     if ( datum(Z_DIRECTION) >= max_z ) then
   183)       owc(Z_DIRECTION) = datum(Z_DIRECTION) + 1.d0
   184)     else
   185)       owc(Z_DIRECTION) = max_z + 1.d0 ! place owc 1 m above domain
   186)     end if
   187)     datum_in_water = PETSC_TRUE
   188)   end if 
   189)   
   190)   ! finds out where datume is located
   191)   if ( datum(Z_DIRECTION) >= owc(Z_DIRECTION) ) then
   192)     datum_in_water = PETSC_FALSE !datum is in the oil region 
   193)   else
   194)     datum_in_water = PETSC_TRUE !datum is in the water region
   195)   end if
   196) 
   197)   if (dabs(wat_press_grad(Z_DIRECTION)) >= 1.d-40) pw_hydrostatic = PETSC_FALSE
   198)   if (dabs(oil_press_grad(Z_DIRECTION)) >= 1.d-40) po_hydrostatic = PETSC_FALSE
   199) 
   200)   ! checks to tunr off unnecessary hydrostatic computations
   201)   if (owc(Z_DIRECTION) > max_z )  po_hydrostatic = PETSC_FALSE
   202)   if (owc(Z_DIRECTION) < min_z )  pw_hydrostatic = PETSC_FALSE
   203) 
   204)   !if one of the phases requires automatic hydrostatic pressure 
   205)   ! the 1D domain and discretisation is needed
   206)   !if ( (oil_press_grad(Z_DIRECTION) < 1.d-40) .or. &
   207)   !     (wat_press_grad(Z_DIRECTION) < 1.d-40 ) &
   208)   !   ) then
   209)   if ( pw_hydrostatic .or. po_hydrostatic ) then
   210) 
   211)     gravity_magnitude = sqrt(DotProduct(option%gravity,option%gravity))
   212)   
   213)     if (dabs(gravity_magnitude-9.8068d0) > 0.1d0) then
   214)       option%io_buffer = 'Magnitude of gravity vector is not near 9.81.'
   215)       call printErrMsg(option)
   216)     endif
   217)  
   218)     ! ceat 1D domain and discretization needed for interpolations
   219)     one_d_grid => CreateOneDimGrid(min_z,max_z,datum)
   220) 
   221)     allocate(temperature_array(size(one_d_grid%z(:))))
   222)     temperature_array = 0.d0
   223)     call CompVertTempProfile(one_d_grid,temperature_grad, &
   224)                              temperature_at_datum,temperature_array)
   225)     ! allocate pressure, density and temperature arrays
   226)     !allocate(pressure_array(2,size(one_d_grid%z(:)))) 
   227)     !allocate(density_array(2,size(one_d_grid%z(:))))
   228)     if (pw_hydrostatic) then
   229)       allocate(wat_pressure_array(size(one_d_grid%z(:))))
   230)       allocate(wat_density_array(size(one_d_grid%z(:))))
   231)     end if
   232)     if (po_hydrostatic) then
   233)       allocate(oil_pressure_array(size(one_d_grid%z(:))))
   234)       allocate(oil_density_array(size(one_d_grid%z(:))))
   235)     end if
   236)   end if
   237)   
   238)   dist_x = 0.d0
   239)   dist_x = 0.d0
   240)   dist_z = owc(Z_DIRECTION) - datum(Z_DIRECTION)
   241)   po_owc = 0.d0
   242)   pw_owc = 0.d0
   243)   ! identify where the owc is located in the one_dim mesh
   244)   if (pw_hydrostatic .or. po_hydrostatic) then 
   245)     i_owc = one_d_grid%idatum+int(dist_z/one_d_grid%delta_z)
   246)     dist_z_for_pressure = owc(Z_DIRECTION) - one_d_grid%z(i_owc)
   247)     temp_owc = temperature_array(i_owc) + &
   248)                dist_z_for_pressure * temperature_grad(Z_DIRECTION)
   249)   end if
   250) 
   251)   ghosted_id_min_dist = &
   252)       GetCouplerCellOnPhaseConact(coupler,grid,imat,owc(Z_DIRECTION),option)
   253) 
   254)   !write(*,*) "my_rank", option%myrank, "min_ghost", ghosted_id_min_dist, &
   255)   !           "sat_fun_id", sat_func_id(ghosted_id_min_dist)
   256) 
   257)   characteristic_curves => &
   258)       characteristic_curves_array(sat_func_id(ghosted_id_min_dist))%ptr
   259)   !characteristic_curves = characteristic_curves_array(func_id)%ptr
   260)   ! the OWC is assumed to be located where So = So_ir 
   261)   sat_ir(:) = CharCurvesGetGetResidualSats(characteristic_curves,option) 
   262)   sat_liq_owc = 1.0 - sat_ir(2)
   263)       
   264)   call characteristic_curves%saturation_function% &
   265)               CapillaryPressure(sat_liq_owc,pc_owc,option)
   266) 
   267)   ! compute pressure and density profiles for phases where hydrostatic pressure
   268)   ! is imposed. And pressure (water or oil) at owc elevation
   269)   if (datum_in_water) then 
   270)     if (pw_hydrostatic) then
   271)       call PhaseHydrostaticPressure(one_d_grid,option%gravity, &
   272)                 HYDRO_LIQ_PHASE,pressure_at_datum, &
   273)                 one_d_grid%idatum,xm_nacl,temperature_array, &
   274)                 wat_pressure_array,wat_density_array)   
   275)       pw_owc = PressInterp(i_owc,dist_x,dist_y,dist_z_for_pressure, &
   276)                            option%gravity,wat_pressure_array, &
   277)                            wat_density_array,wat_press_grad)
   278)     else
   279)       pw_owc = PressGrad(dist_x,dist_y,dist_z,pressure_at_datum,wat_press_grad) 
   280)     end if
   281)     ! test pc=0
   282)     !po_owc = pw_owc
   283)     po_owc = pw_owc + pc_owc
   284) 
   285)     if (po_hydrostatic) then
   286)       ! compute oil press and denisty profiles
   287)       !id_loc_owc = one_d_grid%ElevationIdLoc(owc(Z_DIRECTION))
   288)       ipress_start = i_owc + 1
   289)       !if ( ipress_start > size(one_d_grid%z(:)) ) & !need to avoid this computation if owc > z_max
   290)       !  ipress_start = size(one_d_grid%z(:))
   291)       dist_owc_start = one_d_grid%z(ipress_start) - owc(Z_DIRECTION)
   292)       press_start = po_owc + dist_owc_start * &
   293)                     PhaseDensity(HYDRO_OIL_PHASE,po_owc,temp_owc,xm_nacl) * &
   294)                     option%gravity(Z_DIRECTION)
   295)       call PhaseHydrostaticPressure(one_d_grid,option%gravity, &
   296)                 HYDRO_OIL_PHASE,press_start, &
   297)                 ipress_start,xm_nacl,temperature_array, &
   298)                 oil_pressure_array,oil_density_array)   
   299)     end if
   300)   else ! datum is in the oil region
   301)     if (po_hydrostatic) then
   302)       call PhaseHydrostaticPressure(one_d_grid,option%gravity, &
   303)                 HYDRO_OIL_PHASE,pressure_at_datum, &
   304)                 one_d_grid%idatum,xm_nacl,temperature_array, &
   305)                 oil_pressure_array,oil_density_array)   
   306)       po_owc = PressInterp(i_owc,dist_x,dist_y,dist_z_for_pressure, &
   307)                            option%gravity,oil_pressure_array, &
   308)                            oil_density_array,oil_press_grad)
   309)     else
   310)       po_owc = PressGrad(dist_x,dist_y,dist_z,pressure_at_datum,oil_press_grad) 
   311)     end if
   312)     ! testing pc = 0 
   313)     !pw_owc = po_owc
   314)     pw_owc = po_owc - pc_owc
   315) 
   316)     if (pw_hydrostatic) then
   317)       ! conmpute water press and denisty profiles
   318)       !id_loc_owc = one_d_grid%ElevationIdLoc(owc(Z_DIRECTION))
   319)       ipress_start = i_owc + 1
   320)       dist_owc_start = one_d_grid%z(ipress_start) - owc(Z_DIRECTION)
   321)       press_start = pw_owc + dist_owc_start * &
   322)                     PhaseDensity(HYDRO_LIQ_PHASE,pw_owc,temp_owc,xm_nacl) * &
   323)                     option%gravity(Z_DIRECTION)
   324)       call PhaseHydrostaticPressure(one_d_grid,option%gravity, &
   325)                 HYDRO_LIQ_PHASE,press_start, &
   326)                 ipress_start,xm_nacl,temperature_array, &
   327)                 wat_pressure_array,wat_density_array) 
   328)     end if
   329)   end if
   330)   
   331)   !compute pressure values in the coupler region cells 
   332) 
   333)   dx_conn = 0.d0
   334)   dy_conn = 0.d0
   335)   dz_conn = 0.d0
   336) 
   337)   do iconn=1,coupler%connection_set%num_connections 
   338)     local_id = coupler%connection_set%id_dn(iconn)
   339)     ghosted_id = grid%nL2G(local_id)
   340)  
   341)     ! geh: note that this is a boundary connection, thus the entire distance is between
   342)     ! the face and cell center
   343)     if (associated(coupler%connection_set%dist)) then
   344)       dx_conn = coupler%connection_set%dist(0,iconn) * &
   345)                       coupler%connection_set%dist(1,iconn)
   346)       dy_conn = coupler%connection_set%dist(0,iconn) * &
   347)                       coupler%connection_set%dist(2,iconn)
   348)       dz_conn = coupler%connection_set%dist(0,iconn) * &
   349)                       coupler%connection_set%dist(3,iconn)
   350)     endif
   351) 
   352)     ! note the negative (-) d?_conn is required due to the offset of the boundary face
   353)     dist_x = grid%x(ghosted_id)-dx_conn-datum(X_DIRECTION) !datume here can be datum or owc !!
   354)     dist_y = grid%y(ghosted_id)-dy_conn-datum(Y_DIRECTION)
   355)     dist_z = grid%z(ghosted_id)-dz_conn-datum(Z_DIRECTION)
   356)     ! 
   357)     if ( pw_hydrostatic .or. po_hydrostatic ) then
   358)       !location in the press_arrays
   359)       ipressure = one_d_grid%idatum+int(dist_z/one_d_grid%delta_z) 
   360)       dist_z_for_pressure = grid%z(ghosted_id) - &
   361)                             dz_conn - one_d_grid%z(ipressure) 
   362)     end if
   363)   
   364)     if ( (.not.pw_hydrostatic) .or. (.not.po_hydrostatic) ) then 
   365)       dist_z_owc = grid%z(ghosted_id)-dz_conn-owc(Z_DIRECTION) !z_ref is owc
   366)     end if
   367) 
   368)     if (pw_hydrostatic) then
   369)       pw_cell = PressInterp(ipressure,dist_x,dist_y,dist_z_for_pressure, &
   370)                             option%gravity,wat_pressure_array, &
   371)                             wat_density_array,wat_press_grad)
   372)     else
   373)       pw_cell = PressGrad(dist_x,dist_y,dist_z_owc,pw_owc,wat_press_grad)
   374)     end if 
   375) 
   376)     if (po_hydrostatic) then
   377)       po_cell = PressInterp(ipressure,dist_x,dist_y,dist_z_for_pressure, &
   378)                             option%gravity,oil_pressure_array, &
   379)                             oil_density_array,oil_press_grad)
   380)     else
   381)       po_cell = PressGrad(dist_x,dist_y,dist_z_owc,po_owc,oil_press_grad)
   382)     end if 
   383)     
   384)     !COMPUTE HERE SATURATION and adjust pressure if required
   385)     !at the moment pc = 0, above owc So=1, below owc Sw=1 
   386)     ! once this is tested include pc
   387) 
   388)     if (owc(Z_DIRECTION) > max_z) then !owc above domain (water only)
   389)       coupler%flow_aux_real_var(1,iconn) = pw_cell
   390)       coupler%flow_aux_real_var(2,iconn) = 1.0d-6 !to avoid truncation erros
   391)     else if (owc(Z_DIRECTION) < min_z) then !owc below domain (oil only)
   392)       !OIL PRESSURE
   393)       coupler%flow_aux_real_var(1,iconn) = po_cell 
   394)       !OIL SATURATION 
   395)       ! coupler%flow_aux_real_var(2,iconn) = 1.0d0 - sat_ir(1)
   396)       ! assign value read from input
   397)       coupler%flow_aux_real_var(2,iconn) = &
   398)                 coupler%flow_condition%toil_ims%saturation%dataset%rarray(1)
   399)     else
   400)       !use instgructions below when imposing pc=0 capillary pressure 
   401)       !if ( grid%z(ghosted_id) > owc(Z_DIRECTION) ) then
   402)       !  !OIL PRESSURE
   403)       !  coupler%flow_aux_real_var(1,iconn) = po_cell 
   404)       !  !OIL SATURATION
   405)       !  coupler%flow_aux_real_var(2,iconn) = 1.0d0
   406)       !else 
   407)       !  coupler%flow_aux_real_var(1,iconn) = pw_cell
   408)       !  coupler%flow_aux_real_var(2,iconn) = 1.0d-6 !to avoid truncation erros
   409)       !end if
   410)       !use insytruction below for pc /= 0 
   411)       pc_comp = po_cell - pw_cell
   412)       if ( pc_comp <= 0.d0 ) then ! water-only region 
   413)         coupler%flow_aux_real_var(1,iconn) = pw_cell
   414)         coupler%flow_aux_real_var(2,iconn) = 1.0d-6 !to avoid truncation erros
   415)       else if ( pc_comp >= characteristic_curves%saturation_function%pcmax ) &
   416)         then
   417)         ! oil region: can consider here connate water if required, or Sw_ir
   418)         ! sat_ir(1) currenlty used, this Sw_ir taken from owc characteristic curve
   419)         ! should consider input from deck
   420)         coupler%flow_aux_real_var(1,iconn) = po_cell
   421)         coupler%flow_aux_real_var(2,iconn) = 1.0d0 - sat_ir(1)
   422)       else
   423)         ! water/oil transition zone
   424)         coupler%flow_aux_real_var(1,iconn) = po_cell      
   425)         call characteristic_curves%saturation_function%Saturation(pc_comp, &
   426)                 sat_liq_comp,dsat_dpres,option) 
   427)         coupler%flow_aux_real_var(2,iconn) = 1.0d0 - sat_liq_comp
   428)         if (coupler%flow_aux_real_var(2,iconn) < 1.0d-6 ) &
   429)            coupler%flow_aux_real_var(2,iconn) = 1.0d-6 
   430)       end if
   431)     end if
   432) 
   433)     ! assign temperature
   434)     temperature = temperature_at_datum + &
   435)                   temperature_grad(X_DIRECTION)*dist_x + & ! gradient in K/m
   436)                   temperature_grad(Y_DIRECTION)*dist_y + &
   437)                   temperature_grad(Z_DIRECTION)*dist_z 
   438)     coupler%flow_aux_real_var(3,iconn) = temperature
   439) 
   440)   enddo
   441) 
   442)   call DestroyOneDimGrid(one_d_grid)
   443) 
   444)   call DeallocateArray(temperature_array)
   445)   call DeallocateArray(wat_pressure_array)
   446)   call DeallocateArray(wat_density_array)
   447)   call DeallocateArray(oil_pressure_array)
   448)   call DeallocateArray(oil_density_array)
   449)   
   450) 
   451) end subroutine TOIHydrostaticUpdateCoupler
   452) 
   453) ! ************************************************************************** !
   454) 
   455) function GetCouplerCellOnPhaseConact(coupler,grid,imat,z_phase_contact,option)
   456) 
   457)   ! Returns the ghosted_id of the closest cell to phase contact  
   458)   ! Where more cells have the same minimum distance from z_phase_contact,
   459)   ! the first cell in the list will be selected as for the minloc function 
   460)   !
   461)   ! Author: Paolo Orsini
   462)   ! Date: 12/31/15
   463)   ! 
   464) 
   465)   use Grid_module
   466)   use Coupler_module
   467)   use Utility_module
   468)   use Option_module
   469) 
   470)   implicit none
   471) 
   472)   type(coupler_type), intent(in) :: coupler
   473)   type(grid_type), intent(in) :: grid
   474)   PetscInt, pointer, intent(in) :: imat(:)
   475)   PetscReal, intent(in) :: z_phase_contact
   476)   type(option_type) :: option
   477) 
   478)   PetscInt :: GetCouplerCellOnPhaseConact
   479) 
   480)   PetscInt :: iconn, local_id, ghosted_id
   481)   PetscInt :: iconn_min(1)
   482)   PetscReal, pointer :: phase_contact_dist(:) 
   483) 
   484)   allocate(phase_contact_dist(coupler%connection_set%num_connections))
   485)   phase_contact_dist = 1.d20
   486)   
   487)   do iconn=1,coupler%connection_set%num_connections
   488)     local_id = coupler%connection_set%id_dn(iconn)
   489)     ghosted_id = grid%nL2G(local_id)
   490)     if (imat(ghosted_id) <= 0) cycle
   491)     phase_contact_dist(iconn) = dabs(grid%z(ghosted_id) - z_phase_contact)
   492)   end do
   493) 
   494)   iconn_min = minloc(phase_contact_dist(:))
   495) 
   496)   local_id = coupler%connection_set%id_dn(iconn_min(1))
   497) 
   498)   !write(*,*) "in get ghost -rank=", option%myrank, "icon_min=", iconn_min(1), &
   499)   !           " ghost =", grid%nL2G(local_id), "size dist = ", size(phase_contact_dist(:))
   500) 
   501)   GetCouplerCellOnPhaseConact = grid%nL2G(local_id) 
   502) 
   503)   call DeallocateArray(phase_contact_dist)
   504)  
   505) 
   506) end function GetCouplerCellOnPhaseConact
   507) 
   508) ! ************************************************************************** !
   509) 
   510) subroutine PhaseHydrostaticPressure(one_d_grid,gravity,iphase,press_start, &
   511)                                     id_start,xm_nacl,temp,press,den_kg)
   512)   ! 
   513)   ! Compute an hydrostatic pressure profile for a given phase and 1D 
   514)   ! 1D discretisation
   515)   ! The "starting point" for the computation of the pressure profile
   516)   ! is the elevation where a reference pressure is given, it can be the datum,
   517)   ! or one of the phase contact interface (e.g. OWC, OGC, etc)
   518)   !
   519)   ! Author: Paolo Orsini
   520)   ! Date: 12/21/15
   521)   ! 
   522) 
   523)   implicit none
   524) 
   525)   class(one_dim_grid_type) :: one_d_grid
   526)   PetscReal, intent(in) :: gravity(:) ! this is option%gravity
   527)   PetscInt, intent(in) :: iphase
   528)   PetscReal, intent(in) :: press_start
   529)   PetscInt, intent(in) :: id_start
   530)   PetscReal, intent(in) :: temp(:)
   531)   PetscReal, intent(in) :: xm_nacl
   532)   PetscReal, intent(out) :: press(:)
   533)   PetscReal, intent(out) :: den_kg(:)
   534) 
   535)   PetscReal :: pressure, pressure0, rho, rho_one, rho_kg, rho_zero
   536)   PetscInt :: ipressure, num_iteration
   537)   
   538)   if(iphase == HYDRO_GAS_PHASE ) then
   539)     print *, "PhaseHydrostaticPressure does not support gas"
   540)     stop
   541)   end if
   542) 
   543)   rho_kg = PhaseDensity(iphase,press_start,temp(id_start),xm_nacl)
   544) 
   545)   ! fill properties for reference pressure
   546)   den_kg(id_start) = rho_kg
   547)   press(id_start) = press_start 
   548) 
   549)   pressure0 = press_start 
   550)   rho_zero = rho_kg 
   551)   do ipressure=id_start+1,size(one_d_grid%z(:))
   552)     rho_kg = PhaseDensity(iphase,pressure0,temp(ipressure),xm_nacl)
   553)     num_iteration = 0
   554)     do 
   555)       pressure = pressure0 + 0.5d0*(rho_kg+rho_zero) * &
   556)                  gravity(Z_DIRECTION) * one_d_grid%delta_z
   557)       rho_one = PhaseDensity(iphase,pressure,temp(ipressure),xm_nacl)
   558)       !check convergence on density
   559)       if (dabs(rho_kg-rho_one) < 1.d-10) exit
   560)       rho_kg = rho_one
   561)       num_iteration = num_iteration + 1
   562)       if (num_iteration > 100) then
   563)         print *,'Phase-Hydrostatic iteration failed to converge', &
   564)                  num_iteration,rho_one,rho_kg
   565)         !print *, condition%name, idatum
   566)         !print *, pressure_array
   567)         stop
   568)       endif
   569)     enddo
   570)     rho_zero = rho_kg
   571)     press(ipressure) = pressure
   572)     den_kg(ipressure) = rho_kg
   573)     pressure0 = pressure
   574)   enddo
   575) 
   576)   ! compute pressures below one_d_grid%z(id_start), if any
   577)   pressure0 = press(id_start)
   578)   rho_zero = den_kg(id_start)
   579)   do ipressure=id_start-1,1,-1
   580)     rho_kg = PhaseDensity(iphase,pressure0,temp(ipressure),xm_nacl)
   581)     num_iteration = 0
   582)     do                   ! notice the negative sign (-) here
   583)       pressure = pressure0 - 0.5d0*(rho_kg+rho_zero) * &
   584)                  gravity(Z_DIRECTION) * one_d_grid%delta_z
   585)       rho_one = PhaseDensity(iphase,pressure,temp(ipressure),xm_nacl)
   586)       !check convergence on density
   587)       if (dabs(rho_kg-rho_one) < 1.d-10) exit
   588)       rho_kg = rho_one
   589)       num_iteration = num_iteration + 1
   590)       if (num_iteration > 100) then
   591)         print *,'Phase-Hydrostatic iteration failed to converge', &
   592)                  num_iteration,rho_one,rho_kg
   593)         !print *, condition%name, idatum
   594)         !print *, pressure_array
   595)         stop
   596)       endif
   597)     enddo
   598)     rho_zero = rho_kg
   599)     press(ipressure) = pressure
   600)     den_kg(ipressure) = rho_kg
   601)     pressure0 = pressure
   602)   enddo
   603) 
   604) end subroutine PhaseHydrostaticPressure
   605) 
   606) ! ************************************************************************** !
   607) function PhaseDensity(iphase,p,t,xm_nacl) 
   608)   !
   609)   ! computes phase density given the specified phase
   610)   !
   611)   ! Author: Paolo Orsini
   612)   ! Date: 12/21/15
   613)   ! 
   614) 
   615)   use EOS_Oil_module
   616)   use EOS_Water_module
   617)   use EOS_Gas_module ! when gas is considered
   618) 
   619)   implicit none
   620) 
   621)   PetscInt, intent(in) :: iphase
   622)   PetscReal, intent(in) :: p
   623)   PetscReal, intent(in) :: t
   624)   PetscReal, intent(in) :: xm_nacl
   625)  
   626)   PetscReal :: PhaseDensity ! kg/m3 
   627)   PetscReal :: dw_mol
   628)   PetscReal :: aux(1)
   629) 
   630)   PetscErrorCode :: ierr
   631) 
   632)   select case(iphase)
   633)     case(HYDRO_LIQ_PHASE)
   634)       aux(1) = xm_nacl
   635)       call EOSWaterDensityExt(t,p,aux,PhaseDensity,dw_mol,ierr)
   636)     case(HYDRO_GAS_PHASE)
   637)       !call EOSGasDensityNoDerive(t,p,PhaseDensity,ierr)
   638)       ! rho_kg = rho * GAS_FMW (to get gas FMW currenlty mode specific)
   639)       ! gas_fmw should be defined in gas_eos 
   640)     case(HYDRO_OIL_PHASE)
   641)       call EOSOilDensity(t,p,PhaseDensity,ierr)
   642)       PhaseDensity = PhaseDensity * EOSOilGetFMW() 
   643)   end select
   644) 
   645) end function PhaseDensity 
   646) 
   647) ! ************************************************************************** !
   648) 
   649) function PressInterp(ipressure,dist_x,dist_y,dist_z_for_pressure,gravity, &
   650)                      pressure_array,density_array,pressure_gradient)
   651) 
   652)   ! Computes hydrostatic pressure over dz from a reference pressure and
   653)   ! a density, combining possible horizontal gradients  
   654)   !
   655)   ! Author: Paolo Orsini
   656)   ! Date: 12/21/15
   657) 
   658) 
   659)   implicit none
   660) 
   661)   PetscInt, intent(in) :: ipressure
   662)   PetscReal, intent(in) :: dist_x
   663)   PetscReal, intent(in) :: dist_y
   664)   PetscReal, intent(in) :: dist_z_for_pressure
   665)   PetscReal, intent(in) :: gravity(:)
   666)   PetscReal, intent(in) :: pressure_array(:)
   667)   PetscReal, intent(in) :: density_array(:)
   668)   PetscReal, intent(in) :: pressure_gradient(:)
   669) 
   670)   PetscReal :: PressInterp
   671) 
   672)   PressInterp = pressure_array(ipressure) + &
   673)                 density_array(ipressure) * gravity(Z_DIRECTION) * &
   674)                 dist_z_for_pressure + &
   675)                 pressure_gradient(X_DIRECTION) * dist_x + & ! gradient in Pa/m
   676)                 pressure_gradient(Y_DIRECTION) * dist_y
   677) 
   678) end function PressInterp
   679) 
   680) ! ************************************************************************** !
   681) 
   682) !function HydrostaticPressOverDz(dz,gravity,press_ref,density_ref)
   683) !
   684) !  implicit none
   685) !
   686) !  PetscReal, intent(in) :: dz
   687) !  PetscReal, intent(in) :: gravity(:)
   688) !  PetscReal, intent(in) :: press_ref
   689) !  PetscReal, intent(in) :: density_ref
   690) !
   691) !  PetscReal :: HydrostaticPressOverDz
   692) !
   693) !  HydrostaticPressOverDz = press_ref + density_ref * gravity(Z_DIRECTION) * dz
   694) !
   695) !end function HydrostaticPressOverDz
   696) 
   697) ! ************************************************************************** !
   698) 
   699) function PressGrad(dist_x,dist_y,dist_z,press_ref,pressure_gradient)
   700) 
   701)   ! Computes pressure from a reference pressure, distances in the three 
   702)   ! directions, and a 3d local pressure gradient  
   703)   !
   704)   ! Author: Paolo Orsini
   705)   ! Date: 12/21/15
   706) 
   707) 
   708)   implicit none
   709) 
   710)   PetscReal, intent(in) :: dist_x
   711)   PetscReal, intent(in) :: dist_y
   712)   PetscReal, intent(in) :: dist_z
   713)   PetscReal, intent(in) :: press_ref
   714)   PetscReal, intent(in) :: pressure_gradient(:)
   715) 
   716)   PetscReal :: PressGrad
   717) 
   718)   PressGrad = press_ref + &
   719)               pressure_gradient(X_DIRECTION)*dist_x + & ! gradient in Pa/m
   720)               pressure_gradient(Y_DIRECTION)*dist_y + &
   721)               pressure_gradient(Z_DIRECTION)*dist_z 
   722) 
   723) end function PressGrad
   724) 
   725) ! ************************************************************************** !
   726) 
   727) 
   728) subroutine CompVertTempProfile(one_d_grid,temp_grad,temp_at_datum, &
   729)                                temp_profile)
   730)   ! 
   731)   ! Computes the temperature vertical profile on the 1D grid use for the 
   732)   ! hydrostatic pressure calculation
   733)   !
   734)   ! Author: Paolo Orsini
   735)   ! Date: 12/21/15
   736)   ! 
   737) 
   738)   implicit none
   739) 
   740)   class(one_dim_grid_type) :: one_d_grid
   741)   PetscReal, intent(in) :: temp_grad(:)
   742)   PetscReal, intent(in) :: temp_at_datum
   743)   PetscReal, intent(out) :: temp_profile(:)
   744)  
   745)   PetscInt :: i_z
   746) 
   747)   temp_profile(one_d_grid%idatum) = temp_at_datum
   748) 
   749)   do i_z=one_d_grid%idatum+1,size(one_d_grid%z(:))
   750)     temp_profile(i_z) = temp_profile(i_z-1) + &
   751)                         temp_grad(Z_DIRECTION)*one_d_grid%delta_z   
   752)   end do
   753) 
   754)   do i_z=one_d_grid%idatum-1,1,-1
   755)     temp_profile(i_z) = temp_profile(i_z+1) - & ! note the (-) sign
   756)                         temp_grad(Z_DIRECTION)*one_d_grid%delta_z   
   757)   end do
   758) 
   759) end subroutine CompVertTempProfile
   760) ! ************************************************************************** !
   761) 
   762) function CreateOneDimGrid(min_z,max_z,datum)
   763)   ! 
   764)   ! Computes 1D grid for interpolation needed in hydrostatic pressure
   765)   ! computation
   766)   !
   767)   ! Author: Paolo Orsini
   768)   ! Date: 12/21/15
   769)   ! 
   770) 
   771)   implicit none
   772) 
   773)   class(one_dim_grid_type), pointer :: one_d_grid
   774)   PetscReal,intent(in) :: datum(3)
   775)   PetscReal, intent(in) :: min_z, max_z
   776) 
   777)   class(one_dim_grid_type), pointer :: CreateOneDimGrid
   778) 
   779)   PetscInt :: num_z, i_z
   780)   PetscReal :: dist_z
   781) 
   782)   allocate(one_d_grid)
   783) 
   784)   one_d_grid%min_z = min_z
   785)   one_d_grid%max_z = max_z
   786) 
   787)   one_d_grid%delta_z = min((max_z-min_z)/500.d0,1.d0)
   788)   ! if zero, assign 1.d0 to avoid divide by zero below. essentially the grid
   789)   ! is flat.
   790)   if (one_d_grid%delta_z < 1.d-40) one_d_grid%delta_z = 1.d0
   791) 
   792)   num_z = int((max_z-min_z)/one_d_grid%delta_z) + 1
   793) 
   794)   allocate(one_d_grid%z(num_z))
   795) 
   796)   one_d_grid%idatum = int((datum(Z_DIRECTION)-min_z)/(max_z-min_z) * &
   797)                         dble(num_z))+1  
   798) 
   799)   one_d_grid%z(one_d_grid%idatum) = datum(Z_DIRECTION)  
   800) 
   801)   dist_z = 0.d0
   802)   do i_z=one_d_grid%idatum+1,num_z
   803)     dist_z = dist_z + one_d_grid%delta_z
   804)     one_d_grid%z(i_z) = one_d_grid%z(one_d_grid%idatum) + dist_z
   805)   enddo
   806) 
   807)   dist_z = 0.d0
   808)   do i_z = one_d_grid%idatum-1,1,-1
   809)     dist_z = dist_z + one_d_grid%delta_z
   810)     one_d_grid%z(i_z) = one_d_grid%z(one_d_grid%idatum) - dist_z
   811)   enddo
   812) 
   813)   CreateOneDimGrid => one_d_grid
   814) 
   815) end function CreateOneDimGrid
   816) 
   817) ! ************************************************************************** !
   818) function ElevationIdLoc(this,elevation)
   819)   ! 
   820)   ! Detect id location in one_d_grid given an absolute elevation
   821)   ! Note: absolute elevation, not relative to the datum 
   822)   !
   823)   ! Author: Paolo Orsini
   824)   ! Date: 12/21/15
   825)   ! 
   826) 
   827)   implicit none
   828) 
   829)   class(one_dim_grid_type) :: this
   830)   PetscReal, intent(in) :: elevation !this is the global elevation
   831)   
   832)   PetscInt :: ElevationIdLoc
   833)    
   834)   ElevationIdLoc = int( (elevation-this%min_z)/(this%max_z-this%min_z) * &
   835)                         dble(size(this%z(:))) ) + 1 
   836) 
   837)   !  idatum = int((datum(Z_DIRECTION)-min_z)/(max_z-min_z) * &
   838)   !               dble(num_pressures))+1
   839) 
   840) end function ElevationIdLoc
   841) 
   842) ! ************************************************************************** !
   843) 
   844) subroutine DestroyOneDimGrid(one_d_grid)
   845)   ! 
   846)   ! Author: Paolo Orsini
   847)   ! Date: 12/30/15
   848)   ! 
   849)   ! destroys OneDimGrid
   850) 
   851)   use Utility_module 
   852) 
   853)   implicit none
   854) 
   855)   class(one_dim_grid_type), pointer :: one_d_grid
   856) 
   857)   if (.not.associated(one_d_grid) ) return
   858) 
   859)   call DeallocateArray(one_d_grid%z)
   860) 
   861)   deallocate(one_d_grid)
   862)   nullify(one_d_grid)
   863) 
   864) end subroutine DestroyOneDimGrid
   865) 
   866) ! ************************************************************************** !
   867) 
   868) end module HydrostaticMultiPhase_module
   869) 

generated by
Intel(R) C++/Fortran Compiler code-coverage tool
Web-Page Owner: Nobody