Merge lp:~fluidity-core/fluidity/darcy_impes_proper into lp:fluidity

Proposed by Richard Ferrier
Status: Needs review
Proposed branch: lp:~fluidity-core/fluidity/darcy_impes_proper
Merge into: lp:fluidity
Diff against target: 272198 lines (+267531/-1508)
278 files modified
Makefile.in (+13/-4)
assemble/Darcy_IMPES_Assemble.F90 (+5920/-0)
assemble/Makefile.dependencies (+19/-0)
assemble/Makefile.in (+1/-1)
assemble/Petsc_Solve_State.F90 (+53/-1)
error_measures/Metric_advection.F90 (+9/-1)
examples/flow_past_sphere_Re1/unit_sphere.ele (+130208/-0)
examples/flow_past_sphere_Re1/unit_sphere.face (+11294/-0)
examples/flow_past_sphere_Re1/unit_sphere.node (+24975/-0)
femtools/Boundary_Conditions.F90 (+95/-12)
femtools/CV_Face_Values.F90 (+2/-1)
femtools/CV_Options.F90 (+2/-1)
femtools/Petsc_Tools.F90 (+108/-3)
femtools/Solvers.F90 (+120/-11)
femtools/Sparse_Tools_Petsc.F90 (+24/-1)
femtools/Transform_elements.F90 (+15/-1)
main/Darcy_IMPES.F90 (+2221/-0)
main/Makefile.dependencies (+25/-0)
manual/configuring_fluidity.tex (+1/-2)
manual/model_equations.tex (+1/-1)
preprocessor/Boundary_Conditions_From_Options.F90 (+7/-5)
preprocessor/Populate_State.F90 (+234/-33)
schemas/adaptivity_options.rnc (+902/-739)
schemas/adaptivity_options.rng (+612/-545)
schemas/darcy_impes_options.rnc (+2386/-0)
schemas/darcy_impes_options.rng (+2499/-0)
schemas/porous_media.rnc (+4/-4)
schemas/porous_media.rng (+4/-4)
tests/darcy_impes_common/Depend.mk (+18/-0)
tests/darcy_impes_common/batch_tools.py (+186/-0)
tests/darcy_impes_common/buckley_leverett_test_tools.py (+312/-0)
tests/darcy_impes_common/manufactured_solution_generation_tools.py (+222/-0)
tests/darcy_impes_common/manufactured_solution_test_tools.py (+393/-0)
tests/darcy_impes_common/mesh_data/cube_A.geo (+41/-0)
tests/darcy_impes_common/mesh_data/cube_A.msh (+524/-0)
tests/darcy_impes_common/mesh_data/cube_B.geo (+41/-0)
tests/darcy_impes_common/mesh_data/cube_B.msh (+1014/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_A.bound (+4/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_A.ele (+12/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_A.node (+13/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_B.bound (+4/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_B.ele (+22/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_B.node (+23/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_C.bound (+4/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_C.ele (+42/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_C.node (+43/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_D.bound (+4/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_D.ele (+82/-0)
tests/darcy_impes_common/mesh_data/line_mesh_1d_D.node (+83/-0)
tests/darcy_impes_common/mesh_data/square_A.geo (+30/-0)
tests/darcy_impes_common/mesh_data/square_A.msh (+106/-0)
tests/darcy_impes_common/mesh_data/square_B.geo (+30/-0)
tests/darcy_impes_common/mesh_data/square_B.msh (+196/-0)
tests/darcy_impes_common/mesh_data/square_C.geo (+30/-0)
tests/darcy_impes_common/mesh_data/square_C.msh (+376/-0)
tests/darcy_impes_common/mesh_data/template_cuboid_irreg.geo (+51/-0)
tests/darcy_impes_common/mesh_data/template_cuboid_reg.geo (+26/-0)
tests/darcy_impes_common/mesh_data/template_line.sh (+1/-0)
tests/darcy_impes_common/mesh_data/template_rectangle_irreg.geo (+20/-0)
tests/darcy_impes_common/mesh_data/template_rectangle_reg.geo (+19/-0)
tests/darcy_impes_common/test_tools.py (+412/-0)
tests/darcy_impes_mms_p1_2phase_coreyrelperm/Makefile (+62/-0)
tests/darcy_impes_mms_p1_2phase_coreyrelperm/darcy_impes_mms_p1_2phase_coreyrelperm.py (+99/-0)
tests/darcy_impes_mms_p1_2phase_coreyrelperm/darcy_impes_mms_p1_2phase_coreyrelperm.xml (+51/-0)
tests/darcy_impes_mms_p1_2phase_coreyrelperm/processing.py (+60/-0)
tests/darcy_impes_mms_p1_2phase_coreyrelperm/solution_generator.py (+82/-0)
tests/darcy_impes_mms_p1_2phase_coreyrelperm/template_darcy_impes_mms_p1_2phase_coreyrelperm.diml (+616/-0)
tests/darcy_impes_mms_p1_2phase_coreyrelperm/template_darcy_impes_mms_p1_2phase_coreyrelperm_velbc.diml (+609/-0)
tests/darcy_impes_mms_p1_2phase_quadraticrelperm/Makefile (+62/-0)
tests/darcy_impes_mms_p1_2phase_quadraticrelperm/darcy_impes_mms_p1_2phase_quadraticrelperm.py (+93/-0)
tests/darcy_impes_mms_p1_2phase_quadraticrelperm/darcy_impes_mms_p1_2phase_quadraticrelperm.xml (+83/-0)
tests/darcy_impes_mms_p1_2phase_quadraticrelperm/processing.py (+54/-0)
tests/darcy_impes_mms_p1_2phase_quadraticrelperm/solution_generator.py (+76/-0)
tests/darcy_impes_mms_p1_2phase_quadraticrelperm/template_darcy_impes_mms_p1_2phase_quadraticrelperm.diml (+619/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/Makefile (+40/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag.xml (+630/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_1d_A.diml (+498/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_2d_A.diml (+510/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_3d_A.diml (+510/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_1d_A.diml (+493/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_2d_A.diml (+505/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_3d_A.diml (+505/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/processing.py (+17/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/analytic_BL_CoreyPerm_saturation2.txt (+480/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_1d_A_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_1d_B_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_1d_C_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_1d_D_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_2d_A_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_2d_B_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_2d_C_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_3d_A_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_3d_B_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_1d_A_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_1d_B_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_1d_C_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_1d_D_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_2d_A_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_2d_B_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_2d_C_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_3d_A_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_3d_B_1.vtu (+53/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_adaptive/Makefile (+34/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_adaptive/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_adaptive.xml (+105/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_adaptive/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_adaptive_relpermupwind_2d_A.diml (+611/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_adaptive/mesh_data/square_A.geo (+30/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_adaptive/mesh_data/square_A.msh (+106/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_adaptive/reference_solution/analytic_BL_CoreyPerm_saturation2.txt (+480/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_parallel/Makefile (+36/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_parallel/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_parallel.xml (+105/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_parallel/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_parallel_relpermupwind_2d_A.diml (+548/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_parallel/mesh_data/square_A.geo (+30/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_parallel/reference_solution/analytic_BL_CoreyPerm_saturation2.txt (+480/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_subcycle/Makefile (+34/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_subcycle/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_subcycle.xml (+114/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_subcycle/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_subcycle_relpermupwind_2d_A.diml (+561/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_subcycle/mesh_data/square_A.geo (+30/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_subcycle/reference_solution/analytic_BL_CoreyPerm_saturation2.txt (+480/-0)
tests/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_subcycle/reference_solution/darcy_impes_p1_2phase_coreyrelperm_velBCinlet_strongpressoutlet_p1satdiag_subcycle_relpermupwind_2d_A_1.vtu (+52/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/Makefile (+41/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag.xml (+823/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_1d_A.diml (+561/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_2d_A.diml (+573/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_3d_A.diml (+573/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_1d_A.diml (+556/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_2d_A.diml (+568/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_3d_A.diml (+568/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/processing.py (+16/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/analytic_BL_QuadraticPerm_pressure2.txt (+299/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/analytic_BL_QuadraticPerm_saturation2.txt (+345/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_1d_A_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_1d_B_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_1d_C_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_1d_D_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_2d_A_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_2d_B_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_2d_C_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_3d_A_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_modrelpermupwind_satfesweby_3d_B_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_1d_A_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_1d_B_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_1d_C_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_1d_D_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_2d_A_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_2d_B_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_2d_C_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_3d_A_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_p1satdiag_relpermupwind_3d_B_1.vtu (+57/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/Makefile (+41/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip.xml (+767/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_1d_A.diml (+552/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_2d_A.diml (+563/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_3d_A.diml (+563/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_1d_A.diml (+547/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_2d_A.diml (+558/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_3d_A.diml (+558/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/processing.py (+16/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/analytic_BL_QuadraticPerm_nogravity_saturation2.txt (+633/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/analytic_BL_QuadraticPerm_withgravity_updip_saturation2.txt (+605/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_1d_A_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_1d_B_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_1d_C_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_1d_D_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_2d_A_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_2d_B_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_2d_C_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_3d_A_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_modrelpermupwind_satfesweby_3d_B_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_1d_A_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_1d_B_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_1d_C_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_1d_D_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_2d_A_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_2d_B_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_2d_C_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_3d_A_1.vtu (+56/-0)
tests/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip/reference_solution/darcy_impes_p1_2phase_quadraticrelperm_velBCinlet_strongpressoutlet_withgravity_updip_relpermupwind_3d_B_1.vtu (+56/-0)
tests/darcy_impes_p1_3phase_layered/Makefile (+40/-0)
tests/darcy_impes_p1_3phase_layered/darcy_impes_p1_3phase_layered.xml (+1201/-0)
tests/darcy_impes_p1_3phase_layered/darcy_impes_p1_3phase_layered_modrelpermupwind_satfesweby_1d.diml (+744/-0)
tests/darcy_impes_p1_3phase_layered/darcy_impes_p1_3phase_layered_modrelpermupwind_satfesweby_2d.diml (+744/-0)
tests/darcy_impes_p1_3phase_layered/darcy_impes_p1_3phase_layered_modrelpermupwind_satfesweby_3d.diml (+746/-0)
tests/darcy_impes_p1_3phase_layered/darcy_impes_p1_3phase_layered_relpermupwind_1d.diml (+739/-0)
tests/darcy_impes_p1_3phase_layered/darcy_impes_p1_3phase_layered_relpermupwind_2d.diml (+739/-0)
tests/darcy_impes_p1_3phase_layered/darcy_impes_p1_3phase_layered_relpermupwind_3d.diml (+741/-0)
tests/darcy_impes_p1_3phase_layered/mesh_data/cube.geo (+43/-0)
tests/darcy_impes_p1_3phase_layered/mesh_data/cube.msh (+4665/-0)
tests/darcy_impes_p1_3phase_layered/mesh_data/square.geo (+31/-0)
tests/darcy_impes_p1_3phase_layered/mesh_data/square.msh (+385/-0)
tests/darcy_impes_p1_3phase_layered/reference_solution/darcy_impes_p1_3phase_layered_modrelpermupwind_satfesweby_1d_1.vtu (+365/-0)
tests/darcy_impes_p1_3phase_layered/reference_solution/darcy_impes_p1_3phase_layered_modrelpermupwind_satfesweby_2d_1.vtu (+1665/-0)
tests/darcy_impes_p1_3phase_layered/reference_solution/darcy_impes_p1_3phase_layered_modrelpermupwind_satfesweby_3d_1.vtu (+13792/-0)
tests/darcy_impes_p1_3phase_layered/reference_solution/darcy_impes_p1_3phase_layered_relpermupwind_1d_1.vtu (+365/-0)
tests/darcy_impes_p1_3phase_layered/reference_solution/darcy_impes_p1_3phase_layered_relpermupwind_2d_1.vtu (+1665/-0)
tests/darcy_impes_p1_3phase_layered/reference_solution/darcy_impes_p1_3phase_layered_relpermupwind_3d_1.vtu (+13792/-0)
tests/darcy_impes_p1_pseudo1phase_pressBCinlet/Makefile (+40/-0)
tests/darcy_impes_p1_pseudo1phase_pressBCinlet/darcy_impes_p1_pseudo1phase_pressBCinlet.xml (+439/-0)
tests/darcy_impes_p1_pseudo1phase_pressBCinlet/darcy_impes_p1_pseudo1phase_pressBCinlet_1d.diml (+517/-0)
tests/darcy_impes_p1_pseudo1phase_pressBCinlet/darcy_impes_p1_pseudo1phase_pressBCinlet_2d.diml (+529/-0)
tests/darcy_impes_p1_pseudo1phase_pressBCinlet/darcy_impes_p1_pseudo1phase_pressBCinlet_3d.diml (+529/-0)
tests/darcy_impes_p1_pseudo1phase_pressBCinlet/mesh_data/cube.geo (+43/-0)
tests/darcy_impes_p1_pseudo1phase_pressBCinlet/mesh_data/cube.msh (+4665/-0)
tests/darcy_impes_p1_pseudo1phase_pressBCinlet/mesh_data/square.geo (+31/-0)
tests/darcy_impes_p1_pseudo1phase_pressBCinlet/mesh_data/square.msh (+385/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/Makefile (+35/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/darcy_impes_p1_pseudo1phase_velBCinlet.xml (+472/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/darcy_impes_p1_pseudo1phase_velBCinlet_1d.diml (+613/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/darcy_impes_p1_pseudo1phase_velBCinlet_2d.diml (+625/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/darcy_impes_p1_pseudo1phase_velBCinlet_3d.diml (+625/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/mesh_data/cube.geo (+43/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/mesh_data/cube.msh (+4665/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/mesh_data/darcy_impes_p1_pseudo1phase_velBCinlet_1d.bound (+4/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/mesh_data/darcy_impes_p1_pseudo1phase_velBCinlet_1d.ele (+22/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/mesh_data/darcy_impes_p1_pseudo1phase_velBCinlet_1d.node (+23/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/mesh_data/square.geo (+31/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/mesh_data/square.msh (+385/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/reference_solution/darcy_impes_p1_pseudo1phase_velBCinlet_1d_1.vtu (+55/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/reference_solution/darcy_impes_p1_pseudo1phase_velBCinlet_2d_1.vtu (+55/-0)
tests/darcy_impes_p1_pseudo1phase_velBCinlet/reference_solution/darcy_impes_p1_pseudo1phase_velBCinlet_3d_1.vtu (+58/-0)
tests/darcy_p0p1_test_cty_cv_pressBCinlet/darcy_p0p1_test_cty_cv_pressBCinlet_1d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet/darcy_p0p1_test_cty_cv_pressBCinlet_2d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet/darcy_p0p1_test_cty_cv_pressBCinlet_3d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p0_steptwochannel/advect_tracer_cons_exp_weakbc_upwind_p0_2d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p0_steptwochannel/darcy_p0p1_test_cty_cv_pressBCinlet_2d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cg/advect_tracer_cons_imp_p1cg_2d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cg/advect_tracer_cons_imp_p1cg_3d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cg/darcy_p0p1_test_cty_cv_pressBCinlet_2d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cg/darcy_p0p1_test_cty_cv_pressBCinlet_3d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/advect_tracer_cons_exp_weakbc_feultimate_p1cv_2d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/advect_tracer_cons_exp_weakbc_feultimate_p1cv_3d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/advect_tracer_cons_exp_weakbc_hyperc_p1cv_2d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/advect_tracer_cons_exp_weakbc_hyperc_p1cv_3d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/advect_tracer_cons_exp_weakbc_upwind_p1cv_2d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/advect_tracer_cons_exp_weakbc_upwind_p1cv_3d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/advect_tracer_cons_imp_weakbc_fesweby_p1cv_2d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/advect_tracer_cons_imp_weakbc_fesweby_p1cv_3d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/advect_tracer_cons_imp_weakbc_upwind_p1cv_2d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/advect_tracer_cons_imp_weakbc_upwind_p1cv_3d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/darcy_p0p1_test_cty_cv_pressBCinlet_2d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv/darcy_p0p1_test_cty_cv_pressBCinlet_3d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv_steptwochannel/advect_tracer_cons_exp_weakbc_hyperc_p1cv_2d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv_steptwochannel/advect_tracer_cons_exp_weakbc_upwind_p1cv_2d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv_steptwochannel/darcy_p0p1_test_cty_cv_pressBCinlet_2d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv_steptwochannel_adaptive/advect_tracer_cons_exp_weakbc_hyperc_p1cv_2d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1cv_steptwochannel_adaptive/darcy_p0p1_test_cty_cv_pressBCinlet_2d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1dg/advect_tracer_cons_imp_p1dg_2d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1dg/advect_tracer_cons_imp_p1dg_3d.flml (+1/-1)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1dg/darcy_p0p1_test_cty_cv_pressBCinlet_2d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_advect_tracer_p1dg/darcy_p0p1_test_cty_cv_pressBCinlet_3d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_pressBCinlet_rotated_domain/darcy_p0p1_test_cty_cv_pressBCinlet_rotated_domain_2d.flml (+2/-2)
tests/darcy_p0p1_test_cty_cv_velBCinlet/darcy_p0p1_test_cty_cv_velBCinlet_1d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_velBCinlet/darcy_p0p1_test_cty_cv_velBCinlet_2d.flml (+3/-3)
tests/darcy_p0p1_test_cty_cv_velBCinlet/darcy_p0p1_test_cty_cv_velBCinlet_3d.flml (+3/-3)
tests/darcy_p0p1cv_pressBCinlet/darcy_p0p1cv_pressBCinlet_1d.flml (+3/-3)
tests/darcy_p0p1cv_pressBCinlet/darcy_p0p1cv_pressBCinlet_2d.flml (+3/-3)
tests/darcy_p0p1cv_pressBCinlet/darcy_p0p1cv_pressBCinlet_3d.flml (+3/-3)
tests/darcy_p0p1cv_pressBCinlet_1solidphase/darcy_p0p1cv_pressBCinlet_1solidphase_1d.flml (+3/-3)
tests/darcy_p0p1cv_pressBCinlet_1solidphase/darcy_p0p1cv_pressBCinlet_1solidphase_2d.flml (+3/-3)
tests/darcy_p0p1cv_pressBCinlet_1solidphase/darcy_p0p1cv_pressBCinlet_1solidphase_3d.flml (+3/-3)
tests/darcy_p0p1cv_pressBCinlet_rotated_domain/darcy_p0p1cv_pressBCinlet_rotated_domain_2d.flml (+2/-2)
tests/darcy_p0p1cv_velBCinlet/darcy_p0p1cv_velBCinlet_1d.flml (+3/-3)
tests/darcy_p0p1cv_velBCinlet/darcy_p0p1cv_velBCinlet_2d.flml (+2/-2)
tests/darcy_p0p1cv_velBCinlet/darcy_p0p1cv_velBCinlet_3d.flml (+3/-3)
tests/darcy_p0p1cv_velBCinlet_1solidphase/darcy_p0p1cv_velBCinlet_1solidphase_1d.flml (+3/-3)
tests/darcy_p0p1cv_velBCinlet_1solidphase/darcy_p0p1cv_velBCinlet_1solidphase_2d.flml (+3/-3)
tests/darcy_p0p1cv_velBCinlet_1solidphase/darcy_p0p1cv_velBCinlet_1solidphase_3d.flml (+3/-3)
tests/darcy_p0p1cv_velBCinlet_rotated_domain/darcy_p0p1cv_velBCinlet_rotated_domain_2d.flml (+2/-2)
tests/darcy_p1dgp2_pressBCinlet/darcy_p1dgp2_pressBCinlet_1d.flml (+3/-3)
tests/darcy_p1dgp2_pressBCinlet/darcy_p1dgp2_pressBCinlet_2d.flml (+5/-5)
tests/darcy_p1dgp2_pressBCinlet/darcy_p1dgp2_pressBCinlet_3d.flml (+5/-5)
tests/darcy_p1dgp2_test_cty_cv_pressBCinlet/darcy_p1dgp2_test_cty_cv_pressBCinlet_2d.flml (+3/-3)
tests/darcy_p1dgp2_test_cty_cv_pressBCinlet/darcy_p1dgp2_test_cty_cv_pressBCinlet_3d.flml (+3/-3)
tests/darcy_p1dgp2_velBCinlet/darcy_p1dgp2_velBCinlet_1d.flml (+3/-3)
tests/darcy_p1dgp2_velBCinlet/darcy_p1dgp2_velBCinlet_2d.flml (+3/-3)
tests/darcy_p1dgp2_velBCinlet/darcy_p1dgp2_velBCinlet_3d.flml (+3/-3)
tests/electrochemical_p1p1_2d/electrochemical.flml (+2/-2)
tests/electrokinetic_p1p1_2d/electrokinetic.flml (+2/-2)
tests/electrothermal_p1p1_2d/electrothermal.flml (+2/-2)
To merge this branch: bzr merge lp:~fluidity-core/fluidity/darcy_impes_proper
Reviewer Review Type Date Requested Status
James Robert Percival Pending
Review via email: mp+207924@code.launchpad.net

Description of the change

The darcy_impes program solves multiphase flow through porous media using an implicit pressure, explicit saturation (IMPES) method. See, for example, Mostaghini P., Tollit B.S., Neethling S.J., Gorman G.J. and Pain C.C., A control volume finite element method for adaptive mesh simulation of flow in heap leaching, J Eng Math, 1--11, 2013.

The test/darcy_impes_p1_* folders making up the test suite contain a number of different types of test (contact me for the details - I tried to insert a table here but the formatting got messed up). Basic tests include checks that the solver has converged, field values do not exceed certain boundary conditions, and so on. Regression tests are comparisons with previously computed solutions. Analytical comparisons are the most reliable checks that the program is behaving as expected, with comparisons made against a 1D quasi-analytical profile.

Brendan Tollit (btollit) implemented an extensive coverage of the three types of test, to which I have made a few changes. The general idea is to promote analytical comparisons over regression tests (or implement the latter only where analytical solutions are not available), since the regression solutions are sensitive to e.g. mesh design and are not guaranteed to be correct. It is intended that analytical tests will eventually come to replace regression tests, although I have erred on the side of caution and not deleted regression tests at this stage.

To post a comment you must log in.
Revision history for this message
Stephan Kramer (s-kramer) wrote :

Hello, only had a quick look at this merge. Most code changes to code shared with fluidity seem reasonable at first glance.

I have some worries about the need to add this to trunk Fluidity, in terms of maintainability, etc. but these are probably better discussed in another forum.

The main problem at the moment is that this merge seems to add about 150M to a clean checkout (current checkout size is 300M). The main cause of this seem to be the tests/Tarantula_mesh/ and tests/Tarantula_mesh_v2 directories that were added. In general there seems to be a whole lot of things in there (reports and stuff) that are not appropriate in the tests directory. If such a large data set is needed for testing, I suggest changing it to a long test. Also, are we sure that there are no license issues associated with any of it? If we do remove these directories, we have to rebuild the history after their commits to avoid polluting the history with these.

Revision history for this message
Richard Ferrier (rjferrier) wrote :

Good point Stephen. I had completely missed the Tarantula folders. I will have a look and see what can be done with them. It will probably need discussion with Peyman who is on leave at the moment.

Revision history for this message
James Robert Percival (j-percival) wrote :

It appears that neither directory actually contains a test (in the test harness sense) at the moment anyway. As a secondary part of the question of the trunk merge, I note that the darcy solver gets built as default by the root makefile. Other similar codes (e.g. Colin Cotter's shallow water code) are only built if requested, or if the code is being tested.

Revision history for this message
Gerard (g-gorman) wrote :

Hi Richards

Can I suggest that you create a new branch to cache this tarantula work (call it tarantula), and then delete it entirely from the Darcy branch.

Cheers
Gerard

On 24 Feb 2014, at 15:06, Stephan Kramer <email address hidden> wrote:

> Hello, only had a quick look at this merge. Most code changes to code shared with fluidity seem reasonable at first glance.
>
> I have some worries about the need to add this to trunk Fluidity, in terms of maintainability, etc. but these are probably better discussed in another forum.
>
> The main problem at the moment is that this merge seems to add about 150M to a clean checkout (current checkout size is 300M). The main cause of this seem to be the tests/Tarantula_mesh/ and tests/Tarantula_mesh_v2 directories that were added. In general there seems to be a whole lot of things in there (reports and stuff) that are not appropriate in the tests directory. If such a large data set is needed for testing, I suggest changing it to a long test. Also, are we sure that there are no license issues associated with any of it? If we do remove these directories, we have to rebuild the history after their commits to avoid polluting the history with these.
> --
> https://code.launchpad.net/~fluidity-core/fluidity/darcy_impes_proper/+merge/207924
> Your team Fluidity Core Team is subscribed to branch lp:fluidity.

4136. By Richard Ferrier

Default building of darcy_impes binary removed from the root Makefile. The 3phase test folder's meshes had not been checked into R4133 (oops); they are herewith restored. This will be the last revision to contain the Tarantula test folders, deemed to bulky/experimental to include in the proposed merge. A new development branch will be created to keep those folders.

4137. By Richard Ferrier

Tarantula folders deleted.

4138. By Richard Ferrier

Makefile was still buggy, trying to test before the binary had been built. Fixed it and added a diagnostic line to the python script.

4139. By Richard Ferrier

Refactored python code in preparation for tests based on the method of manufactured solutions (MMS). Previously the code was littered with nested for-loops to iterate over various simulation options, error norms and convergence rates. This situation onlys worsens with MMS-based tests. The current revision therefore replaces the loops with handling trees that can be composed at run-time to suit the context. The trees are passed command objects encapsulating operations at various levels. These Handler classes and abstract Command class have been placed in test_tools.py. The classes are used in buckley_leverett_test_tools.py (replacing darcy_impes_tools.py) and will be used in manufactured_solution_test_tools.py.

4140. By Richard Ferrier

Corrected commented-out line that was breaking a test

4141. By Richard Ferrier

Added manufactured_solution_test_tools.py; split up test_tools.py to reflect general-purpose and problem-specific classes

4142. By Richard Ferrier

Added the first MMS-based test (the harness will be added shortly). Parameters may be adjusted in due course.

4143. By Richard Ferrier

Added code for generating the XML file and cleaning up.

4144. By Richard Ferrier

Forgot to add geometry templates to the previous two revisions; these are now in place. Fixed some scripting bugs that were breaking tests.

4145. By Richard Ferrier

Geometry templates really checked in this time\!

4146. By Richard Ferrier

Minor changes, adding functionality to support factorial experiments where physical variables are controlled.

4147. By Richard Ferrier

Continuing the changes of the last revision, generation of symbolic expressions is now done within ManufacturedSolutionTestSuite. Also, WriteXMLSnippet has been replaced by WriteXMLFile to allow multiple solution-dependent XML files to be generated.

4148. By Richard Ferrier

Fixed XML inconsistency with schema. Adjusted symbolic expressions to work when generated by a different version of sympy (this generation is not triggered by the test harness, however).

4149. By Richard Ferrier

Tweak to the Makefile in darcy_impes_mms_p1_2phase_quadraticrelperm

4150. By Richard Ferrier

Added another MMS-based test.

4151. By Richard Ferrier

Edited the tests to work around a problem with spatial convergence of the pressure field. The nonconvergence is caused by the pressure fields reconfiguring themselves to be completely different to the forced solution at certain levels of mesh and timestep refinement. This effect has appeared since introducing more timesteps into the tests to make them more rigorous. Saturation fields appear to be unaffected, and they will continue to be used in checking convergence. Note the necessary change of minus sign on diff(phi*self.s[i], t) in darcy_impes_common/manufactured_solution_generation_tools.py. The now-transient tests break otherwise.

4152. By Richard Ferrier

Merge with fluidity trunk.

4153. By Richard Ferrier

Minor changes.

4154. By Richard Ferrier

Merge with fluidity trunk.

Unmerged revisions

4154. By Richard Ferrier

Merge with fluidity trunk.

4153. By Richard Ferrier

Minor changes.

4152. By Richard Ferrier

Merge with fluidity trunk.

4151. By Richard Ferrier

Edited the tests to work around a problem with spatial convergence of the pressure field. The nonconvergence is caused by the pressure fields reconfiguring themselves to be completely different to the forced solution at certain levels of mesh and timestep refinement. This effect has appeared since introducing more timesteps into the tests to make them more rigorous. Saturation fields appear to be unaffected, and they will continue to be used in checking convergence. Note the necessary change of minus sign on diff(phi*self.s[i], t) in darcy_impes_common/manufactured_solution_generation_tools.py. The now-transient tests break otherwise.

4150. By Richard Ferrier

Added another MMS-based test.

4149. By Richard Ferrier

Tweak to the Makefile in darcy_impes_mms_p1_2phase_quadraticrelperm

4148. By Richard Ferrier

Fixed XML inconsistency with schema. Adjusted symbolic expressions to work when generated by a different version of sympy (this generation is not triggered by the test harness, however).

4147. By Richard Ferrier

Continuing the changes of the last revision, generation of symbolic expressions is now done within ManufacturedSolutionTestSuite. Also, WriteXMLSnippet has been replaced by WriteXMLFile to allow multiple solution-dependent XML files to be generated.

4146. By Richard Ferrier

Minor changes, adding functionality to support factorial experiments where physical variables are controlled.

4145. By Richard Ferrier

Geometry templates really checked in this time\!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile.in'
2--- Makefile.in 2013-12-13 16:00:27 +0000
3+++ Makefile.in 2014-05-30 12:10:35 +0000
4@@ -185,6 +185,7 @@
5 sw: bin/shallow_water
6 be: bin/burgers_equation
7 hh: bin/hybridized_helmholtz_solver
8+di: bin/darcy_impes
9
10 bin/shallow_water: fluidity_library bin/hybridized_helmholtz_solver main/Shallow_Water.F90
11 @cd main; $(MAKE) Shallow_Water.o
12@@ -211,6 +212,14 @@
13 @echo " LD burgers_equation"
14 @$(EVAL) $(FC) -o bin/burgers_equation main/Burgers_Equation.o $(FCFLAGS) $(LIBS)
15
16+bin/darcy_impes: fluidity_library main/Darcy_IMPES.F90
17+ @cd main; $(MAKE) Darcy_IMPES.o
18+ @echo "BUILD darcy_impes"
19+ @echo " MKDIR bin"
20+ @mkdir -p bin
21+ @echo " LD darcy_impes"
22+ @$(EVAL) $(FC) -o bin/darcy_impes main/Darcy_IMPES.o $(FCFLAGS) $(LIBS)
23+
24 ifeq (@ENABLE_PSMILE@,yes)
25 LIBPSMILE=@FLPSMILE_PATH@/lib/libpsmile_oa4.MPI1.a @FLPSMILE_PATH@/lib/libcommon_oa4.a @FLPSMILE_PATH@/lib/libmpp_io.a -lxml2
26 bin/test_coupler: fluidity_library main/test_coupler.F90
27@@ -498,12 +507,12 @@
28 @find ./ \( -name make.log \) -exec rm -f {} \; > /dev/null
29 @rm -f Makefile > /dev/null
30
31-test: fltools bin/$(FLUIDITY) bin/shallow_water serialtest bin/burgers_equation
32+test: fltools bin/$(FLUIDITY) bin/shallow_water bin/darcy_impes serialtest bin/burgers_equation
33
34-serialtest: fltools bin/$(FLUIDITY) bin/shallow_water
35+serialtest: fltools bin/$(FLUIDITY) bin/shallow_water bin/darcy_impes
36 @cd tests; ../bin/testharness -l short $(EXCLUDE_TAGS) -n $(THREADS)
37
38-mediumtest: fltools bin/$(FLUIDITY) manual bin/burgers_equation bin/shallow_water spudtools
39+mediumtest: fltools bin/$(FLUIDITY) manual bin/burgers_equation bin/shallow_water bin/darcy_impes spudtools
40 @cd tests; ../bin/testharness -l medium $(EXCLUDE_TAGS) -n $(THREADS)
41
42 .PHONY: spudtools
43@@ -607,7 +616,7 @@
44 $(MAKE) clean-light
45 @echo " Congratulations, make makefiles succeeded!"
46
47-install: default fltools bin/shallow_water bin/burgers_equation
48+install: default fltools bin/shallow_water bin/burgers_equation bin/darcy_impes
49 @mkdir -p $(DESTDIR)$(bindir) $(DESTDIR)$(docdir)/fluidity
50 find bin/ -maxdepth 1 -type f -exec cp '{}' $(DESTDIR)$(bindir) \;
51 rm -f $(DESTDIR)$(bindir)/spud-* $(DESTDIR)$(bindir)/diamond $(DESTDIR)$(bindir)/silenteval $(DESTDIR)$(bindir)/runut
52
53=== added file 'assemble/Darcy_IMPES_Assemble.F90'
54--- assemble/Darcy_IMPES_Assemble.F90 1970-01-01 00:00:00 +0000
55+++ assemble/Darcy_IMPES_Assemble.F90 2014-05-30 12:10:35 +0000
56@@ -0,0 +1,5920 @@
57+! Copyright (C) 2006 Imperial College London and others.
58+!
59+! Please see the AUTHORS file in the main source directory for a full list
60+! of copyright holders.
61+!
62+! Prof. C Pain
63+! Applied Modelling and Computation Group
64+! Department of Earth Science and Engineering
65+! Imperial College London
66+!
67+! amcgsoftware@imperial.ac.uk
68+!
69+! This library is free software; you can redistribute it and/or
70+! modify it under the terms of the GNU Lesser General Public
71+! License as published by the Free Software Foundation,
72+! version 2.1 of the License.
73+!
74+! This library is distributed in the hope that it will be useful,
75+! but WITHOUT ANY WARRANTY; without even the implied warranty of
76+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
77+! Lesser General Public License for more details.
78+!
79+! You should have received a copy of the GNU Lesser General Public
80+! License along with this library; if not, write to the Free Software
81+! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
82+! USA
83+
84+#include "fdebug.h"
85+
86+module darcy_impes_assemble_module
87+
88+ ! keep in this order, please:
89+ use quadrature
90+ use elements
91+ use sparse_tools
92+ use fields
93+ use sparse_tools_petsc
94+ !
95+ use field_derivatives
96+ use cv_shape_functions
97+ use cv_faces
98+ use cvtools
99+ use cv_fields
100+ use cv_upwind_values
101+ use cv_face_values
102+ use cv_options
103+ use boundary_conditions
104+ use fefields, only: compute_cv_mass
105+ use petsc_solve_state_module
106+ use sparse_matrices_fields
107+ use transform_elements, only: transform_cvsurf_to_physical, &
108+ transform_cvsurf_facet_to_physical
109+ use state_module
110+ use fldebug
111+ use spud
112+ use porous_media
113+ use parallel_tools
114+ use adaptive_timestepping
115+ use halos
116+ use signal_vars, only : SIG_INT
117+ use global_parameters, only : FIELD_NAME_LEN, OPTION_PATH_LEN
118+
119+ implicit none
120+
121+ private
122+
123+ public :: darcy_impes_type, &
124+ darcy_impes_cv_options_type, &
125+ darcy_impes_copy_to_old, &
126+ darcy_impes_copy_to_iterated, &
127+ darcy_impes_assemble_and_solve_part_one, &
128+ darcy_impes_assemble_and_solve_part_two, &
129+ darcy_impes_assemble_and_solve_part_three, &
130+ darcy_impes_calculate_gradient_pressures, &
131+ darcy_impes_calculate_non_first_phase_pressures, &
132+ darcy_impes_calculate_phase_one_saturation_diagnostic, &
133+ darcy_impes_calculate_vel_mob_ff_and_cfl_fields, &
134+ darcy_impes_calculate_sum_saturation, &
135+ darcy_impes_calculate_relperm_fields, &
136+ darcy_impes_calculate_densities, &
137+ darcy_impes_calculate_cflnumber_field_based_dt, &
138+ darcy_impes_initialise_cached_face_value, &
139+ darcy_impes_calculate_inverse_characteristic_length, &
140+ darcy_impes_calculate_relperm_den_first_face_values, &
141+ darcy_impes_calculate_relperm_isub_face_values, &
142+ darcy_impes_get_entire_sfield_boundary_condition, &
143+ darcy_impes_get_v_boundary_condition, &
144+ darcy_impes_assemble_saturation_rhs_adv, &
145+ darcy_impes_assemble_and_solve_phase_pressures, &
146+ darcy_impes_calculate_divergence_total_darcy_velocity, &
147+ darcy_impes_calculate_inverse_cv_sa
148+
149+ ! Parameters defining Darcy IMPES cached options
150+ integer, parameter, public :: RELPERM_CORRELATION_POWER = 1, &
151+ RELPERM_CORRELATION_COREY2PHASE = 2, &
152+ RELPERM_CORRELATION_COREY2PHASEOPPOSITE = 3, &
153+ RELPERM_CORRELATION_MINERAL = 4, &
154+ RELPERM_CORRELATION_VANGENUCHTEN = 5, &
155+ RELPERM_CORRELATION_JACKSON2PHASE = 6, &
156+ RELPERM_CORRELATION_JACKSON2PHASEOPPOSITE = 7
157+
158+ ! Parameters defining Darcy IMPES CV face value schemes
159+ integer, parameter, public :: DARCY_IMPES_CV_FACEVALUE_NONE = 0, &
160+ DARCY_IMPES_CV_FACEVALUE_FIRSTORDERUPWIND = 1, &
161+ DARCY_IMPES_CV_FACEVALUE_FINITEELEMENT = 2, &
162+ DARCY_IMPES_CV_FACEVALUE_RELPERMOVERSATUPWIND = 3, &
163+ DARCY_IMPES_CV_FACEVALUE_RELPERMOVERSATFINITEELEMENT = 4, &
164+ DARCY_IMPES_CV_FACEVALUE_RELPERMOVERSATCORRELATION = 5
165+
166+ ! Options associated with the relative permeability correlation
167+ type darcy_impes_relperm_corr_options_type
168+ ! The correlation type to use
169+ integer :: type
170+ ! The exponent for the power law correlation for each phase
171+ real, dimension(:), pointer :: exponents
172+ ! The residual saturation for each phase
173+ real, dimension(:), pointer :: residual_saturations
174+ ! The cut off value for saturation when calculating relperm
175+ real, dimension(:), pointer :: cutoff_saturations
176+ ! The scaling_coefficients when calculating relperm
177+ real, dimension(:), pointer :: scaling_coefficients
178+ end type darcy_impes_relperm_corr_options_type
179+
180+ ! Options associated with the CV discretisation for the darcy impes solver
181+ type darcy_impes_cv_options_type
182+ ! what CV_FACEVALUE_ to use
183+ integer :: facevalue
184+ ! the number of face value iterations
185+ integer :: number_face_value_iteration
186+ ! whether to limit the face value spatially
187+ logical :: limit_facevalue
188+ ! what CV_LIMITER_ to use
189+ integer :: limiter
190+ ! the slopes of the limiter being used (if Sweby)
191+ real, dimension(2) :: limiter_slopes
192+ ! what upwind scheme are we using (if any)
193+ integer :: upwind_scheme
194+ end type darcy_impes_cv_options_type
195+
196+ ! Options associated with explicit advection subcycling for CV scalar field solver
197+ type darcy_impes_subcycle_options_type
198+ logical :: have
199+ integer :: number
200+ logical :: consistent
201+ end type darcy_impes_subcycle_options_type
202+
203+ ! Options associated with adaptive time stepping
204+ type darcy_impes_adaptive_dt_options_type
205+ logical :: have
206+ real :: requested_cfl
207+ real :: min_dt
208+ real :: max_dt
209+ real :: increase_tolerance
210+ logical :: min_dt_terminate_if_reached
211+ logical :: at_first_dt
212+ end type darcy_impes_adaptive_dt_options_type
213+
214+ ! Options associated with EoS for a phase
215+ type darcy_impes_eos_options_type
216+ logical :: have_fluids_linear
217+ real :: fluids_linear_reference_density
218+ end type darcy_impes_eos_options_type
219+
220+ ! Data associated with the cached CV face values
221+ type cached_face_value_type
222+ real, dimension(:,:,:,:), pointer :: relperm ! nsub, ngi_vele, vele, nphase
223+ real, dimension(:,:,:,:), pointer :: relperm_bdy ! nsub, ngi_sele, sele, nphase
224+ real, dimension(:,:,:), pointer :: den ! ngi_vele, vele, nphase
225+ real, dimension(:,:,:), pointer :: den_bdy ! ngi_sele, sele, nphase
226+ real, dimension(:,:), pointer :: detwei ! ngi_vele, vele
227+ real, dimension(:,:), pointer :: detwei_bdy ! ngi_sele, sele
228+ real, dimension(:,:,:), pointer :: normal ! ndim, ngi_vele, vele
229+ real, dimension(:,:,:), pointer :: normal_bdy ! ndim, ngi_sele, sele
230+ real, dimension(:,:,:,:), pointer :: p_dshape ! nloc, ngi_vele, ndim, vele
231+!!!!! *** THIS IS NOT POSSIBLE YET ***
232+!!!!! real, dimension(:,:,:,:), pointer :: p_dshape_bdy ! nloc, ngi_sele, ndim, sele
233+ logical :: cached_detwei_normal
234+ logical :: cached_p_dshape
235+ end type cached_face_value_type
236+
237+ ! Data associated with a generic prognostic sfield, some of which will point to fields in state
238+ type darcy_impes_generic_prog_sfield_type
239+ ! The phase this sfield is associated with
240+ integer :: phase
241+ type(scalar_field), pointer :: sfield
242+ type(scalar_field), pointer :: old_sfield
243+ type(scalar_field), pointer :: sfield_abs
244+ type(scalar_field), pointer :: sfield_src
245+ type(tensor_field), pointer :: sfield_diff
246+ logical :: have_diff
247+ logical :: have_abs
248+ logical :: have_src
249+ logical :: have_adv
250+ type(darcy_impes_cv_options_type) :: sfield_cv_options
251+ end type darcy_impes_generic_prog_sfield_type
252+
253+ type darcy_impes_type
254+ ! *** Pointers to fields from state that have array length of number of phases ***
255+ type(vector_field_pointer), dimension(:), pointer :: darcy_velocity
256+ type(scalar_field_pointer), dimension(:), pointer :: mobility
257+ type(scalar_field_pointer), dimension(:), pointer :: fractional_flow
258+ type(scalar_field_pointer), dimension(:), pointer :: saturation
259+ type(scalar_field_pointer), dimension(:), pointer :: old_saturation
260+ type(scalar_field_pointer), dimension(:), pointer :: saturation_source
261+ type(scalar_field_pointer), dimension(:), pointer :: relative_permeability
262+ type(scalar_field_pointer), dimension(:), pointer :: old_relative_permeability
263+ type(scalar_field_pointer), dimension(:), pointer :: viscosity
264+ type(scalar_field_pointer), dimension(:), pointer :: cfl
265+ type(scalar_field_pointer), dimension(:), pointer :: pressure
266+ type(scalar_field_pointer), dimension(:), pointer :: capilliary_pressure
267+ type(scalar_field_pointer), dimension(:), pointer :: density
268+ type(scalar_field_pointer), dimension(:), pointer :: old_density
269+ ! *** Pointers to fields from state that are NOT phase dependent ***
270+ type(mesh_type), pointer :: pressure_mesh
271+ type(mesh_type), pointer :: elementwise_mesh
272+ type(scalar_field), pointer :: average_pressure
273+ type(scalar_field), pointer :: porosity
274+ type(scalar_field), pointer :: absolute_permeability
275+ type(vector_field), pointer :: positions
276+ type(vector_field), pointer :: total_darcy_velocity
277+ type(scalar_field), pointer :: total_mobility
278+ type(scalar_field), pointer :: sum_saturation
279+ type(scalar_field), pointer :: div_total_darcy_velocity
280+ type(vector_field), pointer :: gravity_direction
281+ type(vector_field), pointer :: bulk_darcy_velocity
282+ ! ***** Pointers to DUAL fields from state that have array length of number of phases *****
283+ type(scalar_field_pointer), dimension(:), pointer :: pressure_other_porous_media
284+ type(scalar_field_pointer), dimension(:), pointer :: transmissibility_lambda_dual
285+ ! *** Pointer to the pressure mesh - pressure mesh sparsity, used for pressure matrix and finding CV upwind values ***
286+ type(csr_sparsity), pointer :: sparsity_pmesh_pmesh
287+ ! *** Data associated with generic prognostic scalar fields, some of which points to fields in state ***
288+ type(darcy_impes_generic_prog_sfield_type), dimension(:), pointer :: generic_prog_sfield
289+ ! *** Data associated with GradientPressure fields ***
290+ type(element_type) :: gradient_pressure_shape
291+ type(mesh_type) :: gradient_pressure_mesh
292+ type(vector_field_pointer), dimension(:), pointer :: gradient_pressure
293+ type(vector_field_pointer), dimension(:), pointer :: iterated_gradient_pressure
294+ ! *** Data associated with gravity ***
295+ logical :: have_gravity
296+ real :: gravity_magnitude
297+ type(vector_field) :: gravity
298+ ! *** Fields allocated here used in assemble algorithm ***
299+ type(vector_field) :: positions_pressure_mesh
300+ type(csr_matrix) :: matrix
301+ type(petsc_csr_matrix) :: dual_block_pressure_matrix
302+ type(csr_matrix) :: pressure_matrix
303+ type(scalar_field), pointer :: pressure_rhs
304+ type(scalar_field) :: lhs
305+ type(scalar_field) :: rhs
306+ type(scalar_field) :: rhs_full
307+ type(scalar_field) :: rhs_high_resolution
308+ type(scalar_field) :: inverse_cv_mass_pressure_mesh
309+ type(scalar_field) :: cv_mass_pressure_mesh_with_source
310+ type(scalar_field) :: cv_mass_pressure_mesh_with_porosity
311+ type(scalar_field) :: cv_mass_pressure_mesh_with_old_porosity
312+ type(scalar_field) :: inverse_cv_sa_pressure_mesh
313+ type(scalar_field) :: modified_relative_permeability
314+ type(scalar_field), pointer :: constant_zero_sfield_pmesh
315+ type(scalar_field), pointer :: constant_zero_sfield_elementwisemesh
316+ type(scalar_field_pointer), dimension(:), pointer :: old_saturation_subcycle
317+ ! ***** coupling field associated with DUAL model *****
318+ type(scalar_field) :: cv_mass_pressure_mesh_with_lambda_dual
319+ ! ***** rhs src field associated with DUAL model *****
320+ type(scalar_field) :: rhs_dual
321+ ! *** Data associated with v, pressure and sfield BC allocated here ***
322+ type(mesh_type) :: bc_surface_mesh
323+ type(scalar_field) :: v_bc_value
324+ integer, dimension(:), pointer :: v_bc_flag
325+ type(scalar_field) :: sfield_bc_value
326+ integer, dimension(:), pointer :: sfield_bc_flag
327+ type(scalar_field) :: pressure_bc_value
328+ integer, dimension(:), pointer :: pressure_bc_flag
329+ type(scalar_field) :: inverse_characteristic_length
330+ real :: weak_pressure_bc_coeff
331+ ! *** The number of phase and the CV surface quadrature degree to use ***
332+ integer :: number_phase, cv_surface_quaddegree
333+ ! *** Data specifically associated with the CV discretisation allocated here ***
334+ type(darcy_impes_cv_options_type) :: saturation_cv_options
335+ type(darcy_impes_cv_options_type) :: relperm_cv_options
336+ type(darcy_impes_cv_options_type) :: density_cv_options
337+ type(cv_faces_type) :: cvfaces
338+ type(element_type) :: x_cvshape_full
339+ type(element_type) :: p_cvshape_full
340+ type(element_type) :: gradp_cvshape_full
341+ type(element_type) :: x_cvshape
342+ type(element_type) :: p_cvshape
343+ type(element_type) :: gradp_cvshape
344+ type(element_type) :: x_cvbdyshape
345+ type(element_type) :: p_cvbdyshape
346+ type(element_type) :: gradp_cvbdyshape
347+ type(darcy_impes_subcycle_options_type) :: subcy_opt_sat
348+ type(csr_matrix) :: relperm_upwind
349+ type(csr_matrix) :: sfield_upwind
350+ ! *** The minimum value of saturation to use in the denominator of modrelperm face value ***
351+ real :: minimum_denominator_saturation_value
352+ ! *** A flag for whether saturation face values need to be determined
353+ logical :: determine_saturation_face_values
354+ ! *** Data associate with the relperm correlation options ***
355+ type(darcy_impes_relperm_corr_options_type) :: relperm_corr_options
356+ ! *** Flag for each phase for whether there is capilliary pressure ***
357+ logical, dimension(:), pointer :: have_capilliary_pressure
358+ ! *** Flag for each phase for whether there is a saturation source ***
359+ logical, dimension(:), pointer :: have_saturation_source
360+ ! *** Flag for whether the first phase saturation is diagnostic, else it is prognostic ***
361+ logical :: phase_one_saturation_diagnostic
362+ ! *** Flag for whether the first phase pressure is prognostic, else it is prescribed ***
363+ logical :: first_phase_pressure_prognostic
364+ ! *** The cached face values for all phases ***
365+ type(cached_face_value_type) :: cached_face_value
366+ ! *** The advection subcycle timestep size ***
367+ real :: dt_subcycle
368+ ! *** Time time step size, also stored here for convenience ***
369+ real :: dt
370+ ! *** The current time, also stored here for convenience ***
371+ real :: current_time
372+ ! *** Non linear iteration, also stored here for convencience ***
373+ integer :: nonlinear_iter
374+ ! *** Max Non linear iteration for this timestep, also stored here for convencience ***
375+ integer :: max_nonlinear_iter_this_timestep
376+ ! *** The number of volume, surface elements and nodes, stored here for convenience ***
377+ integer :: number_vele
378+ integer :: number_sele
379+ integer :: number_pmesh_node
380+ ! *** Geometric dimension, also stored here for convenience ***
381+ integer :: ndim
382+ ! *** Options data associated with adaptive time stepping stored here ***
383+ type(darcy_impes_adaptive_dt_options_type) :: adaptive_dt_options
384+ ! *** Options data associated with each phase EoS stored here ***
385+ type(darcy_impes_eos_options_type), dimension(:), pointer :: eos_options
386+ ! *** Pointer to main state array, for convenience ***
387+ type(state_type), dimension(:), pointer :: state
388+ end type darcy_impes_type
389+
390+ contains
391+
392+! ----------------------------------------------------------------------------
393+
394+ subroutine darcy_impes_copy_to_old(di)
395+
396+ !!< Copy to old darcy impes data not associated with di%state
397+
398+ type(darcy_impes_type), intent(inout) :: di
399+
400+ call set(di%cv_mass_pressure_mesh_with_old_porosity, di%cv_mass_pressure_mesh_with_porosity)
401+
402+ end subroutine darcy_impes_copy_to_old
403+
404+! ----------------------------------------------------------------------------
405+
406+ subroutine darcy_impes_copy_to_iterated(di)
407+
408+ !!< Copy to iterated darcy impes data not associated with di%state
409+
410+ type(darcy_impes_type), intent(inout) :: di
411+
412+ ! local variables
413+ integer :: p
414+
415+ do p = 1, di%number_phase
416+
417+ call set(di%iterated_gradient_pressure(p)%ptr, di%gradient_pressure(p)%ptr)
418+
419+ end do
420+
421+ end subroutine darcy_impes_copy_to_iterated
422+
423+! ----------------------------------------------------------------------------
424+
425+ subroutine darcy_impes_assemble_and_solve_part_one(di, have_dual)
426+
427+ !!< Assemble and solve the Darcy equations using an CIMPESS algorithm
428+ !!< which is a modification of the IMPES to include consistent subcycling.
429+ !!< Part one: form cv mass and initial saturation solve for subcycling
430+
431+ type(darcy_impes_type), intent(inout) :: di
432+ logical , intent(in) :: have_dual
433+
434+ ! local variables
435+ logical :: form_new_subcycle_relperm_face_values
436+
437+ ewrite(1,*) 'Start Darcy IMPES assemble and solve part one'
438+
439+ ! Calculate the latest CV mass on the pressure mesh with porosity included
440+ call compute_cv_mass(di%positions, di%cv_mass_pressure_mesh_with_porosity, di%porosity)
441+
442+ ! If it is the first iteration and there is subcycling (>1)
443+ ! and a consistent global continuity then solve the saturations
444+ if ((di%nonlinear_iter == 1) .and. &
445+ (di%subcy_opt_sat%number > 1) .and. &
446+ (di%subcy_opt_sat%consistent)) then
447+
448+ form_new_subcycle_relperm_face_values = .true.
449+
450+ call darcy_impes_assemble_and_solve_phase_saturations(di, &
451+ form_new_subcycle_relperm_face_values, &
452+ have_dual)
453+
454+ end if
455+
456+ ewrite(1,*) 'Finished Darcy IMPES assemble and solve part one'
457+
458+ end subroutine darcy_impes_assemble_and_solve_part_one
459+
460+! ----------------------------------------------------------------------------
461+
462+ subroutine darcy_impes_assemble_and_solve_part_two(di, di_dual, have_dual, solve_dual_pressure)
463+
464+ !!< Assemble and solve the Darcy equations using an CIMPESS algorithm
465+ !!< which is a modification of the IMPES to include consistent subcycling.
466+ !!< Part two: solve for the pressure
467+
468+ type(darcy_impes_type), intent(inout) :: di
469+ type(darcy_impes_type), intent(inout) :: di_dual
470+ logical , intent(in) :: have_dual
471+ logical , intent(in) :: solve_dual_pressure
472+
473+ ewrite(1,*) 'Start Darcy IMPES assemble and solve part two'
474+
475+ ! Assemble and solve the phase pressures
476+ call darcy_impes_assemble_and_solve_phase_pressures(di, di_dual, have_dual, solve_dual_pressure)
477+
478+ ewrite(1,*) 'Finished Darcy IMPES assemble and solve part two'
479+
480+ end subroutine darcy_impes_assemble_and_solve_part_two
481+
482+! ----------------------------------------------------------------------------
483+
484+ subroutine darcy_impes_assemble_and_solve_part_three(di, have_dual)
485+
486+ !!< Assemble and solve the Darcy equations using an CIMPESS algorithm
487+ !!< which is a modification of the IMPES to include consistent subcycling.
488+ !!< Part three: find pressure gradients, calc div.u, solve for saturation
489+ !!< and generic scalar fields, calc sum S, calc density, calc relperm.
490+
491+ type(darcy_impes_type), intent(inout) :: di
492+ logical , intent(in) :: have_dual
493+
494+ ! local variables
495+ logical :: form_new_subcycle_relperm_face_values
496+
497+ ewrite(1,*) 'Start Darcy IMPES assemble and solve part three'
498+
499+ ! Calculate the gradient pressures
500+ call darcy_impes_calculate_gradient_pressures(di)
501+
502+ ! Calculate the divergence total darcy velocity
503+ call darcy_impes_calculate_divergence_total_darcy_velocity(di)
504+
505+ ! Assemble and solve the phase saturations
506+
507+ if ((di%nonlinear_iter == di%max_nonlinear_iter_this_timestep) .and. &
508+ (di%subcy_opt_sat%consistent)) then
509+
510+ form_new_subcycle_relperm_face_values = .false.
511+
512+ else
513+
514+ form_new_subcycle_relperm_face_values = .true.
515+
516+ end if
517+
518+ call darcy_impes_assemble_and_solve_phase_saturations(di, &
519+ form_new_subcycle_relperm_face_values, &
520+ have_dual)
521+
522+ call darcy_impes_assemble_and_solve_generic_prog_sfields(di)
523+
524+ ! Calculate the sum of the saturations
525+ call darcy_impes_calculate_sum_saturation(di)
526+
527+ ! Calculate the density field of each phase
528+ call darcy_impes_calculate_densities(di)
529+
530+ ! Calculate the relative permeabilities of each phase
531+ call darcy_impes_calculate_relperm_fields(di)
532+
533+ ewrite(1,*) 'Finished Darcy IMPES assemble and solve part three'
534+
535+ end subroutine darcy_impes_assemble_and_solve_part_three
536+
537+! ----------------------------------------------------------------------------
538+
539+ subroutine darcy_impes_assemble_and_solve_phase_pressures(di, di_dual, have_dual, solve_dual_pressure)
540+
541+ !!< Assemble and solve the phase pressures. The first phase pressure
542+ !!< is solved via a matrix equation (if prognostic) and the other
543+ !!< phases pressures are calculated from the first phase pressure
544+ !!< and their own capilliary pressures
545+
546+ type(darcy_impes_type), intent(inout) :: di
547+ type(darcy_impes_type), intent(inout) :: di_dual
548+ logical , intent(in) :: have_dual
549+ logical , intent(in) :: solve_dual_pressure
550+
551+ ! Assemble and solve the first phase pressure if it is prognostic
552+ if (di%first_phase_pressure_prognostic) call darcy_impes_assemble_and_solve_first_phase_pressure(di, di_dual, have_dual, solve_dual_pressure)
553+
554+ ! Calculate the non first phase pressure's
555+ call darcy_impes_calculate_non_first_phase_pressures(di)
556+ if (have_dual) call darcy_impes_calculate_non_first_phase_pressures(di_dual)
557+
558+ ! Calculate the average pressure
559+ call darcy_impes_calculate_average_pressure(di)
560+ if (have_dual) call darcy_impes_calculate_average_pressure(di_dual)
561+
562+ end subroutine darcy_impes_assemble_and_solve_phase_pressures
563+
564+! ----------------------------------------------------------------------------
565+
566+ subroutine darcy_impes_assemble_and_solve_first_phase_pressure(di, di_dual, have_dual, solve_dual_pressure)
567+
568+ !!< Assemble and solve the first phase pressure. A source is included
569+ !!< due to the capilliary pressures of non first phases as well as gravity
570+ !!< and the rate of change of porosity and the individual phase sources.
571+ !!< Face values for relative permeability and density have already been evaluated.
572+ !!< If have_dual and solve_dual_pressure are both true then a block matrix using
573+ !!< di%dual_block_pressure_matrix is solved for. If have_dual is true but
574+ !!< solve_dual_pressure is false then a single matrix using di%pressure_matrix
575+ !!< is solved for the prime pressure phase 1 then the dual pressure phase 1
576+ !!< is set to this. If have_dual is false then di%pressure_matrix is used.
577+ !!< (This is because an error is occuring for petsc_csr_matrix in 2d)
578+
579+ type(darcy_impes_type), intent(inout) :: di
580+ type(darcy_impes_type), intent(inout) :: di_dual
581+ logical , intent(in) :: have_dual
582+ logical , intent(in) :: solve_dual_pressure
583+
584+ ! local variables
585+ type(scalar_field_pointer), dimension(:), pointer :: all_pressure
586+ type(scalar_field_pointer), dimension(:), pointer :: all_rhs
587+ integer :: p, vele, sele, iloc, oloc, jloc, face, gi, ggi
588+ real :: face_value, grad_cap_p_dot_n, g_dot_n
589+ real, dimension(1) :: absperm_ele, visc_ele
590+ real, dimension(:,:), pointer :: grav_ele
591+ real, dimension(:,:), pointer :: grad_cap_pressure_face_quad
592+ real, dimension(:,:), pointer :: x_ele
593+ real, dimension(:,:,:), pointer :: p_dshape
594+ real, dimension(:,:), pointer :: normal
595+ real, dimension(:), pointer :: detwei
596+ real, dimension(:), pointer :: normgi
597+ logical, dimension(:), pointer :: notvisited
598+ real, dimension(:,:), pointer :: p_mat_local
599+ real, dimension(:), pointer :: p_rhs_local
600+ real, dimension(:,:), pointer :: x_face_quad
601+ integer, dimension(:), pointer :: x_pmesh_nodes
602+ integer, dimension(:), pointer :: p_nodes
603+ real, dimension(1) :: absperm_ele_bdy, visc_ele_bdy
604+ real, dimension(:,:), pointer :: grav_ele_bdy
605+!!!!! *** THIS IS NOT POSSIBLE YET ***
606+!!!!! real, dimension(:,:), pointer :: grad_cap_pressure_face_quad_bdy
607+!!!!! real, dimension(:,:,:), pointer :: p_dshape_bdy
608+ real, dimension(:), pointer :: bc_sele_val
609+ real, dimension(:), pointer :: inv_char_len_ele_bdy
610+ real, dimension(:,:), pointer :: normal_bdy
611+ real, dimension(:), pointer :: detwei_bdy
612+ real, dimension(:,:), pointer :: x_ele_bdy
613+ real, dimension(:), pointer :: p_rhs_local_bdy
614+ real, dimension(:,:), pointer :: p_matrix_local_bdy
615+ integer, dimension(:), pointer :: p_nodes_bdy
616+ integer, parameter :: PRESSURE_BC_TYPE_WEAKDIRICHLET = 1, PRESSURE_BC_TYPE_DIRICHLET = 2
617+ integer, parameter :: V_BC_TYPE_PRESCRIBED_NORMAL_FLOW = 1, V_BC_TYPE_NO_NORMAL_FLOW = 2
618+
619+ ! allocate arrays used in assemble process - many assume
620+ ! that all elements are the same type.
621+ allocate(x_ele(di%ndim, ele_loc(di%positions,1)))
622+ if (.not. di%cached_face_value%cached_p_dshape) then
623+ allocate(p_dshape(ele_loc(di%pressure_mesh,1), di%p_cvshape%ngi, mesh_dim(di%pressure_mesh)))
624+ end if
625+ if (.not. di%cached_face_value%cached_detwei_normal) then
626+ allocate(normal(di%ndim,di%x_cvshape%ngi))
627+ allocate(detwei(di%x_cvshape%ngi))
628+ end if
629+ allocate(normgi(di%ndim))
630+ allocate(notvisited(di%x_cvshape%ngi))
631+ allocate(p_mat_local(ele_loc(di%pressure_mesh,1), ele_loc(di%pressure_mesh,1)))
632+ allocate(p_rhs_local(ele_loc(di%pressure_mesh,1)))
633+ allocate(x_face_quad(di%ndim, di%x_cvshape%ngi))
634+ allocate(grav_ele(di%ndim,1))
635+ allocate(grad_cap_pressure_face_quad(di%ndim, di%p_cvshape%ngi))
636+
637+ allocate(grav_ele_bdy(di%ndim,1))
638+ allocate(bc_sele_val(face_loc(di%pressure_mesh,1)))
639+ allocate(inv_char_len_ele_bdy(face_loc(di%pressure_mesh,1)))
640+ if (.not. di%cached_face_value%cached_detwei_normal) then
641+ allocate(detwei_bdy(di%x_cvbdyshape%ngi))
642+ allocate(normal_bdy(di%ndim, di%x_cvbdyshape%ngi))
643+ end if
644+ allocate(p_rhs_local_bdy(face_loc(di%pressure_mesh,1)))
645+ allocate(p_matrix_local_bdy(face_loc(di%pressure_mesh,1),face_loc(di%pressure_mesh,1)))
646+ allocate(x_ele_bdy(di%ndim, face_loc(di%positions,1)))
647+ allocate(p_nodes_bdy(face_loc(di%pressure_mesh,1)))
648+!!!!! *** THIS IS NOT POSSIBLE YET ***
649+!!!!! allocate(grad_cap_pressure_face_quad_bdy(di%ndim, di%p_cvbdyshape_full%ngi))
650+!!!!! if (.not. di%cached_face_value%cached_p_dshape) then
651+!!!!! allocate(p_dshape_bdy(face_loc(di%pressure_mesh,1), di%p_cvbdyshape_full%ngi, mesh_dim(di%pressure_mesh)))
652+!!!!! end if
653+
654+ ewrite(1,*) 'Solve first phase Pressure'
655+
656+ ! Initialise the matrix and rhs and solution pointer
657+ call zero(di%pressure_rhs)
658+
659+ if (have_dual .and. solve_dual_pressure) then
660+ call zero(di%dual_block_pressure_matrix)
661+ call zero(di_dual%pressure_rhs)
662+
663+ allocate(all_pressure(2))
664+ allocate(all_rhs(2))
665+ all_pressure(1)%ptr => di%pressure(1)%ptr
666+ all_pressure(2)%ptr => di_dual%pressure(1)%ptr
667+ all_rhs(1)%ptr => di%pressure_rhs
668+ all_rhs(2)%ptr => di_dual%pressure_rhs
669+ else
670+ call zero(di%pressure_matrix)
671+ allocate(all_pressure(1))
672+ allocate(all_rhs(1))
673+ all_pressure(1)%ptr => di%pressure(1)%ptr
674+ all_rhs(1)%ptr => di%pressure_rhs
675+ end if
676+
677+ ewrite(1,*) 'Add phase sources to global continuity'
678+
679+ src_phase_loop: do p = 1, di%number_phase
680+
681+ ! Should this take account of subcycling?!?!
682+ call compute_cv_mass(di%positions, di%cv_mass_pressure_mesh_with_source, di%saturation_source(p)%ptr)
683+
684+ ! Should this include porosity ?!?!
685+ call addto(di%pressure_rhs, di%cv_mass_pressure_mesh_with_source)
686+
687+ end do src_phase_loop
688+
689+ if (have_dual .and. solve_dual_pressure) then
690+
691+ dual_src_phase_loop: do p = 1, di_dual%number_phase
692+
693+ ! Should this take account of subcycling?!?!
694+ call compute_cv_mass(di_dual%positions, di_dual%cv_mass_pressure_mesh_with_source, di_dual%saturation_source(p)%ptr)
695+
696+ ! Should this include porosity ?!?!
697+ call addto(di_dual%pressure_rhs, di_dual%cv_mass_pressure_mesh_with_source)
698+
699+ end do dual_src_phase_loop
700+
701+ end if
702+
703+ ! Add the transmissibility lambda dual to each block diagonal
704+ if (have_dual .and. solve_dual_pressure) then
705+ transmiss_phase_loop: do p = 1, di_dual%number_phase
706+ call compute_cv_mass(di_dual%positions, di_dual%cv_mass_pressure_mesh_with_lambda_dual, di_dual%transmissibility_lambda_dual(p)%ptr)
707+
708+ call addto_diag(di%dual_block_pressure_matrix, 1, 1, di_dual%cv_mass_pressure_mesh_with_lambda_dual, scale = 1.0)
709+ call addto_diag(di%dual_block_pressure_matrix, 1, 2, di_dual%cv_mass_pressure_mesh_with_lambda_dual, scale = -1.0)
710+ call addto_diag(di%dual_block_pressure_matrix, 2, 1, di_dual%cv_mass_pressure_mesh_with_lambda_dual, scale = -1.0)
711+ call addto_diag(di%dual_block_pressure_matrix, 2, 2, di_dual%cv_mass_pressure_mesh_with_lambda_dual, scale = 1.0)
712+
713+ if (p > 1) then
714+ ! Add lambda*(PC_dual - PC_prime) to prime rhs
715+ call set(di%rhs, di_dual%capilliary_pressure(p)%ptr)
716+ call addto(di%rhs, di%capilliary_pressure(p)%ptr, scale = -1.0)
717+ call scale(di%rhs, di_dual%cv_mass_pressure_mesh_with_lambda_dual)
718+ call addto(di%pressure_rhs, di%rhs)
719+
720+ ! Add lambda*(PC_prime- PC_dual) to dual rhs
721+ call set(di%rhs, di%capilliary_pressure(p)%ptr)
722+ call addto(di%rhs, di_dual%capilliary_pressure(p)%ptr, scale = -1.0)
723+ call scale(di%rhs, di_dual%cv_mass_pressure_mesh_with_lambda_dual)
724+
725+ call addto(di_dual%pressure_rhs, di%rhs)
726+ end if
727+ end do transmiss_phase_loop
728+ end if
729+
730+ ewrite(1,*) 'Add rate of change of porosity to global continuity equation'
731+
732+ ! Add rate of change of porosity to rhs
733+ call addto(di%pressure_rhs, di%cv_mass_pressure_mesh_with_old_porosity, scale = 1.0/di%dt)
734+
735+ call addto(di%pressure_rhs, di%cv_mass_pressure_mesh_with_porosity, scale = -1.0/di%dt)
736+
737+ if (have_dual .and. solve_dual_pressure) then
738+
739+ call addto(di_dual%pressure_rhs, di_dual%cv_mass_pressure_mesh_with_old_porosity, scale = 1.0/di%dt)
740+
741+ call addto(di_dual%pressure_rhs, di_dual%cv_mass_pressure_mesh_with_porosity, scale = -1.0/di%dt)
742+
743+ end if
744+
745+ ! Assemble a contribution from each phase to form a global continuity equation to solve for first phase pressure
746+ phase_loop: do p = 1, di%number_phase
747+
748+ ewrite(1,*) 'Assemble volume contribution to global continuity from phase ',p
749+
750+ ! Loop volume elements assembling local contributions
751+ vol_element_loop: do vele = 1, di%number_vele
752+
753+ call pressure_volume_element_local_assemble(di)
754+
755+ ! Add volume element contribution to global pressure matrix and rhs
756+ if (have_dual .and. solve_dual_pressure) then
757+ call addto(di%dual_block_pressure_matrix, 1, 1, p_nodes, p_nodes, p_mat_local)
758+
759+ call addto(di%pressure_rhs, p_nodes, p_rhs_local)
760+
761+ call pressure_volume_element_local_assemble(di_dual)
762+
763+ call addto(di%dual_block_pressure_matrix, 2, 2, p_nodes, p_nodes, p_mat_local)
764+
765+ call addto(di_dual%pressure_rhs, p_nodes, p_rhs_local)
766+
767+ else
768+
769+ call addto(di%pressure_matrix, p_nodes, p_nodes, p_mat_local)
770+
771+ call addto(di%pressure_rhs, p_nodes, p_rhs_local)
772+
773+ end if
774+
775+ end do vol_element_loop
776+
777+ end do phase_loop
778+
779+ ! Add normal v BC integrals for each phase, else include if required
780+ ! a weak pressure BC (which if not given is assumed zero).
781+
782+ ! Get the pressure BC - if no v and weak pressure then extra integrals are added
783+ ! - also get strong pressure BC as this implies no need to add any surface integrals
784+ call darcy_impes_get_entire_sfield_boundary_condition(di%pressure(1)%ptr, &
785+ (/"weakdirichlet", &
786+ "dirichlet "/), &
787+ di%bc_surface_mesh, &
788+ di%pressure_bc_value, &
789+ di%pressure_bc_flag)
790+
791+ if (have_dual .and. solve_dual_pressure) then
792+ call darcy_impes_get_entire_sfield_boundary_condition(di_dual%pressure(1)%ptr, &
793+ (/"weakdirichlet", &
794+ "dirichlet "/), &
795+ di_dual%bc_surface_mesh, &
796+ di_dual%pressure_bc_value, &
797+ di_dual%pressure_bc_flag)
798+ end if
799+
800+ phase_loop_bc: do p = 1, di%number_phase
801+
802+ ewrite(1,*) 'Assemble boundary contribution to global continuity from phase ',p
803+
804+ ! Get this phase v BC info - only for no_normal_flow and prescribed_normal_flow which is special as it is a scalar
805+ call darcy_impes_get_v_boundary_condition(di%darcy_velocity(p)%ptr, &
806+ (/"prescribed_normal_flow", &
807+ "no_normal_flow "/), &
808+ di%bc_surface_mesh, &
809+ di%v_bc_value, &
810+ di%v_bc_flag)
811+
812+ if (have_dual .and. solve_dual_pressure) then
813+ call darcy_impes_get_v_boundary_condition(di_dual%darcy_velocity(p)%ptr, &
814+ (/"prescribed_normal_flow", &
815+ "no_normal_flow "/), &
816+ di_dual%bc_surface_mesh, &
817+ di_dual%v_bc_value, &
818+ di_dual%v_bc_flag)
819+ end if
820+
821+ sele_loop: do sele = 1, di%number_sele
822+
823+ call pressure_surface_element_local_assemble(di)
824+
825+ if (have_dual .and. solve_dual_pressure) then
826+
827+ call addto(di%dual_block_pressure_matrix, 1, 1, p_nodes_bdy, p_nodes_bdy, p_matrix_local_bdy)
828+
829+ call addto(di%pressure_rhs, p_nodes_bdy, p_rhs_local_bdy)
830+
831+ call pressure_surface_element_local_assemble(di_dual)
832+
833+ call addto(di%dual_block_pressure_matrix, 2, 2, p_nodes_bdy, p_nodes_bdy, p_matrix_local_bdy)
834+
835+ call addto(di_dual%pressure_rhs, p_nodes_bdy, p_rhs_local_bdy)
836+
837+ else
838+
839+ call addto(di%pressure_matrix, p_nodes_bdy, p_nodes_bdy, p_matrix_local_bdy)
840+
841+ call addto(di%pressure_rhs, p_nodes_bdy, p_rhs_local_bdy)
842+
843+ end if
844+
845+ end do sele_loop
846+
847+ end do phase_loop_bc
848+
849+ ! Apply any strong dirichlet BC's - that can only be applied to the first phase pressure
850+ ! of both the prime and dual porous media
851+ if (have_dual .and. solve_dual_pressure) then
852+ call apply_dirichlet_conditions(di%dual_block_pressure_matrix, all_rhs, all_pressure)
853+ else
854+ call apply_dirichlet_conditions(di%pressure_matrix, all_rhs(1)%ptr, all_pressure(1)%ptr)
855+ end if
856+
857+ ! Solve the pressure(s)
858+ if (have_dual .and. solve_dual_pressure) then
859+ call petsc_solve(all_pressure, di%dual_block_pressure_matrix, all_rhs, di%state(1))
860+ else
861+ call petsc_solve(all_pressure(1)%ptr, di%pressure_matrix, all_rhs(1)%ptr, di%state(1))
862+ end if
863+
864+ ! Set the strong BC nodes to the values to be consistent
865+ call set_dirichlet_consistent(di%pressure(1)%ptr)
866+
867+ if (have_dual) then
868+
869+ if (solve_dual_pressure) then
870+
871+ call set_dirichlet_consistent(di_dual%pressure(1)%ptr)
872+
873+ else
874+
875+ call set(di_dual%pressure(1)%ptr, di%pressure(1)%ptr)
876+
877+ end if
878+
879+ end if
880+
881+ ! deallocate local variables as required
882+ deallocate(x_ele)
883+ if (di%cached_face_value%cached_p_dshape) then
884+ nullify(p_dshape)
885+ else
886+ deallocate(p_dshape)
887+ end if
888+ if (di%cached_face_value%cached_detwei_normal) then
889+ nullify(detwei)
890+ nullify(normal)
891+ else
892+ deallocate(detwei)
893+ deallocate(normal)
894+ end if
895+ deallocate(normgi)
896+ deallocate(notvisited)
897+ deallocate(p_mat_local)
898+ deallocate(p_rhs_local)
899+ deallocate(x_face_quad)
900+ deallocate(grav_ele)
901+ deallocate(grad_cap_pressure_face_quad)
902+
903+ deallocate(grav_ele_bdy)
904+ deallocate(bc_sele_val)
905+ deallocate(inv_char_len_ele_bdy)
906+ if (di%cached_face_value%cached_detwei_normal) then
907+ nullify(detwei_bdy)
908+ nullify(normal_bdy)
909+ else
910+ deallocate(detwei_bdy)
911+ deallocate(normal_bdy)
912+ end if
913+ deallocate(p_rhs_local_bdy)
914+ deallocate(p_matrix_local_bdy)
915+ deallocate(x_ele_bdy)
916+ deallocate(p_nodes_bdy)
917+!!!!! *** THIS IS NOT POSSIBLE YET ***
918+!!!!! deallocate(grad_cap_pressure_face_quad_bdy)
919+
920+ deallocate(all_pressure)
921+ deallocate(all_rhs)
922+
923+ ewrite(1,*) 'Finished solve first phase Pressure'
924+
925+ ewrite_minmax(di%pressure(1)%ptr)
926+
927+ if (have_dual) then
928+ ewrite_minmax(di_dual%pressure(1)%ptr)
929+ end if
930+
931+ contains
932+
933+ ! --------------------------------------------------------------------------------------
934+
935+ subroutine pressure_volume_element_local_assemble(di)
936+
937+ !!< Assemble the local volume element pressure matrix and rhs
938+
939+ type(darcy_impes_type), intent(inout) :: di
940+
941+ ! The node indices of the pressure mesh
942+ p_nodes => ele_nodes(di%pressure_mesh, vele)
943+
944+ ! The gravity values for this element for each direction
945+ grav_ele = ele_val(di%gravity, vele)
946+
947+ ! get the viscosity value for this element for this phase
948+ visc_ele = ele_val(di%viscosity(p)%ptr, vele)
949+
950+ ! get the absolute permeability value for this element
951+ absperm_ele = ele_val(di%absolute_permeability, vele)
952+
953+ ! obtain the transformed determinant*weight and normals
954+ if (di%cached_face_value%cached_detwei_normal) then
955+
956+ detwei => di%cached_face_value%detwei(:,vele)
957+
958+ normal => di%cached_face_value%normal(:,:,vele)
959+
960+ else
961+
962+ ! get the coordinate values for this element for each positions local node
963+ x_ele = ele_val(di%positions, vele)
964+
965+ ! get the coordinate values for this element for each quadrature point
966+ x_face_quad = ele_val_at_quad(di%positions, vele, di%x_cvshape)
967+
968+ ! The node indices of the positions projected to the pressure mesh
969+ x_pmesh_nodes => ele_nodes(di%positions_pressure_mesh, vele)
970+
971+ call transform_cvsurf_to_physical(x_ele, di%x_cvshape, detwei, normal, di%cvfaces)
972+
973+ end if
974+
975+ ! obtain the derivative of the pressure mesh shape function at the CV face quadrature points
976+ if (di%cached_face_value%cached_p_dshape) then
977+
978+ p_dshape => di%cached_face_value%p_dshape(:,:,:,vele)
979+
980+ else
981+
982+ call transform_to_physical(di%positions, vele, x_shape = di%x_cvshape_full, &
983+ shape = di%p_cvshape_full, dshape = p_dshape)
984+
985+ end if
986+
987+ ! get the gradient capilliary pressure at the cv surface quadrature points for each direction
988+ if (p > 1) then
989+ grad_cap_pressure_face_quad = &
990+ &darcy_impes_ele_grad_at_quad_scalar(di%capilliary_pressure(p)%ptr, vele, dn = p_dshape)
991+ end if
992+
993+ ! Initialise array for the quadrature points of this
994+ ! element for whether it has already been visited
995+ notvisited = .true.
996+
997+ ! Initialise the local p matrix and rhs to assemble for this element
998+ p_mat_local = 0.0
999+ p_rhs_local = 0.0
1000+
1001+ ! loop over local nodes within this element
1002+ nodal_loop_i: do iloc = 1, di%pressure_mesh%shape%loc
1003+
1004+ ! loop over CV faces internal to this element
1005+ face_loop: do face = 1, di%cvfaces%faces
1006+
1007+ ! is this a face neighbouring iloc?
1008+ is_neigh: if(di%cvfaces%neiloc(iloc, face) /= 0) then
1009+
1010+ ! find the opposing local node across the CV face
1011+ oloc = di%cvfaces%neiloc(iloc, face)
1012+
1013+ ! loop over gauss points on face
1014+ quadrature_loop: do gi = 1, di%cvfaces%shape%ngi
1015+
1016+ ! global gauss pt index for this element
1017+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
1018+
1019+ ! check if this quadrature point has already been visited
1020+ check_visited: if(notvisited(ggi)) then
1021+
1022+ notvisited(ggi) = .false.
1023+
1024+ if (di%cached_face_value%cached_detwei_normal) then
1025+
1026+ ! cached normal has correct orientation already
1027+ normgi = normal(:,ggi)
1028+
1029+ else
1030+
1031+ ! correct the orientation of the normal so it points away from iloc
1032+ normgi = orientate_cvsurf_normgi(node_val(di%positions_pressure_mesh, x_pmesh_nodes(iloc)), &
1033+ &x_face_quad(:,ggi), normal(:,ggi))
1034+
1035+ end if
1036+
1037+ ! Form the face value = detwei * (relperm*absperm/visc)
1038+ if (di%subcy_opt_sat%have .and. di%subcy_opt_sat%consistent) then
1039+
1040+ face_value = detwei(ggi) * &
1041+ sum(di%cached_face_value%relperm(:,ggi,vele,p)) * &
1042+ absperm_ele(1) / &
1043+ visc_ele(1)
1044+
1045+ else
1046+
1047+ face_value = detwei(ggi) * &
1048+ di%cached_face_value%relperm(1,ggi,vele,p) * &
1049+ absperm_ele(1) / &
1050+ visc_ele(1)
1051+
1052+ end if
1053+
1054+ ! Form the local matrix given by - n_i . sum_{phase} ( relperm*absperm/visc ) dP_1/dx_j
1055+ do jloc = 1,di%pressure_mesh%shape%loc
1056+
1057+ p_mat_local(iloc,jloc) = p_mat_local(iloc,jloc) - &
1058+ sum(p_dshape(jloc, ggi, :)*normgi, 1) * &
1059+ face_value
1060+
1061+ p_mat_local(oloc,jloc) = p_mat_local(oloc,jloc) - &
1062+ sum(p_dshape(jloc, ggi, :)*(-normgi), 1) * &
1063+ face_value
1064+
1065+ end do
1066+
1067+ ! Add gravity term to rhs = - n_i . sum_{phase} ( relperm*absperm/visc ) * den*grav
1068+
1069+ ! Find g dot n
1070+ g_dot_n = dot_product(grav_ele(:,1), normgi)
1071+
1072+ p_rhs_local(iloc) = p_rhs_local(iloc) - &
1073+ face_value * &
1074+ di%cached_face_value%den(ggi,vele,p) * &
1075+ g_dot_n
1076+
1077+ ! Add opposite node value with change of sign due to opposite normal direction
1078+ p_rhs_local(oloc) = p_rhs_local(oloc) + &
1079+ face_value * &
1080+ di%cached_face_value%den(ggi,vele,p) * &
1081+ g_dot_n
1082+
1083+ ! Add capilliary pressure term to rhs = n_i . sum_{phase} ( relperm*absperm/visc ) dP_c/dx_j
1084+ ! only for phase > 1
1085+ if (p > 1) then
1086+
1087+ ! Find grad_P_c dot n
1088+ grad_cap_p_dot_n = dot_product(grad_cap_pressure_face_quad(:,ggi), normgi)
1089+
1090+ p_rhs_local(iloc) = p_rhs_local(iloc) + &
1091+ face_value * &
1092+ grad_cap_p_dot_n
1093+
1094+ ! Add opposite node value with change of sign due to opposite normal direction
1095+ p_rhs_local(oloc) = p_rhs_local(oloc) - &
1096+ face_value * &
1097+ grad_cap_p_dot_n
1098+
1099+ end if
1100+
1101+ end if check_visited
1102+
1103+ end do quadrature_loop
1104+
1105+ end if is_neigh
1106+
1107+ end do face_loop
1108+
1109+ end do nodal_loop_i
1110+
1111+ end subroutine pressure_volume_element_local_assemble
1112+
1113+ ! --------------------------------------------------------------------------------------
1114+
1115+ subroutine pressure_surface_element_local_assemble(di)
1116+
1117+ !!< Assemble the local surface element pressure matrix and rhs
1118+
1119+ type(darcy_impes_type), intent(inout) :: di
1120+
1121+ p_matrix_local_bdy = 0.0
1122+ p_rhs_local_bdy = 0.0
1123+
1124+ p_nodes_bdy = face_global_nodes(di%pressure_mesh, sele)
1125+
1126+ ! A no_normal_flow BC adds nothing to the matrix and rhs so return zeros
1127+ if (di%v_bc_flag(sele) == V_BC_TYPE_NO_NORMAL_FLOW) return
1128+
1129+ ! If phase 1 and strong pressure BC then no need to add integrals so return zeros
1130+ if (di%pressure_bc_flag(sele) == PRESSURE_BC_TYPE_DIRICHLET) return
1131+
1132+ ! obtain the transformed determinant*weight and normals
1133+ if (di%cached_face_value%cached_detwei_normal) then
1134+
1135+ detwei_bdy => di%cached_face_value%detwei_bdy(:,sele)
1136+
1137+ normal_bdy => di%cached_face_value%normal_bdy(:,:,sele)
1138+
1139+ else
1140+
1141+ x_ele = ele_val(di%positions, face_ele(di%positions, sele))
1142+ x_ele_bdy = face_val(di%positions, sele)
1143+
1144+ call transform_cvsurf_facet_to_physical(x_ele, x_ele_bdy, di%x_cvbdyshape, normal_bdy, detwei_bdy)
1145+
1146+ end if
1147+
1148+ if (di%v_bc_flag(sele) == V_BC_TYPE_PRESCRIBED_NORMAL_FLOW) then
1149+
1150+ bc_sele_val = ele_val(di%v_bc_value, sele)
1151+
1152+ else
1153+
1154+ ! get the viscosity value for this sele for this phase
1155+ visc_ele_bdy = face_val(di%viscosity(p)%ptr, sele)
1156+
1157+ ! get the absolute permeability value for this sele
1158+ absperm_ele_bdy = face_val(di%absolute_permeability, sele)
1159+
1160+ ! the inverse characteristic length used for pressure weak bc
1161+ inv_char_len_ele_bdy = ele_val(di%inverse_characteristic_length, sele)
1162+
1163+ ! Get the pressure BC value if required
1164+ if (di%pressure_bc_flag(sele) == PRESSURE_BC_TYPE_WEAKDIRICHLET) then
1165+
1166+ bc_sele_val = ele_val(di%pressure_bc_value, sele)
1167+
1168+ end if
1169+
1170+ ! The gravity values for this element for each direction
1171+ grav_ele_bdy = face_val(di%gravity, sele)
1172+
1173+!!!!! *** THIS IS NOT POSSIBLE YET ***
1174+!!!!! ! get the gradient capilliary pressure at the cv surface quadrature points for each direction
1175+!!!!! if (p > 1) then
1176+!!!!! grad_cap_pressure_face_quad_bdy = &
1177+!!!!! &darcy_impes_face_grad_at_quad_scalar(di%capilliary_pressure(p)%ptr, sele, dn = p_dshape)
1178+!!!!! end if
1179+
1180+!!!!! ! obtain the derivative of the pressure mesh shape function at the CV face quadrature points
1181+!!!!! if (di%cached_face_value%cached_p_dshape) then
1182+
1183+!!!!! p_dshape_bdy => di%cached_face_value%p_dshape_bdy(:,:,:,sele)
1184+
1185+!!!!! else
1186+
1187+!!!!! call transform_to_physical(di%positions, sele, x_shape = di%x_cvbdyshape_full, &
1188+!!!!! shape = di%p_cvbdyshape_full, dshape = p_dshape_bdy)
1189+
1190+!!!!! end if
1191+
1192+ end if
1193+
1194+ bc_iloc_loop: do iloc = 1, di%pressure_mesh%faces%shape%loc
1195+
1196+ bc_face_loop: do face = 1, di%cvfaces%sfaces
1197+
1198+ bc_neigh_if: if(di%cvfaces%sneiloc(iloc,face)/=0) then
1199+
1200+ bc_quad_loop: do gi = 1, di%cvfaces%shape%ngi
1201+
1202+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
1203+
1204+ prescribed_normal_flow: if (di%v_bc_flag(sele) == V_BC_TYPE_PRESCRIBED_NORMAL_FLOW) then
1205+
1206+ ! If have prescribed_normal_flow BC for this phase then include CV integral of value
1207+
1208+ if (di%subcy_opt_sat%have .and. di%subcy_opt_sat%consistent) then
1209+
1210+ p_rhs_local_bdy(iloc) = p_rhs_local_bdy(iloc) - &
1211+ di%subcy_opt_sat%number * &
1212+ bc_sele_val(iloc) * &
1213+ detwei_bdy(ggi)
1214+
1215+ else
1216+
1217+ p_rhs_local_bdy(iloc) = p_rhs_local_bdy(iloc) - &
1218+ bc_sele_val(iloc) * &
1219+ detwei_bdy(ggi)
1220+
1221+ end if
1222+
1223+ else prescribed_normal_flow
1224+
1225+ ! Form the face value = detwei * (relperm*absperm/visc)
1226+ if (di%subcy_opt_sat%have .and. di%subcy_opt_sat%consistent) then
1227+
1228+ face_value = detwei_bdy(ggi) * &
1229+ sum(di%cached_face_value%relperm_bdy(:,ggi,sele,p)) * &
1230+ absperm_ele_bdy(1) / &
1231+ visc_ele_bdy(1)
1232+
1233+ else
1234+
1235+ face_value = detwei_bdy(ggi) * &
1236+ di%cached_face_value%relperm_bdy(1,ggi,sele,p) * &
1237+ absperm_ele_bdy(1) / &
1238+ visc_ele_bdy(1)
1239+
1240+ end if
1241+
1242+ ! Add gravity term to rhs = - n_i . sum_{phase} ( relperm*absperm/visc ) * den*grav
1243+
1244+ ! Find g dot n
1245+ g_dot_n = dot_product(grav_ele_bdy(:,1), normal_bdy(:,ggi))
1246+
1247+ p_rhs_local_bdy(iloc) = p_rhs_local_bdy(iloc) - &
1248+ face_value * &
1249+ di%cached_face_value%den_bdy(ggi,sele,p) * &
1250+ g_dot_n
1251+
1252+!!!!! *** THIS IS NOT POSSIBLE YET ***
1253+!!!!! ! Add capilliary pressure term to rhs = n_i . sum_{phase} ( relperm*absperm/visc ) dP_c/dx_j
1254+!!!!! ! only for phase > 1
1255+!!!!! if (p > 1) then
1256+
1257+!!!!! ! Find grad_P_c dot n
1258+!!!!! grad_cap_p_dot_n = dot_product(grad_cap_pressure_face_quad_bdy(:,ggi), normal_bdy(:,ggi))
1259+
1260+!!!!! p_rhs_local(iloc) = p_rhs_local(iloc) + &
1261+!!!!! face_value * &
1262+!!!!! grad_cap_p_dot_n
1263+
1264+!!!!! end if
1265+
1266+!!!!! ! Add implicit gradient of pressure phase 1 to matrix with coeff
1267+!!!!! ! - n_i . sum_{phase} ( relperm*absperm/visc )
1268+
1269+
1270+ ! If have phase weak pressure BC then include integral of BC value in rhs
1271+ ! and an implicit surface mass matrix term
1272+ pressure_weak: if (di%pressure_bc_flag(sele) == PRESSURE_BC_TYPE_WEAKDIRICHLET) then
1273+
1274+ do jloc = 1,di%pressure_mesh%faces%shape%loc
1275+
1276+ p_rhs_local_bdy(iloc) = p_rhs_local_bdy(iloc) - &
1277+ inv_char_len_ele_bdy(jloc) * &
1278+ di%p_cvbdyshape%n(jloc,ggi) * &
1279+ bc_sele_val(jloc) * &
1280+ sum(normal_bdy(:,ggi)) * &
1281+ face_value * &
1282+ di%weak_pressure_bc_coeff
1283+
1284+ end do
1285+
1286+ do jloc = 1,di%pressure_mesh%faces%shape%loc
1287+
1288+ p_matrix_local_bdy(iloc,jloc) = p_matrix_local_bdy(iloc,jloc) - &
1289+ inv_char_len_ele_bdy(jloc) * &
1290+ di%p_cvbdyshape%n(jloc,ggi) * &
1291+ sum(normal_bdy(:,ggi)) * &
1292+ face_value * &
1293+ di%weak_pressure_bc_coeff
1294+
1295+ end do
1296+
1297+ end if pressure_weak
1298+
1299+ end if prescribed_normal_flow
1300+
1301+ end do bc_quad_loop
1302+
1303+ end if bc_neigh_if
1304+
1305+ end do bc_face_loop
1306+
1307+ end do bc_iloc_loop
1308+
1309+ end subroutine pressure_surface_element_local_assemble
1310+
1311+ ! --------------------------------------------------------------------------------------
1312+
1313+ end subroutine darcy_impes_assemble_and_solve_first_phase_pressure
1314+
1315+! ----------------------------------------------------------------------------
1316+
1317+ subroutine darcy_impes_get_v_boundary_condition(v, &
1318+ types, &
1319+ bc_surface_mesh, &
1320+ v_bc_value, &
1321+ v_bc_flag)
1322+
1323+ !!< Form the data associated with any v BC by returning
1324+ !!< full surface mesh arrays of a flag indicating either
1325+ !!< no_normal_flow or prescribed_normal_flow and the value.
1326+
1327+ type(vector_field), intent(in), target :: v
1328+ character(len=*), dimension(:), intent(in) :: types
1329+ type(mesh_type), intent(in) :: bc_surface_mesh
1330+ type(scalar_field), intent(inout) :: v_bc_value
1331+ integer, dimension(:), intent(inout) :: v_bc_flag
1332+
1333+ ! Local variables
1334+ character(len=FIELD_NAME_LEN) :: bctype
1335+ type(scalar_field) :: scalar_surface_field
1336+ integer, dimension(:), pointer :: surface_element_list
1337+ integer :: i, j, k, sele
1338+
1339+ ewrite(1,*) 'Get DarcyVelocity boundary condition data'
1340+
1341+ ! Zero the prescribed_normal_flow value surface field on whole boundary mesh
1342+ call zero(v_bc_value)
1343+
1344+ ! Initialise flag for whether surface element has prescribed_normal_flow BC
1345+ v_bc_flag = 0
1346+
1347+ ! Loop each BC object instance for the v
1348+ ! (May have multiple prescribed_normal_flow BC's applied to different surface id's)
1349+ BC_loop: do i=1, get_boundary_condition_count(v)
1350+
1351+ ! Get this BC info
1352+ call get_boundary_condition(v, i, type = bctype, &
1353+ surface_element_list = surface_element_list)
1354+
1355+ ! check this is a prescribed_normal_flow BC or no_normal_flow (nothing else is permitted)
1356+ if ((trim(bctype) /= 'prescribed_normal_flow') .and. (trim(bctype) /= 'no_normal_flow')) then
1357+ FLAbort('Have unknown BC type for a DarcyVelocity')
1358+ end if
1359+
1360+ ! Extract the surface_field for this BC for prescribed_normal_flow
1361+ if (trim(bctype) == 'prescribed_normal_flow') then
1362+ if (associated(v%bc%boundary_condition(i)%surface_fields)) then
1363+ scalar_surface_field = extract_scalar_field(&
1364+ v%bc%boundary_condition(i)%surface_fields(1), 1)
1365+ else
1366+ FLAbort('Component surface_fields for DarcyVelocity BC type not associated')
1367+ end if
1368+ end if
1369+
1370+ ! Loop the surface elements associated with this BC instance
1371+ ! and place the required BC value in whole boundary field
1372+ ! for the prescribed_normal_flow BC type
1373+ BC_sele_loop: do k = 1, size(surface_element_list)
1374+
1375+ ! Find the whole domain surface element number
1376+ sele = surface_element_list(k)
1377+
1378+ ! Check that there is only 1 BC applied per surface element
1379+ if (v_bc_flag(sele) /= 0) then
1380+ FLExit('Cannot apply more than 1 BC to a surface element for DarcyVelocity')
1381+ end if
1382+
1383+ ! Set the sele flag to indicate the BC type
1384+ do j = 1, size(types)
1385+ if (trim(types(j)) == trim(bctype)) exit
1386+ end do
1387+ if (j > size(types)) then
1388+ FLAbort('Cannot find no_normal_flow or prescribed_normal_flow bctype for DarcyVelocity')
1389+ end if
1390+
1391+ v_bc_flag(sele) = j
1392+
1393+ ! Set the prescribed_normal_flow field values from this BC for its sele
1394+ if (trim(bctype) == 'prescribed_normal_flow') then
1395+ call set(v_bc_value, &
1396+ ele_nodes(bc_surface_mesh, sele), &
1397+ ele_val(scalar_surface_field, k))
1398+ end if
1399+
1400+ end do BC_sele_loop
1401+
1402+ end do BC_loop
1403+
1404+ ewrite_minmax(v_bc_value)
1405+
1406+ ewrite(1,*) 'Finished get DarcyVelocity boundary condition data'
1407+
1408+ end subroutine darcy_impes_get_v_boundary_condition
1409+
1410+! ----------------------------------------------------------------------------
1411+
1412+ subroutine darcy_impes_get_entire_sfield_boundary_condition(sfield, &
1413+ types, &
1414+ bc_surface_mesh, &
1415+ sfield_bc_value, &
1416+ sfield_bc_flag)
1417+
1418+ !!< Get the entire BC data for either the saturation or pressure field
1419+
1420+ type(scalar_field), intent(in), target :: sfield
1421+ character(len=*), dimension(:), intent(in) :: types
1422+ type(mesh_type), intent(in) :: bc_surface_mesh
1423+ type(scalar_field), intent(inout) :: sfield_bc_value
1424+ integer, dimension(:), intent(inout) :: sfield_bc_flag
1425+
1426+ ! local variables
1427+ character(len=FIELD_NAME_LEN) :: bctype
1428+ type(scalar_field), pointer :: surface_field
1429+ integer, dimension(:), pointer :: surface_element_list
1430+ integer :: i, j, k, sele
1431+
1432+ ewrite(1,*) 'Get ',trim(sfield%name),' boundary condition data'
1433+
1434+ ! zero the bc value field
1435+ call zero(sfield_bc_value)
1436+
1437+ ! Initialise the bc type list for each sele
1438+ sfield_bc_flag = 0
1439+
1440+ ! Loop each BC object for the sfield
1441+ ! (May have multiple BC's applied to different suface id's)
1442+ BC_loop: do i=1, get_boundary_condition_count(sfield)
1443+
1444+ ! Get this BC info
1445+ call get_boundary_condition(sfield, i, type = bctype, &
1446+ surface_element_list = surface_element_list)
1447+
1448+ ! see if we're interested in this one, if not skip it
1449+ do j = 1, size(types)
1450+ if (trim(types(j)) == trim(bctype)) exit
1451+ end do
1452+ if (j > size(types)) cycle
1453+
1454+ ! Extract the surface field for this BC
1455+ if (associated(sfield%bc%boundary_condition(i)%surface_fields)) then
1456+ ! extract 1st surface field
1457+ surface_field => sfield%bc%boundary_condition(i)%surface_fields(1)
1458+ else
1459+ FLAbort('Component surface_fields for Saturation or Pressure BC type not associated')
1460+ end if
1461+
1462+ ! Loop the surface elements associated with this BC instance
1463+ ! and place the required BC value in whole boundary field
1464+ BC_sele_loop: do k = 1, size(surface_element_list)
1465+
1466+ ! Find the whole domain surface element number
1467+ sele = surface_element_list(k)
1468+
1469+ ! Check that there is only 1 BC applied per surface element
1470+ if (sfield_bc_flag(sele)/=0) then
1471+ ewrite(0,*) 'Requested types:', types
1472+ ewrite(0,*) 'Of these boundary condition types only one may be applied'
1473+ ewrite(0,*) 'to each surface element.'
1474+ ewrite(0,*) 'Surface element nr.:', sele
1475+ ewrite(0,*) 'has types', types(sfield_bc_flag(sele)), bctype
1476+ ewrite(0,*) 'on field: ', sfield%name
1477+ FLAbort('Issue with BC data for Saturation or Pressure')
1478+ end if
1479+
1480+ ! Set the sele flag to indicate the BC type
1481+ sfield_bc_flag(sele) = j
1482+
1483+ ! Set the BC sfield values from this BC for its sele
1484+ call set(sfield_bc_value, &
1485+ ele_nodes(bc_surface_mesh, sele), &
1486+ ele_val(surface_field, k))
1487+
1488+ end do BC_sele_loop
1489+
1490+ end do BC_loop
1491+
1492+ ewrite_minmax(sfield_bc_value)
1493+
1494+ ewrite(1,*) 'Finished get ',trim(sfield%name),' boundary condition data'
1495+
1496+ end subroutine darcy_impes_get_entire_sfield_boundary_condition
1497+
1498+! ----------------------------------------------------------------------------
1499+
1500+ subroutine darcy_impes_calculate_non_first_phase_pressures(di)
1501+
1502+ !!< Calcuate the non first phase pressures which = first_phase_pressure + capilliary pressure
1503+
1504+ type(darcy_impes_type), intent(inout) :: di
1505+
1506+ ! local variables
1507+ integer :: p
1508+
1509+ ewrite(1,*) 'Calculate Non first phase Pressures'
1510+
1511+ phase_loop: do p = 2, di%number_phase
1512+
1513+ call set(di%pressure(p)%ptr, di%pressure(1)%ptr)
1514+
1515+ call addto(di%pressure(p)%ptr, di%capilliary_pressure(p)%ptr)
1516+
1517+ ewrite_minmax(di%pressure(p)%ptr)
1518+
1519+ end do phase_loop
1520+
1521+ ewrite(1,*) 'Finished Calculate Non first phase Pressures'
1522+
1523+ end subroutine darcy_impes_calculate_non_first_phase_pressures
1524+
1525+! ----------------------------------------------------------------------------
1526+
1527+ subroutine darcy_impes_calculate_average_pressure(di)
1528+
1529+ !!< Calcuate the average phase pressure
1530+
1531+ type(darcy_impes_type), intent(inout) :: di
1532+
1533+ ! local variables
1534+ integer :: p
1535+
1536+ ewrite(1,*) 'Calculate AveragePressure'
1537+
1538+ call zero(di%average_pressure)
1539+
1540+ phase_loop: do p = 1, di%number_phase
1541+
1542+ call addto(di%average_pressure, di%pressure(p)%ptr)
1543+
1544+ end do phase_loop
1545+
1546+ call scale(di%average_pressure, 1.0/real(di%number_phase))
1547+
1548+ ewrite_minmax(di%average_pressure)
1549+
1550+ ewrite(1,*) 'Finished Calculate AveragePressure'
1551+
1552+ end subroutine darcy_impes_calculate_average_pressure
1553+
1554+! ----------------------------------------------------------------------------
1555+
1556+ subroutine darcy_impes_calculate_gradient_pressures(di)
1557+
1558+ !!< Calculate the gradient pressures for each phase
1559+
1560+ ! This routine requires optimisation and would become
1561+ ! not required if ele_grad_at_quad is used for pressure
1562+ ! and a face_grad_at_quad is made available
1563+
1564+ type(darcy_impes_type), intent(inout) :: di
1565+
1566+ ! local variables
1567+ integer :: p
1568+
1569+ ewrite(1,*) 'Calculate GradientPressure for each phase'
1570+
1571+ phase_loop: do p = 1, di%number_phase
1572+
1573+ call grad(di%pressure(p)%ptr, &
1574+ di%positions, &
1575+ di%gradient_pressure(p)%ptr)
1576+
1577+ ewrite_minmax(di%gradient_pressure(p)%ptr)
1578+
1579+ end do phase_loop
1580+
1581+ ewrite(1,*) 'Finished Calculate GradientPressure for each phase'
1582+
1583+ end subroutine darcy_impes_calculate_gradient_pressures
1584+
1585+! ----------------------------------------------------------------------------
1586+
1587+ subroutine darcy_impes_calculate_divergence_total_darcy_velocity(di)
1588+
1589+ !!< Calculate the divergence of the total divergence velocity,
1590+ !!< which may include terms summed over subcycles
1591+
1592+ type(darcy_impes_type), intent(inout) :: di
1593+
1594+ ! local variables
1595+ integer :: vele, p, iloc, oloc, jloc, face, gi, ggi, sele, dim
1596+ real :: darcy_vel_face_value_dot_n, v_over_relperm_dot_n, face_value
1597+ real, dimension(1) :: absperm_ele, visc_ele
1598+ real, dimension(:,:), pointer :: grad_pressure_face_quad
1599+ real, dimension(:,:), pointer :: grav_ele
1600+ real, dimension(:,:), pointer :: x_ele
1601+ real, dimension(:,:), pointer :: normal
1602+ real, dimension(:), pointer :: detwei
1603+ real, dimension(:), pointer :: normgi
1604+ logical, dimension(:), pointer :: notvisited
1605+ real, dimension(:), pointer :: div_tvel_rhs_local
1606+ real, dimension(:,:), pointer :: x_face_quad
1607+ integer, dimension(:), pointer :: x_pmesh_nodes
1608+ integer, dimension(:), pointer :: p_nodes
1609+ real, dimension(1) :: absperm_ele_bdy, visc_ele_bdy
1610+ real, dimension(:,:), pointer :: grav_ele_bdy
1611+ real, dimension(:,:), pointer :: grad_pressure_face_quad_bdy
1612+ real, dimension(:,:), pointer :: v_over_relperm_face_quad_bdy
1613+ real, dimension(:), pointer :: bc_sele_val
1614+ real, dimension(:), pointer :: pressure_ele_bdy
1615+ real, dimension(:), pointer :: inv_char_len_ele_bdy
1616+ real, dimension(:,:), pointer :: normal_bdy
1617+ real, dimension(:), pointer :: detwei_bdy
1618+ real, dimension(:,:), pointer :: x_ele_bdy
1619+ real, dimension(:), pointer :: div_tvel_rhs_local_bdy
1620+ integer, dimension(:), pointer :: p_nodes_bdy
1621+ integer, parameter :: V_BC_TYPE_PRESCRIBED_NORMAL_FLOW = 1, V_BC_TYPE_NO_NORMAL_FLOW = 2
1622+ integer, parameter :: PRESSURE_BC_TYPE_WEAKDIRICHLET = 1
1623+
1624+ ewrite(1,*) 'Calculate the DivergenceTotalDarcyVelocity'
1625+
1626+ ! allocate arrays used in assemble process - many assume
1627+ ! that all elements are the same type.
1628+ allocate(x_ele(di%ndim, ele_loc(di%positions,1)))
1629+ if (.not. di%cached_face_value%cached_detwei_normal) then
1630+ allocate(normal(di%ndim,di%x_cvshape%ngi))
1631+ allocate(detwei(di%x_cvshape%ngi))
1632+ end if
1633+ allocate(normgi(di%ndim))
1634+ allocate(notvisited(di%x_cvshape%ngi))
1635+ allocate(div_tvel_rhs_local(ele_loc(di%pressure_mesh,1)))
1636+ allocate(x_face_quad(di%ndim, di%x_cvshape%ngi))
1637+ allocate(grad_pressure_face_quad(di%ndim, di%p_cvshape%ngi))
1638+ allocate(grav_ele(di%ndim,1))
1639+
1640+ allocate(grav_ele_bdy(di%ndim,1))
1641+ allocate(grad_pressure_face_quad_bdy(di%ndim, di%p_cvbdyshape%ngi))
1642+ allocate(v_over_relperm_face_quad_bdy(di%ndim, di%p_cvbdyshape%ngi))
1643+ allocate(bc_sele_val(face_loc(di%pressure_mesh,1)))
1644+ allocate(pressure_ele_bdy(face_loc(di%pressure_mesh,1)))
1645+ allocate(inv_char_len_ele_bdy(face_loc(di%pressure_mesh,1)))
1646+ if (.not. di%cached_face_value%cached_detwei_normal) then
1647+ allocate(detwei_bdy(di%x_cvbdyshape%ngi))
1648+ allocate(normal_bdy(di%ndim, di%x_cvbdyshape%ngi))
1649+ end if
1650+ allocate(div_tvel_rhs_local_bdy(face_loc(di%pressure_mesh,1)))
1651+ allocate(x_ele_bdy(di%ndim, face_loc(di%positions,1)))
1652+ allocate(p_nodes_bdy(face_loc(di%pressure_mesh,1)))
1653+
1654+ call zero(di%div_total_darcy_velocity)
1655+
1656+ ! Get the pressure BC - required if no v given and weak pressure dirichlet given for extra integrals
1657+ call darcy_impes_get_entire_sfield_boundary_condition(di%pressure(1)%ptr, &
1658+ (/"weakdirichlet"/), &
1659+ di%bc_surface_mesh, &
1660+ di%pressure_bc_value, &
1661+ di%pressure_bc_flag)
1662+
1663+ phase_loop: do p = 1, di%number_phase
1664+
1665+ vele_loop: do vele = 1, di%number_vele
1666+
1667+ ! The node indices of the pressure field
1668+ p_nodes => ele_nodes(di%pressure_mesh, vele)
1669+
1670+ ! The gravity values for this element for each direction
1671+ grav_ele = ele_val(di%gravity, vele)
1672+
1673+ ! get the viscosity value for this element for this phase
1674+ visc_ele = ele_val(di%viscosity(p)%ptr, vele)
1675+
1676+ ! get the absolute permeability value for this element
1677+ absperm_ele = ele_val(di%absolute_permeability, vele)
1678+
1679+ ! get the latest gradient pressure at the cv surface quadrature points for each direction for this phase
1680+ grad_pressure_face_quad = ele_val_at_quad(di%gradient_pressure(p)%ptr, vele, di%gradp_cvshape)
1681+
1682+ ! obtain the transformed determinant*weight and normals
1683+ if (di%cached_face_value%cached_detwei_normal) then
1684+
1685+ detwei => di%cached_face_value%detwei(:,vele)
1686+
1687+ normal => di%cached_face_value%normal(:,:,vele)
1688+
1689+ else
1690+
1691+ ! get the coordinate values for this element for each positions local node
1692+ x_ele = ele_val(di%positions, vele)
1693+
1694+ ! get the coordinate values for this element for each quadrature point
1695+ x_face_quad = ele_val_at_quad(di%positions, vele, di%x_cvshape)
1696+
1697+ ! The node indices of the positions projected to the pressure mesh
1698+ x_pmesh_nodes => ele_nodes(di%positions_pressure_mesh, vele)
1699+
1700+ call transform_cvsurf_to_physical(x_ele, di%x_cvshape, detwei, normal, di%cvfaces)
1701+
1702+ end if
1703+
1704+ ! Initialise array for the quadrature points of this
1705+ ! element for whether it has already been visited
1706+ notvisited = .true.
1707+
1708+ ! Initialise the local rhs to assemble for this element
1709+ div_tvel_rhs_local = 0.0
1710+
1711+ ! loop over local nodes within this element
1712+ nodal_loop_i: do iloc = 1, di%pressure_mesh%shape%loc
1713+
1714+ ! loop over CV faces internal to this element
1715+ face_loop: do face = 1, di%cvfaces%faces
1716+
1717+ ! is this a face neighbouring iloc?
1718+ is_neigh: if(di%cvfaces%neiloc(iloc, face) /= 0) then
1719+
1720+ ! find the opposing local node across the CV face
1721+ oloc = di%cvfaces%neiloc(iloc, face)
1722+
1723+ ! loop over gauss points on face
1724+ quadrature_loop: do gi = 1, di%cvfaces%shape%ngi
1725+
1726+ ! global gauss pt index for this element
1727+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
1728+
1729+ ! check if this quadrature point has already been visited
1730+ check_visited: if(notvisited(ggi)) then
1731+
1732+ notvisited(ggi) = .false.
1733+
1734+ if (di%cached_face_value%cached_detwei_normal) then
1735+
1736+ ! cached normal has correct orientation already
1737+ normgi = normal(:,ggi)
1738+
1739+ else
1740+
1741+ ! correct the orientation of the normal so it points away from iloc
1742+ normgi = orientate_cvsurf_normgi(node_val(di%positions_pressure_mesh, x_pmesh_nodes(iloc)), &
1743+ &x_face_quad(:,ggi), normal(:,ggi))
1744+
1745+ end if
1746+
1747+ ! Form the face value = detwei * (relperm*absperm/visc)
1748+ if (di%subcy_opt_sat%have .and. di%subcy_opt_sat%consistent) then
1749+
1750+ face_value = detwei(ggi) * &
1751+ sum(di%cached_face_value%relperm(:,ggi,vele,p)) * &
1752+ absperm_ele(1) / &
1753+ visc_ele(1)
1754+
1755+ else
1756+
1757+ face_value = detwei(ggi) * &
1758+ di%cached_face_value%relperm(1,ggi,vele,p) * &
1759+ absperm_ele(1) / &
1760+ visc_ele(1)
1761+
1762+ end if
1763+
1764+ darcy_vel_face_value_dot_n = - dot_product( normgi, &
1765+ &face_value * (grad_pressure_face_quad(:,ggi) - di%cached_face_value%den(ggi,vele,p) * grav_ele(:,1)) )
1766+
1767+ div_tvel_rhs_local(iloc) = div_tvel_rhs_local(iloc) + &
1768+ darcy_vel_face_value_dot_n
1769+
1770+ div_tvel_rhs_local(oloc) = div_tvel_rhs_local(oloc) - &
1771+ darcy_vel_face_value_dot_n
1772+
1773+ end if check_visited
1774+
1775+ end do quadrature_loop
1776+
1777+ end if is_neigh
1778+
1779+ end do face_loop
1780+
1781+ end do nodal_loop_i
1782+
1783+ call addto(di%div_total_darcy_velocity, p_nodes, div_tvel_rhs_local)
1784+
1785+ end do vele_loop
1786+
1787+ ! Get this phase v BC info - only for no_normal_flow and prescribed_normal_flow which is special as it is a scalar
1788+ call darcy_impes_get_v_boundary_condition(di%darcy_velocity(p)%ptr, &
1789+ (/"prescribed_normal_flow", &
1790+ "no_normal_flow "/), &
1791+ di%bc_surface_mesh, &
1792+ di%v_bc_value, &
1793+ di%v_bc_flag)
1794+
1795+ sele_loop: do sele = 1, di%number_sele
1796+
1797+ if (di%v_bc_flag(sele) == V_BC_TYPE_NO_NORMAL_FLOW) cycle sele_loop
1798+
1799+ p_nodes_bdy = face_global_nodes(di%pressure_mesh, sele)
1800+
1801+ ! obtain the transformed determinant*weight and normals
1802+ if (di%cached_face_value%cached_detwei_normal) then
1803+
1804+ detwei_bdy => di%cached_face_value%detwei_bdy(:,sele)
1805+
1806+ normal_bdy => di%cached_face_value%normal_bdy(:,:,sele)
1807+
1808+ else
1809+
1810+ x_ele = ele_val(di%positions, face_ele(di%positions, sele))
1811+ x_ele_bdy = face_val(di%positions, sele)
1812+
1813+ call transform_cvsurf_facet_to_physical(x_ele, x_ele_bdy, di%x_cvbdyshape, normal_bdy, detwei_bdy)
1814+
1815+ end if
1816+
1817+ if (di%v_bc_flag(sele) == V_BC_TYPE_PRESCRIBED_NORMAL_FLOW) then
1818+
1819+ bc_sele_val = ele_val(di%v_bc_value, sele)
1820+
1821+ else
1822+
1823+ visc_ele_bdy = face_val(di%viscosity(p)%ptr, sele)
1824+ absperm_ele_bdy = face_val(di%absolute_permeability, sele)
1825+ inv_char_len_ele_bdy = ele_val(di%inverse_characteristic_length, sele)
1826+ if (di%pressure_bc_flag(sele) == PRESSURE_BC_TYPE_WEAKDIRICHLET) then
1827+ bc_sele_val = ele_val(di%pressure_bc_value, sele)
1828+ end if
1829+ grad_pressure_face_quad_bdy = face_val_at_quad(di%gradient_pressure(p)%ptr, sele, di%gradp_cvbdyshape)
1830+ grav_ele_bdy = face_val(di%gravity, sele)
1831+ pressure_ele_bdy = face_val(di%pressure(p)%ptr, sele)
1832+
1833+ ! the latest DarcyVelocity/relperm at the quadrature points
1834+ do dim = 1,di%ndim
1835+
1836+ v_over_relperm_face_quad_bdy(dim,:) = &
1837+- (absperm_ele_bdy(1) / visc_ele_bdy(1)) * &
1838+(grad_pressure_face_quad_bdy(dim,:) - face_val_at_quad(di%density(p)%ptr, sele, di%p_cvbdyshape) * grav_ele_bdy(dim,1))
1839+
1840+ end do
1841+
1842+ end if
1843+
1844+ ! Initialise the local rhs to assemble for this element
1845+ div_tvel_rhs_local_bdy = 0.0
1846+
1847+ bc_iloc_loop: do iloc = 1, di%pressure_mesh%faces%shape%loc
1848+
1849+ bc_face_loop: do face = 1, di%cvfaces%sfaces
1850+
1851+ bc_neigh_if: if(di%cvfaces%sneiloc(iloc,face)/=0) then
1852+
1853+ bc_quad_loop: do gi = 1, di%cvfaces%shape%ngi
1854+
1855+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
1856+
1857+ prescribed_normal_flow: if (di%v_bc_flag(sele) == V_BC_TYPE_PRESCRIBED_NORMAL_FLOW) then
1858+
1859+ if (di%subcy_opt_sat%have .and. di%subcy_opt_sat%consistent) then
1860+
1861+ div_tvel_rhs_local_bdy(iloc) = div_tvel_rhs_local_bdy(iloc) + &
1862+ di%subcy_opt_sat%number * &
1863+ bc_sele_val(iloc) * &
1864+ detwei_bdy(ggi)
1865+
1866+ else
1867+
1868+ div_tvel_rhs_local_bdy(iloc) = div_tvel_rhs_local_bdy(iloc) + &
1869+ bc_sele_val(iloc) * &
1870+ detwei_bdy(ggi)
1871+
1872+ end if
1873+
1874+ else prescribed_normal_flow
1875+
1876+ ! NOTE this v_over_relperm_dot_n does not contain the relperm terms
1877+ v_over_relperm_dot_n = dot_product(v_over_relperm_face_quad_bdy(:,ggi), normal_bdy(:,ggi))
1878+
1879+ ! Adding this term includes the gradient of pressure, gradient of
1880+ ! capilliary pressure and the gravity term.
1881+ if (di%subcy_opt_sat%have .and. di%subcy_opt_sat%consistent) then
1882+
1883+ div_tvel_rhs_local_bdy(iloc) = div_tvel_rhs_local_bdy(iloc) + &
1884+ sum(di%cached_face_value%relperm_bdy(:,ggi,sele,p)) * &
1885+ v_over_relperm_dot_n * &
1886+ detwei_bdy(ggi)
1887+
1888+ else
1889+
1890+ div_tvel_rhs_local_bdy(iloc) = div_tvel_rhs_local_bdy(iloc) + &
1891+ di%cached_face_value%relperm_bdy(1,ggi,sele,p) * &
1892+ v_over_relperm_dot_n * &
1893+ detwei_bdy(ggi)
1894+
1895+ end if
1896+
1897+ ! Add two extra terms associated with weak pressure BC's
1898+
1899+ ! Add two extra terms associated with weak pressure BC's
1900+ pressure_weak: if (di%pressure_bc_flag(sele) == PRESSURE_BC_TYPE_WEAKDIRICHLET) then
1901+
1902+ ! Form the face value = detwei * (relperm*absperm/visc)
1903+ if (di%subcy_opt_sat%have .and. di%subcy_opt_sat%consistent) then
1904+
1905+ face_value = detwei_bdy(ggi) * &
1906+ sum(di%cached_face_value%relperm_bdy(:,ggi,sele,p)) * &
1907+ absperm_ele_bdy(1) / &
1908+ visc_ele_bdy(1)
1909+
1910+ else
1911+
1912+ face_value = detwei_bdy(ggi) * &
1913+ di%cached_face_value%relperm_bdy(1,ggi,sele,p) * &
1914+ absperm_ele_bdy(1) / &
1915+ visc_ele_bdy(1)
1916+
1917+ end if
1918+
1919+ do jloc = 1, di%pressure_mesh%faces%shape%loc
1920+
1921+ div_tvel_rhs_local_bdy(iloc) = div_tvel_rhs_local_bdy(iloc) - &
1922+ inv_char_len_ele_bdy(jloc) * &
1923+ di%p_cvbdyshape%n(jloc,ggi) * &
1924+ bc_sele_val(jloc) * &
1925+ sum(normal_bdy(:,ggi)) * &
1926+ face_value * &
1927+ di%weak_pressure_bc_coeff
1928+
1929+ end do
1930+
1931+ do jloc = 1, di%pressure_mesh%faces%shape%loc
1932+
1933+ div_tvel_rhs_local_bdy(iloc) = div_tvel_rhs_local_bdy(iloc) + &
1934+ inv_char_len_ele_bdy(jloc) * &
1935+ di%p_cvbdyshape%n(jloc,ggi) * &
1936+ pressure_ele_bdy(jloc) * &
1937+ sum(normal_bdy(:,ggi)) * &
1938+ face_value * &
1939+ di%weak_pressure_bc_coeff
1940+
1941+ end do
1942+
1943+ end if pressure_weak
1944+
1945+ end if prescribed_normal_flow
1946+
1947+ end do bc_quad_loop
1948+
1949+ end if bc_neigh_if
1950+
1951+ end do bc_face_loop
1952+
1953+ end do bc_iloc_loop
1954+
1955+ call addto(di%div_total_darcy_velocity, p_nodes_bdy, div_tvel_rhs_local_bdy)
1956+
1957+ end do sele_loop
1958+
1959+ end do phase_loop
1960+
1961+ call scale(di%div_total_darcy_velocity, di%inverse_cv_mass_pressure_mesh)
1962+
1963+ ewrite_minmax(di%div_total_darcy_velocity)
1964+
1965+ ! deallocate local variables as required
1966+ deallocate(x_ele)
1967+ if (di%cached_face_value%cached_detwei_normal) then
1968+ nullify(detwei)
1969+ nullify(normal)
1970+ else
1971+ deallocate(detwei)
1972+ deallocate(normal)
1973+ end if
1974+ deallocate(normgi)
1975+ deallocate(notvisited)
1976+ deallocate(div_tvel_rhs_local)
1977+ deallocate(x_face_quad)
1978+ deallocate(grad_pressure_face_quad)
1979+ deallocate(grav_ele)
1980+
1981+ deallocate(grav_ele_bdy)
1982+ deallocate(grad_pressure_face_quad_bdy)
1983+ deallocate(v_over_relperm_face_quad_bdy)
1984+ deallocate(bc_sele_val)
1985+ deallocate(pressure_ele_bdy)
1986+ deallocate(inv_char_len_ele_bdy)
1987+ if (di%cached_face_value%cached_detwei_normal) then
1988+ nullify(detwei_bdy)
1989+ nullify(normal_bdy)
1990+ else
1991+ deallocate(detwei_bdy)
1992+ deallocate(normal_bdy)
1993+ end if
1994+ deallocate(div_tvel_rhs_local_bdy)
1995+ deallocate(x_ele_bdy)
1996+ deallocate(p_nodes_bdy)
1997+
1998+ ewrite(1,*) 'Finished Calculate the DivergenceTotalDarcyVelocity'
1999+
2000+ end subroutine darcy_impes_calculate_divergence_total_darcy_velocity
2001+
2002+! ----------------------------------------------------------------------------
2003+
2004+ subroutine darcy_impes_assemble_and_solve_phase_saturations(di, &
2005+ form_new_subcycle_relperm_face_values, &
2006+ have_dual)
2007+
2008+ !!< Assemble and solve the saturations for each subcycle.
2009+ !!< If form_new_subcycle_relperm_face_values is true
2010+ !!< and there are subcycles then new relperm face values are
2011+ !!< formed. Phase 1 is special as it may be either solved
2012+ !!< prognostically or calculated diagnostically from the
2013+ !!< other phase saturation values that are solved first (for each subcycle).
2014+
2015+ type(darcy_impes_type), intent(inout) :: di
2016+ logical, intent(in) :: form_new_subcycle_relperm_face_values
2017+ logical, intent(in) :: have_dual
2018+
2019+ ! local variables
2020+ integer :: p, isub, isub_index
2021+ real :: alpha_start, alpha_end
2022+
2023+ ewrite(1,*) 'Assemble and solve the saturations for each phase'
2024+
2025+ ! Solve the saturations for each subcycle via:
2026+ ! - Form the relperm face values for each phase if required
2027+ ! - For each phase:
2028+ ! - Form the lhs = cv_mass_sfield_mesh_with_porosity / dt
2029+ ! - Form the rhs time = cv_mass_pressure_mesh_with_old_porosity * old_saturation_field / dt and add to rhs
2030+ ! - Add the s_source to rhs, which may include the dual perm transmissibility term
2031+ ! - Assemble and add the rhs adv to rhs
2032+ ! - Apply any strong dirichlet BCs
2033+ ! - solve for latest saturations and copy to start subcycle saturations step
2034+
2035+ ! Note: the porosity at the start and end of a subcycle time step
2036+ ! are linearly interpolated values from the main time step start and end
2037+
2038+ ! Deduce the subcycle time step size
2039+ if (di%subcy_opt_sat%have) then
2040+
2041+ di%dt_subcycle = di%dt/real(di%subcy_opt_sat%number)
2042+
2043+ else
2044+
2045+ di%dt_subcycle = di%dt
2046+
2047+ end if
2048+
2049+ ! Set the initial old saturation subcycle field
2050+ do p = 1, di%number_phase
2051+ call set(di%old_saturation_subcycle(p)%ptr, di%old_saturation(p)%ptr)
2052+ end do
2053+
2054+ ! Get the pressure BC - required if no v given and weak pressure dirichlet given for extra integrals
2055+ call darcy_impes_get_entire_sfield_boundary_condition(di%pressure(1)%ptr, &
2056+ (/"weakdirichlet"/), &
2057+ di%bc_surface_mesh, &
2058+ di%pressure_bc_value, &
2059+ di%pressure_bc_flag)
2060+
2061+ sub_loop: do isub = 1, di%subcy_opt_sat%number
2062+
2063+ ewrite(1,*) 'Start subcycle ',isub
2064+
2065+ ! form the start and end of subcycle dt
2066+ ! porosity linear interpolents
2067+ alpha_start = (isub - 1) / di%subcy_opt_sat%number
2068+ alpha_end = isub / di%subcy_opt_sat%number
2069+
2070+ ! Determine the index for cached face values depending on subcycling
2071+ if (di%subcy_opt_sat%have .and. di%subcy_opt_sat%consistent) then
2072+ isub_index = isub
2073+ else
2074+ isub_index = 1
2075+ end if
2076+
2077+ ! If this is not the first subcycle then form the relperms
2078+ ! for the start of this subcycle from the end of last subcycle sat
2079+ ! and face values if required
2080+ if (form_new_subcycle_relperm_face_values .and. (isub > 1)) then
2081+ call darcy_impes_calculate_relperm_fields(di)
2082+
2083+ call darcy_impes_calculate_relperm_isub_face_values(di, isub_index)
2084+ end if
2085+
2086+ phase_loop: do p = di%number_phase, 1, -1
2087+
2088+ ewrite(1,*) 'Assemble and solve phase ',p
2089+
2090+ ! If this is phase 1 and it is diagnostic then calculate it and exit loop
2091+ if ((p == 1) .and. di%phase_one_saturation_diagnostic) then
2092+
2093+ call darcy_impes_calculate_phase_one_saturation_diagnostic(di)
2094+
2095+ ! Copy latest phase 1 solution to old subcycle field
2096+ call set(di%old_saturation_subcycle(1)%ptr, di%saturation(1)%ptr)
2097+
2098+ exit phase_loop
2099+
2100+ end if
2101+
2102+ ! Allocate and get the BC data. If the BC is time dependent then
2103+ ! the end of overall time step values are used for all subcycles.
2104+
2105+ ! Get this phase v BC info - only for no_normal_flow and prescribed_normal_flow which is special as it is a scalar
2106+ call darcy_impes_get_v_boundary_condition(di%darcy_velocity(p)%ptr, &
2107+ (/"prescribed_normal_flow", &
2108+ "no_normal_flow "/), &
2109+ di%bc_surface_mesh, &
2110+ di%v_bc_value, &
2111+ di%v_bc_flag)
2112+
2113+ call zero(di%lhs)
2114+ call zero(di%rhs)
2115+
2116+ call addto(di%lhs, di%cv_mass_pressure_mesh_with_porosity, scale = alpha_end / di%dt_subcycle)
2117+
2118+ call addto(di%lhs, di%cv_mass_pressure_mesh_with_old_porosity, scale = (1.0 - alpha_end) / di%dt_subcycle)
2119+
2120+ ! form the rhs time contribution and add
2121+ call addto(di%rhs, di%cv_mass_pressure_mesh_with_porosity, scale = alpha_start / di%dt_subcycle)
2122+
2123+ call addto(di%rhs, di%cv_mass_pressure_mesh_with_old_porosity, scale = (1.0 - alpha_start) / di%dt_subcycle)
2124+
2125+ call scale(di%rhs, di%old_saturation_subcycle(p)%ptr)
2126+
2127+ ! Add the saturation_source contribution
2128+ call compute_cv_mass(di%positions, di%cv_mass_pressure_mesh_with_source, di%saturation_source(p)%ptr)
2129+
2130+ ! Should this include porosity ?!?!
2131+ call addto(di%rhs, di%cv_mass_pressure_mesh_with_source)
2132+
2133+ ! Add the dual source term
2134+ if (have_dual) then
2135+ call compute_cv_mass(di%positions, di%cv_mass_pressure_mesh_with_lambda_dual, di%transmissibility_lambda_dual(p)%ptr)
2136+
2137+ call set(di%rhs_dual, di%pressure_other_porous_media(p)%ptr)
2138+ call addto(di%rhs_dual, di%pressure(p)%ptr, scale = -1.0)
2139+ call scale(di%rhs_dual, di%cv_mass_pressure_mesh_with_lambda_dual)
2140+
2141+ call addto(di%rhs, di%rhs_dual)
2142+ end if
2143+
2144+ ! assemble the rhs adv contribution and add
2145+ call darcy_impes_assemble_saturation_rhs_adv(di, &
2146+ p, &
2147+ isub_index)
2148+
2149+ ! apply strong dirichlet BC
2150+ call apply_dirichlet_conditions(di%lhs, di%rhs, di%saturation(p)%ptr)
2151+
2152+ ! Solve for the saturation
2153+ di%saturation(p)%ptr%val = di%rhs%val / di%lhs%val
2154+
2155+ ! Update the halos
2156+ call halo_update(di%saturation(p)%ptr)
2157+
2158+ ! Set the strong BC nodes to the values to be consistent
2159+ call set_dirichlet_consistent(di%saturation(p)%ptr)
2160+
2161+ ! Copy latest solution to old subcycle
2162+ call set(di%old_saturation_subcycle(p)%ptr, di%saturation(p)%ptr)
2163+
2164+ end do phase_loop
2165+
2166+ end do sub_loop
2167+
2168+ ewrite(1,*) 'Finished assemble and solve the saturations for each phase'
2169+
2170+ end subroutine darcy_impes_assemble_and_solve_phase_saturations
2171+
2172+! ----------------------------------------------------------------------------
2173+
2174+ subroutine darcy_impes_assemble_saturation_rhs_adv(di, &
2175+ p, &
2176+ isub_index)
2177+
2178+ !!< Assemble the rhs advection contribtion for saturation phase p
2179+
2180+ type(darcy_impes_type), intent(inout) :: di
2181+ integer, intent(in) :: p
2182+ integer, intent(in) :: isub_index
2183+
2184+ ! local variables
2185+ integer :: vele, iloc, oloc, jloc, face, gi, ggi, sele, dim
2186+ real :: face_value, v_over_relperm_dot_n
2187+ real, dimension(1) :: absperm_ele, visc_ele
2188+ real, dimension(:,:), pointer :: grad_pressure_face_quad
2189+ real, dimension(:,:), pointer :: grav_ele
2190+ real, dimension(:,:), pointer :: x_ele
2191+ real, dimension(:,:), pointer :: normal
2192+ real, dimension(:), pointer :: detwei
2193+ real, dimension(:), pointer :: normgi
2194+ logical, dimension(:), pointer :: notvisited
2195+ real, dimension(:), pointer :: s_rhs_local
2196+ real, dimension(:,:), pointer :: x_face_quad
2197+ integer, dimension(:), pointer :: x_pmesh_nodes
2198+ integer, dimension(:), pointer :: p_nodes
2199+ real, dimension(1) :: absperm_ele_bdy, visc_ele_bdy
2200+ real, dimension(:,:), pointer :: grav_ele_bdy
2201+ real, dimension(:,:), pointer :: grad_pressure_face_quad_bdy
2202+ real, dimension(:,:), pointer :: v_over_relperm_face_quad_bdy
2203+ real, dimension(:), pointer :: bc_sele_val
2204+ real, dimension(:), pointer :: pressure_ele_bdy
2205+ real, dimension(:), pointer :: inv_char_len_ele_bdy
2206+ real, dimension(:,:), pointer :: normal_bdy
2207+ real, dimension(:), pointer :: detwei_bdy
2208+ real, dimension(:,:), pointer :: x_ele_bdy
2209+ real, dimension(:), pointer :: s_rhs_local_bdy
2210+ integer, dimension(:), pointer :: p_nodes_bdy
2211+ integer, parameter :: V_BC_TYPE_PRESCRIBED_NORMAL_FLOW = 1, V_BC_TYPE_NO_NORMAL_FLOW = 2
2212+ integer, parameter :: PRESSURE_BC_TYPE_WEAKDIRICHLET = 1
2213+
2214+ ! allocate arrays used in assemble process - many assume
2215+ ! that all elements are the same type.
2216+ allocate(x_ele(di%ndim, ele_loc(di%positions,1)))
2217+ if (.not. di%cached_face_value%cached_detwei_normal) then
2218+ allocate(normal(di%ndim,di%x_cvshape%ngi))
2219+ allocate(detwei(di%x_cvshape%ngi))
2220+ end if
2221+ allocate(normgi(di%ndim))
2222+ allocate(notvisited(di%x_cvshape%ngi))
2223+ allocate(s_rhs_local(ele_loc(di%pressure_mesh,1)))
2224+ allocate(x_face_quad(di%ndim, di%x_cvshape%ngi))
2225+ allocate(grad_pressure_face_quad(di%ndim, di%p_cvshape%ngi))
2226+ allocate(grav_ele(di%ndim,1))
2227+
2228+ allocate(grav_ele_bdy(di%ndim,1))
2229+ allocate(grad_pressure_face_quad_bdy(di%ndim, di%p_cvbdyshape%ngi))
2230+ allocate(v_over_relperm_face_quad_bdy(di%ndim, di%p_cvbdyshape%ngi))
2231+ allocate(bc_sele_val(face_loc(di%pressure_mesh,1)))
2232+ allocate(pressure_ele_bdy(face_loc(di%pressure_mesh,1)))
2233+ allocate(inv_char_len_ele_bdy(face_loc(di%pressure_mesh,1)))
2234+ if (.not. di%cached_face_value%cached_detwei_normal) then
2235+ allocate(detwei_bdy(di%x_cvbdyshape%ngi))
2236+ allocate(normal_bdy(di%ndim, di%x_cvbdyshape%ngi))
2237+ end if
2238+ allocate(s_rhs_local_bdy(face_loc(di%pressure_mesh,1)))
2239+ allocate(x_ele_bdy(di%ndim, face_loc(di%positions,1)))
2240+ allocate(p_nodes_bdy(face_loc(di%pressure_mesh,1)))
2241+
2242+ ! Loop volume elements assembling local contributions
2243+ vol_element_loop: do vele = 1, di%number_vele
2244+
2245+ ! The node indices of the pressure mesh (which saturation is associated with)
2246+ p_nodes => ele_nodes(di%pressure_mesh, vele)
2247+
2248+ ! The node indices of the positions projected to the pressure mesh (which saturation is associated with)
2249+ x_pmesh_nodes => ele_nodes(di%positions_pressure_mesh, vele)
2250+
2251+ ! The gravity values for this element for each direction
2252+ grav_ele = ele_val(di%gravity, vele)
2253+
2254+ ! get the viscosity value for this element
2255+ visc_ele = ele_val(di%viscosity(p)%ptr, vele)
2256+
2257+ ! get the absolute permeability value for this element
2258+ absperm_ele = ele_val(di%absolute_permeability, vele)
2259+
2260+ ! get the latest gradient pressure at the cv surface quadrature points for each direction
2261+ grad_pressure_face_quad = ele_val_at_quad(di%gradient_pressure(p)%ptr, vele, di%gradp_cvshape)
2262+
2263+ ! obtain the transformed determinant*weight and normals
2264+ if (di%cached_face_value%cached_detwei_normal) then
2265+
2266+ detwei => di%cached_face_value%detwei(:,vele)
2267+
2268+ normal => di%cached_face_value%normal(:,:,vele)
2269+
2270+ else
2271+
2272+ ! get the coordinate values for this element for each positions local node
2273+ x_ele = ele_val(di%positions, vele)
2274+
2275+ ! get the coordinate values for this element for each quadrature point
2276+ x_face_quad = ele_val_at_quad(di%positions, vele, di%x_cvshape)
2277+
2278+ call transform_cvsurf_to_physical(x_ele, di%x_cvshape, detwei, normal, di%cvfaces)
2279+
2280+ end if
2281+
2282+ ! Initialise array for the quadrature points of this
2283+ ! element for whether it has already been visited
2284+ notvisited = .true.
2285+
2286+ ! Initialise the local rhs to assemble for this element
2287+ s_rhs_local = 0.0
2288+
2289+ ! loop over local nodes within this element
2290+ nodal_loop_i: do iloc = 1, di%pressure_mesh%shape%loc
2291+
2292+ ! loop over CV faces internal to this element
2293+ face_loop: do face = 1, di%cvfaces%faces
2294+
2295+ ! is this a face neighbouring iloc?
2296+ is_neigh: if(di%cvfaces%neiloc(iloc, face) /= 0) then
2297+
2298+ ! find the opposing local node across the CV face
2299+ oloc = di%cvfaces%neiloc(iloc, face)
2300+
2301+ ! loop over gauss points on face
2302+ quadrature_loop: do gi = 1, di%cvfaces%shape%ngi
2303+
2304+ ! global gauss pt index for this element
2305+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
2306+
2307+ ! check if this quadrature point has already been visited
2308+ check_visited: if(notvisited(ggi)) then
2309+
2310+ notvisited(ggi) = .false.
2311+
2312+ if (di%cached_face_value%cached_detwei_normal) then
2313+
2314+ ! cached normal has correct orientation already
2315+ normgi = normal(:,ggi)
2316+
2317+ else
2318+
2319+ ! correct the orientation of the normal so it points away from iloc
2320+ normgi = orientate_cvsurf_normgi(node_val(di%positions_pressure_mesh, x_pmesh_nodes(iloc)), &
2321+ &x_face_quad(:,ggi), normal(:,ggi))
2322+
2323+ end if
2324+
2325+ face_value = detwei(ggi) * di%cached_face_value%relperm(isub_index,ggi,vele,p) * absperm_ele(1) * &
2326+dot_product((grad_pressure_face_quad(:,ggi) - di%cached_face_value%den(ggi,vele,p) * grav_ele(:,1)), normgi)/ visc_ele(1)
2327+
2328+ ! Form the local rhs for iloc and opposing oloc with normal vector sign change
2329+ s_rhs_local(iloc) = s_rhs_local(iloc) + face_value
2330+
2331+ s_rhs_local(oloc) = s_rhs_local(oloc) - face_value
2332+
2333+ end if check_visited
2334+
2335+ end do quadrature_loop
2336+
2337+ end if is_neigh
2338+
2339+ end do face_loop
2340+
2341+ end do nodal_loop_i
2342+
2343+ ! Add volume element contribution to global rhs field
2344+ call addto(di%rhs, p_nodes, s_rhs_local)
2345+
2346+ end do vol_element_loop
2347+
2348+ ! Add BC integrals
2349+
2350+ sele_loop: do sele = 1, di%number_sele
2351+
2352+ if (di%v_bc_flag(sele) == V_BC_TYPE_NO_NORMAL_FLOW) cycle sele_loop
2353+
2354+ p_nodes_bdy = face_global_nodes(di%pressure_mesh, sele)
2355+
2356+ ! obtain the transformed determinant*weight and normals
2357+ if (di%cached_face_value%cached_detwei_normal) then
2358+
2359+ detwei_bdy => di%cached_face_value%detwei_bdy(:,sele)
2360+
2361+ normal_bdy => di%cached_face_value%normal_bdy(:,:,sele)
2362+
2363+ else
2364+
2365+ x_ele = ele_val(di%positions, face_ele(di%positions, sele))
2366+ x_ele_bdy = face_val(di%positions, sele)
2367+
2368+ call transform_cvsurf_facet_to_physical(x_ele, x_ele_bdy, di%x_cvbdyshape, normal_bdy, detwei_bdy)
2369+
2370+ end if
2371+
2372+ if (di%v_bc_flag(sele) == V_BC_TYPE_PRESCRIBED_NORMAL_FLOW) then
2373+
2374+ bc_sele_val = ele_val(di%v_bc_value, sele)
2375+
2376+ else
2377+
2378+ visc_ele_bdy = face_val(di%viscosity(p)%ptr, sele)
2379+ absperm_ele_bdy = face_val(di%absolute_permeability, sele)
2380+ inv_char_len_ele_bdy = ele_val(di%inverse_characteristic_length, sele)
2381+ if (di%pressure_bc_flag(sele) == PRESSURE_BC_TYPE_WEAKDIRICHLET) then
2382+ bc_sele_val = ele_val(di%pressure_bc_value, sele)
2383+ end if
2384+ grad_pressure_face_quad_bdy = face_val_at_quad(di%gradient_pressure(p)%ptr, sele, di%gradp_cvbdyshape)
2385+ grav_ele_bdy = face_val(di%gravity, sele)
2386+ pressure_ele_bdy = face_val(di%pressure(p)%ptr, sele)
2387+
2388+ ! the latest DarcyVelocity/relperm at the quadrature points for start of subcycle
2389+ ! determined from FE interpolation of each component,
2390+ do dim = 1, di%ndim
2391+
2392+ v_over_relperm_face_quad_bdy(dim,:) = &
2393+- (absperm_ele_bdy(1) / visc_ele_bdy(1)) * &
2394+(grad_pressure_face_quad_bdy(dim,:) - face_val_at_quad(di%density(p)%ptr, sele, di%p_cvbdyshape) * grav_ele_bdy(dim,1))
2395+
2396+ end do
2397+
2398+ end if
2399+
2400+ ! Initialise the local rhs to assemble for this element
2401+ s_rhs_local_bdy = 0.0
2402+
2403+ bc_iloc_loop: do iloc = 1, di%pressure_mesh%faces%shape%loc
2404+
2405+ bc_face_loop: do face = 1, di%cvfaces%sfaces
2406+
2407+ bc_neigh_if: if(di%cvfaces%sneiloc(iloc,face)/=0) then
2408+
2409+ bc_quad_loop: do gi = 1, di%cvfaces%shape%ngi
2410+
2411+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
2412+
2413+ prescribed_normal_flow: if (di%v_bc_flag(sele) == V_BC_TYPE_PRESCRIBED_NORMAL_FLOW) then
2414+
2415+ s_rhs_local_bdy(iloc) = s_rhs_local_bdy(iloc) - &
2416+ bc_sele_val(iloc) * &
2417+ detwei_bdy(ggi)
2418+
2419+ else prescribed_normal_flow
2420+
2421+ ! NOTE this v_over_relperm_dot_n does not contain the relperm terms
2422+ v_over_relperm_dot_n = dot_product(v_over_relperm_face_quad_bdy(:,ggi), normal_bdy(:,ggi))
2423+
2424+ ! This term includes the gradient pressure, gradient capilliary pressure
2425+ ! and the gravity term.
2426+ s_rhs_local_bdy(iloc) = s_rhs_local_bdy(iloc) - &
2427+ di%cached_face_value%relperm_bdy(isub_index,ggi,sele,p) * &
2428+ v_over_relperm_dot_n * &
2429+ detwei_bdy(ggi)
2430+
2431+ ! Add two extra terms associated with weak pressure BC's
2432+ pressure_weak: if (di%pressure_bc_flag(sele) == PRESSURE_BC_TYPE_WEAKDIRICHLET) then
2433+
2434+ ! Form the face value = detwei * (relperm*absperm/visc)
2435+ face_value = detwei_bdy(ggi) * &
2436+ di%cached_face_value%relperm_bdy(isub_index,ggi,sele,p) * &
2437+ absperm_ele_bdy(1) / &
2438+ visc_ele_bdy(1)
2439+
2440+ do jloc = 1, di%pressure_mesh%faces%shape%loc
2441+
2442+ s_rhs_local_bdy(iloc) = s_rhs_local_bdy(iloc) - &
2443+ inv_char_len_ele_bdy(jloc) * &
2444+ di%p_cvbdyshape%n(jloc,ggi) * &
2445+ bc_sele_val(jloc) * &
2446+ sum(normal_bdy(:,ggi)) * &
2447+ face_value * &
2448+ di%weak_pressure_bc_coeff
2449+
2450+ end do
2451+
2452+ do jloc = 1, di%pressure_mesh%faces%shape%loc
2453+
2454+ s_rhs_local_bdy(iloc) = s_rhs_local_bdy(iloc) + &
2455+ inv_char_len_ele_bdy(jloc) * &
2456+ di%p_cvbdyshape%n(jloc,ggi) * &
2457+ pressure_ele_bdy(jloc) * &
2458+ sum(normal_bdy(:,ggi)) * &
2459+ face_value * &
2460+ di%weak_pressure_bc_coeff
2461+
2462+ end do
2463+
2464+ end if pressure_weak
2465+
2466+ end if prescribed_normal_flow
2467+
2468+ end do bc_quad_loop
2469+
2470+ end if bc_neigh_if
2471+
2472+ end do bc_face_loop
2473+
2474+ end do bc_iloc_loop
2475+
2476+ call addto(di%rhs, p_nodes_bdy, s_rhs_local_bdy)
2477+
2478+ end do sele_loop
2479+
2480+ ! deallocate local variables as required
2481+ deallocate(x_ele)
2482+ if (di%cached_face_value%cached_detwei_normal) then
2483+ nullify(detwei)
2484+ nullify(normal)
2485+ else
2486+ deallocate(detwei)
2487+ deallocate(normal)
2488+ end if
2489+ deallocate(normgi)
2490+ deallocate(notvisited)
2491+ deallocate(s_rhs_local)
2492+ deallocate(x_face_quad)
2493+ deallocate(grad_pressure_face_quad)
2494+ deallocate(grav_ele)
2495+
2496+ deallocate(grav_ele_bdy)
2497+ deallocate(grad_pressure_face_quad_bdy)
2498+ deallocate(v_over_relperm_face_quad_bdy)
2499+ deallocate(bc_sele_val)
2500+ deallocate(pressure_ele_bdy)
2501+ deallocate(inv_char_len_ele_bdy)
2502+ if (di%cached_face_value%cached_detwei_normal) then
2503+ nullify(detwei_bdy)
2504+ nullify(normal_bdy)
2505+ else
2506+ deallocate(detwei_bdy)
2507+ deallocate(normal_bdy)
2508+ end if
2509+ deallocate(s_rhs_local_bdy)
2510+ deallocate(x_ele_bdy)
2511+ deallocate(p_nodes_bdy)
2512+
2513+ end subroutine darcy_impes_assemble_saturation_rhs_adv
2514+
2515+! ----------------------------------------------------------------------------
2516+
2517+ subroutine darcy_impes_assemble_and_solve_generic_prog_sfields(di)
2518+
2519+ !!< Assemble and solve generic prognostic scalar fields
2520+
2521+ type(darcy_impes_type), intent(inout) :: di
2522+
2523+ ! local variables
2524+ integer :: f, p
2525+
2526+ ewrite(1,*) 'Assemble and solve generic prognostic scalar fields'
2527+
2528+ sfield_loop: do f = 1, size(di%generic_prog_sfield)
2529+
2530+ p = di%generic_prog_sfield(f)%phase
2531+
2532+ call darcy_impes_assemble_and_solve_generic_prog_sfield(di, f, p)
2533+
2534+ end do sfield_loop
2535+
2536+ ewrite(1,*) 'Finished assemble and solve generic prognostic scalar fields'
2537+
2538+ end subroutine darcy_impes_assemble_and_solve_generic_prog_sfields
2539+
2540+! ----------------------------------------------------------------------------
2541+
2542+ subroutine darcy_impes_assemble_and_solve_generic_prog_sfield(di, f, p)
2543+
2544+ !!< Assemble and a solve generic prognostic scalar field given by index f and p
2545+
2546+ type(darcy_impes_type), intent(inout) :: di
2547+ integer, intent(in) :: f
2548+ integer, intent(in) :: p
2549+
2550+ ! local variables
2551+ integer :: i
2552+
2553+ ewrite(1,*) 'Assemble and solve sfield ',trim(di%generic_prog_sfield(f)%sfield%name),' of phase ',p
2554+
2555+ ! Get this phase v BC info - only for no_normal_flow and prescribed_normal_flow which is special as it is a scalar
2556+ call darcy_impes_get_v_boundary_condition(di%darcy_velocity(p)%ptr, &
2557+ (/"prescribed_normal_flow", &
2558+ "no_normal_flow "/), &
2559+ di%bc_surface_mesh, &
2560+ di%v_bc_value, &
2561+ di%v_bc_flag)
2562+
2563+ ! Get the pressure BC - required if no v given and weak pressure dirichlet given for extra integrals
2564+ call darcy_impes_get_entire_sfield_boundary_condition(di%pressure(1)%ptr, &
2565+ (/"weakdirichlet"/), &
2566+ di%bc_surface_mesh, &
2567+ di%pressure_bc_value, &
2568+ di%pressure_bc_flag)
2569+
2570+ ! Get the sfield BC
2571+ call darcy_impes_get_entire_sfield_boundary_condition(di%generic_prog_sfield(f)%sfield, &
2572+ (/"weakdirichlet"/), &
2573+ di%bc_surface_mesh, &
2574+ di%sfield_bc_value, &
2575+ di%sfield_bc_flag)
2576+
2577+ call zero(di%lhs)
2578+ call zero(di%matrix)
2579+ call zero(di%rhs)
2580+ call zero(di%rhs_full)
2581+
2582+ ! Add porosity*saturation(absorption + 1/dt) to lhs
2583+ if (di%generic_prog_sfield(f)%have_abs) then
2584+
2585+ call addto(di%lhs, di%generic_prog_sfield(f)%sfield_abs)
2586+
2587+ end if
2588+
2589+ call addto(di%lhs, 1.0/di%dt)
2590+ call scale(di%lhs, di%cv_mass_pressure_mesh_with_porosity)
2591+ call scale(di%lhs, di%saturation(p)%ptr)
2592+
2593+ ! Add old_porosity*old_saturation*old_sfield/dt to rhs
2594+ call addto(di%rhs, 1.0/di%dt)
2595+ call scale(di%rhs, di%cv_mass_pressure_mesh_with_old_porosity)
2596+ call scale(di%rhs, di%old_saturation(p)%ptr)
2597+ call scale(di%rhs, di%generic_prog_sfield(f)%old_sfield)
2598+
2599+ ! Add source to rhs
2600+ if (di%generic_prog_sfield(f)%have_src) then
2601+
2602+ call compute_cv_mass(di%positions, di%cv_mass_pressure_mesh_with_source, di%generic_prog_sfield(f)%sfield_src)
2603+
2604+ call addto(di%rhs, di%cv_mass_pressure_mesh_with_source)
2605+
2606+ end if
2607+
2608+ ! Add diagonal lhs to matrix
2609+ call addto_diag(di%matrix, di%lhs)
2610+
2611+ ! Add implicit low order advection and diffusion terms to matrix and rhs
2612+ if (di%generic_prog_sfield(f)%have_adv .or. di%generic_prog_sfield(f)%have_diff) then
2613+
2614+ call darcy_impes_assemble_generic_prog_sfield_adv_diff(di, f, p)
2615+
2616+ end if
2617+
2618+ ! Solve for each face value iteration (default is 1)
2619+ do i = 1, di%generic_prog_sfield(f)%sfield_cv_options%number_face_value_iteration
2620+
2621+ call set(di%rhs_full, di%rhs)
2622+
2623+ ! Assmemble the high resolution rhs and to to rhs_full
2624+ if (di%generic_prog_sfield(f)%have_adv .and. &
2625+ di%generic_prog_sfield(f)%sfield_cv_options%facevalue == DARCY_IMPES_CV_FACEVALUE_FINITEELEMENT) then
2626+
2627+ call zero(di%rhs_high_resolution)
2628+
2629+ call darcy_impes_assemble_generic_prog_sfield_rhs_high_resolution(di, f, p)
2630+
2631+ call addto(di%rhs_full, di%rhs_high_resolution)
2632+
2633+ end if
2634+
2635+ ! Apply any strong dirichlet BC's
2636+ call apply_dirichlet_conditions(di%matrix, di%rhs_full, di%generic_prog_sfield(f)%sfield)
2637+
2638+ ! Solve the sfield
2639+ call petsc_solve(di%generic_prog_sfield(f)%sfield, di%matrix, di%rhs_full, di%state(p))
2640+
2641+ ! Set the strong BC nodes to the values to be consistent
2642+ call set_dirichlet_consistent(di%generic_prog_sfield(f)%sfield)
2643+
2644+ end do
2645+
2646+ ewrite(1,*) 'Finished assemble and solve sfield ',trim(di%generic_prog_sfield(f)%sfield%name),' of phase ',p
2647+
2648+ end subroutine darcy_impes_assemble_and_solve_generic_prog_sfield
2649+
2650+! ----------------------------------------------------------------------------
2651+
2652+ subroutine darcy_impes_assemble_generic_prog_sfield_adv_diff(di, f, p)
2653+
2654+ !!< Assemble the advection and diffusion terms for the
2655+ !!< generic prognostic scalar field given by index f and p
2656+
2657+ type(darcy_impes_type), intent(inout) :: di
2658+ integer, intent(in) :: f
2659+ integer, intent(in) :: p
2660+
2661+ ! local variables
2662+ logical :: inflow
2663+ integer :: vele, iloc, oloc, jloc, face, gi, ggi, sele
2664+ real :: face_value, v_dot_n, income, sat_face_value
2665+ real, dimension(1) :: absperm_ele, visc_ele, porosity_ele
2666+ real, dimension(:,:), pointer :: grad_pressure_face_quad
2667+ real, dimension(:,:), pointer :: grav_ele
2668+ real, dimension(:,:,:), pointer :: diff_ele
2669+ real, dimension(:), pointer :: sat_ele
2670+ real, dimension(:,:), pointer :: x_ele
2671+ real, dimension(:,:,:), pointer :: p_dshape
2672+ real, dimension(:,:), pointer :: normal
2673+ real, dimension(:), pointer :: detwei
2674+ real, dimension(:), pointer :: normgi
2675+ logical, dimension(:), pointer :: notvisited
2676+ real, dimension(:,:), pointer :: matrix_local
2677+ real, dimension(:,:), pointer :: x_face_quad
2678+ integer, dimension(:), pointer :: x_pmesh_nodes
2679+ integer, dimension(:), pointer :: p_nodes
2680+ real, dimension(1) :: absperm_ele_bdy, visc_ele_bdy
2681+ real, dimension(:,:), pointer :: grav_ele_bdy
2682+ real, dimension(:), pointer :: ghost_sfield_ele_bdy
2683+ real, dimension(:,:), pointer :: grad_pressure_face_quad_bdy
2684+ real, dimension(:,:), pointer :: v_over_relperm_face_quad_bdy
2685+ real, dimension(:), pointer :: bc_sele_val
2686+ real, dimension(:), pointer :: pressure_ele_bdy
2687+ real, dimension(:), pointer :: inv_char_len_ele_bdy
2688+ real, dimension(:,:), pointer :: normal_bdy
2689+ real, dimension(:), pointer :: detwei_bdy
2690+ real, dimension(:,:), pointer :: x_ele_bdy
2691+ real, dimension(:), pointer :: rhs_local_bdy
2692+ real, dimension(:), pointer :: matrix_local_bdy
2693+ integer, dimension(:), pointer :: p_nodes_bdy
2694+ integer, parameter :: V_BC_TYPE_PRESCRIBED_NORMAL_FLOW = 1, V_BC_TYPE_NO_NORMAL_FLOW = 2
2695+ integer, parameter :: PRESSURE_BC_TYPE_WEAKDIRICHLET = 1
2696+ integer, parameter :: SFIELD_BC_TYPE_WEAKDIRICHLET = 1
2697+
2698+ ! allocate arrays used in assemble process - many assume
2699+ ! that all elements are the same type.
2700+ allocate(x_ele(di%ndim, ele_loc(di%positions,1)))
2701+ if (.not. di%cached_face_value%cached_p_dshape) then
2702+ allocate(p_dshape(ele_loc(di%pressure_mesh,1), di%p_cvshape%ngi, mesh_dim(di%pressure_mesh)))
2703+ end if
2704+ if (.not. di%cached_face_value%cached_detwei_normal) then
2705+ allocate(normal(di%ndim,di%x_cvshape%ngi))
2706+ allocate(detwei(di%x_cvshape%ngi))
2707+ end if
2708+ allocate(normgi(di%ndim))
2709+ allocate(notvisited(di%x_cvshape%ngi))
2710+ allocate(matrix_local(ele_loc(di%pressure_mesh,1),ele_loc(di%pressure_mesh,1)))
2711+ allocate(x_face_quad(di%ndim, di%x_cvshape%ngi))
2712+ allocate(grad_pressure_face_quad(di%ndim, di%p_cvshape%ngi))
2713+ allocate(grav_ele(di%ndim,1))
2714+ allocate(diff_ele(di%ndim,di%ndim,1))
2715+ allocate(sat_ele(ele_loc(di%positions,1)))
2716+
2717+ allocate(grav_ele_bdy(di%ndim,1))
2718+ allocate(ghost_sfield_ele_bdy(face_loc(di%pressure_mesh,1)))
2719+ allocate(grad_pressure_face_quad_bdy(di%ndim, di%p_cvbdyshape%ngi))
2720+ allocate(v_over_relperm_face_quad_bdy(di%ndim, di%p_cvbdyshape%ngi))
2721+ allocate(bc_sele_val(face_loc(di%pressure_mesh,1)))
2722+ allocate(pressure_ele_bdy(face_loc(di%pressure_mesh,1)))
2723+ allocate(inv_char_len_ele_bdy(face_loc(di%pressure_mesh,1)))
2724+ if (.not. di%cached_face_value%cached_detwei_normal) then
2725+ allocate(detwei_bdy(di%x_cvbdyshape%ngi))
2726+ allocate(normal_bdy(di%ndim, di%x_cvbdyshape%ngi))
2727+ end if
2728+ allocate(rhs_local_bdy(face_loc(di%pressure_mesh,1)))
2729+ allocate(matrix_local_bdy(face_loc(di%pressure_mesh,1)))
2730+ allocate(x_ele_bdy(di%ndim, face_loc(di%positions,1)))
2731+ allocate(p_nodes_bdy(face_loc(di%pressure_mesh,1)))
2732+
2733+ ! Loop volume elements assembling local contributions
2734+ vol_element_loop: do vele = 1, di%number_vele
2735+
2736+ ! The node indices of the pressure mesh (which saturation is associated with)
2737+ p_nodes => ele_nodes(di%pressure_mesh, vele)
2738+
2739+ ! The node indices of the positions projected to the pressure mesh (which saturation is associated with)
2740+ x_pmesh_nodes => ele_nodes(di%positions_pressure_mesh, vele)
2741+
2742+ ! The gravity values for this element for each direction
2743+ grav_ele = ele_val(di%gravity, vele)
2744+
2745+ ! get the viscosity value for this element
2746+ visc_ele = ele_val(di%viscosity(p)%ptr, vele)
2747+
2748+ ! get the absolute permeability value for this element
2749+ absperm_ele = ele_val(di%absolute_permeability, vele)
2750+
2751+ ! get the latest gradient pressure at the cv surface quadrature points for each direction
2752+ grad_pressure_face_quad = ele_val_at_quad(di%gradient_pressure(p)%ptr, vele, di%gradp_cvshape)
2753+
2754+ ! obtain the transformed determinant*weight and normals
2755+ if (di%cached_face_value%cached_detwei_normal) then
2756+
2757+ detwei => di%cached_face_value%detwei(:,vele)
2758+
2759+ normal => di%cached_face_value%normal(:,:,vele)
2760+
2761+ else
2762+
2763+ ! get the coordinate values for this element for each positions local node
2764+ x_ele = ele_val(di%positions, vele)
2765+
2766+ ! get the coordinate values for this element for each quadrature point
2767+ x_face_quad = ele_val_at_quad(di%positions, vele, di%x_cvshape)
2768+
2769+ call transform_cvsurf_to_physical(x_ele, di%x_cvshape, detwei, normal, di%cvfaces)
2770+
2771+ end if
2772+
2773+ if (di%generic_prog_sfield(f)%have_diff) then
2774+
2775+ ! get the sfield diffusivity
2776+ diff_ele = ele_val(di%generic_prog_sfield(f)%sfield_diff,vele)
2777+
2778+ ! get the element values for porosity
2779+ porosity_ele = ele_val(di%porosity, vele)
2780+
2781+ ! get the element values for saturation
2782+ sat_ele = ele_val(di%saturation(p)%ptr, vele)
2783+
2784+ ! obtain the derivative of the pressure mesh shape function at the CV face quadrature points
2785+ if (di%cached_face_value%cached_p_dshape) then
2786+
2787+ p_dshape => di%cached_face_value%p_dshape(:,:,:,vele)
2788+
2789+ else
2790+
2791+ call transform_to_physical(di%positions, vele, x_shape = di%x_cvshape_full, &
2792+ shape = di%p_cvshape_full, dshape = p_dshape)
2793+
2794+ end if
2795+
2796+ end if
2797+
2798+ ! Initialise array for the quadrature points of this
2799+ ! element for whether it has already been visited
2800+ notvisited = .true.
2801+
2802+ ! Initialise the local matrix to assemble for this element
2803+ matrix_local = 0.0
2804+
2805+ ! loop over local nodes within this element
2806+ nodal_loop_i: do iloc = 1, di%pressure_mesh%shape%loc
2807+
2808+ ! loop over CV faces internal to this element
2809+ face_loop: do face = 1, di%cvfaces%faces
2810+
2811+ ! is this a face neighbouring iloc?
2812+ is_neigh: if(di%cvfaces%neiloc(iloc, face) /= 0) then
2813+
2814+ ! find the opposing local node across the CV face
2815+ oloc = di%cvfaces%neiloc(iloc, face)
2816+
2817+ ! loop over gauss points on face
2818+ quadrature_loop: do gi = 1, di%cvfaces%shape%ngi
2819+
2820+ ! global gauss pt index for this element
2821+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
2822+
2823+ ! check if this quadrature point has already been visited
2824+ check_visited: if(notvisited(ggi)) then
2825+
2826+ notvisited(ggi) = .false.
2827+
2828+ if (di%cached_face_value%cached_detwei_normal) then
2829+
2830+ ! cached normal has correct orientation already
2831+ normgi = normal(:,ggi)
2832+
2833+ else
2834+
2835+ ! correct the orientation of the normal so it points away from iloc
2836+ normgi = orientate_cvsurf_normgi(node_val(di%positions_pressure_mesh, x_pmesh_nodes(iloc)), &
2837+ &x_face_quad(:,ggi), normal(:,ggi))
2838+
2839+ end if
2840+
2841+ v_dot_n = - di%cached_face_value%relperm(1,ggi,vele,p) * absperm_ele(1) * &
2842+dot_product((grad_pressure_face_quad(:,ggi) - di%cached_face_value%den(ggi,vele,p) * grav_ele(:,1)), normgi)/ visc_ele(1)
2843+
2844+ inflow = (v_dot_n<=0.0)
2845+
2846+ income = merge(1.0,0.0,inflow)
2847+
2848+ if (di%generic_prog_sfield(f)%have_adv) then
2849+
2850+ matrix_local(iloc, oloc) = matrix_local(iloc, oloc) + &
2851+ detwei(ggi) * &
2852+ v_dot_n * &
2853+ income
2854+
2855+ matrix_local(oloc, iloc) = matrix_local(oloc, iloc) + &
2856+ detwei(ggi) * &
2857+ (-v_dot_n) * &
2858+ (1.0-income)
2859+
2860+ matrix_local(iloc, iloc) = matrix_local(iloc, iloc) + &
2861+ detwei(ggi) * &
2862+ v_dot_n * &
2863+ (1.0-income)
2864+
2865+ matrix_local(oloc, oloc) = matrix_local(oloc, oloc) + &
2866+ detwei(ggi) * &
2867+ (-v_dot_n) * &
2868+ income
2869+
2870+ end if
2871+
2872+ if (di%generic_prog_sfield(f)%have_diff) then
2873+
2874+ ! Find the diffusion term saturation face value (taking upwind)
2875+ sat_face_value = income*sat_ele(oloc) + (1.0-income)*sat_ele(iloc)
2876+
2877+ do jloc=1, di%pressure_mesh%shape%loc
2878+
2879+ matrix_local(iloc,jloc) = matrix_local(iloc,jloc) - &
2880+ sum(matmul(diff_ele(:,:,1), p_dshape(jloc, ggi, :))*normgi, 1) * &
2881+ porosity_ele(1) * &
2882+ sat_face_value * &
2883+ detwei(ggi)
2884+
2885+ matrix_local(oloc, jloc) = matrix_local(oloc,jloc) - &
2886+ sum(matmul(diff_ele(:,:,1), p_dshape(jloc, ggi, :))*(-normgi), 1) * &
2887+ porosity_ele(1) * &
2888+ sat_face_value * &
2889+ detwei(ggi)
2890+
2891+ end do
2892+
2893+ end if
2894+
2895+ end if check_visited
2896+
2897+ end do quadrature_loop
2898+
2899+ end if is_neigh
2900+
2901+ end do face_loop
2902+
2903+ end do nodal_loop_i
2904+
2905+ call addto(di%matrix, p_nodes, p_nodes, matrix_local)
2906+
2907+ end do vol_element_loop
2908+
2909+ ! Add BC integrals associated with an advection term (diffusive flux is assumed zero on all boundary)
2910+
2911+ have_adv_so_add_bc: if (di%generic_prog_sfield(f)%have_adv) then
2912+
2913+ sele_loop: do sele = 1, di%number_sele
2914+
2915+ if (di%v_bc_flag(sele) == V_BC_TYPE_NO_NORMAL_FLOW) cycle sele_loop
2916+
2917+ p_nodes_bdy = face_global_nodes(di%pressure_mesh, sele)
2918+
2919+ ! obtain the transformed determinant*weight and normals
2920+ if (di%cached_face_value%cached_detwei_normal) then
2921+
2922+ detwei_bdy => di%cached_face_value%detwei_bdy(:,sele)
2923+
2924+ normal_bdy => di%cached_face_value%normal_bdy(:,:,sele)
2925+
2926+ else
2927+
2928+ x_ele = ele_val(di%positions, face_ele(di%positions, sele))
2929+ x_ele_bdy = face_val(di%positions, sele)
2930+
2931+ call transform_cvsurf_facet_to_physical(x_ele, x_ele_bdy, di%x_cvbdyshape, normal_bdy, detwei_bdy)
2932+
2933+ end if
2934+
2935+ if (di%v_bc_flag(sele) == V_BC_TYPE_PRESCRIBED_NORMAL_FLOW) then
2936+
2937+ bc_sele_val = ele_val(di%v_bc_value, sele)
2938+
2939+ else
2940+
2941+ visc_ele_bdy = face_val(di%viscosity(p)%ptr, sele)
2942+ absperm_ele_bdy = face_val(di%absolute_permeability, sele)
2943+ inv_char_len_ele_bdy = ele_val(di%inverse_characteristic_length, sele)
2944+ if (di%pressure_bc_flag(sele) == PRESSURE_BC_TYPE_WEAKDIRICHLET) then
2945+ bc_sele_val = ele_val(di%pressure_bc_value, sele)
2946+ end if
2947+ grad_pressure_face_quad_bdy = face_val_at_quad(di%gradient_pressure(p)%ptr, sele, di%gradp_cvbdyshape)
2948+ grav_ele_bdy = face_val(di%gravity, sele)
2949+ pressure_ele_bdy = face_val(di%pressure(p)%ptr, sele)
2950+
2951+ end if
2952+
2953+ if (di%sfield_bc_flag(sele) == SFIELD_BC_TYPE_WEAKDIRICHLET) then
2954+ ghost_sfield_ele_bdy = ele_val(di%sfield_bc_value, sele)
2955+ else
2956+ ghost_sfield_ele_bdy = face_val(di%generic_prog_sfield(f)%sfield, sele)
2957+ end if
2958+
2959+ ! Initialise the local arrays to assemble for this element
2960+ rhs_local_bdy = 0.0
2961+ matrix_local_bdy = 0.0
2962+
2963+ bc_iloc_loop: do iloc = 1, di%pressure_mesh%faces%shape%loc
2964+
2965+ bc_face_loop: do face = 1, di%cvfaces%sfaces
2966+
2967+ bc_neigh_if: if(di%cvfaces%sneiloc(iloc,face)/=0) then
2968+
2969+ bc_quad_loop: do gi = 1, di%cvfaces%shape%ngi
2970+
2971+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
2972+
2973+ prescribed_normal_flow: if (di%v_bc_flag(sele) == V_BC_TYPE_PRESCRIBED_NORMAL_FLOW) then
2974+
2975+ if (bc_sele_val(iloc) <= 0) then
2976+
2977+ income = 1.0
2978+
2979+ else
2980+
2981+ income = 0.0
2982+
2983+ end if
2984+
2985+ rhs_local_bdy(iloc) = rhs_local_bdy(iloc) - &
2986+ bc_sele_val(iloc) * &
2987+ ghost_sfield_ele_bdy(iloc) * &
2988+ detwei_bdy(ggi) * &
2989+ income
2990+
2991+ matrix_local_bdy(iloc) = matrix_local_bdy(iloc) + &
2992+ bc_sele_val(iloc) * &
2993+ detwei_bdy(ggi) * &
2994+ (1.0 - income)
2995+
2996+ else prescribed_normal_flow
2997+
2998+ v_dot_n = - di%cached_face_value%relperm_bdy(1,ggi,sele,p) * absperm_ele_bdy(1) * &
2999+dot_product((grad_pressure_face_quad_bdy(:,ggi) - di%cached_face_value%den_bdy(ggi,sele,p) * grav_ele_bdy(:,1)), normal_bdy(:,ggi))/ visc_ele_bdy(1)
3000+
3001+ if (v_dot_n <= 0) then
3002+
3003+ income = 1.0
3004+
3005+ else
3006+
3007+ income = 0.0
3008+
3009+ end if
3010+
3011+ rhs_local_bdy(iloc) = rhs_local_bdy(iloc) - &
3012+ v_dot_n * &
3013+ ghost_sfield_ele_bdy(iloc) * &
3014+ detwei_bdy(ggi) * &
3015+ income
3016+
3017+ matrix_local_bdy(iloc) = matrix_local_bdy(iloc) + &
3018+ v_dot_n * &
3019+ detwei_bdy(ggi) * &
3020+ (1.0 - income)
3021+
3022+ ! Add two extra terms associated with weak pressure BC's
3023+ pressure_weak: if (di%pressure_bc_flag(sele) == PRESSURE_BC_TYPE_WEAKDIRICHLET) then
3024+
3025+ ! Form the face value = detwei * (relperm*absperm/visc)
3026+ face_value = detwei_bdy(ggi) * &
3027+ di%cached_face_value%relperm_bdy(1,ggi,sele,p) * &
3028+ absperm_ele_bdy(1) / &
3029+ visc_ele_bdy(1)
3030+
3031+ do jloc = 1, di%pressure_mesh%faces%shape%loc
3032+
3033+ rhs_local_bdy(iloc) = rhs_local_bdy(iloc) - &
3034+ inv_char_len_ele_bdy(jloc) * &
3035+ di%p_cvbdyshape%n(jloc,ggi) * &
3036+ bc_sele_val(jloc) * &
3037+ sum(normal_bdy(:,ggi)) * &
3038+ face_value * &
3039+ ghost_sfield_ele_bdy(iloc) * &
3040+ di%weak_pressure_bc_coeff * &
3041+ income
3042+
3043+ matrix_local_bdy(iloc) = matrix_local_bdy(iloc) - &
3044+ inv_char_len_ele_bdy(jloc) * &
3045+ di%p_cvbdyshape%n(jloc,ggi) * &
3046+ bc_sele_val(jloc) * &
3047+ sum(normal_bdy(:,ggi)) * &
3048+ face_value * &
3049+ di%weak_pressure_bc_coeff * &
3050+ (1.0 - income)
3051+
3052+ end do
3053+
3054+ do jloc = 1, di%pressure_mesh%faces%shape%loc
3055+
3056+ rhs_local_bdy(iloc) = rhs_local_bdy(iloc) + &
3057+ inv_char_len_ele_bdy(jloc) * &
3058+ di%p_cvbdyshape%n(jloc,ggi) * &
3059+ pressure_ele_bdy(jloc) * &
3060+ sum(normal_bdy(:,ggi)) * &
3061+ face_value * &
3062+ ghost_sfield_ele_bdy(iloc) * &
3063+ di%weak_pressure_bc_coeff * &
3064+ income
3065+
3066+ matrix_local_bdy(iloc) = matrix_local_bdy(iloc) + &
3067+ inv_char_len_ele_bdy(jloc) * &
3068+ di%p_cvbdyshape%n(jloc,ggi) * &
3069+ pressure_ele_bdy(jloc) * &
3070+ sum(normal_bdy(:,ggi)) * &
3071+ face_value * &
3072+ di%weak_pressure_bc_coeff * &
3073+ (1.0 - income)
3074+
3075+ end do
3076+
3077+ end if pressure_weak
3078+
3079+ end if prescribed_normal_flow
3080+
3081+ end do bc_quad_loop
3082+
3083+ end if bc_neigh_if
3084+
3085+ end do bc_face_loop
3086+
3087+ end do bc_iloc_loop
3088+
3089+ call addto(di%rhs, p_nodes_bdy, rhs_local_bdy)
3090+
3091+ call addto_diag(di%matrix, p_nodes_bdy, matrix_local_bdy)
3092+
3093+ end do sele_loop
3094+
3095+ end if have_adv_so_add_bc
3096+
3097+ ! deallocate local variables as required
3098+ deallocate(x_ele)
3099+ if (di%cached_face_value%cached_p_dshape) then
3100+ nullify(p_dshape)
3101+ else
3102+ deallocate(p_dshape)
3103+ end if
3104+ if (di%cached_face_value%cached_detwei_normal) then
3105+ nullify(detwei)
3106+ nullify(normal)
3107+ else
3108+ deallocate(detwei)
3109+ deallocate(normal)
3110+ end if
3111+ deallocate(normgi)
3112+ deallocate(notvisited)
3113+ deallocate(matrix_local)
3114+ deallocate(x_face_quad)
3115+ deallocate(grad_pressure_face_quad)
3116+ deallocate(grav_ele)
3117+ deallocate(diff_ele)
3118+ deallocate(sat_ele)
3119+
3120+ deallocate(grav_ele_bdy)
3121+ deallocate(ghost_sfield_ele_bdy)
3122+ deallocate(grad_pressure_face_quad_bdy)
3123+ deallocate(v_over_relperm_face_quad_bdy)
3124+ deallocate(bc_sele_val)
3125+ deallocate(pressure_ele_bdy)
3126+ deallocate(inv_char_len_ele_bdy)
3127+ if (di%cached_face_value%cached_detwei_normal) then
3128+ nullify(detwei_bdy)
3129+ nullify(normal_bdy)
3130+ else
3131+ deallocate(detwei_bdy)
3132+ deallocate(normal_bdy)
3133+ end if
3134+ deallocate(rhs_local_bdy)
3135+ deallocate(matrix_local_bdy)
3136+ deallocate(x_ele_bdy)
3137+ deallocate(p_nodes_bdy)
3138+
3139+ end subroutine darcy_impes_assemble_generic_prog_sfield_adv_diff
3140+
3141+! ----------------------------------------------------------------------------
3142+
3143+ subroutine darcy_impes_assemble_generic_prog_sfield_rhs_high_resolution(di, f, p)
3144+
3145+ !!< Assemble the advection high resolution terms for the
3146+ !!< generic prognostic scalar field given by index f and p
3147+
3148+ type(darcy_impes_type), intent(inout) :: di
3149+ integer, intent(in) :: f
3150+ integer, intent(in) :: p
3151+
3152+ ! local variables
3153+ logical :: inflow
3154+ integer :: vele, iloc, oloc, face, gi, ggi, s_upwind_pos
3155+ real :: v_dot_n, income, sfield_face_value, sfield_low_face_value, sfield_high_face_value
3156+ real, dimension(1) :: absperm_ele, visc_ele
3157+ real, dimension(:,:), pointer :: grad_pressure_face_quad
3158+ real, dimension(:,:), pointer :: grav_ele
3159+ real, dimension(:), pointer :: sfield_ele
3160+ real, dimension(:,:), pointer :: x_ele
3161+ real, dimension(:,:,:), pointer :: p_dshape
3162+ real, dimension(:,:), pointer :: normal
3163+ real, dimension(:), pointer :: detwei
3164+ real, dimension(:), pointer :: normgi
3165+ logical, dimension(:), pointer :: notvisited
3166+ real, dimension(:), pointer :: rhs_local
3167+ real, dimension(:,:), pointer :: x_face_quad
3168+ integer, dimension(:), pointer :: x_pmesh_nodes
3169+ integer, dimension(:), pointer :: p_nodes
3170+ integer, dimension(:), pointer :: s_upwind_nodes
3171+
3172+ ! allocate arrays used in assemble process - many assume
3173+ ! that all elements are the same type.
3174+ allocate(x_ele(di%ndim, ele_loc(di%positions,1)))
3175+ if (.not. di%cached_face_value%cached_p_dshape) then
3176+ allocate(p_dshape(ele_loc(di%pressure_mesh,1), di%p_cvshape%ngi, mesh_dim(di%pressure_mesh)))
3177+ end if
3178+ if (.not. di%cached_face_value%cached_detwei_normal) then
3179+ allocate(normal(di%ndim,di%x_cvshape%ngi))
3180+ allocate(detwei(di%x_cvshape%ngi))
3181+ end if
3182+ allocate(normgi(di%ndim))
3183+ allocate(notvisited(di%x_cvshape%ngi))
3184+ allocate(rhs_local(ele_loc(di%pressure_mesh,1)))
3185+ allocate(x_face_quad(di%ndim, di%x_cvshape%ngi))
3186+ allocate(grad_pressure_face_quad(di%ndim, di%p_cvshape%ngi))
3187+ allocate(grav_ele(di%ndim,1))
3188+ allocate(sfield_ele(ele_loc(di%positions,1)))
3189+
3190+ if(di%generic_prog_sfield(f)%sfield_cv_options%limit_facevalue) then
3191+
3192+ ! NOTE only new upwind values are required but this procedure
3193+ ! expects latest and old. So pass in new twice - not optimal
3194+ call find_upwind_values(di%state, &
3195+ di%positions_pressure_mesh, &
3196+ di%generic_prog_sfield(f)%sfield, &
3197+ di%sfield_upwind, &
3198+ di%generic_prog_sfield(f)%sfield, &
3199+ di%sfield_upwind, &
3200+ option_path = trim(di%generic_prog_sfield(f)%sfield%option_path))
3201+
3202+ end if
3203+
3204+ ! Initialise optimisation flag used in finding upwind value in high resolution schemes
3205+ s_upwind_pos = 0
3206+
3207+ ! Loop volume elements assembling local contributions
3208+ vol_element_loop: do vele = 1, di%number_vele
3209+
3210+ ! The node indices of the pressure mesh (which saturation is associated with)
3211+ p_nodes => ele_nodes(di%pressure_mesh, vele)
3212+
3213+ ! The node indices of the positions projected to the pressure mesh (which saturation is associated with)
3214+ x_pmesh_nodes => ele_nodes(di%positions_pressure_mesh, vele)
3215+
3216+ ! The gravity values for this element for each direction
3217+ grav_ele = ele_val(di%gravity, vele)
3218+
3219+ ! get the viscosity value for this element
3220+ visc_ele = ele_val(di%viscosity(p)%ptr, vele)
3221+
3222+ ! get the absolute permeability value for this element
3223+ absperm_ele = ele_val(di%absolute_permeability, vele)
3224+
3225+ ! get the latest gradient pressure at the cv surface quadrature points for each direction
3226+ grad_pressure_face_quad = ele_val_at_quad(di%gradient_pressure(p)%ptr, vele, di%gradp_cvshape)
3227+
3228+ ! get the sfield value for this element
3229+ sfield_ele = ele_val(di%generic_prog_sfield(f)%sfield, vele)
3230+
3231+ ! Determine the node numbers to use to determine the sfield upwind values
3232+ if((di%generic_prog_sfield(f)%sfield_cv_options%upwind_scheme == CV_UPWINDVALUE_PROJECT_POINT).or.&
3233+ (di%generic_prog_sfield(f)%sfield_cv_options%upwind_scheme == CV_UPWINDVALUE_PROJECT_GRAD)) then
3234+
3235+ s_upwind_nodes => x_pmesh_nodes
3236+
3237+ else
3238+
3239+ s_upwind_nodes => p_nodes
3240+
3241+ end if
3242+
3243+ ! obtain the transformed determinant*weight and normals
3244+ if (di%cached_face_value%cached_detwei_normal) then
3245+
3246+ detwei => di%cached_face_value%detwei(:,vele)
3247+
3248+ normal => di%cached_face_value%normal(:,:,vele)
3249+
3250+ else
3251+
3252+ ! get the coordinate values for this element for each positions local node
3253+ x_ele = ele_val(di%positions, vele)
3254+
3255+ ! get the coordinate values for this element for each quadrature point
3256+ x_face_quad = ele_val_at_quad(di%positions, vele, di%x_cvshape)
3257+
3258+ call transform_cvsurf_to_physical(x_ele, di%x_cvshape, detwei, normal, di%cvfaces)
3259+
3260+ end if
3261+
3262+ ! Initialise array for the quadrature points of this
3263+ ! element for whether it has already been visited
3264+ notvisited = .true.
3265+
3266+ ! Initialise the local rhs to assemble for this element
3267+ rhs_local = 0.0
3268+
3269+ ! loop over local nodes within this element
3270+ nodal_loop_i: do iloc = 1, di%pressure_mesh%shape%loc
3271+
3272+ ! loop over CV faces internal to this element
3273+ face_loop: do face = 1, di%cvfaces%faces
3274+
3275+ ! is this a face neighbouring iloc?
3276+ is_neigh: if(di%cvfaces%neiloc(iloc, face) /= 0) then
3277+
3278+ ! find the opposing local node across the CV face
3279+ oloc = di%cvfaces%neiloc(iloc, face)
3280+
3281+ ! loop over gauss points on face
3282+ quadrature_loop: do gi = 1, di%cvfaces%shape%ngi
3283+
3284+ ! global gauss pt index for this element
3285+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
3286+
3287+ ! check if this quadrature point has already been visited
3288+ check_visited: if(notvisited(ggi)) then
3289+
3290+ notvisited(ggi) = .false.
3291+
3292+ if (di%cached_face_value%cached_detwei_normal) then
3293+
3294+ ! cached normal has correct orientation already
3295+ normgi = normal(:,ggi)
3296+
3297+ else
3298+
3299+ ! correct the orientation of the normal so it points away from iloc
3300+ normgi = orientate_cvsurf_normgi(node_val(di%positions_pressure_mesh, x_pmesh_nodes(iloc)), &
3301+ &x_face_quad(:,ggi), normal(:,ggi))
3302+
3303+ end if
3304+
3305+ v_dot_n = - di%cached_face_value%relperm(1,ggi,vele,p) * absperm_ele(1) * &
3306+dot_product((grad_pressure_face_quad(:,ggi) - di%cached_face_value%den(ggi,vele,p) * grav_ele(:,1)), normgi)/ visc_ele(1)
3307+
3308+ inflow = (v_dot_n<=0.0)
3309+
3310+ income = merge(1.0,0.0,inflow)
3311+
3312+ ! form the high resolution face value
3313+ call darcy_impes_evaluate_sfield_face_val(sfield_high_face_value, &
3314+ iloc, &
3315+ oloc, &
3316+ ggi, &
3317+ s_upwind_nodes, &
3318+ di%p_cvshape, &
3319+ sfield_ele, &
3320+ di%sfield_upwind, &
3321+ inflow, &
3322+ income, &
3323+ di%generic_prog_sfield(f)%sfield_cv_options, &
3324+ save_pos = s_upwind_pos)
3325+
3326+ ! form and add the lower order iterated term to rhs
3327+ sfield_low_face_value = income*sfield_ele(oloc) + (1.0-income)*sfield_ele(iloc)
3328+
3329+ ! form the rhs face value and add to the rhs field
3330+ sfield_face_value = sfield_low_face_value - sfield_high_face_value
3331+
3332+ rhs_local(iloc) = rhs_local(iloc) + &
3333+ sfield_face_value * &
3334+ v_dot_n * &
3335+ detwei(ggi)
3336+
3337+ rhs_local(oloc) = rhs_local(oloc) - &
3338+ sfield_face_value * &
3339+ v_dot_n * &
3340+ detwei(ggi)
3341+
3342+ end if check_visited
3343+
3344+ end do quadrature_loop
3345+
3346+ end if is_neigh
3347+
3348+ end do face_loop
3349+
3350+ end do nodal_loop_i
3351+
3352+ call addto(di%rhs_high_resolution, p_nodes, rhs_local)
3353+
3354+ end do vol_element_loop
3355+
3356+ ! deallocate local variables as required
3357+ deallocate(x_ele)
3358+ if (di%cached_face_value%cached_p_dshape) then
3359+ nullify(p_dshape)
3360+ else
3361+ deallocate(p_dshape)
3362+ end if
3363+ if (di%cached_face_value%cached_detwei_normal) then
3364+ nullify(detwei)
3365+ nullify(normal)
3366+ else
3367+ deallocate(detwei)
3368+ deallocate(normal)
3369+ end if
3370+ deallocate(normgi)
3371+ deallocate(notvisited)
3372+ deallocate(rhs_local)
3373+ deallocate(x_face_quad)
3374+ deallocate(grad_pressure_face_quad)
3375+ deallocate(grav_ele)
3376+ deallocate(sfield_ele)
3377+
3378+ end subroutine darcy_impes_assemble_generic_prog_sfield_rhs_high_resolution
3379+
3380+! ----------------------------------------------------------------------------
3381+
3382+ subroutine darcy_impes_calculate_phase_one_saturation_diagnostic(di)
3383+
3384+ !!< Calculate the first phase diagnostic saturation as 1.0 - the rest
3385+
3386+ type(darcy_impes_type), intent(inout) :: di
3387+
3388+ ! local variables
3389+ integer :: p
3390+
3391+ ewrite(1,*) 'Calculate phase 1 diagnostic Saturation'
3392+
3393+ call set(di%saturation(1)%ptr, 1.0)
3394+
3395+ do p = 2, di%number_phase
3396+
3397+ call addto(di%saturation(1)%ptr, di%saturation(p)%ptr, scale = -1.0)
3398+
3399+ end do
3400+
3401+ ewrite_minmax(di%saturation(1)%ptr)
3402+
3403+ end subroutine darcy_impes_calculate_phase_one_saturation_diagnostic
3404+
3405+! ----------------------------------------------------------------------------
3406+
3407+ subroutine darcy_impes_calculate_vel_mob_ff_and_cfl_fields(di)
3408+
3409+ !!< Calculate the various velocities, mobilities, fractional flows, and CFL fields
3410+
3411+ type(darcy_impes_type), intent(inout) :: di
3412+
3413+ ! local variables
3414+ type(vector_field) :: aux_vfield
3415+ logical :: inflow
3416+ integer :: vele, p, dim, iloc, oloc, face, gi, ggi, sele
3417+ real :: income, v_dot_n
3418+ real, dimension(1) :: visc_ele, absperm_ele
3419+ real, dimension(:,:), pointer :: grad_pressure_face_quad
3420+ real, dimension(:,:), pointer :: v_local
3421+ real, dimension(:), pointer :: m_local
3422+ real, dimension(:,:), pointer :: grav_ele
3423+ real, dimension(:,:), pointer :: x_ele
3424+ real, dimension(:,:), pointer :: normal
3425+ real, dimension(:), pointer :: detwei
3426+ real, dimension(:), pointer :: normgi
3427+ logical, dimension(:), pointer :: notvisited
3428+ real, dimension(:), pointer :: cfl_rhs_local
3429+ real, dimension(:,:), pointer :: x_face_quad
3430+ integer, dimension(:), pointer :: x_pmesh_nodes
3431+ integer, dimension(:), pointer :: p_nodes
3432+ real, dimension(1) :: visc_ele_bdy, absperm_ele_bdy
3433+ real, dimension(:,:), pointer :: grav_ele_bdy
3434+ real, dimension(:,:), pointer :: grad_pressure_face_quad_bdy
3435+ real, dimension(:,:), pointer :: normal_bdy
3436+ real, dimension(:), pointer :: detwei_bdy
3437+ real, dimension(:,:), pointer :: x_ele_bdy
3438+ real, dimension(:), pointer :: cfl_rhs_local_bdy
3439+ real, dimension(:,:), pointer :: v_local_bdy
3440+ real, dimension(:), pointer :: m_local_bdy
3441+ integer, dimension(:), pointer :: p_nodes_bdy
3442+ real, dimension(:), pointer :: bc_sele_val
3443+ integer, parameter :: V_BC_TYPE_PRESCRIBED_NORMAL_FLOW = 1, V_BC_TYPE_NO_NORMAL_FLOW = 2
3444+
3445+ ewrite(1,*) 'Calculate CFL, Velocity, Mobilities and FractionalFlow fields'
3446+
3447+ ! allocate arrays used in CFL assemble process - many assume
3448+ ! that all elements are the same type.
3449+ allocate(x_ele(di%ndim, ele_loc(di%positions,1)))
3450+ if (.not. di%cached_face_value%cached_detwei_normal) then
3451+ allocate(normal(di%ndim,di%x_cvshape%ngi))
3452+ allocate(detwei(di%x_cvshape%ngi))
3453+ end if
3454+ allocate(normgi(di%ndim))
3455+ allocate(notvisited(di%x_cvshape%ngi))
3456+ allocate(cfl_rhs_local(ele_loc(di%pressure_mesh,1)))
3457+ allocate(x_face_quad(di%ndim, di%x_cvshape%ngi))
3458+ allocate(grad_pressure_face_quad(di%ndim, di%p_cvshape%ngi))
3459+ allocate(grav_ele(di%ndim,1))
3460+
3461+ allocate(grav_ele_bdy(di%ndim,1))
3462+ allocate(grad_pressure_face_quad_bdy(di%ndim, di%p_cvbdyshape%ngi))
3463+ if (.not. di%cached_face_value%cached_detwei_normal) then
3464+ allocate(detwei_bdy(di%x_cvbdyshape%ngi))
3465+ allocate(normal_bdy(di%ndim, di%x_cvbdyshape%ngi))
3466+ end if
3467+ allocate(cfl_rhs_local_bdy(face_loc(di%pressure_mesh,1)))
3468+ allocate(x_ele_bdy(di%ndim, face_loc(di%positions,1)))
3469+ allocate(p_nodes_bdy(face_loc(di%pressure_mesh,1)))
3470+ allocate(bc_sele_val(face_loc(di%pressure_mesh,1)))
3471+
3472+ allocate(v_local(di%ndim,ele_loc(di%pressure_mesh,1)))
3473+ allocate(m_local(ele_loc(di%pressure_mesh,1)))
3474+ allocate(v_local_bdy(di%ndim,face_loc(di%pressure_mesh,1)))
3475+ allocate(m_local_bdy(face_loc(di%pressure_mesh,1)))
3476+
3477+ phase_loop: do p = 1, di%number_phase
3478+
3479+ call zero(di%cfl(p)%ptr)
3480+
3481+ call zero(di%darcy_velocity(p)%ptr)
3482+
3483+ call zero(di%mobility(p)%ptr)
3484+
3485+ vele_loop: do vele = 1, di%number_vele
3486+
3487+ ! The node indices of the pressure field
3488+ p_nodes => ele_nodes(di%pressure_mesh, vele)
3489+
3490+ ! The gravity values for this element for each direction
3491+ grav_ele = ele_val(di%gravity, vele)
3492+
3493+ ! get the viscosity value for this element for this phase
3494+ visc_ele = ele_val(di%viscosity(p)%ptr, vele)
3495+
3496+ ! get the absolute permeability value for this element
3497+ absperm_ele = ele_val(di%absolute_permeability, vele)
3498+
3499+ ! get the latest gradient pressure at the cv surface quadrature points for each direction for this phase
3500+ grad_pressure_face_quad = ele_val_at_quad(di%gradient_pressure(p)%ptr, vele, di%gradp_cvshape)
3501+
3502+ ! obtain the transformed determinant*weight and normals
3503+ if (di%cached_face_value%cached_detwei_normal) then
3504+
3505+ detwei => di%cached_face_value%detwei(:,vele)
3506+
3507+ normal => di%cached_face_value%normal(:,:,vele)
3508+
3509+ else
3510+
3511+ ! get the coordinate values for this element for each positions local node
3512+ x_ele = ele_val(di%positions, vele)
3513+
3514+ ! get the coordinate values for this element for each quadrature point
3515+ x_face_quad = ele_val_at_quad(di%positions, vele, di%x_cvshape)
3516+
3517+ ! The node indices of the positions projected to the pressure mesh
3518+ x_pmesh_nodes => ele_nodes(di%positions_pressure_mesh, vele)
3519+
3520+ call transform_cvsurf_to_physical(x_ele, di%x_cvshape, detwei, normal, di%cvfaces)
3521+
3522+ end if
3523+
3524+ ! Initialise array for the quadrature points of this
3525+ ! element for whether it has already been visited
3526+ notvisited = .true.
3527+
3528+ ! Initialise the local assemble arrays for this element
3529+ cfl_rhs_local = 0.0
3530+ v_local = 0.0
3531+ m_local = 0.0
3532+
3533+ ! loop over local nodes within this element
3534+ nodal_loop_i: do iloc = 1, di%pressure_mesh%shape%loc
3535+
3536+ ! loop over CV faces internal to this element
3537+ face_loop: do face = 1, di%cvfaces%faces
3538+
3539+ ! is this a face neighbouring iloc?
3540+ is_neigh: if(di%cvfaces%neiloc(iloc, face) /= 0) then
3541+
3542+ ! find the opposing local node across the CV face
3543+ oloc = di%cvfaces%neiloc(iloc, face)
3544+
3545+ ! loop over gauss points on face
3546+ quadrature_loop: do gi = 1, di%cvfaces%shape%ngi
3547+
3548+ ! global gauss pt index for this element
3549+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
3550+
3551+ ! check if this quadrature point has already been visited
3552+ check_visited: if(notvisited(ggi)) then
3553+
3554+ notvisited(ggi) = .false.
3555+
3556+ if (di%cached_face_value%cached_detwei_normal) then
3557+
3558+ ! cached normal has correct orientation already
3559+ normgi = normal(:,ggi)
3560+
3561+ else
3562+
3563+ ! correct the orientation of the normal so it points away from iloc
3564+ normgi = orientate_cvsurf_normgi(node_val(di%positions_pressure_mesh, x_pmesh_nodes(iloc)), &
3565+ &x_face_quad(:,ggi), normal(:,ggi))
3566+
3567+ end if
3568+
3569+ v_dot_n = &
3570+- di%cached_face_value%relperm(1,ggi,vele,p) * absperm_ele(1) * &
3571+dot_product((grad_pressure_face_quad(:,ggi) - di%cached_face_value%den(ggi,vele,p) * grav_ele(:,1)), normgi) / &
3572+visc_ele(1)
3573+
3574+ inflow = (v_dot_n<=0.0)
3575+
3576+ income = merge(1.0,0.0,inflow)
3577+
3578+ cfl_rhs_local(iloc) = cfl_rhs_local(iloc) + &
3579+ abs(v_dot_n) * &
3580+ detwei(ggi) * &
3581+ (1.0 - income)
3582+
3583+ cfl_rhs_local(oloc) = cfl_rhs_local(oloc) + &
3584+ abs(v_dot_n) * &
3585+ detwei(ggi) * &
3586+ income
3587+
3588+ do dim = 1, di%ndim
3589+
3590+ v_local(dim,iloc) = v_local(dim,iloc) - &
3591+detwei(ggi) * &
3592+di%cached_face_value%relperm(1,ggi,vele,p) * &
3593+absperm_ele(1) * &
3594+(grad_pressure_face_quad(dim,ggi) - di%cached_face_value%den(ggi,vele,p) * grav_ele(dim,1)) / &
3595+visc_ele(1)
3596+
3597+ v_local(dim,oloc) = v_local(dim,oloc) - &
3598+detwei(ggi) * &
3599+di%cached_face_value%relperm(1,ggi,vele,p) * &
3600+absperm_ele(1) * &
3601+(grad_pressure_face_quad(dim,ggi) - di%cached_face_value%den(ggi,vele,p) * grav_ele(dim,1)) / &
3602+visc_ele(1)
3603+
3604+ end do
3605+
3606+ m_local(iloc) = m_local(iloc) + &
3607+ detwei(ggi) * &
3608+ di%cached_face_value%relperm(1,ggi,vele,p) / &
3609+ visc_ele(1)
3610+
3611+ m_local(oloc) = m_local(oloc) + &
3612+ detwei(ggi) * &
3613+ di%cached_face_value%relperm(1,ggi,vele,p) / &
3614+ visc_ele(1)
3615+
3616+ end if check_visited
3617+
3618+ end do quadrature_loop
3619+
3620+ end if is_neigh
3621+
3622+ end do face_loop
3623+
3624+ end do nodal_loop_i
3625+
3626+ call addto(di%cfl(p)%ptr, p_nodes, cfl_rhs_local)
3627+
3628+ call addto(di%darcy_velocity(p)%ptr, p_nodes, v_local)
3629+
3630+ call addto(di%mobility(p)%ptr, p_nodes, m_local)
3631+
3632+ end do vele_loop
3633+
3634+ ! Get this phase v BC info - only for no_normal_flow and
3635+ ! prescribed_normal_flow which is special as it is a scalar
3636+ call darcy_impes_get_v_boundary_condition(&
3637+ di%darcy_velocity(p)%ptr, &
3638+ (/"prescribed_normal_flow", "no_normal_flow "/), &
3639+ di%bc_surface_mesh, di%v_bc_value, di%v_bc_flag)
3640+
3641+ sele_loop: do sele = 1, di%number_sele
3642+
3643+ p_nodes_bdy = face_global_nodes(di%pressure_mesh, sele)
3644+
3645+ ! obtain the transformed determinant*weight and normals
3646+ if (di%cached_face_value%cached_detwei_normal) then
3647+
3648+ detwei_bdy => di%cached_face_value%detwei_bdy(:,sele)
3649+
3650+ normal_bdy => di%cached_face_value%normal_bdy(:,:,sele)
3651+
3652+ else
3653+
3654+ x_ele = ele_val(di%positions, face_ele(di%positions, sele))
3655+ x_ele_bdy = face_val(di%positions, sele)
3656+
3657+ call transform_cvsurf_facet_to_physical(x_ele, x_ele_bdy, di%x_cvbdyshape, normal_bdy, detwei_bdy)
3658+
3659+ end if
3660+
3661+ if (di%v_bc_flag(sele) == V_BC_TYPE_PRESCRIBED_NORMAL_FLOW) then
3662+
3663+ bc_sele_val = ele_val(di%v_bc_value, sele)
3664+
3665+ end if
3666+
3667+ visc_ele_bdy = face_val(di%viscosity(p)%ptr, sele)
3668+ absperm_ele_bdy = face_val(di%absolute_permeability, sele)
3669+ grad_pressure_face_quad_bdy = face_val_at_quad(di%gradient_pressure(p)%ptr, sele, di%gradp_cvbdyshape)
3670+ grav_ele_bdy = face_val(di%gravity, sele)
3671+
3672+ ! Initialise the local assemble arrays for this element
3673+ cfl_rhs_local_bdy = 0.0
3674+ v_local_bdy = 0.0
3675+ m_local_bdy = 0.0
3676+
3677+ bc_iloc_loop: do iloc = 1, di%pressure_mesh%faces%shape%loc
3678+
3679+ bc_face_loop: do face = 1, di%cvfaces%sfaces
3680+
3681+ bc_neigh_if: if(di%cvfaces%sneiloc(iloc,face)/=0) then
3682+
3683+ bc_quad_loop: do gi = 1, di%cvfaces%shape%ngi
3684+
3685+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
3686+
3687+ if (di%v_bc_flag(sele) == V_BC_TYPE_NO_NORMAL_FLOW) then
3688+
3689+ v_dot_n = 0.0
3690+
3691+ else if (di%v_bc_flag(sele) == V_BC_TYPE_PRESCRIBED_NORMAL_FLOW) then
3692+
3693+ v_dot_n = bc_sele_val(iloc)
3694+
3695+ else
3696+
3697+ v_dot_n = &
3698+- di%cached_face_value%relperm_bdy(1,ggi,sele,p) * absperm_ele_bdy(1) * &
3699+dot_product((grad_pressure_face_quad_bdy(:,ggi) - di%cached_face_value%den_bdy(ggi,sele,p) * grav_ele_bdy(:,1)), normal_bdy(:,ggi)) / &
3700+visc_ele_bdy(1)
3701+
3702+ end if
3703+
3704+ if (v_dot_n > 0.0) then
3705+ income = 0.0
3706+ else
3707+ income = 1.0
3708+ end if
3709+
3710+ cfl_rhs_local_bdy(iloc) = cfl_rhs_local_bdy(iloc) + &
3711+ abs(v_dot_n) * &
3712+ detwei_bdy(ggi) * &
3713+ (1.0 - income)
3714+
3715+ do dim = 1, di%ndim
3716+
3717+ v_local_bdy(dim,iloc) = v_local_bdy(dim,iloc) - &
3718+detwei_bdy(ggi) * &
3719+di%cached_face_value%relperm_bdy(1,ggi,sele,p) * &
3720+absperm_ele_bdy(1) * &
3721+(grad_pressure_face_quad_bdy(dim,ggi) - di%cached_face_value%den_bdy(ggi,sele,p) * grav_ele_bdy(dim,1)) / &
3722+visc_ele_bdy(1)
3723+
3724+ end do
3725+
3726+ m_local_bdy(iloc) = m_local_bdy(iloc) + &
3727+ detwei_bdy(ggi) * &
3728+ di%cached_face_value%relperm_bdy(1,ggi,sele,p) / &
3729+ visc_ele_bdy(1)
3730+
3731+ end do bc_quad_loop
3732+
3733+ end if bc_neigh_if
3734+
3735+ end do bc_face_loop
3736+
3737+ end do bc_iloc_loop
3738+
3739+ call addto(di%cfl(p)%ptr, p_nodes_bdy, cfl_rhs_local_bdy)
3740+
3741+ call addto(di%darcy_velocity(p)%ptr, p_nodes_bdy, v_local_bdy)
3742+
3743+ call addto(di%mobility(p)%ptr, p_nodes_bdy, m_local_bdy)
3744+
3745+ end do sele_loop
3746+
3747+ di%cfl(p)%ptr%val = di%cfl(p)%ptr%val * di%dt / di%cv_mass_pressure_mesh_with_porosity%val
3748+
3749+ call scale(di%darcy_velocity(p)%ptr, di%inverse_cv_sa_pressure_mesh)
3750+
3751+ call scale(di%mobility(p)%ptr, di%inverse_cv_sa_pressure_mesh)
3752+
3753+ ewrite_minmax(di%cfl(p)%ptr)
3754+
3755+ ewrite_minmax(di%darcy_velocity(p)%ptr)
3756+
3757+ ewrite_minmax(di%mobility(p)%ptr)
3758+
3759+ end do phase_loop
3760+
3761+ ewrite(1,*) 'Calculate TotalDarcyVelocity and TotalMobility'
3762+
3763+ call set(di%total_darcy_velocity, di%darcy_velocity(1)%ptr)
3764+ call set(di%total_mobility, di%mobility(1)%ptr)
3765+
3766+ do p = 2, di%number_phase
3767+
3768+ call addto(di%total_darcy_velocity, di%darcy_velocity(p)%ptr)
3769+ call addto(di%total_mobility, di%mobility(p)%ptr)
3770+
3771+ end do
3772+
3773+ ewrite_minmax(di%total_darcy_velocity)
3774+ ewrite_minmax(di%total_mobility)
3775+
3776+ ewrite(1,*) 'Calculate BulkDarcyVelocity'
3777+
3778+ call allocate(aux_vfield, di%ndim, di%pressure_mesh)
3779+
3780+ call zero(di%bulk_darcy_velocity)
3781+
3782+ do p = 1, di%number_phase
3783+
3784+ call set(aux_vfield, di%darcy_velocity(p)%ptr)
3785+ call scale(aux_vfield, di%saturation(p)%ptr)
3786+
3787+ call addto(di%bulk_darcy_velocity, aux_vfield)
3788+
3789+ end do
3790+
3791+ call deallocate(aux_vfield)
3792+
3793+ ewrite_minmax(di%bulk_darcy_velocity)
3794+
3795+ ! calculate the fractional flow for each phase
3796+ do p = 1, di%number_phase
3797+
3798+ ewrite(1,*) 'Calculate FractionalFlow for phase ',p
3799+
3800+ call set(di%fractional_flow(p)%ptr, di%total_mobility)
3801+
3802+ call invert(di%fractional_flow(p)%ptr)
3803+
3804+ call scale(di%fractional_flow(p)%ptr, di%mobility(p)%ptr)
3805+
3806+ ewrite_minmax(di%fractional_flow(p)%ptr)
3807+
3808+ end do
3809+
3810+ ! deallocate local variables as required
3811+ deallocate(x_ele)
3812+ if (di%cached_face_value%cached_detwei_normal) then
3813+ nullify(detwei)
3814+ nullify(normal)
3815+ else
3816+ deallocate(detwei)
3817+ deallocate(normal)
3818+ end if
3819+ deallocate(normgi)
3820+ deallocate(notvisited)
3821+ deallocate(cfl_rhs_local)
3822+ deallocate(x_face_quad)
3823+ deallocate(grad_pressure_face_quad)
3824+ deallocate(grav_ele)
3825+
3826+ deallocate(grav_ele_bdy)
3827+ deallocate(grad_pressure_face_quad_bdy)
3828+ if (di%cached_face_value%cached_detwei_normal) then
3829+ nullify(detwei_bdy)
3830+ nullify(normal_bdy)
3831+ else
3832+ deallocate(detwei_bdy)
3833+ deallocate(normal_bdy)
3834+ end if
3835+ deallocate(x_ele_bdy)
3836+ deallocate(p_nodes_bdy)
3837+ deallocate(cfl_rhs_local_bdy)
3838+ deallocate(bc_sele_val)
3839+
3840+ deallocate(v_local)
3841+ deallocate(m_local)
3842+ deallocate(v_local_bdy)
3843+ deallocate(m_local_bdy)
3844+
3845+ end subroutine darcy_impes_calculate_vel_mob_ff_and_cfl_fields
3846+
3847+! ----------------------------------------------------------------------------
3848+
3849+ subroutine darcy_impes_calculate_inverse_cv_sa(di)
3850+
3851+ !!< Calculate the inverse of the surface area of the CV's on the pressure mesh
3852+
3853+ type(darcy_impes_type), intent(inout) :: di
3854+
3855+ ! local variables
3856+ integer :: vele, iloc, oloc, face, gi, ggi, sele
3857+ real, dimension(:), pointer :: sa_local
3858+ real, dimension(:,:), pointer :: x_ele
3859+ real, dimension(:,:), pointer :: normal
3860+ real, dimension(:), pointer :: detwei
3861+ logical, dimension(:), pointer :: notvisited
3862+ integer, dimension(:), pointer :: p_nodes
3863+ real, dimension(:,:), pointer :: normal_bdy
3864+ real, dimension(:), pointer :: detwei_bdy
3865+ real, dimension(:,:), pointer :: x_ele_bdy
3866+ real, dimension(:), pointer :: sa_local_bdy
3867+ integer, dimension(:), pointer :: p_nodes_bdy
3868+
3869+ ewrite(1,*) 'Calculate the inverse of the surface area of CV on the pressure mesh'
3870+
3871+ ! allocate arrays used in assemble process - many assume
3872+ ! that all elements are the same type.
3873+ allocate(x_ele(di%ndim, ele_loc(di%positions,1)))
3874+ if (.not. di%cached_face_value%cached_detwei_normal) then
3875+ allocate(normal(di%ndim,di%x_cvshape%ngi))
3876+ allocate(detwei(di%x_cvshape%ngi))
3877+ end if
3878+ allocate(notvisited(di%x_cvshape%ngi))
3879+
3880+ if (.not. di%cached_face_value%cached_detwei_normal) then
3881+ allocate(detwei_bdy(di%x_cvbdyshape%ngi))
3882+ allocate(normal_bdy(di%ndim, di%x_cvbdyshape%ngi))
3883+ end if
3884+ allocate(x_ele_bdy(di%ndim, face_loc(di%positions,1)))
3885+ allocate(p_nodes_bdy(face_loc(di%pressure_mesh,1)))
3886+ allocate(sa_local(ele_loc(di%pressure_mesh,1)))
3887+ allocate(sa_local_bdy(face_loc(di%pressure_mesh,1)))
3888+
3889+ call zero(di%inverse_cv_sa_pressure_mesh)
3890+
3891+ vele_loop: do vele = 1, di%number_vele
3892+
3893+ ! The node indices of the pressure field
3894+ p_nodes => ele_nodes(di%pressure_mesh, vele)
3895+
3896+ ! obtain the transformed determinant*weight and normals
3897+ if (di%cached_face_value%cached_detwei_normal) then
3898+
3899+ detwei => di%cached_face_value%detwei(:,vele)
3900+
3901+ normal => di%cached_face_value%normal(:,:,vele)
3902+
3903+ else
3904+
3905+ ! get the coordinate values for this element for each positions local node
3906+ x_ele = ele_val(di%positions, vele)
3907+
3908+ call transform_cvsurf_to_physical(x_ele, di%x_cvshape, detwei, normal, di%cvfaces)
3909+
3910+ end if
3911+
3912+ ! Initialise array for the quadrature points of this
3913+ ! element for whether it has already been visited
3914+ notvisited = .true.
3915+
3916+ sa_local = 0.0
3917+
3918+ ! loop over local nodes within this element
3919+ nodal_loop_i: do iloc = 1, di%pressure_mesh%shape%loc
3920+
3921+ ! loop over CV faces internal to this element
3922+ face_loop: do face = 1, di%cvfaces%faces
3923+
3924+ ! is this a face neighbouring iloc?
3925+ is_neigh: if(di%cvfaces%neiloc(iloc, face) /= 0) then
3926+
3927+ ! find the opposing local node across the CV face
3928+ oloc = di%cvfaces%neiloc(iloc, face)
3929+
3930+ ! loop over gauss points on face
3931+ quadrature_loop: do gi = 1, di%cvfaces%shape%ngi
3932+
3933+ ! global gauss pt index for this element
3934+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
3935+
3936+ ! check if this quadrature point has already been visited
3937+ check_visited: if(notvisited(ggi)) then
3938+
3939+ notvisited(ggi) = .false.
3940+
3941+ sa_local(iloc) = sa_local(iloc) + &
3942+ detwei(ggi)
3943+
3944+ sa_local(oloc) = sa_local(oloc) + &
3945+ detwei(ggi)
3946+
3947+ end if check_visited
3948+
3949+ end do quadrature_loop
3950+
3951+ end if is_neigh
3952+
3953+ end do face_loop
3954+
3955+ end do nodal_loop_i
3956+
3957+ call addto(di%inverse_cv_sa_pressure_mesh, p_nodes, sa_local)
3958+
3959+ end do vele_loop
3960+
3961+ sele_loop: do sele = 1, di%number_sele
3962+
3963+ p_nodes_bdy = face_global_nodes(di%pressure_mesh, sele)
3964+
3965+ ! obtain the transformed determinant*weight and normals
3966+ if (di%cached_face_value%cached_detwei_normal) then
3967+
3968+ detwei_bdy => di%cached_face_value%detwei_bdy(:,sele)
3969+
3970+ normal_bdy => di%cached_face_value%normal_bdy(:,:,sele)
3971+
3972+ else
3973+
3974+ x_ele = ele_val(di%positions, face_ele(di%positions, sele))
3975+ x_ele_bdy = face_val(di%positions, sele)
3976+
3977+ call transform_cvsurf_facet_to_physical(x_ele, x_ele_bdy, di%x_cvbdyshape, normal_bdy, detwei_bdy)
3978+
3979+ end if
3980+
3981+ sa_local_bdy = 0.0
3982+
3983+ bc_iloc_loop: do iloc = 1, di%pressure_mesh%faces%shape%loc
3984+
3985+ bc_face_loop: do face = 1, di%cvfaces%sfaces
3986+
3987+ bc_neigh_if: if(di%cvfaces%sneiloc(iloc,face)/=0) then
3988+
3989+ bc_quad_loop: do gi = 1, di%cvfaces%shape%ngi
3990+
3991+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
3992+
3993+ sa_local_bdy(iloc) = sa_local_bdy(iloc) + &
3994+ detwei_bdy(ggi)
3995+
3996+ end do bc_quad_loop
3997+
3998+ end if bc_neigh_if
3999+
4000+ end do bc_face_loop
4001+
4002+ end do bc_iloc_loop
4003+
4004+ call addto(di%inverse_cv_sa_pressure_mesh, p_nodes_bdy, sa_local_bdy)
4005+
4006+ end do sele_loop
4007+
4008+ call invert(di%inverse_cv_sa_pressure_mesh)
4009+
4010+ ! deallocate local variables as required
4011+ deallocate(x_ele)
4012+ if (di%cached_face_value%cached_detwei_normal) then
4013+ nullify(detwei)
4014+ nullify(normal)
4015+ else
4016+ deallocate(detwei)
4017+ deallocate(normal)
4018+ end if
4019+ deallocate(notvisited)
4020+
4021+ if (di%cached_face_value%cached_detwei_normal) then
4022+ nullify(detwei_bdy)
4023+ nullify(normal_bdy)
4024+ else
4025+ deallocate(detwei_bdy)
4026+ deallocate(normal_bdy)
4027+ end if
4028+ deallocate(x_ele_bdy)
4029+ deallocate(p_nodes_bdy)
4030+
4031+ deallocate(sa_local)
4032+ deallocate(sa_local_bdy)
4033+
4034+ ewrite_minmax(di%inverse_cv_sa_pressure_mesh)
4035+
4036+ ewrite(1,*) 'Finished Calculate the inverse of the surface area of CV on the pressure mesh'
4037+
4038+ end subroutine darcy_impes_calculate_inverse_cv_sa
4039+
4040+! ----------------------------------------------------------------------------
4041+
4042+ subroutine darcy_impes_calculate_sum_saturation(di)
4043+
4044+ !!< Calculate the sum of the saturation fields
4045+
4046+ type(darcy_impes_type), intent(inout) :: di
4047+
4048+ ! local variables
4049+ integer :: p
4050+
4051+ ewrite(1,*) 'Calculate SumSaturation'
4052+
4053+ call zero(di%sum_saturation)
4054+
4055+ do p = 1, di%number_phase
4056+
4057+ call addto(di%sum_saturation, di%saturation(p)%ptr)
4058+
4059+ end do
4060+
4061+ ewrite_minmax(di%sum_saturation)
4062+
4063+ end subroutine darcy_impes_calculate_sum_saturation
4064+
4065+! ----------------------------------------------------------------------------
4066+
4067+ subroutine darcy_impes_calculate_densities(di)
4068+
4069+ !!< Calculate the density field of each phase
4070+
4071+ type(darcy_impes_type), intent(inout) :: di
4072+
4073+ ! local variables
4074+ integer :: p
4075+
4076+ ewrite(1,*) 'Calculate Density of each phase'
4077+
4078+ do p = 1, di%number_phase
4079+
4080+ if (di%eos_options(p)%have_fluids_linear) then
4081+
4082+ ! Currently no variation of the reference density by any pertubation
4083+
4084+ call set(di%density(p)%ptr, di%eos_options(p)%fluids_linear_reference_density)
4085+
4086+ end if
4087+
4088+ ewrite_minmax(di%density(p)%ptr)
4089+
4090+ end do
4091+
4092+ ewrite(1,*) 'Finished Calculate Density of each phase'
4093+
4094+ end subroutine darcy_impes_calculate_densities
4095+
4096+! ----------------------------------------------------------------------------
4097+
4098+ subroutine darcy_impes_calculate_relperm_fields(di)
4099+
4100+ !!< Calculate the latest relperm fields from the latest saturations.
4101+ !!< This is assumes that the relperm and saturation fields are
4102+ !!< on the same mesh, which is all the input permits
4103+
4104+ type(darcy_impes_type), intent(inout) :: di
4105+
4106+ ! local variables
4107+ integer :: p, node
4108+ real :: relperm_node_val
4109+ real, dimension(:), pointer :: sat_node_val_all_phases
4110+
4111+ ewrite(1,*) 'Calculate RelativePermeability field of each phase'
4112+
4113+ allocate(sat_node_val_all_phases(di%number_phase))
4114+
4115+ ! Calc relperm phase values for each node
4116+ node_loop: do node = 1, di%number_pmesh_node
4117+
4118+ ! Find all the phase saturation node values
4119+ do p = 1, di%number_phase
4120+
4121+ sat_node_val_all_phases(p) = node_val(di%saturation(p)%ptr, node)
4122+
4123+ end do
4124+
4125+ ! Calc and set relperm node value for each phase
4126+ do p = 1, di%number_phase
4127+
4128+ call darcy_impes_calculate_relperm_value(relperm_node_val, &
4129+ sat_node_val_all_phases, &
4130+ p, &
4131+ di%relperm_corr_options%type, &
4132+ di%relperm_corr_options%exponents, &
4133+ di%relperm_corr_options%residual_saturations, &
4134+ di%relperm_corr_options%cutoff_saturations, &
4135+ di%relperm_corr_options%scaling_coefficients)
4136+
4137+ call set(di%relative_permeability(p)%ptr, &
4138+ node, &
4139+ relperm_node_val)
4140+
4141+ end do
4142+
4143+ end do node_loop
4144+
4145+ deallocate(sat_node_val_all_phases)
4146+
4147+ ewrite(1,*) 'Finished Calculate RelativePermeability field of each phase'
4148+
4149+ end subroutine darcy_impes_calculate_relperm_fields
4150+
4151+! ----------------------------------------------------------------------------
4152+
4153+ subroutine darcy_impes_calculate_relperm_value(relperm_val, &
4154+ sat_val_all_phases, &
4155+ p, &
4156+ relperm_corr_type, &
4157+ relperm_corr_exponents, &
4158+ relperm_corr_residual_sats, &
4159+ relperm_corr_cutoff_sats, &
4160+ relperm_corr_scaling_coefficients)
4161+
4162+ !!< Calculate the latest relperm value for phase p for the
4163+ !!< given saturation values of all phases using the given options.
4164+
4165+ real, intent(out) :: relperm_val
4166+ real, dimension(:), intent(in) :: sat_val_all_phases
4167+ integer, intent(in) :: p
4168+ integer, intent(in) :: relperm_corr_type
4169+ real, dimension(:), intent(in) :: relperm_corr_exponents
4170+ real, dimension(:), intent(in) :: relperm_corr_residual_sats
4171+ real, dimension(:), intent(in) :: relperm_corr_cutoff_sats
4172+ real, dimension(:), intent(in) :: relperm_corr_scaling_coefficients
4173+
4174+ ! local variables
4175+ real :: sat_minus_res_sat
4176+ real :: sat_effective
4177+
4178+ select case (relperm_corr_type)
4179+
4180+ case (RELPERM_CORRELATION_POWER)
4181+
4182+ relperm_val = (sat_val_all_phases(p) - relperm_corr_residual_sats(p)) ** relperm_corr_exponents(p)
4183+
4184+ case (RELPERM_CORRELATION_COREY2PHASE)
4185+
4186+ sat_minus_res_sat = sat_val_all_phases(1) - relperm_corr_residual_sats(1)
4187+
4188+ if (p == 1) then
4189+
4190+ relperm_val = sat_minus_res_sat ** 4
4191+
4192+ else if (p == 2) then
4193+
4194+ relperm_val = (1.0 - sat_minus_res_sat ** 2) * (1.0 - sat_minus_res_sat) ** 2
4195+
4196+ else
4197+
4198+ ! This has already been option checked so should not happen
4199+ FLAbort('Trying to use Corey2Phase relative permeabiltiy correlation for simulation with more than 2 phases')
4200+
4201+ end if
4202+
4203+ case (RELPERM_CORRELATION_COREY2PHASEOPPOSITE)
4204+
4205+ sat_minus_res_sat = sat_val_all_phases(2) - relperm_corr_residual_sats(2)
4206+
4207+ if (p == 1) then
4208+
4209+ relperm_val = (1.0 - sat_minus_res_sat ** 2) * (1.0 - sat_minus_res_sat) ** 2
4210+
4211+ else if (p == 2) then
4212+
4213+ relperm_val = sat_minus_res_sat ** 4
4214+
4215+ else
4216+
4217+ ! This has already been option checked so should not happen
4218+ FLAbort('Trying to use Corey2PhaseOpposite relative permeabiltiy correlation for simulation with more than 2 phases')
4219+
4220+ end if
4221+
4222+ case (RELPERM_CORRELATION_MINERAL)
4223+
4224+ relperm_val = ((max(relperm_corr_cutoff_sats(p), sat_val_all_phases(p)) - relperm_corr_residual_sats(p)) **&
4225+ &relperm_corr_exponents(p)) / ((1.0 - relperm_corr_residual_sats(p)) ** relperm_corr_exponents(p))
4226+
4227+ case (RELPERM_CORRELATION_VANGENUCHTEN)
4228+
4229+ sat_effective = (sat_val_all_phases(2) - relperm_corr_residual_sats(2) ) / ( 1.0 - relperm_corr_residual_sats(1) - &
4230+ &relperm_corr_residual_sats(2))
4231+
4232+ if (p == 1) then
4233+
4234+ relperm_val = ( 1.0 - sat_effective )**(1.0/3.0) * (1.0 - sat_effective ** ( 1.0/ relperm_corr_exponents(p)) ) ** (2* relperm_corr_exponents(p))
4235+
4236+ else if (p == 2) then
4237+
4238+ relperm_val = sat_effective ** (1.0/2.0) * ( 1.0 - ( 1.0 - sat_effective ** ( 1.0 / relperm_corr_exponents(p))) ** relperm_corr_exponents(p))**2.0
4239+
4240+ else
4241+
4242+ ! This has already been option checked so should not happen
4243+ FLAbort('Trying to use VanGenuchten relative permeabiltiy correlation for simulation with more than 2 phases')
4244+
4245+ end if
4246+
4247+ case (RELPERM_CORRELATION_JACKSON2PHASE)
4248+
4249+ sat_effective = (sat_val_all_phases(2) - relperm_corr_residual_sats(2)) / &
4250+ (1.0 - relperm_corr_residual_sats(1) - relperm_corr_residual_sats(2))
4251+ if ( sat_effective >= 1.0 ) then
4252+ sat_effective = 1.0
4253+ end if
4254+
4255+ if ( sat_effective <= 0.0 ) then
4256+ sat_effective = 0.0
4257+ end if
4258+
4259+ if (p == 1) then
4260+
4261+ relperm_val = relperm_corr_scaling_coefficients(1) * (1.0 - sat_effective) ** relperm_corr_exponents(1)
4262+
4263+ else if (p == 2) then
4264+
4265+ relperm_val = relperm_corr_scaling_coefficients(2) * sat_effective ** relperm_corr_exponents(2)
4266+
4267+ else
4268+
4269+ ! This has already been option checked so should not happen
4270+ FLAbort('Trying to use Jackson2Phase relative permeabiltiy correlation for simulation with more than 2 phases')
4271+
4272+ end if
4273+
4274+ case (RELPERM_CORRELATION_JACKSON2PHASEOPPOSITE)
4275+
4276+ sat_effective = (sat_val_all_phases(1) - relperm_corr_residual_sats(1)) / &
4277+ (1.0 - relperm_corr_residual_sats(1) - relperm_corr_residual_sats(2))
4278+
4279+ if (p == 1) then
4280+
4281+ relperm_val = relperm_corr_scaling_coefficients(1) * sat_effective ** relperm_corr_exponents(1)
4282+
4283+ else if (p == 2) then
4284+
4285+ relperm_val = relperm_corr_scaling_coefficients(2) * (1.0 - sat_effective) ** relperm_corr_exponents(2)
4286+
4287+ else
4288+
4289+ ! This has already been option checked so should not happen
4290+ FLAbort('Trying to use Jackson2PhaseOpposite relative permeabiltiy correlation for simulation with more than 2 phases')
4291+
4292+ end if
4293+
4294+ end select
4295+
4296+ end subroutine darcy_impes_calculate_relperm_value
4297+
4298+! ----------------------------------------------------------------------------
4299+
4300+ subroutine darcy_impes_calculate_cflnumber_field_based_dt(di)
4301+
4302+ !!< Calculate the cfl number field based adaptive time step
4303+
4304+ type(darcy_impes_type), intent(inout) :: di
4305+
4306+ !! NEW NoT TESTED FROM HERE
4307+ type(logical) :: diff_cfl
4308+
4309+
4310+ real :: ds, dpds, diff, deltax
4311+ type(scalar_field), pointer::sat, phi, perm, vis
4312+
4313+ type(vector_field), pointer:: X
4314+
4315+ real, dimension(:), allocatable :: detwei
4316+ real, dimension(:), pointer :: phi_ele, perm_ele, sat_ele, vis_ele
4317+ integer, dimension(:), pointer :: sat_ele_nodes
4318+ integer :: i , ele
4319+ real, dimension(:, :, :), allocatable :: invJ
4320+ real :: sat_node
4321+ type(state_type) :: state
4322+
4323+ !! TILL HERE
4324+
4325+
4326+ ! local variables
4327+ integer :: p
4328+ real, dimension(di%number_phase) :: phase_dt, dtdiff
4329+
4330+ ewrite(1,*) 'Calculate CFL number field based adaptive timestep'
4331+
4332+ ! Find the adaptive dt for each phase then take the minimum
4333+
4334+ phase_dt = di%dt
4335+
4336+ phase_loop: do p = 1, di%number_phase
4337+
4338+ phase_dt(p) = cflnumber_field_based_dt(di%cfl(p)%ptr, &
4339+ di%dt, &
4340+ di%adaptive_dt_options%requested_cfl, &
4341+ di%adaptive_dt_options%min_dt, &
4342+ di%adaptive_dt_options%max_dt, &
4343+ di%adaptive_dt_options%increase_tolerance)
4344+
4345+ end do phase_loop
4346+
4347+
4348+ ! NEW NOT TESTED FROM HERE
4349+! diff_cfl = .False.
4350+! if (diff_cfl) then
4351+
4352+! do p = 1, di%number_phase
4353+
4354+! sat=>extract_scalar_field(state(p), "Saturation")
4355+! phi=>extract_scalar_field(state(p), "Porosity")
4356+! perm=>extract_scalar_field(state(p), "Permeability")
4357+! vis=>extract_scalar_field(state(p), "Viscosity")
4358+
4359+! X=>extract_vector_field(state(1), "Coordinate")
4360+! allocate (invj(mesh_dim(x), mesh_dim(x), ele_ngi(x, 1)))
4361+! allocate (detwei(ele_ngi(X,ele)))
4362+
4363+
4364+! ds = 1.e-10
4365+! dpds=0.
4366+
4367+! diff= 0.
4368+
4369+! do ele = 1, ele_count(sat)
4370+
4371+! sat_ele_nodes => ele_nodes(sat, ele)
4372+
4373+! phi_ele = ele_val(phi, ele)
4374+! perm_ele = ele_val(perm, ele)
4375+! vis_ele = ele_val(vis, ele)
4376+
4377+ ! call compute_inverse_jacobian(ele_val(X,ele), ele_shape(X,ele), &
4378+ ! detwei=detwei, invJ=invJ)
4379+
4380+
4381+
4382+! deltax = minval(invJ)
4383+
4384+! do i = 1, size(sat_ele_nodes)
4385+
4386+! sat_node = node_val(sat, sat_ele_nodes(i) )
4387+! dpds = abs( ( (sat_node+ds)**(-0.5) - (sat_node-ds)**(-0.5) ) /(2.*ds) )
4388+
4389+ ! diff = max( diff, ( 1./phi_ele(ele)) * (perm_ele(ele) / vis_ele(ele)) * dpds )
4390+
4391+! end do
4392+
4393+! dtdiff(p) = deltax**2 / (2*diff)
4394+
4395+ ! end do
4396+
4397+! deallocate (invj)
4398+! deallocate (detwei)
4399+
4400+! end do
4401+
4402+
4403+
4404+! di%dt = min(minval(dtdiff), minval(phase_dt))
4405+
4406+! end if
4407+
4408+! UNTIL HERE
4409+
4410+ di%dt = minval(phase_dt)
4411+
4412+ if(di%adaptive_dt_options%min_dt_terminate_if_reached) then
4413+ if(di%dt <= di%adaptive_dt_options%min_dt + spacing(di%adaptive_dt_options%min_dt)) then
4414+ ewrite(0, *) "Minimum timestep reached - terminating"
4415+ SIG_INT = .true.
4416+ end if
4417+ end if
4418+
4419+ ewrite(1,*) 'Finished Calculate CFL number field based adaptive timestep'
4420+
4421+ end subroutine darcy_impes_calculate_cflnumber_field_based_dt
4422+
4423+! ----------------------------------------------------------------------------
4424+
4425+ subroutine darcy_impes_initialise_cached_face_value(di)
4426+
4427+ !!< Initialise the cached_face_value variable's by
4428+ !!< allocating and zeroing the values and setting the
4429+ !!< detwei, normal and p_dshape components as required.
4430+
4431+ type(darcy_impes_type), intent(inout) :: di
4432+
4433+ ! local variable
4434+ integer :: vele, sele, iloc, face, gi, ggi
4435+ real, dimension(:), allocatable :: normgi
4436+ logical, dimension(:), allocatable :: notvisited
4437+ real, dimension(:,:), allocatable :: x_face_quad
4438+ integer, dimension(:), pointer :: x_pmesh_nodes
4439+
4440+ ewrite(1,*) 'Initialise cached phase face value types'
4441+
4442+ if (di%subcy_opt_sat%have .and. di%subcy_opt_sat%consistent) then
4443+
4444+ allocate(di%cached_face_value%relperm(di%subcy_opt_sat%number, di%p_cvshape%ngi, di%number_vele, di%number_phase))
4445+ allocate(di%cached_face_value%relperm_bdy(di%subcy_opt_sat%number, di%p_cvbdyshape%ngi, di%number_sele, di%number_phase))
4446+
4447+ else
4448+
4449+ allocate(di%cached_face_value%relperm(1, di%p_cvshape%ngi, di%number_vele, di%number_phase))
4450+ allocate(di%cached_face_value%relperm_bdy(1, di%p_cvbdyshape%ngi, di%number_sele, di%number_phase))
4451+
4452+ end if
4453+
4454+ di%cached_face_value%relperm = 0.0
4455+ di%cached_face_value%relperm_bdy = 0.0
4456+
4457+ allocate(di%cached_face_value%den(di%p_cvshape%ngi, di%number_vele, di%number_phase))
4458+ allocate(di%cached_face_value%den_bdy(di%p_cvbdyshape%ngi, di%number_sele, di%number_phase))
4459+
4460+ di%cached_face_value%den = 0.0
4461+ di%cached_face_value%den_bdy = 0.0
4462+
4463+ if (di%cached_face_value%cached_detwei_normal) then
4464+
4465+ allocate(di%cached_face_value%detwei(di%p_cvshape%ngi, di%number_vele))
4466+ allocate(di%cached_face_value%detwei_bdy(di%p_cvbdyshape%ngi, di%number_sele))
4467+
4468+ di%cached_face_value%detwei = 0.0
4469+ di%cached_face_value%detwei_bdy = 0.0
4470+
4471+ allocate(di%cached_face_value%normal(di%ndim, di%p_cvshape%ngi, di%number_vele))
4472+ allocate(di%cached_face_value%normal_bdy(di%ndim, di%p_cvbdyshape%ngi, di%number_sele))
4473+
4474+ di%cached_face_value%normal = 0.0
4475+ di%cached_face_value%normal_bdy = 0.0
4476+
4477+ end if
4478+
4479+ if (di%cached_face_value%cached_p_dshape) then
4480+
4481+ allocate(di%cached_face_value%p_dshape(di%pressure_mesh%shape%loc, di%p_cvshape%ngi, di%ndim, di%number_vele))
4482+!!!!! *** THIS IS NOT POSSIBLE YET ***
4483+!!!!! allocate(di%cached_face_value%p_dshape_bdy(di%pressure_mesh%faces%shape%loc, di%p_cvbdyshape_full%ngi, di%ndim, di%number_sele))
4484+
4485+ di%cached_face_value%p_dshape = 0.0
4486+!!!!! *** THIS IS NOT POSSIBLE YET ***
4487+!!!!! di%cached_face_value%p_dshape_bdy = 0.0
4488+
4489+ end if
4490+
4491+ allocate(normgi(di%ndim))
4492+ allocate(notvisited(di%p_cvshape%ngi))
4493+ allocate(x_face_quad(di%ndim, di%p_cvshape%ngi))
4494+
4495+ ! Determine the detwei and normal if required
4496+ find_cached_detwei_normal: if (di%cached_face_value%cached_detwei_normal) then
4497+
4498+ vele_loop_detwei_normal: do vele = 1, di%number_vele
4499+
4500+ call transform_cvsurf_to_physical(ele_val(di%positions, vele), &
4501+ di%x_cvshape, &
4502+ di%cached_face_value%detwei(:,vele), &
4503+ di%cached_face_value%normal(:,:,vele), &
4504+ di%cvfaces)
4505+
4506+ ! Correct the orientation of the normal
4507+
4508+ ! get the coordinate values for this element for each quadrature point
4509+ x_face_quad = ele_val_at_quad(di%positions, vele, di%x_cvshape)
4510+
4511+ ! The node indices of the positions projected to the pressure mesh
4512+ x_pmesh_nodes => ele_nodes(di%positions_pressure_mesh, vele)
4513+
4514+ ! Initialise array for the quadrature points of this
4515+ ! element for whether it has already been visited
4516+ notvisited = .true.
4517+
4518+ ! loop over local nodes within this element
4519+ nodal_loop_i: do iloc = 1, di%pressure_mesh%shape%loc
4520+
4521+ ! loop over CV faces internal to this element
4522+ face_loop: do face = 1, di%cvfaces%faces
4523+
4524+ ! is this a face neighbouring iloc?
4525+ is_neigh: if(di%cvfaces%neiloc(iloc, face) /= 0) then
4526+
4527+ ! loop over gauss points on face
4528+ quadrature_loop: do gi = 1, di%cvfaces%shape%ngi
4529+
4530+ ! global gauss pt index for this element
4531+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
4532+
4533+ ! check if this quadrature point has already been visited
4534+ check_visited: if(notvisited(ggi)) then
4535+
4536+ notvisited(ggi) = .false.
4537+
4538+ ! correct the orientation of the normal so it points away from iloc
4539+ normgi = orientate_cvsurf_normgi(node_val(di%positions_pressure_mesh, x_pmesh_nodes(iloc)), &
4540+ x_face_quad(:,ggi), &
4541+ di%cached_face_value%normal(:,ggi,vele))
4542+
4543+ di%cached_face_value%normal(:,ggi,vele) = normgi
4544+
4545+ end if check_visited
4546+
4547+ end do quadrature_loop
4548+
4549+ end if is_neigh
4550+
4551+ end do face_loop
4552+
4553+ end do nodal_loop_i
4554+
4555+ end do vele_loop_detwei_normal
4556+
4557+ sele_loop_detwei_normal: do sele = 1, di%number_sele
4558+
4559+ call transform_cvsurf_facet_to_physical(ele_val(di%positions, face_ele(di%positions, sele)), &
4560+ face_val(di%positions, sele), &
4561+ di%x_cvbdyshape, &
4562+ di%cached_face_value%normal_bdy(:,:,sele), &
4563+ di%cached_face_value%detwei_bdy(:,sele))
4564+
4565+ end do sele_loop_detwei_normal
4566+
4567+ end if find_cached_detwei_normal
4568+
4569+ deallocate(normgi)
4570+ deallocate(notvisited)
4571+ deallocate(x_face_quad)
4572+
4573+ ! Determine the p_dshape if required
4574+ find_cached_p_dshape: if (di%cached_face_value%cached_p_dshape) then
4575+
4576+ vele_loop_p_dshape: do vele = 1, di%number_vele
4577+
4578+ call transform_to_physical(di%positions, &
4579+ vele, &
4580+ x_shape = di%x_cvshape_full, &
4581+ shape = di%p_cvshape_full, &
4582+ dshape = di%cached_face_value%p_dshape(:,:,:,vele))
4583+
4584+ end do vele_loop_p_dshape
4585+
4586+!!!!! *** THIS IS NOT POSSIBLE YET ***
4587+!!!!! sele_loop_p_dshape: do sele = 1, di%number_sele
4588+
4589+!!!!! call transform_to_physical(di%positions, &
4590+!!!!! sele, &
4591+!!!!! x_shape = di%x_cvbdyshape_full, &
4592+!!!!! shape = di%p_cvbdyshape_full, &
4593+!!!!! dshape = di%cached_face_value%p_dshape_bdy(:,:,:,sele))
4594+
4595+!!!!! end do sele_loop_p_dshape
4596+
4597+ end if find_cached_p_dshape
4598+
4599+ ewrite(1,*) 'Finished Initialise cached face value types'
4600+
4601+ end subroutine darcy_impes_initialise_cached_face_value
4602+
4603+! ----------------------------------------------------------------------------
4604+
4605+ subroutine darcy_impes_calculate_relperm_den_first_face_values(di)
4606+
4607+ !!< Find the relperm and density CV first face values for all phase and cache.
4608+
4609+ type(darcy_impes_type), intent(inout) :: di
4610+
4611+ ! local variables
4612+ logical :: inflow
4613+ integer :: p, vele, sele, iloc, oloc, face, gi, ggi
4614+ integer :: r_upwind_pos, d_upwind_pos, s_upwind_pos, dim, sat_p
4615+ real :: income, v_over_relperm_dot_n, old_relperm_face_value, den_face_value, old_sat_face_value
4616+ real, dimension(1) :: absperm_ele, visc_ele
4617+ real, dimension(:), pointer :: old_relperm_ele
4618+ real, dimension(:), pointer :: den_ele
4619+ real, dimension(:,:), pointer :: old_sat_ele
4620+ real, dimension(:,:), pointer :: grav_ele
4621+ real, dimension(:,:), pointer :: grad_pressure_face_quad
4622+ real, dimension(:,:), pointer :: v_over_relperm_face_quad
4623+ real, dimension(:,:), pointer :: x_ele
4624+ real, dimension(:,:,:), pointer :: p_dshape
4625+ real, dimension(:,:), pointer :: normal
4626+ real, dimension(:), pointer :: detwei
4627+ real, dimension(:), pointer :: normgi
4628+ logical, dimension(:), pointer :: notvisited
4629+ real, dimension(:,:), pointer :: x_face_quad
4630+ integer, dimension(:), pointer :: x_pmesh_nodes
4631+ integer, dimension(:), pointer :: p_nodes
4632+ integer, dimension(:), pointer :: r_upwind_nodes
4633+ integer, dimension(:), pointer :: d_upwind_nodes
4634+ integer, dimension(:), pointer :: s_upwind_nodes
4635+ real, dimension(:), pointer :: den_ele_bdy
4636+ real, dimension(:), pointer :: old_relperm_ele_bdy
4637+
4638+ ! allocate arrays used in assemble process - many assume
4639+ ! that all elements are the same type.
4640+ allocate(x_ele(di%ndim, ele_loc(di%positions,1)))
4641+ if (.not. di%cached_face_value%cached_p_dshape) then
4642+ allocate(p_dshape(ele_loc(di%pressure_mesh,1), di%x_cvshape%ngi, mesh_dim(di%pressure_mesh)))
4643+ end if
4644+ if (.not. di%cached_face_value%cached_detwei_normal) then
4645+ allocate(normal(di%ndim,di%x_cvshape%ngi))
4646+ allocate(detwei(di%x_cvshape%ngi))
4647+ end if
4648+ allocate(normgi(di%ndim))
4649+ allocate(notvisited(di%x_cvshape%ngi))
4650+ allocate(x_face_quad(di%ndim, di%x_cvshape%ngi))
4651+ allocate(old_relperm_ele(ele_loc(di%pressure_mesh,1)))
4652+ allocate(den_ele(ele_loc(di%pressure_mesh,1)))
4653+ allocate(old_sat_ele(ele_loc(di%pressure_mesh,1), di%number_phase))
4654+ allocate(grav_ele(di%ndim,1))
4655+ allocate(grad_pressure_face_quad(di%ndim, di%p_cvshape%ngi))
4656+ allocate(v_over_relperm_face_quad(di%ndim,di%p_cvshape%ngi))
4657+
4658+ allocate(den_ele_bdy(face_loc(di%pressure_mesh,1)))
4659+ allocate(old_relperm_ele_bdy(face_loc(di%pressure_mesh,1)))
4660+
4661+ ewrite(1,*) 'Calculate relperm and density and first face values'
4662+
4663+ ! Initialise the cached face values
4664+ di%cached_face_value%relperm(1,:,:,:) = 0.0
4665+ di%cached_face_value%relperm_bdy(1,:,:,:) = 0.0
4666+ di%cached_face_value%den = 0.0
4667+ di%cached_face_value%den_bdy = 0.0
4668+
4669+ phase_loop: do p = 1, di%number_phase
4670+
4671+ ! Determine the upwind relperm values of all node pairs if required for higher order CV face value.
4672+ ! If the relperm face value is a RELPERMOVERSAT... scheme then the upwind values
4673+ ! of modrelperm are required (= relperm / sat)
4674+ if(di%relperm_cv_options%limit_facevalue) then
4675+
4676+ if (di%determine_saturation_face_values) then
4677+
4678+ call darcy_impes_calculate_old_modified_relative_permeability(di, p)
4679+
4680+ ! NOTE only old values are required but this procedure
4681+ ! expects latest and old. So pass in old twice - not optimal
4682+ call find_upwind_values(di%state, &
4683+ di%positions_pressure_mesh, &
4684+ di%modified_relative_permeability, &
4685+ di%relperm_upwind, &
4686+ di%modified_relative_permeability, &
4687+ di%relperm_upwind, &
4688+ option_path = trim(di%relative_permeability(p)%ptr%option_path))
4689+
4690+ else
4691+
4692+ ! NOTE only old values are required but this procedure
4693+ ! expects latest and old. So pass in old twice - not optimal
4694+ call find_upwind_values(di%state, &
4695+ di%positions_pressure_mesh, &
4696+ di%old_relative_permeability(p)%ptr, &
4697+ di%relperm_upwind, &
4698+ di%old_relative_permeability(p)%ptr, &
4699+ di%relperm_upwind, &
4700+ option_path = trim(di%relative_permeability(p)%ptr%option_path))
4701+
4702+ end if
4703+
4704+ end if
4705+
4706+ ! If the relperm face value is a RELPERMOVERSAT... scheme then the saturation
4707+ ! face values need determining which may require the upwind values.
4708+ if (di%determine_saturation_face_values .and. di%saturation_cv_options%limit_facevalue) then
4709+
4710+ ! NOTE only old values are required but this procedure
4711+ ! expects latest and old. So pass in old twice - not optimal
4712+ call find_upwind_values(di%state, &
4713+ di%positions_pressure_mesh, &
4714+ di%old_saturation(p)%ptr, &
4715+ di%sfield_upwind, &
4716+ di%old_saturation(p)%ptr, &
4717+ di%sfield_upwind, &
4718+ option_path = trim(di%saturation(p)%ptr%option_path))
4719+
4720+ end if
4721+
4722+ ! Initialise optimisation flag used in finding upwind value in high resolution schemes
4723+ r_upwind_pos = 0
4724+ s_upwind_pos = 0
4725+
4726+ vol_element_loop_relperm: do vele = 1, di%number_vele
4727+
4728+ ! The node indices of the pressure mesh
4729+ p_nodes => ele_nodes(di%pressure_mesh, vele)
4730+
4731+ ! The node indices of the positions projected to the pressure mesh
4732+ x_pmesh_nodes => ele_nodes(di%positions_pressure_mesh, vele)
4733+
4734+ ! Determine the node numbers to use to determine the relperm upwind values
4735+ if((di%relperm_cv_options%upwind_scheme == CV_UPWINDVALUE_PROJECT_POINT).or.&
4736+ (di%relperm_cv_options%upwind_scheme == CV_UPWINDVALUE_PROJECT_GRAD)) then
4737+
4738+ r_upwind_nodes => x_pmesh_nodes
4739+
4740+ else
4741+
4742+ r_upwind_nodes => p_nodes
4743+
4744+ end if
4745+
4746+ if (di%determine_saturation_face_values) then
4747+
4748+ ! Determine the node numbers to use to determine the saturation upwind values
4749+ if((di%saturation_cv_options%upwind_scheme == CV_UPWINDVALUE_PROJECT_POINT).or.&
4750+ (di%saturation_cv_options%upwind_scheme == CV_UPWINDVALUE_PROJECT_GRAD)) then
4751+
4752+ s_upwind_nodes => x_pmesh_nodes
4753+
4754+ else
4755+
4756+ s_upwind_nodes => p_nodes
4757+
4758+ end if
4759+
4760+ do sat_p = 1, di%number_phase
4761+
4762+ ! get the old saturation ele values for this phase
4763+ old_sat_ele(:,sat_p) = ele_val(di%old_saturation(sat_p)%ptr, vele)
4764+
4765+ end do
4766+
4767+ end if
4768+
4769+ ! get the old_relperm ele values for this phase
4770+ old_relperm_ele = ele_val(di%old_relative_permeability(p)%ptr, vele)
4771+
4772+ ! The gravity values for this element for each direction
4773+ grav_ele = ele_val(di%gravity, vele)
4774+
4775+ ! get the viscosity value for this element for this phase
4776+ visc_ele = ele_val(di%viscosity(p)%ptr, vele)
4777+
4778+ ! get the absolute permeability value for this element
4779+ absperm_ele = ele_val(di%absolute_permeability, vele)
4780+
4781+ ! obtain the transformed determinant*weight and normals
4782+ if (di%cached_face_value%cached_detwei_normal) then
4783+
4784+ detwei => di%cached_face_value%detwei(:,vele)
4785+
4786+ normal => di%cached_face_value%normal(:,:,vele)
4787+
4788+ else
4789+
4790+ ! get the coordinate values for this element for each positions local node
4791+ x_ele = ele_val(di%positions, vele)
4792+
4793+ ! get the coordinate values for this element for each quadrature point
4794+ x_face_quad = ele_val_at_quad(di%positions, vele, di%x_cvshape)
4795+
4796+ call transform_cvsurf_to_physical(x_ele, di%x_cvshape, detwei, normal, di%cvfaces)
4797+
4798+ end if
4799+
4800+ ! obtain the derivative of the pressure mesh shape function at the CV face quadrature points
4801+ if (di%cached_face_value%cached_p_dshape) then
4802+
4803+ p_dshape => di%cached_face_value%p_dshape(:,:,:,vele)
4804+
4805+ else
4806+
4807+ call transform_to_physical(di%positions, vele, x_shape = di%x_cvshape_full, &
4808+ shape = di%p_cvshape_full, dshape = p_dshape)
4809+
4810+ end if
4811+
4812+ ! get the gradient pressure at the cv surface quadrature points for each direction for this phase
4813+ grad_pressure_face_quad = darcy_impes_ele_grad_at_quad_scalar(di%pressure(p)%ptr, vele, dn = p_dshape)
4814+
4815+ ! the latest DarcyVelocity/relperm at the quadrature points
4816+ ! determined from FE interpolation of each component, only used to determine upwind.
4817+ do dim = 1,di%ndim
4818+
4819+ v_over_relperm_face_quad(dim,:) = - (absperm_ele(1) / visc_ele(1)) * &
4820+(grad_pressure_face_quad(dim,:) - ele_val_at_quad(di%density(p)%ptr, vele, di%p_cvshape) * grav_ele(dim,1))
4821+
4822+ end do
4823+
4824+ ! Initialise array for the quadrature points of this
4825+ ! element for whether it has already been visited
4826+ notvisited = .true.
4827+
4828+ ! loop over local nodes within this element
4829+ nodal_loop_i_relperm: do iloc = 1, di%pressure_mesh%shape%loc
4830+
4831+ ! loop over CV faces internal to this element
4832+ face_loop_relperm: do face = 1, di%cvfaces%faces
4833+
4834+ ! is this a face neighbouring iloc?
4835+ is_neigh_relperm: if(di%cvfaces%neiloc(iloc, face) /= 0) then
4836+
4837+ ! find the opposing local node across the CV face
4838+ oloc = di%cvfaces%neiloc(iloc, face)
4839+
4840+ ! loop over gauss points on face
4841+ quadrature_loop_relperm: do gi = 1, di%cvfaces%shape%ngi
4842+
4843+ ! global gauss pt index for this element
4844+ ggi = (face-1)*di%cvfaces%shape%ngi + gi
4845+
4846+ ! check if this quadrature point has already been visited
4847+ check_visited_relperm: if(notvisited(ggi)) then
4848+
4849+ notvisited(ggi) = .false.
4850+
4851+ if (di%cached_face_value%cached_detwei_normal) then
4852+
4853+ ! cached normal has correct orientation already
4854+ normgi = normal(:,ggi)
4855+
4856+ else
4857+
4858+ ! correct the orientation of the normal so it points away from iloc
4859+ normgi = orientate_cvsurf_normgi(node_val(di%positions_pressure_mesh, x_pmesh_nodes(iloc)), &
4860+ &x_face_quad(:,ggi), normal(:,ggi))
4861+
4862+ end if
4863+
4864+ ! determine if the flow is in or out of the face at this quadrature
4865+ ! with respect to the normal orientation using the latest v_over_relperm
4866+ v_over_relperm_dot_n = dot_product(v_over_relperm_face_quad(:,ggi), normgi)
4867+
4868+ inflow = (v_over_relperm_dot_n<=0.0)
4869+
4870+ income = merge(1.0,0.0,inflow)
4871+
4872+ ! Evaluate the face value for relperm
4873+ call darcy_impes_evaluate_relperm_face_val(old_relperm_face_value, &
4874+ iloc, &
4875+ oloc, &
4876+ ggi, &
4877+ r_upwind_nodes, &
4878+ di%p_cvshape, &
4879+ old_relperm_ele, &
4880+ di%relperm_upwind, &
4881+ inflow, &
4882+ income, &
4883+ old_sat_ele, &
4884+ di%minimum_denominator_saturation_value, &
4885+ p, &
4886+ di%number_phase, &
4887+ di%relperm_corr_options, &
4888+ di%relperm_cv_options, &
4889+ save_pos = r_upwind_pos)
4890+
4891+ ! Evaluate the face value for saturation if required, else set to 1.0
4892+ if (di%determine_saturation_face_values) then
4893+
4894+ call darcy_impes_evaluate_sfield_face_val(old_sat_face_value, &
4895+ iloc, &
4896+ oloc, &
4897+ ggi, &
4898+ s_upwind_nodes, &
4899+ di%p_cvshape, &
4900+ old_sat_ele(:,p), &
4901+ di%sfield_upwind, &
4902+ inflow, &
4903+ income, &
4904+ di%saturation_cv_options, &
4905+ save_pos = s_upwind_pos)
4906+
4907+ else
4908+
4909+ old_sat_face_value = 1.0
4910+
4911+ end if
4912+
4913+ ! Cache the old relperm (or modrelperm*sat) face value
4914+ di%cached_face_value%relperm(1,ggi,vele,p) = old_relperm_face_value * old_sat_face_value
4915+
4916+ end if check_visited_relperm
4917+
4918+ end do quadrature_loop_relperm
4919+
4920+ end if is_neigh_relperm
4921+
4922+ end do face_loop_relperm
4923+
4924+ end do nodal_loop_i_relperm
4925+
4926+ end do vol_element_loop_relperm
4927+
4928+ ! Determine the upwind density values of all node pairs if required for higher order CV face value
4929+ if(di%density_cv_options%limit_facevalue) then
4930+
4931+ ! NOTE only new upwind values are required but this procedure
4932+ ! expects latest and old. So pass in new twice - not optimal
4933+ call find_upwind_values(di%state, &
4934+ di%positions_pressure_mesh, &
4935+ di%density(p)%ptr, &
4936+ di%sfield_upwind, &
4937+ di%density(p)%ptr, &
4938+ di%sfield_upwind, &
4939+ option_path = trim(di%density(p)%ptr%option_path))
4940+
4941+ end if
4942+
4943+ ! Initialise optimisation flag used in finding upwind value in high resolution schemes
4944+ d_upwind_pos = 0
4945+
4946+ vol_element_loop_den: do vele = 1, di%number_vele
4947+
4948+ ! The node indices of the pressure mesh
4949+ p_nodes => ele_nodes(di%pressure_mesh, vele)
4950+
4951+ ! The node indices of the positions projected to the pressure mesh
4952+ x_pmesh_nodes => ele_nodes(di%positions_pressure_mesh, vele)
4953+
4954+ ! Determine the node numbers to use to determine the density upwind values
4955+ if((di%density_cv_options%upwind_scheme == CV_UPWINDVALUE_PROJECT_POINT).or.&
4956+ (di%density_cv_options%upwind_scheme == CV_UPWINDVALUE_PROJECT_GRAD)) then
4957+
4958+ d_upwind_nodes => x_pmesh_nodes
4959+
4960+ else
4961+
4962+ d_upwind_nodes => p_nodes
4963+
4964+ end if
4965+
4966+ ! get the density value for this element for this phase
4967+ den_ele = ele_val(di%density(p)%ptr, vele)
4968+
4969+ ! The gravity values for this element for each direction
4970+ grav_ele = ele_val(di%gravity, vele)
4971+
4972+ ! get the viscosity value for this element for this phase
4973+ visc_ele = ele_val(di%viscosity(p)%ptr, vele)
4974+
4975+ ! get the absolute permeability value for this element
4976+ absperm_ele = ele_val(di%absolute_permeability, vele)
4977+
4978+ ! obtain the transformed determinant*weight and normals
4979+ if (di%cached_face_value%cached_detwei_normal) then
4980+
4981+ detwei => di%cached_face_value%detwei(:,vele)
4982+
4983+ normal => di%cached_face_value%normal(:,:,vele)
4984+
4985+ else
4986+
4987+ ! get the coordinate values for this element for each positions local node
4988+ x_ele = ele_val(di%positions, vele)
4989+
4990+ ! get the coordinate values for this element for each quadrature point
4991+ x_face_quad = ele_val_at_quad(di%positions, vele, di%x_cvshape)
4992+
4993+ call transform_cvsurf_to_physical(x_ele, di%x_cvshape, detwei, normal, di%cvfaces)
4994+
4995+ end if
4996+
4997+ ! obtain the derivative of the pressure mesh shape function at the CV face quadrature points
4998+ if (di%cached_face_value%cached_p_dshape) then
4999+
5000+ p_dshape => di%cached_face_value%p_dshape(:,:,:,vele)
The diff has been truncated for viewing.