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)