├── .gitignore ├── gui ├── mainApp.mlapp ├── meshOptions.mlapp ├── mechanicalModel.mlapp ├── data │ ├── mat_mec_linearElastic.csv │ ├── mat_mec_vonMises.csv │ ├── mat_mec_druckerPrager.csv │ └── mat_mec_isoDamage.csv ├── regMeshGeneration.mlapp └── images │ ├── logo_porouslab_vertical.png │ └── logo_porouslab_vertical_reduced.png ├── docs ├── figures │ ├── logos │ │ ├── logo_puc.png │ │ ├── logo_upc.png │ │ ├── logo_cimne.png │ │ ├── logo_secco2.png │ │ └── logo_porouslab.png │ ├── examples │ │ ├── kueper_result.png │ │ ├── kueper_scheme.png │ │ ├── mcwhorter_result.png │ │ ├── mcwhorter_scheme.png │ │ ├── discontinuity_set.png │ │ ├── buckley_leverett_result.png │ │ ├── fractured_cell_fluid_flow.png │ │ ├── pressurized_cylinder_result.png │ │ ├── discontinuity_set_original_geometry.png │ │ └── discontinuity_set_linearized_geometry.png │ └── diagrams │ │ ├── uml_class_anl_white.png │ │ ├── uml_class_anl_transp.png │ │ ├── uml_class_model_white.png │ │ ├── uml_class_material_white.png │ │ ├── uml_class_model_transp.png │ │ └── uml_class_material_transp.png └── html │ ├── doc_eq05501865606120862508.png │ ├── doc_eq07208238743096903220.png │ ├── doc_eq08081079891865937472.png │ ├── doc_eq10757933797838149667.png │ ├── doc_eq17067059646665314470.png │ ├── doc_eq17454244308657937853.png │ ├── doc_physics_mechanical_eq03146882213354163936.png │ ├── doc_physics_mechanical_eq05501865606120862508.png │ ├── doc_physics_mechanical_eq05845194390529047301.png │ ├── doc_physics_mechanical_eq07208238743096903220.png │ ├── doc_physics_mechanical_eq08081079891865937472.png │ ├── doc_physics_mechanical_eq17067059646665314470.png │ ├── doc_physics_mechanical_eq17305928180582294089.png │ └── doc_physics_mechanical_eq17454244308657937853.png ├── examples ├── M │ ├── MeshStripFooting.mat │ ├── MeshSlopeStability.mat │ ├── MeshSlopeStabilityTransfinite.mat │ ├── MeshSlopeStabilityTransfiniteQuadratic.mat │ ├── example_m_plane_stress_traction_hybridmesh.m │ ├── example_m_plane_stress_traction_quadratic.m │ ├── example_m_porepressure.m │ ├── example_m_axissym_cylinder.m │ ├── example_m_plane_stress_traction.m │ ├── example_m_slope_stability.m │ ├── example_m_plate_discontinuity.m │ ├── example_m_compression_contact_stick_q4_discontinuity.m │ ├── example_m_strip_footing.m │ ├── example_m_stretching_discontinuity.m │ ├── example_m_pressurized_reservoir.m │ ├── example_m_partial_tension_q4_discontinuity.m │ ├── example_m_pressurized_cylinder.m │ ├── example_m_porepressure_discontinuity.m │ └── example_m_pressurized_cylinder_asymptotic.m ├── H │ ├── FractureDataReservoirCell.mat │ ├── example_h_fluid_flow_discontinuity.m │ ├── example_h_fluid_flow_rock.m │ ├── example_h_fluid_flow_barrier.m │ ├── example_h_fluid_flow_dam.m │ └── example_h_fractured_reservoir_cell.m ├── HM │ ├── example_hm_terzaghi.m │ └── example_hm_terzaghi_analytical.m └── H2 │ ├── example_h2_mcwhorter_pc_pg.m │ ├── example_h2_mcwhorter_pl_pg.m │ ├── example_h2_five_spot_pc_pg.m │ ├── example_h2_buckley_leverett_pl_pg.m │ ├── example_h2_buckley_leverett_pc_pg.m │ └── example_h2_liakopoulos_pc_pg.m ├── tests ├── regression │ ├── files │ │ ├── MeshStripFooting.mat │ │ ├── test_hm_terzaghi_ref.mat │ │ ├── test_h_fluid_flow_dam_ref.mat │ │ ├── test_m_strip_footing_ref.mat │ │ ├── test_h2_five_spot_pc_pg_ref.mat │ │ ├── test_h2_mcwhorter_pl_pg_ref.mat │ │ ├── test_h_fluid_flow_rock_ref.mat │ │ ├── test_m_axissym_cylinder_ref.mat │ │ ├── test_m_slope_stability_ref.mat │ │ ├── test_h2_liakopoulos_pc_pg_ref.mat │ │ ├── test_h_fluid_flow_barrier_ref.mat │ │ ├── test_m_plate_discontinuity_ref.mat │ │ ├── test_m_plane_stress_traction_ref.mat │ │ ├── test_m_pressurized_cylinder_ref.mat │ │ ├── test_h2_buckley_leverett_pc_pg_ref.mat │ │ ├── test_h_fluid_flow_discontinuity_ref.mat │ │ ├── MeshSlopeStabilityTransfiniteQuadratic.mat │ │ ├── test_h2_dnapl_infiltration_pc_pg_ref.mat │ │ ├── test_m_plane_stress_traction_hybridmesh_ref.mat │ │ ├── test_m_plane_stress_traction_quadratic_ref.mat │ │ ├── test_m_plane_stress_traction_quadratic.m │ │ ├── test_m_plane_stress_traction_hybridmesh.m │ │ ├── test_m_axissym_cylinder.m │ │ ├── test_hm_terzaghi.m │ │ ├── test_h_fluid_flow_discontinuity.m │ │ ├── test_h_fluid_flow_rock.m │ │ ├── test_m_plane_stress_traction.m │ │ ├── test_m_plate_discontinuity.m │ │ ├── test_h_fluid_flow_dam.m │ │ ├── test_m_slope_stability.m │ │ ├── test_h_fluid_flow_barrier.m │ │ ├── test_m_strip_footing.m │ │ ├── test_h2_mcwhorter_pl_pg.m │ │ ├── test_m_pressurized_cylinder.m │ │ ├── test_h2_buckley_leverett_pc_pg.m │ │ ├── test_h2_five_spot_pc_pg.m │ │ └── test_h2_liakopoulos_pc_pg.m │ ├── generate_reference_results.m │ └── run_tests.m └── validation │ ├── validation_stress_integration_dp.m │ └── validation_stress_integration_vm.m ├── .github ├── PULL_REQUEST_TEMPLATE │ └── pull_request.md └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── CITATION.cff ├── src ├── analysis │ ├── Anl.m │ ├── ControlMethod.m │ ├── ControlMethod_Load.m │ ├── ControlMethod_MinNorm.m │ ├── ControlMethod_GenDispl.m │ ├── ControlMethod_Displ.m │ ├── ControlMethod_OrtResidual.m │ ├── ControlMethod_Work.m │ ├── ControlMethod_ArcUNP.m │ ├── Anl_Linear.m │ ├── ControlMethod_ArcFNP.m │ ├── ControlMethod_ArcCyl.m │ ├── ControlMethod_ArcSph.m │ ├── NonlinearScheme.m │ └── NonlinearScheme_Newton.m ├── fem │ └── Element.m ├── auxiliary │ ├── print_header.m │ ├── isInsideRectangle.m │ └── Gmsh2Porouslab.py ├── material │ ├── relativePermeability │ │ ├── RelativePermeability.m │ │ ├── RelativePermeabilityBrooksCoreyLiquid.m │ │ ├── RelativePermeabilityBrooksCoreyGas.m │ │ ├── RelativePermeabilityPolynomialGas.m │ │ ├── RelativePermeabilityPolynomialLiquid.m │ │ ├── RelativePermeabilityUMAT.m │ │ └── RelativePermeabilityLiakopoulosLiquid.m │ ├── Fluid.m │ ├── saturationLaw │ │ ├── CapillaryPressure.m │ │ ├── CapillaryPressureBrooksCorey.m │ │ └── CapillaryPressureLiakopoulos.m │ ├── IdealGas.m │ └── cohesiveLaw │ │ └── MechanicalCohesiveLinearElastic.m ├── porouslab.m ├── mesh │ ├── discontinuity │ │ ├── generateFract.m │ │ └── findElemIntersected.m │ └── convertToQuadraticMesh.m ├── physics │ ├── H │ │ ├── MaterialDiscontinuity_H.m │ │ └── Material_H.m │ └── M │ │ ├── MaterialDiscontinuity_M.m │ │ └── Material_M.m ├── pos │ └── Result.m └── shape │ └── Shape.m ├── LICENSE ├── CONTRIBUTING.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.asv -------------------------------------------------------------------------------- /gui/mainApp.mlapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/gui/mainApp.mlapp -------------------------------------------------------------------------------- /gui/meshOptions.mlapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/gui/meshOptions.mlapp -------------------------------------------------------------------------------- /gui/mechanicalModel.mlapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/gui/mechanicalModel.mlapp -------------------------------------------------------------------------------- /gui/data/mat_mec_linearElastic.csv: -------------------------------------------------------------------------------- 1 | Young modulus,1.00E+06,kPa 2 | Poisson ratio,0.2, 3 | Density,2000,kg/m3 4 | -------------------------------------------------------------------------------- /gui/regMeshGeneration.mlapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/gui/regMeshGeneration.mlapp -------------------------------------------------------------------------------- /docs/figures/logos/logo_puc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/logos/logo_puc.png -------------------------------------------------------------------------------- /docs/figures/logos/logo_upc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/logos/logo_upc.png -------------------------------------------------------------------------------- /examples/M/MeshStripFooting.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/examples/M/MeshStripFooting.mat -------------------------------------------------------------------------------- /docs/figures/logos/logo_cimne.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/logos/logo_cimne.png -------------------------------------------------------------------------------- /docs/figures/logos/logo_secco2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/logos/logo_secco2.png -------------------------------------------------------------------------------- /examples/M/MeshSlopeStability.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/examples/M/MeshSlopeStability.mat -------------------------------------------------------------------------------- /docs/figures/logos/logo_porouslab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/logos/logo_porouslab.png -------------------------------------------------------------------------------- /docs/figures/examples/kueper_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/examples/kueper_result.png -------------------------------------------------------------------------------- /docs/figures/examples/kueper_scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/examples/kueper_scheme.png -------------------------------------------------------------------------------- /docs/html/doc_eq05501865606120862508.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_eq05501865606120862508.png -------------------------------------------------------------------------------- /docs/html/doc_eq07208238743096903220.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_eq07208238743096903220.png -------------------------------------------------------------------------------- /docs/html/doc_eq08081079891865937472.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_eq08081079891865937472.png -------------------------------------------------------------------------------- /docs/html/doc_eq10757933797838149667.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_eq10757933797838149667.png -------------------------------------------------------------------------------- /docs/html/doc_eq17067059646665314470.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_eq17067059646665314470.png -------------------------------------------------------------------------------- /docs/html/doc_eq17454244308657937853.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_eq17454244308657937853.png -------------------------------------------------------------------------------- /examples/H/FractureDataReservoirCell.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/examples/H/FractureDataReservoirCell.mat -------------------------------------------------------------------------------- /gui/images/logo_porouslab_vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/gui/images/logo_porouslab_vertical.png -------------------------------------------------------------------------------- /docs/figures/examples/mcwhorter_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/examples/mcwhorter_result.png -------------------------------------------------------------------------------- /docs/figures/examples/mcwhorter_scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/examples/mcwhorter_scheme.png -------------------------------------------------------------------------------- /docs/figures/diagrams/uml_class_anl_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/diagrams/uml_class_anl_white.png -------------------------------------------------------------------------------- /docs/figures/examples/discontinuity_set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/examples/discontinuity_set.png -------------------------------------------------------------------------------- /examples/M/MeshSlopeStabilityTransfinite.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/examples/M/MeshSlopeStabilityTransfinite.mat -------------------------------------------------------------------------------- /tests/regression/files/MeshStripFooting.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/MeshStripFooting.mat -------------------------------------------------------------------------------- /docs/figures/diagrams/uml_class_anl_transp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/diagrams/uml_class_anl_transp.png -------------------------------------------------------------------------------- /docs/figures/diagrams/uml_class_model_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/diagrams/uml_class_model_white.png -------------------------------------------------------------------------------- /gui/images/logo_porouslab_vertical_reduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/gui/images/logo_porouslab_vertical_reduced.png -------------------------------------------------------------------------------- /tests/regression/files/test_hm_terzaghi_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_hm_terzaghi_ref.mat -------------------------------------------------------------------------------- /docs/figures/diagrams/uml_class_material_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/diagrams/uml_class_material_white.png -------------------------------------------------------------------------------- /docs/figures/diagrams/uml_class_model_transp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/diagrams/uml_class_model_transp.png -------------------------------------------------------------------------------- /docs/figures/examples/buckley_leverett_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/examples/buckley_leverett_result.png -------------------------------------------------------------------------------- /gui/data/mat_mec_vonMises.csv: -------------------------------------------------------------------------------- 1 | Young modulus,1.00E+06,kPa 2 | Poisson ratio,0.2, 3 | Density,2000,kg/m3 4 | Yield stress in uniaxial tensile,1.00E+05,kPa 5 | -------------------------------------------------------------------------------- /docs/figures/diagrams/uml_class_material_transp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/diagrams/uml_class_material_transp.png -------------------------------------------------------------------------------- /docs/figures/examples/fractured_cell_fluid_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/examples/fractured_cell_fluid_flow.png -------------------------------------------------------------------------------- /tests/regression/files/test_h_fluid_flow_dam_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_h_fluid_flow_dam_ref.mat -------------------------------------------------------------------------------- /tests/regression/files/test_m_strip_footing_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_m_strip_footing_ref.mat -------------------------------------------------------------------------------- /docs/figures/examples/pressurized_cylinder_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/examples/pressurized_cylinder_result.png -------------------------------------------------------------------------------- /examples/M/MeshSlopeStabilityTransfiniteQuadratic.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/examples/M/MeshSlopeStabilityTransfiniteQuadratic.mat -------------------------------------------------------------------------------- /tests/regression/files/test_h2_five_spot_pc_pg_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_h2_five_spot_pc_pg_ref.mat -------------------------------------------------------------------------------- /tests/regression/files/test_h2_mcwhorter_pl_pg_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_h2_mcwhorter_pl_pg_ref.mat -------------------------------------------------------------------------------- /tests/regression/files/test_h_fluid_flow_rock_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_h_fluid_flow_rock_ref.mat -------------------------------------------------------------------------------- /tests/regression/files/test_m_axissym_cylinder_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_m_axissym_cylinder_ref.mat -------------------------------------------------------------------------------- /tests/regression/files/test_m_slope_stability_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_m_slope_stability_ref.mat -------------------------------------------------------------------------------- /tests/regression/files/test_h2_liakopoulos_pc_pg_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_h2_liakopoulos_pc_pg_ref.mat -------------------------------------------------------------------------------- /tests/regression/files/test_h_fluid_flow_barrier_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_h_fluid_flow_barrier_ref.mat -------------------------------------------------------------------------------- /tests/regression/files/test_m_plate_discontinuity_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_m_plate_discontinuity_ref.mat -------------------------------------------------------------------------------- /docs/html/doc_physics_mechanical_eq03146882213354163936.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_physics_mechanical_eq03146882213354163936.png -------------------------------------------------------------------------------- /docs/html/doc_physics_mechanical_eq05501865606120862508.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_physics_mechanical_eq05501865606120862508.png -------------------------------------------------------------------------------- /docs/html/doc_physics_mechanical_eq05845194390529047301.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_physics_mechanical_eq05845194390529047301.png -------------------------------------------------------------------------------- /docs/html/doc_physics_mechanical_eq07208238743096903220.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_physics_mechanical_eq07208238743096903220.png -------------------------------------------------------------------------------- /docs/html/doc_physics_mechanical_eq08081079891865937472.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_physics_mechanical_eq08081079891865937472.png -------------------------------------------------------------------------------- /docs/html/doc_physics_mechanical_eq17067059646665314470.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_physics_mechanical_eq17067059646665314470.png -------------------------------------------------------------------------------- /docs/html/doc_physics_mechanical_eq17305928180582294089.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_physics_mechanical_eq17305928180582294089.png -------------------------------------------------------------------------------- /docs/html/doc_physics_mechanical_eq17454244308657937853.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/html/doc_physics_mechanical_eq17454244308657937853.png -------------------------------------------------------------------------------- /tests/regression/files/test_m_plane_stress_traction_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_m_plane_stress_traction_ref.mat -------------------------------------------------------------------------------- /tests/regression/files/test_m_pressurized_cylinder_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_m_pressurized_cylinder_ref.mat -------------------------------------------------------------------------------- /docs/figures/examples/discontinuity_set_original_geometry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/examples/discontinuity_set_original_geometry.png -------------------------------------------------------------------------------- /tests/regression/files/test_h2_buckley_leverett_pc_pg_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_h2_buckley_leverett_pc_pg_ref.mat -------------------------------------------------------------------------------- /tests/regression/files/test_h_fluid_flow_discontinuity_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_h_fluid_flow_discontinuity_ref.mat -------------------------------------------------------------------------------- /docs/figures/examples/discontinuity_set_linearized_geometry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/docs/figures/examples/discontinuity_set_linearized_geometry.png -------------------------------------------------------------------------------- /tests/regression/files/MeshSlopeStabilityTransfiniteQuadratic.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/MeshSlopeStabilityTransfiniteQuadratic.mat -------------------------------------------------------------------------------- /tests/regression/files/test_h2_dnapl_infiltration_pc_pg_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_h2_dnapl_infiltration_pc_pg_ref.mat -------------------------------------------------------------------------------- /gui/data/mat_mec_druckerPrager.csv: -------------------------------------------------------------------------------- 1 | Young modulus,1.00E+06,kPa 2 | Poisson ratio,0.2, 3 | Density,2,g/cm3 4 | Cohesion,0.00E+00,kPa 5 | Friction angle,20,degree 6 | Dilation angle,20,degree 7 | -------------------------------------------------------------------------------- /tests/regression/files/test_m_plane_stress_traction_hybridmesh_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_m_plane_stress_traction_hybridmesh_ref.mat -------------------------------------------------------------------------------- /tests/regression/files/test_m_plane_stress_traction_quadratic_ref.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbcavalcanti/porousLab/HEAD/tests/regression/files/test_m_plane_stress_traction_quadratic_ref.mat -------------------------------------------------------------------------------- /gui/data/mat_mec_isoDamage.csv: -------------------------------------------------------------------------------- 1 | Young modulus,1.00E+06,kPa 2 | Poisson ratio,0.2, 3 | Density,2000,kg/m3 4 | Damage threshold,1.00E-04, 5 | Mode 1 fracture energy,5.00E-02,kN/m 6 | Tensile and compressive strength ratio,10.00, 7 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/pull_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Pull request 3 | about: Bug fix, new features or other implementations 4 | assignees: dbcavalcanti 5 | 6 | --- 7 | 8 | **Description** 9 | A clear and concise description of the PR. 10 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this software, please cite it using these metadata." 3 | title: "PorousLab" 4 | type: software 5 | authors: 6 | - family-names: Cavalcanti 7 | given-names: Danilo 8 | version: 1.0.0 9 | date-released: "2025-06-01" 10 | license: MIT 11 | repository-code: "https://github.com/dbcavalcanti/porousLab" 12 | doi: 10.5281/zenodo.15624962 13 | -------------------------------------------------------------------------------- /src/analysis/Anl.m: -------------------------------------------------------------------------------- 1 | %% Anl Class 2 | % This in an abstract class that defines an analysis object. 3 | % 4 | %% Authors 5 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 6 | % 7 | %% Class definition 8 | classdef Anl < handle 9 | %% Public properties 10 | properties (SetAccess = public, GetAccess = public) 11 | type = []; 12 | end 13 | 14 | %% Constructor method 15 | methods 16 | %------------------------------------------------------------------ 17 | function this = Anl(type) 18 | if nargin > 0 19 | this.type = type; 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /src/fem/Element.m: -------------------------------------------------------------------------------- 1 | %% Element Class 2 | % This in an abstract class that defines a finite element. 3 | % 4 | %% Authors 5 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 6 | % 7 | %% Class definition 8 | classdef Element < handle 9 | %% Public properties 10 | properties (SetAccess = public, GetAccess = public) 11 | type = []; 12 | end 13 | 14 | %% Constructor method 15 | methods 16 | %------------------------------------------------------------------ 17 | function this = Element(type) 18 | if nargin > 0 19 | this.type = type; 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /src/auxiliary/print_header.m: -------------------------------------------------------------------------------- 1 | fprintf('==================================================================\n'); 2 | fprintf(' PorousLab \n'); 3 | fprintf(' FEM framework for multiphysics problems in porous media \n\n'); 4 | fprintf(' Version 1.0 - June 2025 \n\n'); 5 | fprintf(' International Center for Numerical Methods in Engineering (CIMNE)\n'); 6 | fprintf(' Applied Computational Physics Group \n\n'); 7 | fprintf(' Danilo Cavalcanti (dborges@cimne.upc.edu) \n'); 8 | fprintf('==================================================================\n\n'); 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this software 4 | labels: enhancement 5 | assignees: dbcavalcanti 6 | 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /src/auxiliary/isInsideRectangle.m: -------------------------------------------------------------------------------- 1 | %% isInsideRectangle Function 2 | % This function checks whether a set of points lies inside a rectangle defined by two opposite corners, X1 and X2. 3 | % The rectangle is assumed to be axis-aligned. 4 | % 5 | %% Inputs 6 | % * P* A matrix of size Nx2, where each row represents a point (x, y).. 7 | % * X1: A 1x2 vector representing the coordinates of one corner of the rectangle. 8 | % * X2: A 1x2 vector representing the coordinates of opposite corner of the rectangle. 9 | % 10 | %% Outputs 11 | % * d: A column vector of size Nx1, where each element is 1 if the corresponding point in P is inside the rectangle, and 0 otherwise. 12 | % 13 | %% Authors 14 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 15 | % 16 | %% Function definition 17 | function d = isInsideRectangle(P,X1,X2) 18 | d = (P(:,1)>=X1(1)) .* (P(:,2)>=X1(2)) .* (P(:,1)<=X2(1)) .* (P(:,2)<=X2(2)); 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug, problem, issue or a missing feature 4 | labels: bug 5 | assignees: dbcavalcanti 6 | 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 1. Go to '...' 15 | 2. Click on '....' 16 | 3. Scroll down to '....' 17 | 4. See error 18 | 19 | **Expected behavior** 20 | A description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Environment (please complete the following information):** 26 | Please specify your operating system, MATLAB version, branch name, or any other environment information that you consider relevant. 27 | E.g.: 28 | - OS: Windows 10 29 | - MATLAB 2022b 30 | - Branch: main 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Danilo Cavalcanti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/regression/files/test_m_plane_stress_traction_quadratic.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Uniform traction on a plate with linear elastic model and quadratic finite element mesh. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | [node, elem] = regularMesh(0.11, 0.04, 22, 8); 20 | [node, elem] = convertToQuadraticMesh(node, elem); 21 | 22 | % Set mesh to model 23 | mdl.setMesh(node, elem); 24 | mdl.resequenceNodes(); 25 | 26 | %% MATERIALS 27 | 28 | % Create porous media 29 | rock = PorousMedia('rock'); 30 | rock.mechanical = 'elastic'; % Constitutive law 31 | rock.Young = 2.0e+10; % Young modulus (Pa) 32 | rock.nu = 0.0; % Poisson ratio 33 | 34 | % Set materials to model 35 | mdl.setMaterial(rock); 36 | 37 | %% BOUNDARY CONDITIONS 38 | 39 | % Displacements 40 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, 0.0]); 41 | 42 | % Loads 43 | mdl.addLoadAtBorder('right', 1, 2.0e+6); 44 | 45 | %% PROCESS 46 | 47 | % Run analysis 48 | anl = Anl_Linear(); 49 | anl.run(mdl); -------------------------------------------------------------------------------- /tests/regression/generate_reference_results.m: -------------------------------------------------------------------------------- 1 | %% PorousLab - FEM framework for multiphysics problems in porous media 2 | % 3 | % This is the reference generation file for regression tests in PorousLab. 4 | % Execute this file to generate or overwrite the reference results of each test case. 5 | % 6 | clc; clearvars; close all; 7 | 8 | files_dir = fullfile(pwd, 'files'); 9 | test_files = dir(fullfile(files_dir, 'test_*.m')); 10 | src_dir = fullfile(fileparts(mfilename('fullpath')), '..', '..', 'src'); 11 | addpath(genpath(src_dir)); 12 | 13 | for i = 1:length(test_files) 14 | test_name = test_files(i).name(1:end-2); 15 | fprintf('Running %s...\n', test_name); 16 | 17 | try 18 | clear mdl U_ref; 19 | run(fullfile(files_dir, test_name)); 20 | 21 | if ~exist('mdl', 'var') || ~isprop(mdl, 'U') || isempty(mdl.U) 22 | warning('⚠️ Skipped: mdl.U not found\n\n'); 23 | continue; 24 | end 25 | 26 | U_ref = mdl.U; 27 | ref_name = [test_name,'_ref.mat']; 28 | save(fullfile(files_dir, ref_name), 'U_ref'); 29 | fprintf('✅ Saved reference results in %s\n\n', ref_name); 30 | 31 | catch ME 32 | warning('⚠️ Skipped: Failed to run\n\n'); 33 | continue; 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /tests/regression/files/test_m_plane_stress_traction_hybridmesh.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Uniform traction on a plate with linear elastic model. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | node = [0.0 , 0.0; 20 | 0.0 , 1.0; 21 | 1.0 , 0.0; 22 | 1.0 , 1.0; 23 | 1.5 , 0.5; 24 | 2.0 , 0.0; 25 | 2.0 , 1.0]; 26 | 27 | elem = {[1, 3, 4, 2]; 28 | [3, 6, 5]; 29 | [6, 7, 5]; 30 | [7, 4, 5]; 31 | [4, 3, 5]}; 32 | 33 | % Set mesh to model 34 | mdl.setMesh(node, elem); 35 | 36 | %% MATERIALS 37 | 38 | % Create porous media 39 | rock = PorousMedia('rock'); 40 | rock.mechanical = 'elastic'; % Constitutive law 41 | rock.Young = 2.0e+10; % Young modulus (Pa) 42 | rock.nu = 0.0; % Poisson ratio 43 | 44 | % Set materials to model 45 | mdl.setMaterial(rock); 46 | 47 | %% BOUNDARY CONDITIONS 48 | 49 | % Displacements 50 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, 0.0]); 51 | 52 | % Loads 53 | mdl.addLoadAtBorder('right', 1, 2.0e+6); 54 | 55 | %% PROCESS 56 | 57 | % Run analysis 58 | anl = Anl_Linear(); 59 | anl.run(mdl); -------------------------------------------------------------------------------- /src/material/relativePermeability/RelativePermeability.m: -------------------------------------------------------------------------------- 1 | %% RelativePermeability Class 2 | % This class defines an abstract base class for modeling relative 3 | % permeability in porous media. It provides a framework for implementing 4 | % specific relative permeability models by defining an abstract method 5 | % _calculate_ that must be implemented in derived classes. 6 | % 7 | %% Methods 8 | % *calculate*: Abstract method to compute the relative permeability. This 9 | % method must be implemented in subclasses. 10 | % 11 | %% Author 12 | % Danilo Cavalcanti 13 | % 14 | %% Version History 15 | % Version 1.00. 16 | % 17 | %% Class Definition 18 | classdef RelativePermeability < handle 19 | %% Public attributes 20 | properties (SetAccess = public, GetAccess = public) 21 | id = 'name1'; 22 | end 23 | 24 | %% Constructor method 25 | methods 26 | %------------------------------------------------------------------ 27 | function this = RelativePermeability(matModel) 28 | this.id = matModel; 29 | end 30 | end 31 | 32 | %% Abstract methods 33 | methods(Abstract) 34 | 35 | %------------------------------------------------------------------ 36 | % Compute the relative permeability 37 | kr = calculate(this, Sw, porousMedia); 38 | 39 | end 40 | 41 | end -------------------------------------------------------------------------------- /tests/regression/files/test_m_axissym_cylinder.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Elastic pressurized cilynder using axisymmetric model. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | mdl.isAxisSymmetric = true; 17 | 18 | %% MESH 19 | 20 | % Cilynder geometrical properties 21 | r_i = 0.1; 22 | r_e = 0.2; 23 | h = 0.5; 24 | 25 | % Create mesh 26 | [node, elem] = regularMesh(r_e - r_i, h, 10, 50); 27 | node(:,1) = node(:,1) + r_i; 28 | 29 | [node, elem] = convertToQuadraticMesh(node, elem); 30 | 31 | % Set mesh to model 32 | mdl.setMesh(node, elem); 33 | mdl.resequenceNodes(); 34 | 35 | %% MATERIALS 36 | 37 | % Create porous media 38 | rock = PorousMedia('rock'); 39 | rock.mechanical = 'elastic'; % Constitutive law 40 | rock.Young = 30.0e6; % Young modulus (Pa) 41 | rock.nu = 0.3; % Poisson ratio 42 | 43 | % Set materials to model 44 | mdl.setMaterial(rock); 45 | 46 | %% BOUNDARY CONDITIONS 47 | 48 | % Displacements 49 | mdl.setDisplacementDirichletBCAtBorder('top' , [NaN, 0.0]); 50 | mdl.setDisplacementDirichletBCAtBorder('bottom', [NaN, 0.0]); 51 | 52 | % Loads 53 | pint = 1.0; 54 | mdl.addLoadAtBorder('left', 1, pint); 55 | 56 | %% PROCESS 57 | 58 | % Run analysis 59 | anl = Anl_Linear(); 60 | anl.run(mdl); -------------------------------------------------------------------------------- /src/porouslab.m: -------------------------------------------------------------------------------- 1 | %% PorousLab - FEM framework for multiphysics problems in porous media 2 | % 3 | % This is the main function of PorousLab. 4 | % To run a simulation, call this function by passing the full path to the simulation script as input argument. 5 | % If no input argument is provided, a dialog appears for manual selection of the simulation script. 6 | % 7 | function porouslab(varargin) 8 | clc; clearvars -except varargin; close all; 9 | addpath(genpath(pwd)); 10 | print_header; 11 | 12 | if nargin == 0 13 | [file_name, file_path] = uigetfile('*.m', 'Select a script to run'); 14 | if isequal(file_name, 0) 15 | disp('No file selected.'); 16 | return; 17 | end 18 | elseif nargin == 1 19 | script = varargin{1}; 20 | if ischar(script) || isstring(script) 21 | script = char(script); 22 | [file_path, file_name, ext] = fileparts(script); 23 | file_name = [file_name, ext]; 24 | if ~strcmp(ext,'.m') || ~exist(script,'file') 25 | error('The provided file must be a valid Matlab script.'); 26 | end 27 | else 28 | error('Input must be a string or character vector.'); 29 | end 30 | else 31 | error('Invalid number of input arguments.'); 32 | end 33 | 34 | addpath(file_path); 35 | run(file_name); 36 | end 37 | -------------------------------------------------------------------------------- /src/mesh/discontinuity/generateFract.m: -------------------------------------------------------------------------------- 1 | %% generateFract Function 2 | % This function creates a set of nodes and connectivity information for a 3 | % fracture line defined between two points in 2D space. The fracture is 4 | % discretized into a specified number of divisions. 5 | % 6 | %% Inputs 7 | % * *X0*: A vector specifying the starting point of the fracture [x, y]. 8 | % * *X1*: A vector specifying the ending point of the fracture [x, y]. 9 | % * *nDiv*: An integer specifying the number of divisions for the fracture. 10 | % 11 | %% Outputs 12 | % * *NODE_D*: A matrix containing the coordinates of the nodes along the 13 | % fracture. Each row represents a node, with the first column 14 | % being the x-coordinate and the second column being the 15 | % y-coordinate. 16 | % * *FRACT*: A matrix representing the connectivity of the fracture 17 | % segments. Each row defines a segment by specifying the 18 | % indices of its two endpoints in NODE_D. 19 | % 20 | %% Author 21 | % Danilo Cavalcanti 22 | % 23 | %% Version History 24 | % Version 1.00. 25 | % 26 | %% Function definition 27 | function [NODE_D,FRACT] = generateFract(X0, X1, nDiv) 28 | 29 | NODE_D = [linspace(X0(1),X1(1),nDiv+1)',linspace(X0(2),X1(2),nDiv+1)']; 30 | 31 | FRACT = zeros(nDiv,2); 32 | FRACT(1,:) = [1 2]; 33 | for i = 2:nDiv 34 | FRACT(i,:) = FRACT(i-1,:) + [1 1]; 35 | end 36 | 37 | end 38 | -------------------------------------------------------------------------------- /src/material/relativePermeability/RelativePermeabilityBrooksCoreyLiquid.m: -------------------------------------------------------------------------------- 1 | %% RelativePermeabilityBrooksCoreyLiquid Class 2 | % This class implements the Brooks-Corey model for calculating the relative 3 | % permeability of the liquid phase in a porous medium. It inherits from the 4 | % _RelativePermeability_ base class. 5 | % 6 | %% Method 7 | % * *calculate*: Computes the liquid phase relative permeability based on 8 | % the effective saturation degree Se and the Brooks-Corey 9 | % model. 10 | % 11 | %% Author 12 | % Danilo Cavalcanti 13 | % 14 | %% Version History 15 | % Version 1.00. 16 | % 17 | %% Class Definition 18 | classdef RelativePermeabilityBrooksCoreyLiquid < RelativePermeability 19 | %% Constructor method 20 | methods 21 | %------------------------------------------------------------------ 22 | function this = RelativePermeabilityBrooksCoreyLiquid() 23 | this = this@RelativePermeability('brooksCoreyLiquid'); 24 | end 25 | end 26 | 27 | %% Public methods 28 | methods 29 | 30 | %------------------------------------------------------------------ 31 | % Compute the liquid phase relative permeability 32 | function klr = calculate(~, Sl, porousMedia) 33 | Se = porousMedia.effectiveSaturationDegree(Sl); 34 | klr = Se^((2.0 + 3.0 * porousMedia.lambda)/porousMedia.lambda); 35 | klr = max(klr,porousMedia.klrmin); 36 | end 37 | 38 | end 39 | end -------------------------------------------------------------------------------- /examples/M/example_m_plane_stress_traction_hybridmesh.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Uniform traction on a plate with linear elastic model. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | node = [0.0 , 0.0; 20 | 0.0 , 1.0; 21 | 1.0 , 0.0; 22 | 1.0 , 1.0; 23 | 1.5 , 0.5; 24 | 2.0 , 0.0; 25 | 2.0 , 1.0]; 26 | 27 | elem = {[1, 3, 4, 2]; 28 | [3, 6, 5]; 29 | [6, 7, 5]; 30 | [7, 4, 5]; 31 | [4, 3, 5]}; 32 | 33 | % Set mesh to model 34 | mdl.setMesh(node, elem); 35 | 36 | %% MATERIALS 37 | 38 | % Create porous media 39 | rock = PorousMedia('rock'); 40 | rock.mechanical = 'elastic'; % Constitutive law 41 | rock.Young = 2.0e+10; % Young modulus (Pa) 42 | rock.nu = 0.0; % Poisson ratio 43 | 44 | % Set materials to model 45 | mdl.setMaterial(rock); 46 | 47 | %% BOUNDARY CONDITIONS 48 | 49 | % Displacements 50 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, 0.0]); 51 | 52 | % Loads 53 | mdl.addLoadAtBorder('right', 1, 2.0e+6); 54 | 55 | %% PROCESS 56 | 57 | % Run analysis 58 | anl = Anl_Linear(); 59 | anl.run(mdl); 60 | 61 | %% POS-PROCESS 62 | 63 | % Print results to command window 64 | mdl.printResults(); 65 | 66 | % Plot contours 67 | mdl.plotFieldAlongSegment('Ux',[0.0,0.5],[2.0,0.5],10) 68 | mdl.plotField('Ux'); 69 | mdl.plotField('Sx'); 70 | -------------------------------------------------------------------------------- /examples/M/example_m_plane_stress_traction_quadratic.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Uniform traction on a plate with linear elastic model and quadratic finite element mesh. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | Lx = 0.11; % Horizontal dimension (m) 20 | Ly = 0.04; % Vertical dimension (m) 21 | Nx = 22; % Number of elements in the x-direction 22 | Ny = 8; % Number of elements in the y-direction 23 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 24 | [node, elem] = convertToQuadraticMesh(node, elem); 25 | 26 | % Set mesh to model 27 | mdl.setMesh(node, elem); 28 | mdl.resequenceNodes(); 29 | 30 | %% MATERIALS 31 | 32 | % Create porous media 33 | rock = PorousMedia('rock'); 34 | rock.mechanical = 'elastic'; % Constitutive law 35 | rock.Young = 2.0e+10; % Young modulus (Pa) 36 | rock.nu = 0.0; % Poisson ratio 37 | 38 | % Set materials to model 39 | mdl.setMaterial(rock); 40 | 41 | %% BOUNDARY CONDITIONS 42 | 43 | % Displacements 44 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, 0.0]); 45 | 46 | % Loads 47 | mdl.addLoadAtBorder('right', 1, 2.0e+6); 48 | 49 | %% PROCESS 50 | 51 | % Run analysis 52 | anl = Anl_Linear(); 53 | anl.run(mdl); 54 | 55 | %% POS-PROCESS 56 | 57 | % Print results to command window 58 | mdl.printResults(); 59 | 60 | % Plot contours 61 | mdl.plotField('Ux'); 62 | mdl.plotField('Sx'); 63 | -------------------------------------------------------------------------------- /src/material/relativePermeability/RelativePermeabilityBrooksCoreyGas.m: -------------------------------------------------------------------------------- 1 | %% RelativePermeabilityBrooksCoreyGas Class 2 | % This class implements the Brooks-Corey model for calculating the 3 | % relative permeability of the gas phase in porous media. The model is 4 | % based on the effective saturation degree and incorporates a minimum 5 | % relative permeability threshold. 6 | % 7 | %% Method 8 | % * *calculate*: Computes the gas phase relative permeability based on the 9 | % effective saturation degree Se and the Brooks-Corey model. 10 | % 11 | %% Author 12 | % Danilo Cavalcanti 13 | % 14 | %% Version History 15 | % Version 1.00. 16 | % 17 | %% Class Definition 18 | classdef RelativePermeabilityBrooksCoreyGas < RelativePermeability 19 | %% Constructor method 20 | methods 21 | %------------------------------------------------------------------ 22 | function this = RelativePermeabilityBrooksCoreyGas() 23 | this = this@RelativePermeability('brooksCoreyGas'); 24 | end 25 | end 26 | 27 | %% Public methods 28 | methods 29 | 30 | %------------------------------------------------------------------ 31 | % Compute the gas phase relative permeability 32 | function kgr = calculate(~, Sl, porousMedia) 33 | Se = porousMedia.effectiveSaturationDegree(Sl); 34 | kgr = (1.0 - Se)*(1.0 - Se)*(1.0 - Se^((2.0 + porousMedia.lambda)/porousMedia.lambda)); 35 | kgr = max(kgr,porousMedia.kgrmin); 36 | end 37 | 38 | end 39 | end -------------------------------------------------------------------------------- /tests/regression/files/test_hm_terzaghi.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Terzaghi consolidation problem. 4 | % 5 | % Physics: 6 | % * Single-phase flow hydro-mechanical (HM) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_HM(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | [node, elem] = regularMesh(0.1, 1.0, 5, 50); 20 | 21 | % Set mesh to model 22 | mdl.setMesh(node, elem); 23 | 24 | %% MATERIALS 25 | 26 | % Create fluids 27 | water = Fluid('water'); 28 | 29 | % Create porous media 30 | rock = PorousMedia('rock'); 31 | rock.K = 1.15741e-12; % Intrinsic permeability (m2) 32 | rock.phi = 0.3; % Porosity 33 | rock.Young = 1.0e+6; % Young modulus (Pa) 34 | rock.nu = 0.3; % Poisson ratio 35 | 36 | % Set materials to model 37 | mdl.setMaterial(rock, water); 38 | 39 | %% BOUNDARY AND INITIAL CONDITIONS 40 | 41 | % Displacements 42 | mdl.setDisplacementDirichletBCAtBorder('bottom', [0.0, 0.0]); 43 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 44 | mdl.setDisplacementDirichletBCAtBorder('right', [0.0, NaN]); 45 | 46 | % Loads 47 | mdl.addLoadAtBorder('top', 2, -1.0e4); 48 | 49 | % Pressure 50 | mdl.setPressureDirichletBCAtBorder('top', 0.0); 51 | 52 | %% PROCESS 53 | 54 | % Analysis parameters 55 | ti = 1.0; % Initial time 56 | dt = 1.0; % Time step 57 | tf = 10.0; % Final time 58 | 59 | % Run analysis 60 | anl = Anl_Transient("Newton"); 61 | anl.setUpTransientSolver(ti, dt, tf); 62 | anl.echo = false; 63 | anl.run(mdl); -------------------------------------------------------------------------------- /src/analysis/ControlMethod.m: -------------------------------------------------------------------------------- 1 | %% Control Method Class 2 | % This in an abstract class that defines a control method object 3 | % for nonlinear quasi-static analysis. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 7 | % * Rafael Rangel (rrangel@cimne.upc.edu) 8 | % 9 | %% Class definition 10 | classdef ControlMethod < handle 11 | %% Public properties 12 | properties (SetAccess = public, GetAccess = public) 13 | end 14 | 15 | %% Constructor method 16 | methods 17 | %------------------------------------------------------------------ 18 | function this = ControlMethod() 19 | return; 20 | end 21 | end 22 | 23 | %% Abstract methods 24 | methods (Abstract) 25 | %------------------------------------------------------------------ 26 | % Compute inrement of load ratio for the predicted solution 27 | % (first iteration of first step). 28 | d_lbd0 = predictedIncrementFirst(this,anl,mdl,sign,D_U,d_Up0); 29 | 30 | %------------------------------------------------------------------ 31 | % Compute inrement of load ratio for the predicted solution 32 | % (first iteration). 33 | d_lbd0 = predictedIncrement(~,anl,mdl,sign,J,GSP,D_lbd,d_lbd0,D_U,d_Up0,Pref); 34 | 35 | %------------------------------------------------------------------ 36 | % Compute inrement of load ratio for the corrected solutions 37 | % (iterations to correct predicted solution). 38 | d_lbd = correctedIncrement(~,anl,mdl,d_lbd0,D_lbd,d_Up0,d_U0,d_Up,d_Ur,D_U,Pref,R); 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /src/material/relativePermeability/RelativePermeabilityPolynomialGas.m: -------------------------------------------------------------------------------- 1 | %% RelativePermeabilityPolynomialGas Class 2 | % This class implements the relative permeability calculation for the gas 3 | % phase using a polynomial model. It inherits from the 4 | % _RelativePermeability_ base class and provides a specific implementation 5 | % for gas phase relative permeability. 6 | % 7 | %% Method 8 | % * *calculate*: Computes the gas phase relative permeability based on the 9 | % liquid saturation Sl and the properties of the porous 10 | % medium _porousMedia_. The calculation ensures that the 11 | % relative permeability does not fall below a specified 12 | % minimum value kgrmin. 13 | % 14 | %% Author 15 | % Danilo Cavalcanti 16 | % 17 | %% Version History 18 | % Version 1.00. 19 | % 20 | %% Class Definition 21 | classdef RelativePermeabilityPolynomialGas < RelativePermeability 22 | %% Constructor method 23 | methods 24 | %------------------------------------------------------------------ 25 | function this = RelativePermeabilityPolynomialGas() 26 | this = this@RelativePermeability('polynomialGas'); 27 | end 28 | end 29 | 30 | %% Public methods 31 | methods 32 | 33 | %------------------------------------------------------------------ 34 | % Compute the gas phase relative permeability 35 | function kgr = calculate(~, Sl, porousMedia) 36 | kgr = (1.0 - Sl)*porousMedia.m; 37 | kgr = max(kgr,porousMedia.kgrmin); 38 | end 39 | 40 | end 41 | end -------------------------------------------------------------------------------- /src/material/relativePermeability/RelativePermeabilityPolynomialLiquid.m: -------------------------------------------------------------------------------- 1 | %% RelativePermeabilityPolynomialLiquid Class 2 | % This class implements the relative permeability calculation for the gas 3 | % phase using a polynomial model. It inherits from the 4 | % _RelativePermeability_ base class and provides a specific implementation 5 | % for gas phase relative permeability. 6 | % 7 | %% Method 8 | % * *calculate*: Computes the gas phase relative permeability based on the 9 | % liquid saturation Sl and the properties of the porous 10 | % medium _porousMedia_. The calculation ensures that the 11 | % relative permeability does not fall below a specified 12 | % minimum value kgrmin. 13 | % 14 | %% Author 15 | % Danilo Cavalcanti 16 | % 17 | %% Version History 18 | % Version 1.00. 19 | % 20 | %% Class Definition 21 | classdef RelativePermeabilityPolynomialLiquid < RelativePermeability 22 | %% Constructor method 23 | methods 24 | %------------------------------------------------------------------ 25 | function this = RelativePermeabilityPolynomialLiquid() 26 | this = this@RelativePermeability('polynomialLiquid'); 27 | end 28 | end 29 | 30 | %% Public methods 31 | methods 32 | 33 | %------------------------------------------------------------------ 34 | % Compute the liquid phase relative permeability 35 | function klr = calculate(~, Sl, porousMedia) 36 | klr = Sl*porousMedia.m; 37 | klr = max(klr,porousMedia.klrmin); 38 | end 39 | 40 | end 41 | end -------------------------------------------------------------------------------- /tests/regression/files/test_h_fluid_flow_discontinuity.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Block crossed by strong discontinuity. 4 | % 5 | % Physics: 6 | % * Single-phase hydraulic (H) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | [node, elem] = regularMesh(5.0, 3.0, 5, 3); 20 | 21 | % Set mesh to model 22 | mdl.setMesh(node, elem); 23 | 24 | %% MATERIALS 25 | 26 | % Create fluids 27 | water = Fluid('water'); 28 | water.rho = 1.0e+3; % Density (kg/m3) 29 | water.mu = 1.0e-3; % Viscosity (Pa*s) 30 | water.K = 2.0e+9; % Compressibility/Bulk modulus (1/Pa) 31 | 32 | % Create porous media 33 | rock = PorousMedia('rock'); 34 | rock.K = 9.8e-16; % Intrinsic permeability (m2) 35 | rock.phi = 0.25; % Porosity 36 | 37 | % Set materials to model 38 | mdl.setMaterial(rock, water); 39 | 40 | %% BOUNDARY CONDITIONS 41 | 42 | % Set Dirichlet boundary conditions 43 | mdl.setPressureDirichletBCAtBorder('left', 0.0); 44 | mdl.setPressureDirichletBCAtBorder('right', 10.0); 45 | 46 | %% DISCONTINUITIES 47 | 48 | % Create discontinuities 49 | Dx = [1.0; 4.0]; % X-coordinates of polyline defining the fracture 50 | Dy = [1.1; 1.9]; % Y-coordinates of polyline defining the fracture 51 | fracture = Discontinuity([Dx, Dy], true); 52 | 53 | % Set fracture material properties 54 | fracture.fluid = water; 55 | fracture.initialAperture = 1.0e-3; 56 | 57 | % Add fractures to model 58 | mdl.addPreExistingDiscontinuities(fracture); 59 | 60 | %% PROCESS 61 | 62 | % Run analysis 63 | anl = Anl_Linear(); 64 | anl.run(mdl); -------------------------------------------------------------------------------- /tests/regression/files/test_h_fluid_flow_rock.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Physics: 4 | % * Single-phase hydraulic (H) 5 | % 6 | % Authors: 7 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 8 | % 9 | %% MODEL 10 | 11 | % Create model 12 | mdl = Model_H(); 13 | 14 | %% MESH 15 | 16 | % Create mesh 17 | [node, elem] = regularMesh(2.0, 1.0, 2, 1); 18 | 19 | % Set mesh to model 20 | mdl.setMesh(node, elem); 21 | 22 | %% MATERIALS 23 | 24 | % Create fluids 25 | water = Fluid('water'); 26 | water.rho = 1.0e+3; % Density (kg/m3) 27 | water.mu = 1.0e-3; % Viscosity (Pa*s) 28 | water.K = 2.0e+9; % Compressibility/Bulk modulus (1/Pa) 29 | 30 | % Create porous media 31 | rock = PorousMedia('rock'); 32 | rock.K = 1.0194e-14; % Intrinsic permeability (m2) 33 | rock.phi = 0.3; % Porosity 34 | rock.Ks = 1.0e+12; % Rock bulk modulus (Pa) 35 | rock.biot = 0.6; % Biot coefficient 36 | 37 | % Set materials to model 38 | mdl.setMaterial(rock, water); 39 | 40 | %% BOUNDARY CONDITIONS 41 | 42 | % Set Dirichlet boundary conditions 43 | mdl.setPressureDirichletBCAtBorder('left', 0.0); 44 | mdl.setPressureDirichletBCAtBorder('right', 10.0); 45 | 46 | %% PROCESS 47 | 48 | % Analysis parameters 49 | ti = 1.0; % Initial time 50 | dt = 1.0; % Time step 51 | tf = 100.0; % Final time 52 | dtmax = 50.0; % Maximum time step 53 | dtmin = 0.001; % Minimum time step 54 | adaptStep = true; % Adaptive step size 55 | 56 | % Run analysis 57 | anl = Anl_Transient("Picard"); 58 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 59 | anl.setRelativeConvergenceCriteria(true); 60 | anl.echo = false; 61 | anl.run(mdl); -------------------------------------------------------------------------------- /src/analysis/ControlMethod_Load.m: -------------------------------------------------------------------------------- 1 | %% ControlMethod_Load Class 2 | % This class inherits from the base class 'ControlMethod' to implement 3 | % the load control method for solving nonlinear systems. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 7 | % * Rafael Rangel (rrangel@cimne.upc.edu) 8 | % 9 | %% Class definition 10 | classdef ControlMethod_Load < ControlMethod 11 | %% Constructor method 12 | methods 13 | %------------------------------------------------------------------ 14 | function this = ControlMethod_Load() 15 | this = this@ControlMethod(); 16 | end 17 | end 18 | 19 | %% Public methods 20 | methods 21 | %------------------------------------------------------------------ 22 | % Compute inrement of load ratio for the predicted solution 23 | % (first iteration of first step). 24 | function d_lbd0 = predictedIncrementFirst(~,anl,~,~,~,~) 25 | d_lbd0 = anl.increment; 26 | end 27 | 28 | %------------------------------------------------------------------ 29 | % Compute inrement of load ratio for the predicted solution 30 | % (first iteration). 31 | function d_lbd0 = predictedIncrement(~,~,~,sign,J,~,~,d_lbd0,~,~,~) 32 | d_lbd0 = sign * J * abs(d_lbd0); 33 | end 34 | 35 | %------------------------------------------------------------------ 36 | % Compute inrement of load ratio for the corrected solutions 37 | % (iterations to correct predicted solution). 38 | function d_lbd = correctedIncrement(~,~,~,~,~,~,~,~,~,~,~,~) 39 | d_lbd = 0; 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /tests/regression/files/test_m_plane_stress_traction.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Uniform traction on a plate with isotropic damage model. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | [node, elem] = regularMesh(0.11, 0.04, 22, 8); 20 | 21 | % Set mesh to model 22 | mdl.setMesh(node, elem); 23 | 24 | %% MATERIALS 25 | 26 | % Create porous media 27 | rock = PorousMedia('rock'); 28 | rock.mechanical = 'isoDamage'; % Constitutive law 29 | rock.Young = 2.0e+10; % Young modulus (Pa) 30 | rock.nu = 0.0; % Poisson ratio 31 | rock.kappa = 10.0; % Ratio of tensile and compressive strength 32 | rock.DamageThreshold = 1.0e-4; % Damage threshold 33 | rock.FractureEnergyMode1 = 50.0; % Fracture energy associated with mode 1 (N/m) 34 | 35 | % Set materials to model 36 | mdl.setMaterial(rock); 37 | 38 | %% BOUNDARY CONDITIONS 39 | 40 | % Displacements 41 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, 0.0]); 42 | 43 | % Loads 44 | mdl.addLoadAtBorder('right', 1, 2.0e+6); 45 | 46 | %% PROCESS 47 | 48 | % Setup analysis 49 | anl = Anl_NonlinearQuasiStatic('ArcLengthCylControl'); 50 | anl.adjustStep = true; 51 | anl.increment = 0.01; 52 | anl.max_lratio = 200.0; 53 | anl.max_step = 15; 54 | anl.max_iter = 100; 55 | anl.trg_iter = 4; 56 | 57 | % Node and DOF used to plot Load Factor vs Displacement 58 | ndId = mdl.closestNodeToPoint([0.11, 0.0]); 59 | anl.setPlotDof(ndId, 1); 60 | 61 | % Run analysis 62 | anl.echo = false; 63 | anl.run(mdl); -------------------------------------------------------------------------------- /src/mesh/discontinuity/findElemIntersected.m: -------------------------------------------------------------------------------- 1 | %% findElemIntersected Function 2 | % This function checks which bars (defined by their endpoints in the 3 | % NODE array) intersect a given rectangle defined by its minimum and 4 | % maximum coordinates. The algorithm uses parametric line equations and 5 | % checks for overlap in the parameter range for each bar. 6 | % 7 | %% Inputs 8 | % * *Amin*: A vector specifying the minimum coordinates of the rectangle. 9 | % * *Amax*: A vector specifying the maximum coordinates of the rectangle. 10 | % * *NODE*: An matrix where each row represents the coordinates of a node. 11 | % * *BARS*: An matrix where each row contains the indices of two nodes 12 | % defining a bar. 13 | % 14 | %% Outputs 15 | % * *elemID*: A logical array where each element is true if the 16 | % corresponding bar intersects the rectangle, and false 17 | % otherwise. 18 | % 19 | % 20 | %% Author 21 | % Danilo Cavalcanti 22 | % 23 | %% Version History 24 | % Version 1.00. 25 | % 26 | %% Function definition 27 | function elemID = findElemIntersected(Amin,Amax,NODE,BARS) 28 | 29 | % Amin and Amax are the rectangle's limit coords: minimum and maximum 30 | Nb= size(BARS,1); 31 | Tmin = zeros(Nb,1); Tmax = ones(Nb,1); 32 | D = NODE(BARS(:,2),:) - NODE(BARS(:,1),:); 33 | for i=1:2 % Check on X (i=1) and Y (i=2) 34 | T1 = ( Amin(i) - NODE(BARS(:,1),i) ) ./ D(:,i); 35 | T2 = ( Amax(i) - NODE(BARS(:,1),i) ) ./ D(:,i); 36 | ind = find(T1>T2); % We require T1=Tmax 41 | elemID = (Tmin < Tmax)'; -------------------------------------------------------------------------------- /tests/regression/files/test_m_plate_discontinuity.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Block crossed by strong discontinuity. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | % Set model options 17 | mdl.isPlaneStress = true; 18 | mdl.condenseEnrDofs = true; 19 | 20 | %% MESH 21 | 22 | % Create mesh 23 | [node, elem] = regularMesh(2.0, 2.0, 1, 1); 24 | 25 | % Set mesh to model 26 | mdl.setMesh(node,elem); 27 | 28 | %% MATERIALS 29 | 30 | % Create porous media 31 | rock = PorousMedia('rock'); 32 | rock.Young = 1.0e+8; % Young modulus (kPa) 33 | rock.nu = 0.0; % Poisson ratio 34 | 35 | % Set materials to model 36 | mdl.setMaterial(rock); 37 | 38 | %% BOUNDARY CONDITIONS 39 | 40 | % Displacements 41 | mdl.setDisplacementDirichletBCAtBorder('bottom', [0.0, 0.0]); 42 | 43 | % Loads 44 | mdl.addLoadAtPoint([0.0,2.0], [-0.5,1.5]); 45 | 46 | %% DISCONTINUITIES 47 | 48 | % Create discontinuities 49 | Dx = [0.00; 2.00]; % X-coordinates of polyline defining the fracture 50 | Dy = [0.25; 1.75]; % Y-coordinates of polyline defining the fracture 51 | fracture = Discontinuity([Dx, Dy], true); 52 | 53 | % Set fracture material properties 54 | fracture.cohesiveLaw = 'elastic'; 55 | fracture.initialAperture = 0.0; 56 | fracture.shearStiffness = 1.0; 57 | fracture.normalStiffness = 1.0; 58 | 59 | % Add fractures to model 60 | discontinuityData = struct('addStretchingMode', false, 'addRelRotationMode', true); 61 | mdl.addPreExistingDiscontinuities(fracture, discontinuityData); 62 | 63 | %% PROCESS 64 | 65 | % Run analysis 66 | anl = Anl_Linear(); 67 | anl.run(mdl); -------------------------------------------------------------------------------- /src/material/Fluid.m: -------------------------------------------------------------------------------- 1 | %% Fluid Class 2 | % This class defines a fluid object with properties such as density, 3 | % viscosity, and compressibility. It provides methods to access these 4 | % properties and allows initialization with specific values. 5 | % 6 | %% Methods 7 | % * *Fluid*: Constructor to initialize the fluid object. If only the id is 8 | % provided, other properties are set to their default values. 9 | % * *getDensity*: Returns the density of the fluid. 10 | % 11 | %% Author 12 | % Danilo Cavalcanti 13 | % 14 | %% Version History 15 | % Version 1.00. 16 | % 17 | %% Class Definition 18 | classdef Fluid < handle 19 | %% Public attributes 20 | properties (SetAccess = public, GetAccess = public) 21 | id = ''; 22 | rho = 1000.0; % Density (kg/m3) 23 | mu = 1.0e-3; % Viscosity (Pa*s) 24 | K = 1.0e25; % Compressibility/Bulk modulus (1/Pa) 25 | end 26 | %% Constructor method 27 | methods 28 | %------------------------------------------------------------------ 29 | % Initialization of the fluid 30 | function this = Fluid(id, density, viscosity, compressibility) 31 | if nargin == 1 32 | this.id = id; 33 | elseif nargin > 1 34 | this.id = id; 35 | this.rho = density; 36 | this.mu = viscosity; 37 | this.K = compressibility; 38 | end 39 | end 40 | end 41 | %% Public methods 42 | methods 43 | %------------------------------------------------------------------ 44 | % Get the density of the fluid 45 | function rho = getDensity(this,~) 46 | rho = this.rho; 47 | end 48 | end 49 | end -------------------------------------------------------------------------------- /examples/M/example_m_porepressure.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Uniform traction on a plate with isotropic damage model. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | % Set model options 17 | mdl.addPorePressure = true; 18 | 19 | %% MESH 20 | 21 | % Create mesh 22 | Lx = 2.0e-1; % Horizontal dimension (m) 23 | Ly = 2.0e-1; % Vertical dimension (m) 24 | Nx = 1; % Number of elements in the x-direction 25 | Ny = 1; % Number of elements in the y-direction 26 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 27 | 28 | % Set mesh to model 29 | mdl.setMesh(node, elem); 30 | 31 | %% MATERIALS 32 | 33 | % Create porous media 34 | rock = PorousMedia('rock'); 35 | rock.Young = 30.0e+9; % Young modulus (Pa) 36 | rock.nu = 0.0; % Poisson ratio 37 | 38 | % Set materials to model 39 | mdl.setMaterial(rock); 40 | 41 | %% BOUNDARY CONDITIONS 42 | 43 | % Displacements 44 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 45 | mdl.setDisplacementDirichletBCAtBorder('bottom', [NaN, 0.0]); 46 | 47 | % Set external pore-pressure 48 | P = 10 * ones(mdl.nnodes,1); 49 | mdl.setPorePressureField(P); 50 | 51 | %% PROCESS 52 | 53 | % Run analysis 54 | anl = Anl_Linear(); 55 | anl.run(mdl); 56 | 57 | %% POST-PROCESS 58 | 59 | % Print stresses 60 | fprintf("\n\n IP Sxx Syy Szz Sxy\n") 61 | elem = mdl.element(1).type; 62 | for i = 1:elem.nIntPoints 63 | stress = elem.intPoint(i).stress; 64 | fprintf("%2d %+.4e %+.4e %+.4e %+.4e \n",i,stress(1),stress(2),stress(3),stress(4)); 65 | end 66 | 67 | % Plot stresses 68 | mdl.plotField('Sx'); 69 | mdl.plotField('Sy'); 70 | mdl.plotField('Sxy'); 71 | -------------------------------------------------------------------------------- /src/material/saturationLaw/CapillaryPressure.m: -------------------------------------------------------------------------------- 1 | %% CapillaryPressure Class 2 | % This class defines an abstract base class for modeling capillary pressure 3 | % and its associated properties in porous media. It provides a framework 4 | % for implementing specific capillary pressure-saturation relationships 5 | % and their derivatives. 6 | % 7 | %% Methods 8 | % * *saturationDegree*: Computes the liquid saturation degree based on the 9 | % capillary pressure and porous media properties. 10 | % * *derivativeSaturationDegree*: Computes the derivative of the liquid 11 | % saturation degree with respect to the 12 | % capillary pressure. 13 | % 14 | %% Author 15 | % Danilo Cavalcanti 16 | % 17 | %% Version History 18 | % Version 1.00. 19 | % 20 | %% Class Definition 21 | classdef CapillaryPressure < handle 22 | %% Public properties 23 | properties (SetAccess = public, GetAccess = public) 24 | id = 'name1'; 25 | end 26 | 27 | %% Constructor method 28 | methods 29 | %------------------------------------------------------------------ 30 | function this = CapillaryPressure(matModel) 31 | this.id = matModel; 32 | end 33 | end 34 | 35 | %% Abstract methods 36 | methods(Abstract) 37 | 38 | %------------------------------------------------------------------ 39 | % Liquid saturation degree 40 | Sw = saturationDegree(this, pc, porousMedia); 41 | 42 | %------------------------------------------------------------------ 43 | % Derivative of the liquid saturation degree wrt to the capillary 44 | % pressure 45 | dSwdPc = derivativeSaturationDegree(this, pc, porousMedia); 46 | 47 | end 48 | 49 | end -------------------------------------------------------------------------------- /examples/M/example_m_axissym_cylinder.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Elastic pressurized cilynder using axisymmetric model. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | mdl.isAxisSymmetric = true; 17 | 18 | %% MESH 19 | 20 | % Cilynder geometrical properties 21 | r_i = 0.1; 22 | r_e = 0.2; 23 | h = 0.5; 24 | 25 | % Create mesh 26 | [node, elem] = regularMesh(r_e - r_i, h, 10, 50); 27 | node(:,1) = node(:,1) + r_i; 28 | 29 | [node, elem] = convertToQuadraticMesh(node, elem); 30 | 31 | % Set mesh to model 32 | mdl.setMesh(node, elem); 33 | mdl.resequenceNodes(); 34 | 35 | %% MATERIALS 36 | 37 | % Create porous media 38 | rock = PorousMedia('rock'); 39 | rock.mechanical = 'elastic'; % Constitutive law 40 | rock.Young = 30.0e6; % Young modulus (Pa) 41 | rock.nu = 0.3; % Poisson ratio 42 | 43 | % Set materials to model 44 | mdl.setMaterial(rock); 45 | 46 | %% BOUNDARY CONDITIONS 47 | 48 | % Displacements 49 | mdl.setDisplacementDirichletBCAtBorder('top' , [NaN, 0.0]); 50 | mdl.setDisplacementDirichletBCAtBorder('bottom', [NaN, 0.0]); 51 | % mdl.setDisplacementDirichletBCAtBorder('right', [0.0, NaN]); 52 | 53 | % Loads 54 | pint = 1.0; 55 | mdl.addLoadAtBorder('left', 1, pint); 56 | 57 | %% PROCESS 58 | 59 | % Run analysis 60 | anl = Anl_Linear(); 61 | anl.run(mdl); 62 | 63 | %% POST-PROCESS 64 | 65 | % Plot contours 66 | mdl.plotField('Sx'); 67 | mdl.plotFieldAlongSegment('Sx',[0.1,0.0],[0.2,0.0]); 68 | hold on 69 | 70 | % Analytical solution for radial stress (external pressure = 0) 71 | r = linspace(r_i, r_e, 50); 72 | sigma_r = (pint * r_i^2) ./ (r_e^2 - r_i^2) .* (1 - (r_e^2 ./ r.^2)); 73 | plot(r - r_i, sigma_r, 'o', 'LineWidth', 2); 74 | -------------------------------------------------------------------------------- /src/material/relativePermeability/RelativePermeabilityUMAT.m: -------------------------------------------------------------------------------- 1 | %% RelativePermeabilityUMAT Class 2 | % This class defines a relative permeability model using a user-defined 3 | % material (UMAT) approach. It inherits from the _RelativePermeability_ 4 | % base class and provides functionality to compute relative permeability 5 | % based on saturation curves. 6 | % 7 | %% Method 8 | % * *calculate*: Computes the relative permeability kr for a given 9 | % saturation Sl using linear interpolation. The result is 10 | % clamped between the minimum relative permeability klrmin 11 | % defined in the _porousMedia_ object and 1.0. 12 | % 13 | %% Author 14 | % Danilo Cavalcanti 15 | % 16 | %% Version History 17 | % Version 1.00. 18 | % 19 | %% Class Definition 20 | classdef RelativePermeabilityUMAT < RelativePermeability 21 | %% Public attributes 22 | properties (SetAccess = public, GetAccess = public) 23 | Sl_curve = []; % Must be sorted!! 24 | kr_curve = []; % Must be sorted!! 25 | end 26 | %% Constructor method 27 | methods 28 | %------------------------------------------------------------------ 29 | function this = RelativePermeabilityUMAT(Sl_curve,kr_curve) 30 | this = this@RelativePermeability('umat'); 31 | this.Sl_curve = Sl_curve; 32 | this.kr_curve = kr_curve; 33 | end 34 | end 35 | 36 | %% Public methods 37 | methods 38 | 39 | %------------------------------------------------------------------ 40 | % Compute the relative permeability 41 | function kr = calculate(this, Sl, porousMedia) 42 | kr = interp1(this.Sl_curve,this.kr_curve,Sl,'linear', 'extrap'); 43 | kr = max(min(kr, 1.0), porousMedia.klrmin); 44 | end 45 | 46 | end 47 | end -------------------------------------------------------------------------------- /tests/regression/files/test_h_fluid_flow_dam.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Fluid-flow through the foundation of a gravity dam. 4 | % 5 | % References: 6 | % * Segura and Carol (2004). On zero-thickness interface elements for diffusion problems. Int J Numer Anal Methods Geomech, 28(9):947-962. 7 | % 8 | % Physics: 9 | % * Single-phase hydraulic (H) 10 | % 11 | % Authors: 12 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 13 | % 14 | %% MODEL 15 | 16 | % Create model 17 | mdl = Model_H(); 18 | 19 | %% MESH 20 | 21 | % Create mesh 22 | [node, elem] = regularMesh(25.0, 6.0, 48, 12); 23 | 24 | % Set mesh to model 25 | mdl.setMesh(node, elem); 26 | 27 | %% MATERIALS 28 | 29 | % Create fluids 30 | water = Fluid('water'); 31 | water.K = 2.0e+9; % Compressibility/Bulk modulus (1/Pa) 32 | 33 | % Create porous media 34 | rock = PorousMedia('rock'); 35 | rock.K = 1.0194e-14; % Intrinsic permeability (m2) 36 | rock.phi = 0.3; % Porosity 37 | 38 | % Set materials to model 39 | mdl.setMaterial(rock, water); 40 | 41 | %% BOUNDARY CONDITIONS 42 | 43 | % Set Dirichlet boundary conditions 44 | for i = 1:size(mdl.NODE,1) 45 | if ((mdl.NODE(i,1) < 8.0) && (abs(mdl.NODE(i,2)-6.0) < 1.0e-9)) 46 | mdl.setPressureDirichletBCAtNode(i, 120.0); 47 | end 48 | if ((mdl.NODE(i,1) > 12.0) && (abs(mdl.NODE(i,2)-6.0) < 1.0e-9)) 49 | mdl.setPressureDirichletBCAtNode(i, 60.0); 50 | end 51 | end 52 | 53 | %% PROCESS 54 | 55 | % Analysis parameters 56 | ti = 1.0; % Initial time 57 | dt = 1.0; % Time step 58 | tf = 50.0; % Final time 59 | dtmax = 50.0; % Maximum time step 60 | dtmin = 0.001; % Minimum time step 61 | adaptStep = true; % Adaptive step size 62 | 63 | % Run analysis 64 | anl = Anl_Transient("Newton"); 65 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 66 | anl.echo = false; 67 | anl.run(mdl); -------------------------------------------------------------------------------- /tests/validation/validation_stress_integration_dp.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Validation script for mechanical constitutive models. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | close all; clear; clc; 12 | 13 | %% MODEL DEFINITION 14 | 15 | % Material properties 16 | rock = PorousMedia('rock'); 17 | rock.mechanical = 'elasticDruckerPrager'; % Mechanical constitutive law 18 | rock.rho = 2.0e+3; % Density (kg/m3) 19 | rock.Young = 2.0e+7; % Young modulus (Pa) 20 | rock.nu = 0.49; % Poisson ratio 21 | rock.cohesion = 5.0e+4; % Cohesion (Pa) 22 | rock.frictionAngle = 20*pi/180; % Friction angle (rad) 23 | 24 | % Material parameters vector 25 | mat = struct('porousMedia', rock); 26 | 27 | % Integration point 28 | ip = IntPoint([0.0,0.0], 1.0, Material_M(mat)); 29 | ip.initializeMechanicalAnalysisModel('PlaneStrain'); 30 | 31 | %% RUN ANALYSIS 32 | 33 | % Strain increment direction 34 | dstrain0 = [0.0; % exx 35 | 0.0; % eyy 36 | 0.0; % ezz 37 | 1.0]; % gxy 38 | 39 | mag = 1.0e-03; 40 | ninc = 150; 41 | 42 | idplot = 4; 43 | p = zeros(ninc+1, 1); 44 | q = zeros(ninc+1, 1); 45 | 46 | for i = 1:ninc 47 | ip.strain = ip.strainOld + mag * dstrain0; 48 | ip.stress = ip.mechanicalLaw(); 49 | ip.stressOld = ip.stress; 50 | ip.strainOld = ip.strain; 51 | 52 | % Stress invariants 53 | p(i+1) = ip.constitutiveMdl.mechanical.hydrostaticStress(ip.stress); 54 | q(i+1) = ip.constitutiveMdl.mechanical.vonMisesStress(ip.stress); 55 | end 56 | 57 | %% POS-PROCESSING 58 | 59 | % Stress vs Total strain 60 | figure; 61 | grid on, box on, hold on; 62 | plot(p, q, 'b-', 'LineWidth', 1.5); 63 | xlabel('p'); 64 | ylabel('q'); 65 | set(gca, 'fontsize', 18, 'TickLabelInterpreter', 'latex'); 66 | -------------------------------------------------------------------------------- /src/analysis/ControlMethod_MinNorm.m: -------------------------------------------------------------------------------- 1 | %% ControlMethod_MinNorm Class 2 | % This class inherits from the base class 'ControlMethod' to implement 3 | % the minimum norm control method for solving nonlinear systems. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 7 | % * Rafael Rangel (rrangel@cimne.upc.edu) 8 | % 9 | %% Class definition 10 | classdef ControlMethod_MinNorm < ControlMethod 11 | %% Constructor method 12 | methods 13 | %------------------------------------------------------------------ 14 | function this = ControlMethod_MinNorm() 15 | this = this@ControlMethod(); 16 | end 17 | end 18 | 19 | %% Public methods 20 | methods 21 | %------------------------------------------------------------------ 22 | % Compute inrement of load ratio for the predicted solution 23 | % (first iteration of first step). 24 | function d_lbd0 = predictedIncrementFirst(~,anl,~,~,~,~) 25 | d_lbd0 = anl.increment; 26 | end 27 | 28 | %------------------------------------------------------------------ 29 | % Compute inrement of load ratio for the predicted solution 30 | % (first iteration). 31 | function d_lbd0 = predictedIncrement(~,~,mdl,sign,J,~,~,~,D_U,d_Up0,~) 32 | D_U = D_U(mdl.doffree); 33 | d_Up0 = d_Up0(mdl.doffree); 34 | d_lbd0 = sign * J * sqrt((D_U'*D_U)/(d_Up0'*d_Up0)); 35 | end 36 | 37 | %------------------------------------------------------------------ 38 | % Compute inrement of load ratio for the corrected solutions 39 | % (iterations to correct predicted solution). 40 | function d_lbd = correctedIncrement(~,~,mdl,~,~,~,~,d_Up,d_Ur,~,~,~) 41 | d_Up = d_Up(mdl.doffree); 42 | d_Ur = d_Ur(mdl.doffree); 43 | d_lbd = -(d_Up'*d_Ur)/(d_Up'*d_Up); 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /src/analysis/ControlMethod_GenDispl.m: -------------------------------------------------------------------------------- 1 | %% ControlMethod_GenDispl Class 2 | % This class inherits from the base class 'ControlMethod' to implement 3 | % the generalized displacement control method for solving nonlinear systems. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 7 | % * Rafael Rangel (rrangel@cimne.upc.edu) 8 | % 9 | %% Class definition 10 | classdef ControlMethod_GenDispl < ControlMethod 11 | %% Constructor method 12 | methods 13 | %------------------------------------------------------------------ 14 | function this = ControlMethod_GenDispl() 15 | this = this@ControlMethod(); 16 | end 17 | end 18 | 19 | %% Public methods 20 | methods 21 | %------------------------------------------------------------------ 22 | % Compute inrement of load ratio for the predicted solution 23 | % (first iteration of first step). 24 | function d_lbd0 = predictedIncrementFirst(~,anl,~,~,~,~) 25 | d_lbd0 = anl.increment; 26 | end 27 | 28 | %------------------------------------------------------------------ 29 | % Compute inrement of load ratio for the predicted solution 30 | % (first iteration). 31 | function d_lbd0 = predictedIncrement(~,anl,~,sign,J,GSP,~,~,~,~,~) 32 | d_lbd0 = sign * J * sqrt(abs(GSP)) * anl.increment; 33 | end 34 | 35 | %------------------------------------------------------------------ 36 | % Compute inrement of load ratio for the corrected solutions 37 | % (iterations to correct predicted solution). 38 | function d_lbd = correctedIncrement(~,~,mdl,~,~,d_Up0,~,d_Up,d_Ur,~,~,~) 39 | % Extract free DOF components 40 | d_Up0 = d_Up0(mdl.doffree); 41 | d_Up = d_Up(mdl.doffree); 42 | d_Ur = d_Ur(mdl.doffree); 43 | d_lbd = -(d_Up0'*d_Ur)/(d_Up0'*d_Up); 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /src/analysis/ControlMethod_Displ.m: -------------------------------------------------------------------------------- 1 | %% ControlMethod_Displ Class 2 | % This class inherits from the base class 'ControlMethod' to implement 3 | % the displacement control method for solving nonlinear systems. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 7 | % * Rafael Rangel (rrangel@cimne.upc.edu) 8 | % 9 | %% Class definition 10 | classdef ControlMethod_Displ < ControlMethod 11 | %% Constructor method 12 | methods 13 | %------------------------------------------------------------------ 14 | function this = ControlMethod_Displ() 15 | this = this@ControlMethod(); 16 | end 17 | end 18 | 19 | %% Public methods 20 | methods 21 | %------------------------------------------------------------------ 22 | % Compute inrement of load ratio for the predicted solution 23 | % (first iteration of first step). 24 | function d_lbd0 = predictedIncrementFirst(this,~,mdl,sign,D_U,d_Up0) 25 | d_lbd0 = this.predictedIncrement(this,mdl,sign,1,1,0.0,0.0,D_U,d_Up0,Fref); 26 | end 27 | 28 | %------------------------------------------------------------------ 29 | % Compute inrement of load ratio for the predicted solution 30 | % (first iteration). 31 | function d_lbd0 = predictedIncrement(~,anl,mdl,sign,J,~,~,~,~,d_Up0,~) 32 | d_Up0 = d_Up0(mdl.doffree); 33 | d_lbd0 = J * sign * anl.increment / d_Up0(anl.ctrlDof); 34 | end 35 | 36 | %------------------------------------------------------------------ 37 | % Compute inrement of load ratio for the corrected solutions 38 | % (iterations to correct predicted solution). 39 | function d_lbd = correctedIncrement(~,anl,mdl,~,~,~,~,d_Up,d_Ur,~,~,~) 40 | d_Up = d_Up(mdl.doffree); 41 | d_Ur = d_Ur(mdl.doffree); 42 | d_lbd = -d_Ur(anl.ctrlDof)/d_Up(anl.ctrlDof); 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /tests/regression/run_tests.m: -------------------------------------------------------------------------------- 1 | %% PorousLab - FEM framework for multiphysics problems in porous media 2 | % 3 | % This is the regression testing file of PorousLab. 4 | % To run tests, execute this file to compare current results with reference values 5 | % considering a given tolerance. 6 | % 7 | clc; clearvars; close all; 8 | tol = 1e-8; 9 | 10 | files_dir = fullfile(pwd, 'files'); 11 | test_files = dir(fullfile(files_dir, 'test_*.m')); 12 | src_dir = fullfile(fileparts(mfilename('fullpath')), '..', '..', 'src'); 13 | addpath(genpath(src_dir)); 14 | 15 | total = 0; 16 | passed = 0; 17 | failed = 0; 18 | skipped = 0; 19 | 20 | for i = 1:length(test_files) 21 | test_name = test_files(i).name(1:end-2); 22 | fprintf('Running %s...\n', test_name); 23 | 24 | clear mdl; 25 | run(fullfile(files_dir, test_name)); 26 | total = total + 1; 27 | 28 | ref_file = fullfile(files_dir, [test_name,'_ref.mat']); 29 | if ~exist(ref_file, 'file') 30 | warning('⚠️ Reference file missing: %s\n\n', ref_file); 31 | skipped = skipped + 1; 32 | continue; 33 | end 34 | 35 | load(ref_file, 'U_ref'); 36 | 37 | if ~isequal(size(mdl.U), size(U_ref)) 38 | fprintf('❌ Failed: size mismatch (mdl.U is [%s], U_ref is [%s])\n\n', num2str(size(mdl.U)), num2str(size(U_ref))); 39 | failed = failed + 1; 40 | continue; 41 | end 42 | 43 | err = norm(mdl.U - U_ref) / norm(U_ref); 44 | 45 | if err < tol 46 | fprintf('✅ Passed (rel. error = %.2e)\n\n', err); 47 | passed = passed + 1; 48 | else 49 | fprintf('❌ Failed (rel. error = %.2e)\n\n', err); 50 | failed = failed + 1; 51 | end 52 | end 53 | 54 | fprintf('======== Test Summary ========\n'); 55 | fprintf('Total tests:........%d\n', total); 56 | fprintf('Passed:.............%d\n', passed); 57 | fprintf('Failed:.............%d\n', failed); 58 | fprintf('Skipped (no ref):...%d\n', skipped); 59 | fprintf('===============================\n'); 60 | -------------------------------------------------------------------------------- /examples/HM/example_hm_terzaghi.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Terzaghi consolidation problem. 4 | % 5 | % Physics: 6 | % * Single-phase flow hydro-mechanical (HM) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_HM(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | Lx = 0.1; % Horizontal dimension (m) 20 | Ly = 1.0; % Vertical dimension (m) 21 | Nx = 5; % Number of elements in the x-direction 22 | Ny = 50; % Number of elements in the y-direction 23 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 24 | 25 | % Set mesh to model 26 | mdl.setMesh(node, elem); 27 | 28 | %% MATERIALS 29 | 30 | % Create fluids 31 | water = Fluid('water'); 32 | 33 | % Create porous media 34 | rock = PorousMedia('rock'); 35 | rock.K = 1.15741e-12; % Intrinsic permeability (m2) 36 | rock.phi = 0.3; % Porosity 37 | rock.Young = 1.0e+6; % Young modulus (Pa) 38 | rock.nu = 0.3; % Poisson ratio 39 | 40 | % Set materials to model 41 | mdl.setMaterial(rock, water); 42 | 43 | %% BOUNDARY AND INITIAL CONDITIONS 44 | 45 | % Displacements 46 | mdl.setDisplacementDirichletBCAtBorder('bottom', [0.0, 0.0]); 47 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 48 | mdl.setDisplacementDirichletBCAtBorder('right', [0.0, NaN]); 49 | 50 | % Loads 51 | mdl.addLoadAtBorder('top', 2, -1.0e4); 52 | 53 | % Pressure 54 | mdl.setPressureDirichletBCAtBorder('top', 0.0); 55 | 56 | %% PROCESS 57 | 58 | % Analysis parameters 59 | ti = 1.0; % Initial time 60 | dt = 1.0; % Time step 61 | tf = 100.0; % Final time 62 | 63 | % Run analysis 64 | anl = Anl_Transient("Newton"); 65 | anl.setUpTransientSolver(ti, dt, tf); 66 | anl.run(mdl); 67 | 68 | %% POST-PROCESS 69 | 70 | % Plot contours 71 | mdl.plotField('Pressure'); 72 | 73 | % Plot graphs 74 | Xi = [0.0, 0.0]; Xf = [0.0, 1.0]; 75 | mdl.plotFieldAlongSegment('Pressure', Xi, Xf, 500, 'y'); 76 | mdl.plotFieldAlongSegment('Uy', Xi, Xf, 500, 'y'); 77 | -------------------------------------------------------------------------------- /src/analysis/ControlMethod_OrtResidual.m: -------------------------------------------------------------------------------- 1 | %% ControlMethod_OrtResidual Class 2 | % This class inherits from the base class 'ControlMethod' to implement 3 | % the orthogonal residual control method for solving nonlinear systems. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 7 | % * Rafael Rangel (rrangel@cimne.upc.edu) 8 | % 9 | %% Class definition 10 | classdef ControlMethod_OrtResidual < ControlMethod 11 | %% Constructor method 12 | methods 13 | %------------------------------------------------------------------ 14 | function this = ControlMethod_OrtResidual() 15 | this = this@ControlMethod(); 16 | end 17 | end 18 | 19 | %% Public methods 20 | methods 21 | %------------------------------------------------------------------ 22 | % Compute inrement of load ratio for the predicted solution 23 | % (first iteration of first step). 24 | function d_lbd0 = predictedIncrementFirst(~,anl,~,~,~,~) 25 | d_lbd0 = anl.increment; 26 | end 27 | 28 | %------------------------------------------------------------------ 29 | % Compute inrement of load ratio for the predicted solution 30 | % (first iteration). 31 | function d_lbd0 = predictedIncrement(~,~,mdl,sign,J,~,~,~,D_U,d_Up0,~) 32 | D_U = D_U(mdl.doffree); 33 | d_Up0 = d_Up0(mdl.doffree); 34 | d_lbd0 = sign * J * sqrt((D_U'*D_U)/(d_Up0'*d_Up0)); 35 | end 36 | 37 | %------------------------------------------------------------------ 38 | % Compute inrement of load ratio for the corrected solutions 39 | % (iterations to correct predicted solution). 40 | function d_lbd = correctedIncrement(~,~,mdl,~,~,~,~,~,~,D_U,Pref,R) 41 | D_U = D_U(mdl.doffree); 42 | Pref = Pref(mdl.doffree); 43 | R = R(mdl.doffree); 44 | d_lbd = -(R'*D_U)/(Pref'*D_U); 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /tests/regression/files/test_m_slope_stability.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Slope stability problem. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | % Set model options 17 | mdl.gravityOn = true; 18 | mdl.intOrder = 2; % Integration quadrature order 19 | 20 | %% MESH 21 | 22 | % Load mesh 23 | load('MeshSlopeStabilityTransfiniteQuadratic'); 24 | 25 | % Set mesh to model 26 | mdl.setMesh(node, elem); 27 | 28 | %% MATERIALS 29 | 30 | % Create porous media 31 | rock = PorousMedia('rock'); 32 | rock.mechanical = 'druckerPrager'; % Constitutive law 33 | rock.MCmatch = "planestrain"; % How Drucker-Prager surfaces matches Mohr-Coulomb 34 | rock.rho = 2.0; % Density (g/cm3) 35 | rock.Young = 2.0e+4; % Young modulus (kPa) 36 | rock.nu = 0.49; % Poisson ratio 37 | rock.cohesion = 50.0; % Cohesion (kPa) 38 | rock.frictionAngle = 20.0*pi/180; % Friction angle (rad) 39 | rock.dilationAngle = 20.0*pi/180; % Dilation angle 40 | 41 | % Set materials to model 42 | mdl.setMaterial(rock); 43 | 44 | %% BOUNDARY CONDITIONS 45 | 46 | % Displacements 47 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 48 | mdl.setDisplacementDirichletBCAtBorder('right', [0.0, NaN]); 49 | mdl.setDisplacementDirichletBCAtBorder('bottom', [0.0, 0.0]); 50 | 51 | %% PROCESS 52 | 53 | % Setup analysis 54 | anl = Anl_NonlinearQuasiStatic('ArcLengthCylControl'); 55 | anl.adjustStep = true; 56 | anl.increment = 0.1; 57 | anl.max_increment = 0.5; 58 | anl.max_lratio = 10.0; 59 | anl.max_step = 10; 60 | anl.max_iter = 100; 61 | anl.trg_iter = 9; 62 | 63 | % Node and DOF used to plot Load Factor vs Displacement 64 | ndId = mdl.closestNodeToPoint([35.0, 40.0]); 65 | anl.setPlotDof(ndId, 2); 66 | 67 | % Run analysis 68 | anl.echo = false; 69 | anl.run(mdl); 70 | -------------------------------------------------------------------------------- /src/analysis/ControlMethod_Work.m: -------------------------------------------------------------------------------- 1 | %% ControlMethod_Work Class 2 | % This class inherits from the base class 'ControlMethod' to implement 3 | % the work control method for solving nonlinear systems. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 7 | % * Rafael Rangel (rrangel@cimne.upc.edu) 8 | % 9 | %% Class definition 10 | classdef ControlMethod_Work < ControlMethod 11 | %% Constructor method 12 | methods 13 | %------------------------------------------------------------------ 14 | function this = ControlMethod_Work() 15 | this = this@ControlMethod(); 16 | end 17 | end 18 | 19 | %% Public methods 20 | methods 21 | %------------------------------------------------------------------ 22 | % Compute inrement of load ratio for the predicted solution 23 | % (first iteration of first step). 24 | function d_lbd0 = predictedIncrementFirst(~,anl,~,~,~,~) 25 | d_lbd0 = anl.increment; 26 | end 27 | 28 | %------------------------------------------------------------------ 29 | % Compute inrement of load ratio for the predicted solution 30 | % (first iteration). 31 | function d_lbd0 = predictedIncrement(~,~,mdl,sign,J,~,D_lbd,~,D_U,d_Up0,Pref) 32 | Pref = Pref(mdl.doffree); 33 | D_U = D_U(mdl.doffree); 34 | d_Up0 = d_Up0(mdl.doffree); 35 | d_lbd0 = sign * J * sqrt(abs((D_lbd*Pref'*D_U)/(Pref'*d_Up0))); 36 | end 37 | 38 | %------------------------------------------------------------------ 39 | % Compute inrement of load ratio for the corrected solutions 40 | % (iterations to correct predicted solution). 41 | function d_lbd = correctedIncrement(~,~,mdl,~,~,~,~,d_Up,d_Ur,~,Pref,~) 42 | d_Up = d_Up(mdl.doffree); 43 | d_Ur = d_Ur(mdl.doffree); 44 | Pref = Pref(mdl.doffree); 45 | d_lbd = -(Pref'*d_Ur)/(Pref'*d_Up); 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /examples/H/example_h_fluid_flow_discontinuity.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Block crossed by strong discontinuity. 4 | % 5 | % Physics: 6 | % * Single-phase hydraulic (H) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | Lx = 5.0; % Horizontal dimension (m) 20 | Ly = 3.0; % Vertical dimension (m) 21 | Nx = 5; % Number of elements in the x-direction 22 | Ny = 3; % Number of elements in the y-direction 23 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 24 | 25 | % Set mesh to model 26 | mdl.setMesh(node, elem); 27 | 28 | %% MATERIALS 29 | 30 | % Create fluids 31 | water = Fluid('water'); 32 | water.rho = 1.0e+3; % Density (kg/m3) 33 | water.mu = 1.0e-3; % Viscosity (Pa*s) 34 | water.K = 2.0e+9; % Compressibility/Bulk modulus (1/Pa) 35 | 36 | % Create porous media 37 | rock = PorousMedia('rock'); 38 | rock.K = 9.8e-16; % Intrinsic permeability (m2) 39 | rock.phi = 0.25; % Porosity 40 | 41 | % Set materials to model 42 | mdl.setMaterial(rock, water); 43 | 44 | %% BOUNDARY CONDITIONS 45 | 46 | % Set Dirichlet boundary conditions 47 | mdl.setPressureDirichletBCAtBorder('left', 0.0); 48 | mdl.setPressureDirichletBCAtBorder('right', 10.0); 49 | 50 | %% DISCONTINUITIES 51 | 52 | % Create discontinuities 53 | Dx = [1.0; 4.0]; % X-coordinates of polyline defining the fracture 54 | Dy = [1.1; 1.9]; % Y-coordinates of polyline defining the fracture 55 | fracture = Discontinuity([Dx, Dy], true); 56 | 57 | % Set fracture material properties 58 | fracture.fluid = water; 59 | fracture.initialAperture = 1.0e-3; 60 | 61 | % Add fractures to model 62 | mdl.addPreExistingDiscontinuities(fracture); 63 | 64 | %% PROCESS 65 | 66 | % Run analysis 67 | anl = Anl_Linear(); 68 | anl.run(mdl); 69 | 70 | %% POST-PROCESS 71 | 72 | % Print results to command window 73 | mdl.printResults(); 74 | 75 | % Plot contours 76 | mdl.plotField('Pressure'); 77 | hold on; 78 | fracture.plotIntersectedGeometry(); 79 | -------------------------------------------------------------------------------- /tests/regression/files/test_h_fluid_flow_barrier.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Block crossed by strong discontinuity acting as a barrier. 4 | % 5 | % Physics: 6 | % * Single-phase hydraulic (H) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | [node, elem] = regularMesh(10.0, 10.0, 20, 20); 20 | 21 | % Set mesh to model 22 | mdl.setMesh(node, elem); 23 | 24 | %% MATERIALS 25 | 26 | % Create fluids 27 | water = Fluid('water'); 28 | water.rho = 1.0e+3; % Density (kg/m3) 29 | water.mu = 1.0e-3; % Viscosity (Pa*s) 30 | water.K = 2.0e+9; % Compressibility/Bulk modulus (1/Pa) 31 | 32 | % Create porous media 33 | rock = PorousMedia('rock'); 34 | rock.K = 9.8e-16; % Intrinsic permeability (m2) 35 | rock.phi = 0.25; % Porosity 36 | 37 | % Set materials to model 38 | mdl.setMaterial(rock, water); 39 | 40 | %% BOUNDARY CONDITIONS 41 | 42 | % Set Dirichlet boundary conditions 43 | mdl.setPressureDirichletBCAtBorder('bottom', 0.0); 44 | mdl.setPressureDirichletBCAtBorder('top', 10.0); 45 | 46 | %% DISCONTINUITY 47 | 48 | % Create discontinuities 49 | Dx = [0.0; 10.0]; % X-coordinates of polyline defining the fracture 50 | Dy = [8.0; 3.0]; % Y-coordinates of polyline defining the fracture 51 | fracture = Discontinuity([Dx, Dy], true); 52 | 53 | % Set fracture material properties 54 | fracture.fluid = water; 55 | fracture.initialAperture = 1.0e-3; 56 | fracture.leakoff = 1.0e-19; 57 | 58 | % Add fractures to model 59 | mdl.addPreExistingDiscontinuities(fracture); 60 | 61 | %% PROCESS 62 | 63 | % Analysis parameters 64 | ti = 1.0; % Initial time 65 | dt = 1.0; % Time step 66 | tf = 100.0; % Final time 67 | dtmax = 50.0; % Maximum time step 68 | dtmin = 0.001; % Minimum time step 69 | adaptStep = true; % Adaptive step size 70 | 71 | % Initialize 72 | anl = Anl_Transient("Newton"); 73 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 74 | anl.echo = false; 75 | anl.run(mdl); -------------------------------------------------------------------------------- /src/analysis/ControlMethod_ArcUNP.m: -------------------------------------------------------------------------------- 1 | %% ControlMethod_ArcUNP Class 2 | % This class inherits from the base class 'ControlMethod' to implement 3 | % the arc length (updated normal plane version) control method for solving nonlinear systems. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 7 | % * Rafael Rangel (rrangel@cimne.upc.edu) 8 | % 9 | %% Class definition 10 | classdef ControlMethod_ArcUNP < ControlMethod 11 | %% Constructor method 12 | methods 13 | %------------------------------------------------------------------ 14 | function this = ControlMethod_ArcUNP() 15 | this = this@ControlMethod(); 16 | end 17 | end 18 | 19 | %% Public methods 20 | methods 21 | %------------------------------------------------------------------ 22 | % Compute inrement of load ratio for the predicted solution 23 | % (first iteration of first step). 24 | function d_lbd0 = predictedIncrementFirst(~,anl,~,~,~,~) 25 | d_lbd0 = anl.increment; 26 | end 27 | 28 | %------------------------------------------------------------------ 29 | % Compute inrement of load ratio for the predicted solution 30 | % (first iteration). 31 | function d_lbd0 = predictedIncrement(~,~,mdl,sign,J,~,~,~,D_U,d_Up0,~) 32 | D_U = D_U(mdl.doffree); 33 | d_Up0 = d_Up0(mdl.doffree); 34 | d_lbd0 = sign * J * sqrt((D_U'*D_U)/(d_Up0'*d_Up0)); 35 | end 36 | 37 | %------------------------------------------------------------------ 38 | % Compute inrement of load ratio for the corrected solutions 39 | % (iterations to correct predicted solution). 40 | function d_lbd = correctedIncrement(~,~,mdl,~,D_lbd,~,~,d_Up,d_Ur,D_U,Pref,~) 41 | d_Up = d_Up(mdl.doffree); 42 | d_Ur = d_Ur(mdl.doffree); 43 | D_U = D_U(mdl.doffree); 44 | Pref = Pref(mdl.doffree); 45 | d_lbd = -(d_Ur'*D_U)/(d_Up'*D_U + D_lbd*(Pref'*Pref)); 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /examples/M/example_m_plane_stress_traction.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Uniform traction on a plate with isotropic damage model. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | Lx = 0.11; % Horizontal dimension (m) 20 | Ly = 0.04; % Vertical dimension (m) 21 | Nx = 22; % Number of elements in the x-direction 22 | Ny = 8; % Number of elements in the y-direction 23 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 24 | 25 | % Set mesh to model 26 | mdl.setMesh(node, elem); 27 | 28 | %% MATERIALS 29 | 30 | % Create porous media 31 | rock = PorousMedia('rock'); 32 | rock.mechanical = 'isoDamage'; % Constitutive law 33 | rock.Young = 2.0e+10; % Young modulus (Pa) 34 | rock.nu = 0.0; % Poisson ratio 35 | rock.kappa = 10.0; % Ratio of tensile and compressive strength 36 | rock.DamageThreshold = 1.0e-4; % Damage threshold 37 | rock.FractureEnergyMode1 = 50.0; % Fracture energy associated with mode 1 (N/m) 38 | 39 | % Set materials to model 40 | mdl.setMaterial(rock); 41 | 42 | %% BOUNDARY CONDITIONS 43 | 44 | % Displacements 45 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, 0.0]); 46 | 47 | % Loads 48 | mdl.addLoadAtBorder('right', 1, 2.0e+6); 49 | 50 | %% PROCESS 51 | 52 | % Setup analysis 53 | anl = Anl_NonlinearQuasiStatic('ArcLengthCylControl'); 54 | anl.adjustStep = true; 55 | anl.increment = 0.01; 56 | anl.max_lratio = 200.0; 57 | anl.max_step = 15; 58 | anl.max_iter = 100; 59 | anl.trg_iter = 4; 60 | 61 | % Node and DOF used to plot Load Factor vs Displacement 62 | ndId = mdl.closestNodeToPoint([Lx, 0.0]); 63 | anl.setPlotDof(ndId, 1); 64 | 65 | % Run analysis 66 | anl.run(mdl); 67 | 68 | %% POST-PROCESS 69 | 70 | % Plot Load Factor vs Displacement 71 | anl.plotCurves(); 72 | 73 | % Plot contours 74 | mdl.plotField('Ux'); 75 | mdl.plotField('Sx'); 76 | mdl.plotField('Sy'); 77 | mdl.plotField('Sxy'); 78 | -------------------------------------------------------------------------------- /tests/regression/files/test_m_strip_footing.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Strip footing problem. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | % Set model options 17 | mdl.intOrder = 2; % Integration quadrature order 18 | 19 | %% MESH 20 | 21 | % Load mesh 22 | load('MeshStripFooting'); 23 | [node, elem] = convertToQuadraticMesh(node, elem); 24 | 25 | % Set mesh to model 26 | mdl.setMesh(node, elem); 27 | 28 | %% MATERIALS 29 | 30 | % Create porous media 31 | rock = PorousMedia('rock'); 32 | rock.mechanical = 'druckerPrager'; % Constitutive law 33 | rock.MCmatch = 'planestrain'; % How Drucker-Prager surfaces matches Mohr-Coulomb 34 | rock.Young = 1.0e+7; % Young modulus (kPa) 35 | rock.nu = 0.48; % Poisson ratio 36 | rock.cohesion = 490.0; % Cohesion (kPa) 37 | rock.frictionAngle = 20*pi/180; % Friction angle (rad) 38 | rock.dilationAngle = 20*pi/180; % Dilation angle (rad) 39 | 40 | % Set materials to model 41 | mdl.setMaterial(rock); 42 | 43 | %% BOUNDARY CONDITIONS 44 | 45 | % Displacements 46 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 47 | mdl.setDisplacementDirichletBCAtBorder('right', [0.0, NaN]); 48 | mdl.setDisplacementDirichletBCAtBorder('bottom', [NaN, 0.0]); 49 | 50 | for i = 1:mdl.nnodes 51 | if ((mdl.NODE(i,1) <= 0.2) && (mdl.NODE(i,2) == 5.0)) 52 | mdl.addLoadAtNode(i, [0.0 , -1.0e2]) 53 | end 54 | end 55 | 56 | %% PROCESS 57 | 58 | % Setup analysis 59 | anl = Anl_NonlinearQuasiStatic('GeneralizedDisplacement'); 60 | anl.adjustStep = true; 61 | anl.increment = 0.01; 62 | anl.max_increment = 0.1; 63 | anl.max_lratio = 10.0; 64 | anl.max_step = 10; 65 | anl.max_iter = 100; 66 | anl.trg_iter = 3; 67 | 68 | % Node and DOF used to plot Load Factor vs Displacement 69 | ndId = mdl.closestNodeToPoint([0.5, 5.0]); 70 | anl.setPlotDof(ndId, 2); 71 | 72 | % Run analysis 73 | anl.echo = false; 74 | anl.run(mdl); -------------------------------------------------------------------------------- /examples/H/example_h_fluid_flow_rock.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Physics: 4 | % * Single-phase hydraulic (H) 5 | % 6 | % Authors: 7 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 8 | % 9 | %% MODEL 10 | 11 | % Create model 12 | mdl = Model_H(); 13 | 14 | %% MESH 15 | 16 | % Create mesh 17 | Lx = 2.0; % Horizontal dimension (m) 18 | Ly = 1.0; % Vertical dimension (m) 19 | Nx = 2; % Number of elements in the x-direction 20 | Ny = 1; % Number of elements in the y-direction 21 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 22 | 23 | % Set mesh to model 24 | mdl.setMesh(node, elem); 25 | 26 | %% MATERIALS 27 | 28 | % Create fluids 29 | water = Fluid('water'); 30 | water.rho = 1.0e+3; % Density (kg/m3) 31 | water.mu = 1.0e-3; % Viscosity (Pa*s) 32 | water.K = 2.0e+9; % Compressibility/Bulk modulus (1/Pa) 33 | 34 | % Create porous media 35 | rock = PorousMedia('rock'); 36 | rock.K = 1.0194e-14; % Intrinsic permeability (m2) 37 | rock.phi = 0.3; % Porosity 38 | rock.Ks = 1.0e+12; % Rock bulk modulus (Pa) 39 | rock.biot = 0.6; % Biot coefficient 40 | 41 | % Set materials to model 42 | mdl.setMaterial(rock, water); 43 | 44 | %% BOUNDARY CONDITIONS 45 | 46 | % Set Dirichlet boundary conditions 47 | mdl.setPressureDirichletBCAtBorder('left', 0.0); 48 | mdl.setPressureDirichletBCAtBorder('right', 10.0); 49 | 50 | %% PROCESS 51 | 52 | % Analysis parameters 53 | ti = 1.0; % Initial time 54 | dt = 1.0; % Time step 55 | tf = 500.0; % Final time 56 | dtmax = 50.0; % Maximum time step 57 | dtmin = 0.001; % Minimum time step 58 | adaptStep = true; % Adaptive step size 59 | 60 | % Run analysis 61 | anl = Anl_Transient("Picard"); 62 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 63 | anl.setRelativeConvergenceCriteria(true); 64 | anl.run(mdl); 65 | 66 | %% POST-PROCESS 67 | 68 | % Print results to command window 69 | mdl.printResults(); 70 | 71 | % Plot contours 72 | mdl.plotField('Pressure'); 73 | 74 | % Plot graphs 75 | Xi = [0.0, Ly/2.0]; Xf = [Lx, Ly/2.0]; 76 | mdl.plotFieldAlongSegment('Pressure', Xi, Xf, 500, 'x'); 77 | -------------------------------------------------------------------------------- /examples/M/example_m_slope_stability.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Slope stability problem. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | % Set model options 17 | mdl.gravityOn = true; 18 | 19 | %% MESH 20 | 21 | % Load mesh 22 | load('MeshSlopeStabilityTransfiniteQuadratic'); 23 | 24 | % Set mesh to model 25 | mdl.setMesh(node, elem); 26 | 27 | %% MATERIALS 28 | 29 | % Create porous media 30 | rock = PorousMedia('rock'); 31 | rock.mechanical = 'druckerPrager'; % Constitutive law 32 | rock.MCmatch = "planestrain"; % How Drucker-Prager surfaces matches Mohr-Coulomb 33 | rock.rho = 2.0; % Density (g/cm3) 34 | rock.Young = 2.0e+4; % Young modulus (kPa) 35 | rock.nu = 0.49; % Poisson ratio 36 | rock.cohesion = 50.0; % Cohesion (kPa) 37 | rock.frictionAngle = 20.0*pi/180; % Friction angle (rad) 38 | rock.dilationAngle = 20.0*pi/180; % Dilation angle 39 | 40 | % Set materials to model 41 | mdl.setMaterial(rock); 42 | 43 | %% BOUNDARY CONDITIONS 44 | 45 | % Displacements 46 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 47 | mdl.setDisplacementDirichletBCAtBorder('right', [0.0, NaN]); 48 | mdl.setDisplacementDirichletBCAtBorder('bottom', [0.0, 0.0]); 49 | 50 | %% PROCESS 51 | 52 | % Setup analysis 53 | anl = Anl_NonlinearQuasiStatic('ArcLengthCylControl'); 54 | anl.adjustStep = true; 55 | anl.increment = 0.1; 56 | anl.max_increment = 0.5; 57 | anl.max_lratio = 10.0; 58 | anl.max_step = 50; 59 | anl.max_iter = 100; 60 | anl.trg_iter = 9; 61 | 62 | % Node and DOF used to plot Load Factor vs Displacement 63 | ndId = mdl.closestNodeToPoint([35.0, 40.0]); 64 | anl.setPlotDof(ndId, 2); 65 | 66 | % Run analysis 67 | anl.run(mdl); 68 | 69 | %% POST-PROCESS 70 | 71 | % Plot Load Factor vs Displacement 72 | anl.plotCurves(); 73 | 74 | % Plot contours 75 | mdl.plotField('E1'); 76 | mdl.plotField('S1'); 77 | mdl.plotField('PEMAG',[0.0,1.0]); 78 | -------------------------------------------------------------------------------- /examples/M/example_m_plate_discontinuity.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Block crossed by strong discontinuity. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | % Set model options 17 | mdl.isPlaneStress = true; 18 | mdl.condenseEnrDofs = true; 19 | 20 | %% MESH 21 | 22 | % Create mesh 23 | Lx = 2.0; % Horizontal dimension (m) 24 | Ly = 2.0; % Vertical dimension (m) 25 | Nx = 1; % Number of elements in the x-direction 26 | Ny = 1; % Number of elements in the y-direction 27 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 28 | 29 | % Set mesh to model 30 | mdl.setMesh(node,elem); 31 | 32 | %% MATERIALS 33 | 34 | % Create porous media 35 | rock = PorousMedia('rock'); 36 | rock.Young = 1.0e+8; % Young modulus (kPa) 37 | rock.nu = 0.0; % Poisson ratio 38 | 39 | % Set materials to model 40 | mdl.setMaterial(rock); 41 | 42 | %% BOUNDARY CONDITIONS 43 | 44 | % Displacements 45 | mdl.setDisplacementDirichletBCAtBorder('bottom', [0.0, 0.0]); 46 | 47 | % Loads 48 | mdl.addLoadAtPoint([0.0,2.0], [-0.5,1.5]); 49 | 50 | %% DISCONTINUITIES 51 | 52 | % Create discontinuities 53 | Dx = [0.00; 2.00]; % X-coordinates of polyline defining the fracture 54 | Dy = [0.25; 1.75]; % Y-coordinates of polyline defining the fracture 55 | fracture = Discontinuity([Dx, Dy], true); 56 | 57 | % Set fracture material properties 58 | fracture.cohesiveLaw = 'elastic'; 59 | fracture.initialAperture = 0.0; 60 | fracture.shearStiffness = 1.0; 61 | fracture.normalStiffness = 1.0; 62 | 63 | % Add fractures to model 64 | discontinuityData = struct('addStretchingMode', false, 'addRelRotationMode', true); 65 | mdl.addPreExistingDiscontinuities(fracture, discontinuityData); 66 | 67 | %% PROCESS 68 | 69 | % Run analysis 70 | anl = Anl_Linear(); 71 | anl.run(mdl); 72 | 73 | %% POST-PROCESS 74 | 75 | % Print results to command window 76 | mdl.printResults(); 77 | 78 | % Plot model 79 | mdl.plotField('Model'); 80 | hold on; 81 | fracture.plotIntersectedGeometry(); 82 | -------------------------------------------------------------------------------- /src/analysis/Anl_Linear.m: -------------------------------------------------------------------------------- 1 | %% Anl_Linear Class 2 | % This class inherits from the base class 'Anl' to implement the solution a static linear analysis. 3 | % 4 | %% Authors 5 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 6 | % 7 | %% Class definition 8 | classdef Anl_Linear < Anl 9 | %% Public properties 10 | properties (SetAccess = public, GetAccess = public) 11 | end 12 | 13 | %% Constructor method 14 | methods 15 | %------------------------------------------------------------------ 16 | function this = Anl_Linear() 17 | this = this@Anl('Linear'); 18 | end 19 | end 20 | 21 | %% Public methods 22 | methods 23 | %------------------------------------------------------------------ 24 | % Execute the linear analysis for the given model object 'mdl'. 25 | function run(~,mdl) 26 | disp("*** Performing linear analysis...") 27 | 28 | % Initialize model object 29 | mdl.preComputations(); 30 | 31 | % Compute global stiffness matrix 32 | [K,~,~,Fext,dFidX] = mdl.globalMatrices(mdl.U); 33 | 34 | % Set linear system 35 | if ((nnz(K)>0) && (nnz(dFidX) == 0)) 36 | A = K; 37 | elseif ((nnz(K) == 0) && (nnz(dFidX) > 0)) 38 | A = dFidX; 39 | elseif ((nnz(K) == 0) && (nnz(dFidX) == 0)) 40 | error("Physics did not fill either K or dFidX.") 41 | end 42 | b = Fext(mdl.doffree) - A(mdl.doffree,mdl.doffixed) * mdl.U(mdl.doffixed); 43 | 44 | % Solve linear system 45 | mdl.U(mdl.doffree) = A(mdl.doffree,mdl.doffree)\b; 46 | 47 | % Save final result 48 | for i = 1:mdl.nelem 49 | gle = mdl.element(i).type.gle; 50 | mdl.element(i).type.ue = mdl.U(gle); 51 | end 52 | 53 | % Call it again to update state variables 54 | mdl.globalMatrices(mdl.U); 55 | mdl.updateStateVar(); 56 | 57 | disp("*** Analysis completed!"); 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /examples/M/example_m_compression_contact_stick_q4_discontinuity.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Contact problem. Block with horizontal discontinuity in the stick 4 | % condition. 5 | % 6 | % Physics: 7 | % * Mechanical (M) 8 | % 9 | % Authors: 10 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 11 | % 12 | %% MODEL 13 | 14 | % Create model 15 | mdl = Model_M(); 16 | 17 | % Set model options 18 | mdl.isPlaneStress = true; 19 | mdl.condenseEnrDofs = false; 20 | % mdl.subDivIntegration = true; 21 | mdl.symmetricSDAEFEM = false; 22 | 23 | %% MESH 24 | 25 | % Create mesh 26 | Lx = 1.0; % Horizontal dimension (m) 27 | Ly = 1.0; % Vertical dimension (m) 28 | Nx = 21; % Number of elements in the x-direction 29 | Ny = 21; % Number of elements in the y-direction 30 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny, [], [], 'CST'); 31 | 32 | % Set mesh to model 33 | mdl.setMesh(node,elem); 34 | 35 | %% MATERIALS 36 | 37 | % Create porous media 38 | rock = PorousMedia('rock'); 39 | rock.Young = 5.0e+9; % Young modulus (Pa) 40 | rock.nu = 0.3; % Poisson ratio 41 | 42 | % Set materials to model 43 | mdl.setMaterial(rock); 44 | 45 | %% BOUNDARY CONDITIONS 46 | 47 | % Displacements 48 | mdl.setDisplacementDirichletBCAtBorder('bottom', [0.0, 0.0]); 49 | mdl.setDisplacementDirichletBCAtBorder('top', [0.0, -1.0e-3]); 50 | 51 | %% DISCONTINUITIES 52 | 53 | % Create discontinuities 54 | Xd = [ 0.0 , 0.51*Ly; 55 | Lx , 0.51*Ly]; 56 | fracture = Discontinuity(Xd, true); 57 | 58 | % Set fracture material properties 59 | fracture.cohesiveLaw = 'elastic'; 60 | fracture.shearStiffness = 1.0; % Pa/m 61 | fracture.normalStiffness = 1.0e15; % Pa/m 62 | 63 | % Add fractures to model 64 | discontinuityData = struct('addStretchingMode', false, 'addRelRotationMode', false); 65 | mdl.addPreExistingDiscontinuities(fracture, discontinuityData); 66 | 67 | %% PROCESS 68 | 69 | % Run analysis 70 | anl = Anl_Linear(); 71 | anl.run(mdl); 72 | 73 | %% POST-PROCESS 74 | 75 | % Plot model 76 | mdl.plotField('Sy'); 77 | hold on; 78 | fracture.plotIntersectedGeometry(); 79 | 80 | mdl.plotFieldAlongDiscontinuiy('Sn',1) 81 | -------------------------------------------------------------------------------- /src/analysis/ControlMethod_ArcFNP.m: -------------------------------------------------------------------------------- 1 | %% ControlMethod_ArcFNP Class 2 | % This class inherits from the base class 'ControlMethod' to implement 3 | % the arc length (fixed normal plane version) control method for solving nonlinear systems. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 7 | % * Rafael Rangel (rrangel@cimne.upc.edu) 8 | % 9 | %% Class definition 10 | classdef ControlMethod_ArcFNP < ControlMethod 11 | %% Constructor method 12 | methods 13 | %------------------------------------------------------------------ 14 | function this = ControlMethod_ArcFNP() 15 | this = this@ControlMethod(); 16 | end 17 | end 18 | 19 | %% Public methods 20 | methods 21 | %------------------------------------------------------------------ 22 | % Compute inrement of load ratio for the predicted solution 23 | % (first iteration of first step). 24 | function d_lbd0 = predictedIncrementFirst(~,anl,~,~,~,~) 25 | d_lbd0 = anl.increment; 26 | end 27 | 28 | %------------------------------------------------------------------ 29 | % Compute inrement of load ratio for the predicted solution 30 | % (first iteration). 31 | function d_lbd0 = predictedIncrement(~,~,mdl,sign,J,~,~,~,D_U,d_Up0,~) 32 | % Extract free DOF components 33 | D_U = D_U(mdl.doffree); 34 | d_Up0 = d_Up0(mdl.doffree); 35 | d_lbd0 = sign * J * sqrt((D_U'*D_U)/(d_Up0'*d_Up0)); 36 | end 37 | 38 | %------------------------------------------------------------------ 39 | % Compute inrement of load ratio for the corrected solutions 40 | % (iterations to correct predicted solution). 41 | function d_lbd = correctedIncrement(~,~,mdl,d_lbd0,~,~,d_U0,d_Up,d_Ur,~,Pref,~) 42 | d_U0 = d_U0(mdl.doffree); 43 | d_Up = d_Up(mdl.doffree); 44 | d_Ur = d_Ur(mdl.doffree); 45 | Pref = Pref(mdl.doffree); 46 | d_lbd = -(d_Ur'*d_U0)/(d_Up'*d_U0 + d_lbd0*(Pref'*Pref)); 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /src/material/relativePermeability/RelativePermeabilityLiakopoulosLiquid.m: -------------------------------------------------------------------------------- 1 | %% RelativePermeabilityLiakopoulosLiquid Class 2 | % This class defines the liquid phase relative permeability model based on 3 | % the Liakopoulos formulation. It inherits from the _RelativePermeability_ 4 | % base class and provides a specific implementation for calculating the 5 | % relative permeability of the liquid phase. 6 | % 7 | %% Method 8 | % * *calculate*: Computes the liquid phase relative permeability klr based 9 | % on the liquid saturation Sl and the porous media 10 | % properties. 11 | % 12 | %% Author 13 | % Danilo Cavalcanti 14 | % 15 | %% Version History 16 | % Version 1.00. 17 | % 18 | %% Class Definition 19 | classdef RelativePermeabilityLiakopoulosLiquid < RelativePermeability 20 | %% Properties 21 | % Parameters taken from OGS-6. 22 | % OGS reference: 23 | % Asadi, R., Ataie-Ashtiani, B. (2015): A Comparison of finite volume 24 | % formulations and coupling strategies for two-phase flow in deforming 25 | % porous media. Comput. Geosci., p. 24ff. 26 | properties (SetAccess = public, GetAccess = public) 27 | a = 2.207; 28 | b = 1.0121; 29 | Slmin = 0.2; 30 | end 31 | %% Constructor method 32 | methods 33 | %------------------------------------------------------------------ 34 | function this = RelativePermeabilityLiakopoulosLiquid() 35 | this = this@RelativePermeability('liakopoulosLiquid'); 36 | end 37 | end 38 | 39 | %% Public methods 40 | methods 41 | 42 | %------------------------------------------------------------------ 43 | % Compute the liquid phase relative permeability 44 | function klr = calculate(this, Sl, porousMedia) 45 | if (Sl < this.Slmin) 46 | klr = porousMedia.klrmin; 47 | elseif (Sl > 1.0) 48 | klr = 1.0; 49 | else 50 | klr = 1.0 - this.a * (1.0 - Sl)^this.b; 51 | klr = max(klr,porousMedia.klrmin); 52 | end 53 | end 54 | 55 | end 56 | end -------------------------------------------------------------------------------- /src/analysis/ControlMethod_ArcCyl.m: -------------------------------------------------------------------------------- 1 | %% ControlMethod_ArcCyl Class 2 | % This class inherits from the base class 'ControlMethod' to implement 3 | % the arc length (cylindrical version) control method for solving nonlinear systems. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 7 | % * Rafael Rangel (rrangel@cimne.upc.edu) 8 | % 9 | %% Class definition 10 | classdef ControlMethod_ArcCyl < ControlMethod 11 | %% Constructor method 12 | methods 13 | %------------------------------------------------------------------ 14 | function this = ControlMethod_ArcCyl() 15 | this = this@ControlMethod(); 16 | end 17 | end 18 | 19 | %% Public methods 20 | methods 21 | %------------------------------------------------------------------ 22 | % Compute inrement of load ratio for the predicted solution 23 | % (first iteration of first step). 24 | function d_lbd0 = predictedIncrementFirst(~,anl,~,~,~,~) 25 | d_lbd0 = anl.increment; 26 | end 27 | 28 | %------------------------------------------------------------------ 29 | % Compute inrement of load ratio for the predicted solution 30 | % (first iteration). 31 | function d_lbd0 = predictedIncrement(~,~,mdl,sign,J,~,~,~,D_U,d_Up0,~) 32 | D_U = D_U(mdl.doffree); 33 | d_Up0 = d_Up0(mdl.doffree); 34 | d_lbd0 = sign * J * sqrt((D_U'*D_U)/(d_Up0'*d_Up0)); 35 | end 36 | 37 | %------------------------------------------------------------------ 38 | % Compute inrement of load ratio for the corrected solutions 39 | % (iterations to correct predicted solution). 40 | function d_lbd = correctedIncrement(~,~,mdl,~,~,~,~,d_Up,d_Ur,D_U,~,~) 41 | d_Up = d_Up(mdl.doffree); 42 | d_Ur = d_Ur(mdl.doffree); 43 | D_U = D_U(mdl.doffree); 44 | a = d_Up'*d_Up; 45 | b = d_Up'*(d_Ur + D_U); 46 | c = d_Ur'*(d_Ur + 2*D_U); 47 | s = sign(D_U'*d_Up); 48 | d_lbd = -b/a + s*sqrt((b/a)^2 - c/a); 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to PorousLab 2 | 3 | Anyone is welcome to contribute to the project in one of the ways described below. 4 | 5 | Please note that this project is released with a [Code of Conduct][code_conduct_link]. 6 | By participating in this project you agree to abide by its terms. 7 | 8 | ## Proposals 9 | 10 | It includes proposing a change/new feature or report a bug. 11 | 12 | Open an [issue][issue_link] through the GitHub interface. 13 | 14 | Describe the proposal/bug clearly, preferably including reproducible examples, illustrations, or outputs. 15 | 16 | Alternatively, you can contact the [authors][authors_link] by email. 17 | 18 | ## Implementations 19 | 20 | It includes implementing a new feature, change an existing one, or fix a bug. 21 | 22 | To modify the source code or files, create a [new branch][new_branch_link] from the master branch, and work on that branch to make the modifications. 23 | 24 | Please check that all tests are passing after finishing the modifications to the source code. 25 | In addition, it is recommended to create new models for testing the implemented features. 26 | 27 | Always try to keep the code organized. 28 | It includes choosing clear and representative names for functions and variables, 29 | paying attention to alignments and spacing, 30 | and avoiding leaving unused code blocks as comments. 31 | 32 | After the implementations are complete, make a [pull request][pull_request_link]. 33 | You should clearly describe the modifications and their purposes in order to facilitate understanding by others. 34 | 35 | The merge of new branches into the master branch is subjected to the authors' approval. 36 | 37 | You can also contact the [authors][authors_link] by email to discuss the modifications in advance. 38 | 39 | [code_conduct_link]: https://github.com/dbcavalcanti/porousLab/blob/main/CODE_OF_CONDUCT.md 40 | [issue_link]: https://github.com/dbcavalcanti/porousLab/issues 41 | [authors_link]: https://github.com/dbcavalcanti/porousLab#authorship 42 | [new_branch_link]: https://github.com/dbcavalcanti/porousLab/branches 43 | [pull_request_link]: https://github.com/dbcavalcanti/porousLab/pulls -------------------------------------------------------------------------------- /tests/validation/validation_stress_integration_vm.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Validation script for mechanical constitutive models. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | close all; clear; clc; 12 | 13 | %% MODEL DEFINITION 14 | 15 | % Material properties 16 | rock = PorousMedia('rock'); 17 | rock.mechanical = 'vonMises'; % Elastoplastic with von Mises criteria 18 | rock.Young = 2.0e+8; % Young modulus (Pa) 19 | rock.nu = 0.3; % Poisson ratio 20 | rock.sy0 = 1.0e+5; % Initial yield stress (Pa) 21 | rock.Kp = 0.0; % Plastic modulus (Pa) 22 | 23 | % Material parameters vector 24 | mat = struct('porousMedia', rock); 25 | 26 | % Integration point 27 | ip = IntPoint([0.0,0.0], 1.0, Material_M(mat)); 28 | ip.initializeMechanicalAnalysisModel('PlaneStrain'); 29 | 30 | %% RUN ANALYSIS 31 | 32 | % Strain increment direction 33 | dstrain0 = [0.0; % exx 34 | 0.0; % eyy 35 | 0.0; % ezz 36 | 1.0]; % gxy 37 | 38 | mag = 1.0e-5; 39 | ninc = 150; 40 | 41 | idplot = 4; 42 | stressplot = zeros(ninc+1, 1); 43 | strainplot = zeros(ninc+1, 1); 44 | pstrainplot = zeros(ninc+1, 1); 45 | 46 | for i = 1:ninc 47 | ip.strain = ip.strainOld + mag * dstrain0; 48 | ip.stress = ip.mechanicalLaw(); 49 | ip.stressOld = ip.stress; 50 | ip.strainOld = ip.strain; 51 | 52 | % Store 53 | stressplot(i+1) = ip.stress(idplot); 54 | strainplot(i+1) = ip.strain(idplot); 55 | pstrainplot(i+1) = ip.plasticstrain(idplot); 56 | end 57 | 58 | %% POS-PROCESSING 59 | 60 | % Stress vs Total strain 61 | figure; 62 | grid on, box on, hold on; 63 | tauy = rock.sy0 / sqrt(3.0); 64 | plot(strainplot, stressplot/tauy, 'b-', 'LineWidth', 1.5); 65 | xlabel('\gamma_{xy}'); 66 | ylabel('\tau_{xy}/\tau_Y'); 67 | set(gca, 'fontsize', 18, 'TickLabelInterpreter', 'latex'); 68 | 69 | % Stress vs Plastic strain 70 | figure; 71 | grid on, box on, hold on; 72 | plot(pstrainplot, stressplot/tauy, 'r-', 'LineWidth', 1.5); 73 | xlabel('\gamma_{xy}^p'); 74 | ylabel('\tau_{xy}/\tau_Y'); 75 | set(gca, 'fontsize', 18, 'TickLabelInterpreter', 'latex'); 76 | -------------------------------------------------------------------------------- /src/physics/H/MaterialDiscontinuity_H.m: -------------------------------------------------------------------------------- 1 | %% MaterialDiscontinuity_H class 2 | % This class represents a material discontinuity in a porous medium, 3 | % characterized by its initial aperture and the fluid properties. 4 | % It provides methods to compute the longitudinal permeability 5 | % coefficient and compressibility based on the material's properties. 6 | % 7 | %% Methods 8 | % * *longitudinalPermeability*: Computes the longitudinal permeability 9 | % coefficient based on the cubic law. 10 | % * *compressibility*: Computes the compressibility of the material 11 | % discontinuity based on its aperture and fluid 12 | % properties. 13 | % 14 | %% Author 15 | % Danilo Cavalcanti 16 | % 17 | %% Version History 18 | % Version 1.00. 19 | % 20 | %% Class definition 21 | classdef MaterialDiscontinuity_H < handle 22 | %% Public attributes 23 | properties (SetAccess = public, GetAccess = public) 24 | initialAperture = 0.0; 25 | leakoff = 1.0; 26 | fluid = Fluid(); 27 | end 28 | %% Constructor method 29 | methods 30 | %------------------------------------------------------------------ 31 | function this = MaterialDiscontinuity_H(matData) 32 | this.initialAperture = matData.initialAperture; 33 | this.fluid = matData.fluid; 34 | this.leakoff = matData.leakoff; 35 | end 36 | end 37 | %% Public methods 38 | methods 39 | 40 | %------------------------------------------------------------------ 41 | % Computes the longitudinal permeability coefficient based on the 42 | % cubic's law 43 | function kl = longitudinalPermeability(this) 44 | w = this.initialAperture(); 45 | kl = w*w*w/12.0/this.fluid.mu; 46 | end 47 | 48 | %------------------------------------------------------------------ 49 | % Computes the compressibility of the material discontinuity 50 | % based on its aperture and fluid properties. 51 | function c = compressibility(this) 52 | w = this.initialAperture(); 53 | c = w / this.fluid.K; 54 | end 55 | 56 | end 57 | end -------------------------------------------------------------------------------- /examples/H/example_h_fluid_flow_barrier.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Block crossed by strong discontinuity acting as a barrier. 4 | % 5 | % Physics: 6 | % * Single-phase hydraulic (H) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | [node, elem] = regularMesh(10.0, 10.0, 20, 20); 20 | 21 | % Set mesh to model 22 | mdl.setMesh(node, elem); 23 | 24 | %% MATERIALS 25 | 26 | % Create fluids 27 | water = Fluid('water'); 28 | water.rho = 1.0e+3; % Density (kg/m3) 29 | water.mu = 1.0e-3; % Viscosity (Pa*s) 30 | water.K = 2.0e+9; % Compressibility/Bulk modulus (1/Pa) 31 | 32 | % Create porous media 33 | rock = PorousMedia('rock'); 34 | rock.K = 9.8e-16; % Intrinsic permeability (m2) 35 | rock.phi = 0.25; % Porosity 36 | 37 | % Set materials to model 38 | mdl.setMaterial(rock, water); 39 | 40 | %% BOUNDARY CONDITIONS 41 | 42 | % Set Dirichlet boundary conditions 43 | mdl.setPressureDirichletBCAtBorder('bottom', 0.0); 44 | mdl.setPressureDirichletBCAtBorder('top', 10.0); 45 | 46 | %% DISCONTINUITY 47 | 48 | % Create discontinuities 49 | Dx = [0.0; 10.0]; % X-coordinates of polyline defining the fracture 50 | Dy = [8.0; 3.0]; % Y-coordinates of polyline defining the fracture 51 | fracture = Discontinuity([Dx, Dy], true); 52 | 53 | % Set fracture material properties 54 | fracture.fluid = water; 55 | fracture.initialAperture = 1.0e-3; 56 | fracture.leakoff = 1.0e-19; 57 | 58 | % Add fractures to model 59 | mdl.addPreExistingDiscontinuities(fracture); 60 | 61 | %% PROCESS 62 | 63 | % Analysis parameters 64 | ti = 1.0; % Initial time 65 | dt = 1.0; % Time step 66 | tf = 8000.0; % Final time 67 | dtmax = 500.0; % Maximum time step 68 | dtmin = 0.001; % Minimum time step 69 | adaptStep = true; % Adaptive step size 70 | 71 | % Initialize 72 | anl = Anl_Transient("Newton"); 73 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 74 | anl.run(mdl); 75 | 76 | %% POST-PROCESS 77 | 78 | % Print results to command window 79 | mdl.printResults(); 80 | 81 | % Plot contours 82 | mdl.plotField('Pressure'); 83 | hold on; 84 | fracture.plotIntersectedGeometry(); 85 | -------------------------------------------------------------------------------- /examples/M/example_m_strip_footing.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Strip footing problem. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | % Set model options 17 | mdl.intOrder = 2; % Integration quadrature order 18 | 19 | %% MESH 20 | 21 | % Load mesh 22 | load('MeshStripFooting'); 23 | [node, elem] = convertToQuadraticMesh(node, elem); 24 | 25 | % Set mesh to model 26 | mdl.setMesh(node, elem); 27 | 28 | %% MATERIALS 29 | 30 | % Create porous media 31 | rock = PorousMedia('rock'); 32 | rock.mechanical = 'druckerPrager'; % Constitutive law 33 | rock.MCmatch = 'planestrain'; % How Drucker-Prager surfaces matches Mohr-Coulomb 34 | rock.Young = 1.0e+7; % Young modulus (kPa) 35 | rock.nu = 0.48; % Poisson ratio 36 | rock.cohesion = 490.0; % Cohesion (kPa) 37 | rock.frictionAngle = 20*pi/180; % Friction angle (rad) 38 | rock.dilationAngle = 20*pi/180; % Dilation angle (rad) 39 | 40 | % Set materials to model 41 | mdl.setMaterial(rock); 42 | 43 | %% BOUNDARY CONDITIONS 44 | 45 | % Displacements 46 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 47 | mdl.setDisplacementDirichletBCAtBorder('right', [0.0, NaN]); 48 | mdl.setDisplacementDirichletBCAtBorder('bottom', [NaN, 0.0]); 49 | 50 | for i = 1:mdl.nnodes 51 | if ((mdl.NODE(i,1) <= 0.2) && (mdl.NODE(i,2) == 5.0)) 52 | mdl.addLoadAtNode(i, [0.0 , -1.0e2]) 53 | end 54 | end 55 | 56 | %% PROCESS 57 | 58 | % Setup analysis 59 | anl = Anl_NonlinearQuasiStatic('GeneralizedDisplacement'); 60 | anl.adjustStep = true; 61 | anl.increment = 0.01; 62 | anl.max_increment = 0.1; 63 | anl.max_lratio = 10.0; 64 | anl.max_step = 60; 65 | anl.max_iter = 100; 66 | anl.trg_iter = 3; 67 | 68 | % Node and DOF used to plot Load Factor vs Displacement 69 | ndId = mdl.closestNodeToPoint([0.5, 5.0]); 70 | anl.setPlotDof(ndId, 2); 71 | 72 | % Run analysis 73 | anl.run(mdl); 74 | 75 | %% POST-PROCESS 76 | 77 | % Plot Load Factor vs Displacement 78 | anl.plotCurves(); 79 | 80 | % Plot contours 81 | mdl.plotField('PEMAG',[0.0,0.0001]); 82 | mdl.plotField('Uy'); 83 | -------------------------------------------------------------------------------- /examples/H/example_h_fluid_flow_dam.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Fluid-flow through the foundation of a gravity dam. 4 | % 5 | % References: 6 | % * Segura and Carol (2004). On zero-thickness interface elements for diffusion problems. Int J Numer Anal Methods Geomech, 28(9):947-962. 7 | % 8 | % Physics: 9 | % * Single-phase hydraulic (H) 10 | % 11 | % Authors: 12 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 13 | % 14 | %% MODEL 15 | 16 | % Create model 17 | mdl = Model_H(); 18 | 19 | %% MESH 20 | 21 | % Create mesh 22 | Lx = 24.0; % Horizontal dimension (m) 23 | Ly = 6.0; % Vertical dimension (m) 24 | Nx = 96/2; % Number of elements in the x-direction 25 | Ny = 24/2; % Number of elements in the y-direction 26 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 27 | 28 | % Set mesh to model 29 | mdl.setMesh(node, elem); 30 | 31 | %% MATERIALS 32 | 33 | % Create fluids 34 | water = Fluid('water'); 35 | water.K = 2.0e+9; % Compressibility/Bulk modulus (1/Pa) 36 | 37 | % Create porous media 38 | rock = PorousMedia('rock'); 39 | rock.K = 1.0194e-14; % Intrinsic permeability (m2) 40 | rock.phi = 0.3; % Porosity 41 | 42 | % Set materials to model 43 | mdl.setMaterial(rock, water); 44 | 45 | %% BOUNDARY CONDITIONS 46 | 47 | % Set Dirichlet boundary conditions 48 | for i = 1:size(mdl.NODE,1) 49 | if ((mdl.NODE(i,1) < 8.0) && (abs(mdl.NODE(i,2)-Ly) < 1.0e-9)) 50 | mdl.setPressureDirichletBCAtNode(i, 120.0); 51 | end 52 | if ((mdl.NODE(i,1) > 12.0) && (abs(mdl.NODE(i,2)-Ly) < 1.0e-9)) 53 | mdl.setPressureDirichletBCAtNode(i, 60.0); 54 | end 55 | end 56 | 57 | %% PROCESS 58 | 59 | % Analysis parameters 60 | ti = 1.0; % Initial time 61 | dt = 1.0; % Time step 62 | tf = 500.0; % Final time 63 | dtmax = 50.0; % Maximum time step 64 | dtmin = 0.001; % Minimum time step 65 | adaptStep = true; % Adaptive step size 66 | 67 | % Run analysis 68 | anl = Anl_Transient("Newton"); 69 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 70 | anl.run(mdl); 71 | 72 | %% POST-PROCESS 73 | 74 | % Print results to command window 75 | mdl.printResults(); 76 | 77 | % Plot contours 78 | mdl.plotField('Pressure'); 79 | 80 | % Plot graphs 81 | Xi = [0.0, Ly/2.0]; Xf = [Lx, Ly/2.0]; 82 | mdl.plotFieldAlongSegment('Pressure', Xi, Xf, 500, 'x'); 83 | -------------------------------------------------------------------------------- /src/analysis/ControlMethod_ArcSph.m: -------------------------------------------------------------------------------- 1 | %% ControlMethod_ArcSph Class 2 | % This class inherits from the base class 'ControlMethod' to implement 3 | % the arc length (spherical version) control method for solving nonlinear systems. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 7 | % * Rafael Rangel (rrangel@cimne.upc.edu) 8 | % 9 | %% Class definition 10 | classdef ControlMethod_ArcSph < ControlMethod 11 | %% Constructor method 12 | methods 13 | %------------------------------------------------------------------ 14 | function this = ControlMethod_ArcSph() 15 | this = this@ControlMethod(); 16 | end 17 | end 18 | 19 | %% Public methods 20 | methods 21 | %------------------------------------------------------------------ 22 | % Compute inrement of load ratio for the predicted solution 23 | % (first iteration of first step). 24 | function d_lbd0 = predictedIncrementFirst(~,anl,~,~,~,~) 25 | d_lbd0 = anl.increment; 26 | end 27 | 28 | %------------------------------------------------------------------ 29 | % Compute inrement of load ratio for the predicted solution 30 | % (first iteration). 31 | function d_lbd0 = predictedIncrement(~,~,mdl,sign,J,~,D_lbd,~,D_U,d_Up0,Pref) 32 | Pref = Pref(mdl.doffree); 33 | D_U = D_U(mdl.doffree); 34 | d_Up0 = d_Up0(mdl.doffree); 35 | d_lbd0 = sign * J * sqrt((D_U'*D_U + D_lbd^2*(Pref'*Pref)) / (d_Up0'*d_Up0 + Pref'*Pref)); 36 | end 37 | 38 | %------------------------------------------------------------------ 39 | % Compute inrement of load ratio for the corrected solutions 40 | % (iterations to correct predicted solution). 41 | function d_lbd = correctedIncrement(~,~,mdl,~,D_lbd,~,~,d_Up,d_Ur,D_U,Pref,~) 42 | d_Up = d_Up(mdl.doffree); 43 | d_Ur = d_Ur(mdl.doffree); 44 | D_U = D_U(mdl.doffree); 45 | Pref = Pref(mdl.doffree); 46 | a = d_Up'*d_Up + Pref'*Pref; 47 | b = d_Up'*(d_Ur + D_U) + D_lbd*(Pref'*Pref); 48 | c = d_Ur'*(d_Ur + 2*D_U); 49 | s = sign(D_U'*d_Up); 50 | d_lbd = -b/a + s*sqrt((b/a)^2 - c/a); 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /src/analysis/NonlinearScheme.m: -------------------------------------------------------------------------------- 1 | %% NonlinearScheme Class 2 | % This in an abstract class that defines a nonlinear scheme object. 3 | % It serves as a base class for implementing nonlinear solution schemes in numerical analysis. 4 | % The class provides a set of abstract methods that must be implemented by subclasses, 5 | % as well as some public properties and methods for managing convergence tolerance and error normalization. 6 | % 7 | %% Authors 8 | % * Danilo Cavalcanti 9 | % 10 | %% Class definition 11 | classdef NonlinearScheme < handle 12 | %% Public properties 13 | properties (SetAccess = public, GetAccess = public) 14 | tol = 1.0e-5; 15 | normalizeError = false; 16 | end 17 | 18 | %% Constructor method 19 | methods 20 | %------------------------------------------------------------------ 21 | function this = NonlinearScheme() 22 | return; 23 | end 24 | end 25 | 26 | %% Abstract methods 27 | methods (Abstract) 28 | %------------------------------------------------------------------ 29 | % Assemble the linear system for the nonlinear problem. 30 | [A,b] = assembleLinearSystem(this,C,K,fi,fe,dfidx,x,xOld,dt); 31 | 32 | %------------------------------------------------------------------ 33 | % Apply boundary conditions to the right-hand side of the system. 34 | bf = applyBCtoRHS(this,A,b,x,doffree,doffixed); 35 | 36 | %------------------------------------------------------------------ 37 | % Add nodal forces to the right-hand side vector. 38 | b = addNodalForces(this,b,fe); 39 | 40 | %------------------------------------------------------------------ 41 | % Evaluates the solution increment and updates the solution vector. 42 | [X,dx] = eval(this,J,r,X,dx,freedof,iter); 43 | 44 | %------------------------------------------------------------------ 45 | % Check for convergence of the nonlinear scheme. 46 | convFlg = convergence(this,X,XOld,dx,b,doffree,iter); 47 | end 48 | 49 | %% Public methods 50 | methods 51 | %------------------------------------------------------------------ 52 | % Set the convergence tolerance. 53 | function setConvergenceTolerance(this,tol) 54 | this.tol = tol; 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /examples/M/example_m_stretching_discontinuity.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Block crossed by strong discontinuity. Stretching mode. 4 | % 5 | % Reference DOI: 10.1016/j.cma.2009.07.013 6 | % 7 | % Physics: 8 | % * Mechanical (M) 9 | % 10 | % Authors: 11 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 12 | % 13 | %% MODEL 14 | 15 | % Create model 16 | mdl = Model_M(); 17 | 18 | % Set model options 19 | mdl.isPlaneStress = true; 20 | mdl.condenseEnrDofs = false; 21 | mdl.subDivIntegration = true; 22 | 23 | %% MESH 24 | 25 | % Create mesh 26 | Lx = 2.0e-3; % Horizontal dimension (m) 27 | Ly = 1.0e-3; % Vertical dimension (m) 28 | Nx = 5; % Number of elements in the x-direction 29 | Ny = 5; % Number of elements in the y-direction 30 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 31 | 32 | % Model thickness 33 | mdl.t = 1.0e-3; 34 | 35 | % Set mesh to model 36 | mdl.setMesh(node,elem); 37 | 38 | %% MATERIALS 39 | 40 | % Create porous media 41 | rock = PorousMedia('rock'); 42 | rock.Young = 30.0e+6; % Young modulus (kPa) 43 | rock.nu = 0.0; % Poisson ratio 44 | 45 | % Set materials to model 46 | mdl.setMaterial(rock); 47 | 48 | %% BOUNDARY CONDITIONS 49 | 50 | % Displacements 51 | mdl.setDisplacementDirichletBCAtBorder('bottom', [0.0, 0.0]); 52 | mdl.setDisplacementDirichletBCAtBorder('top', [NaN, 0.0]); 53 | 54 | % Loads 55 | mdl.addLoadAtPoint([0.0,1.0], [ 13.49,0.0]); 56 | mdl.addLoadAtPoint([2.0,1.0], [-13.49,0.0]); 57 | 58 | %% DISCONTINUITIES 59 | 60 | % Create discontinuities 61 | Dx = [0.0; 2.0e-3]; % X-coordinates of polyline defining the fracture 62 | Dy = [0.5e-3; 0.5e-3]; % Y-coordinates of polyline defining the fracture 63 | fracture = Discontinuity([Dx, Dy], true); 64 | 65 | % Set fracture material properties 66 | fracture.cohesiveLaw = 'elastic'; 67 | fracture.initialAperture = 0.0; 68 | fracture.shearStiffness = 1.0e10; % Pa/m 69 | fracture.normalStiffness = 1.0e10; % Pa/m 70 | 71 | % Add fractures to model 72 | discontinuityData = struct('addStretchingMode', true, 'addRelRotationMode', true); 73 | mdl.addPreExistingDiscontinuities(fracture, discontinuityData); 74 | 75 | %% PROCESS 76 | 77 | % Run analysis 78 | anl = Anl_Linear(); 79 | anl.run(mdl); 80 | 81 | %% POST-PROCESS 82 | 83 | % Print results to command window 84 | mdl.printResults(); 85 | 86 | % Plot model 87 | mdl.plotField('Ux'); 88 | hold on; 89 | fracture.plotIntersectedGeometry(); 90 | -------------------------------------------------------------------------------- /src/physics/H/Material_H.m: -------------------------------------------------------------------------------- 1 | %% Material_H Class 2 | % This class represents a material model that combines fluid and porous 3 | % media properties. It provides methods to compute material properties 4 | % such as permeability tensor and compressibility coefficient. 5 | % 6 | %% Methods 7 | % * *permeabilityTensor*: Computes and returns the permeability tensor of 8 | % the material, which is derived from the 9 | % intrinsic permeability matrix of the porous 10 | % media and the fluid viscosity. 11 | % * *compressibilityCoeff*: Computes and returns the compressibility 12 | % coefficient of the material based on Biot's 13 | % coefficient, porosity, solid bulk modulus, 14 | % and fluid bulk modulus. 15 | % 16 | %% Author 17 | % Danilo Cavalcanti 18 | % 19 | %% Version History 20 | % Version 1.00. 21 | % 22 | %% Class definition 23 | classdef Material_H < handle 24 | %% Public attributes 25 | properties (SetAccess = public, GetAccess = public) 26 | fluid = Fluid(); 27 | porousMedia = PorousMedia(); 28 | end 29 | %% Constructor method 30 | methods 31 | %------------------------------------------------------------------ 32 | function this = Material_H(matData) 33 | this.fluid = matData.fluid; 34 | this.porousMedia = matData.porousMedia; 35 | end 36 | end 37 | %% Public methods 38 | methods 39 | 40 | % ----------------------------------------------------------------- 41 | % Returns the biot coefficient 42 | function kh = permeabilityTensor(this) 43 | kh = this.porousMedia.intrinsicPermeabilityMatrix(); 44 | kh = kh / this.fluid.mu; 45 | end 46 | 47 | % ----------------------------------------------------------------- 48 | % Computes the compressibility coefficient 49 | function comp = compressibilityCoeff(this) 50 | % Get material parameters 51 | biot = this.porousMedia.biot; % Biot's coefficient 52 | phi = this.porousMedia.phi; % Porosity 53 | Ks = this.porousMedia.Ks; % Solid bulk modulus 54 | Kf = this.fluid.K; % Fluid bulk modulus 55 | % Compute the compressibility 56 | comp = (biot - phi)/Ks + phi/Kf; 57 | end 58 | end 59 | end -------------------------------------------------------------------------------- /tests/regression/files/test_h2_mcwhorter_pl_pg.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % McWhorter and Sunada problem using the Pl-Pg two-phase flow formulation 4 | % 5 | % References: 6 | % * McWhorter and Sunada (1990). Exact integral solutions for two-phase flow. Water Resour Res, 26(3):399–413. 7 | % 8 | % Physics: 9 | % * Two-phase hydraulic (H2) 10 | % 11 | % Authors: 12 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 13 | % 14 | %% MODEL 15 | 16 | % Create model 17 | mdl = Model_H2(); 18 | 19 | % Set model options 20 | mdl.massLumping = true; % Diagonalize compressibility matrix (mass lumping) 21 | mdl.lumpStrategy = 2; 22 | mdl.intOrder = 3; % Integration rule order for the domain 23 | 24 | %% MESH 25 | 26 | % Create mesh 27 | [node, elem] = regularMesh(2.6, 0.5, 100, 1); 28 | 29 | % Set mesh to model 30 | mdl.setMesh(node, elem); 31 | 32 | %% MATERIALS 33 | 34 | % Create fluids 35 | water = Fluid('water'); 36 | gas = Fluid('gas'); 37 | 38 | % Create porous media 39 | rock = PorousMedia('rock'); 40 | rock.K = 1.0e-10; % Intrinsic permeability (m2) 41 | rock.phi = 0.3; % Porosity 42 | rock.Slr = 0.0; % Residual liquid saturation 43 | rock.Sgr = 0.0; % Residual gas saturation 44 | rock.Pb = 5.0e+3; % Gas-entry pressure 45 | rock.lambda = 2.0; % Curve-fitting parameter 46 | rock.liqRelPermeability = 'BrooksCorey'; % Liquid relative permeability 47 | rock.gasRelPermeability = 'BrooksCorey'; % Gas relative permeability 48 | rock.capillaryPressure = 'BrooksCorey'; % Saturation degree function 49 | 50 | % Set materials to model 51 | mdl.setMaterial(rock, water, gas); 52 | 53 | %% BOUNDARY AND INITIAL CONDITIONS 54 | 55 | % Set Dirichlet boundary conditions 56 | mdl.setPressureDirichletBCAtBorder('left', 195.0e+3); 57 | mdl.setGasPressureDirichletBCAtBorder('left', 200.0e+3); 58 | 59 | % Set initial conditions 60 | mdl.setInitialPressureAtDomain(-50.0e+3); 61 | 62 | %% PROCESS 63 | 64 | % Analysis parameters 65 | ti = 0.1; % Initial time 66 | dt = 0.1; % Time step 67 | tf = 10; % Final time 68 | dtmax = 10.0; % Maximum time step 69 | dtmin = 0.0000001; % Minimum time step 70 | adaptStep = true; % Adaptive step size 71 | 72 | % Run analysis 73 | anl = Anl_Transient("Newton"); 74 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 75 | anl.maxIter = 10; 76 | anl.echo = false; 77 | anl.run(mdl); -------------------------------------------------------------------------------- /tests/regression/files/test_m_pressurized_cylinder.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Elastoplastic pressurized cylinder. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | [node, elem] = regularMesh(1.0, 1.0, 10, 10); 20 | 21 | % Transform to cylindrical coordinates 22 | ri = 0.1; % Internal cylinder radius 23 | re = 0.2; % External cylinder radius 24 | r = ri + node(:, 1) * (re - ri); 25 | theta = node(:, 2) * (pi / 2); 26 | node = [r .* cos(theta), r .* sin(theta)]; 27 | 28 | % Set mesh to model 29 | mdl.setMesh(node, elem); 30 | 31 | %% MATERIALS 32 | 33 | % Create porous media 34 | rock = PorousMedia('rock'); 35 | rock.mechanical = 'vonMises'; % Constitutive law 36 | rock.Young = 2.1e+11; % Young modulus (Pa) 37 | rock.nu = 0.3; % Poisson ratio 38 | rock.sy0 = 2.4e+8; % Initial yield stress (Pa) 39 | rock.Kp = 0.0; % Plastic modulus (Pa) 40 | 41 | % Set materials to model 42 | mdl.setMaterial(rock); 43 | 44 | %% BOUNDARY CONDITIONS 45 | 46 | % Displacements 47 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 48 | mdl.setDisplacementDirichletBCAtBorder('bottom', [NaN, 0.0]); 49 | 50 | % Radius of each node wrt to center at (0,0) 51 | r = sqrt((mdl.NODE(:,1)).^2 + (mdl.NODE(:,2)).^2); 52 | sn = mdl.NODE(:,2) ./ r; 53 | cs = mdl.NODE(:,1) ./ r; 54 | 55 | % Loaded nodes 56 | internalNodes = (r-ri) < eps; 57 | nInternalNodes = sum(internalNodes); 58 | 59 | % Internal pressure (Pa) and Force magnitude 60 | pint = 192.0905814164710e+06; 61 | F0 = (pint*mdl.t*ri*pi/2.0)/(nInternalNodes-1)/2.0; 62 | 63 | % Occurrences of each node 64 | allNodes = cell2mat(mdl.ELEM(:)); 65 | nodeCount = histcounts(allNodes, 1:(size(mdl.NODE,1)+1))'; 66 | 67 | % Apply internal pressure to internal face nodes 68 | mdl.LOAD(internalNodes,:) = F0 * nodeCount(internalNodes) .* [cs(internalNodes) , sn(internalNodes)]; 69 | 70 | %% PROCESS 71 | 72 | % Setup analysis 73 | anl = Anl_NonlinearQuasiStatic('ArcLengthCylControl'); 74 | anl.adjustStep = true; 75 | anl.increment = 0.1; 76 | anl.max_increment = 0.1; 77 | anl.max_lratio = 2.0; 78 | anl.max_step = 20; 79 | anl.max_iter = 100; 80 | anl.trg_iter = 4; 81 | 82 | % Node and DOF used to plot Load Factor vs Displacement 83 | ndId = mdl.closestNodeToPoint([ri, 0.0]); 84 | anl.setPlotDof(ndId, 1); 85 | 86 | % Run analysis 87 | anl.echo = false; 88 | anl.run(mdl); -------------------------------------------------------------------------------- /src/material/IdealGas.m: -------------------------------------------------------------------------------- 1 | %% IdealGas Class 2 | % This class is a subclass of the _Fluid_ class that represents an ideal 3 | % gas. It provides methods to calculate the density of the gas based on 4 | % the ideal gas law and allows setting key properties such as the 5 | % universal gas constant, molar mass, and temperature. 6 | % 7 | %% Methods 8 | % * *getDensity*: Calculates the density of the gas using the ideal gas 9 | % law considering the gas pressure 10 | % * *setUniversalGasConstant*: Sets the value of the universal gas 11 | % constant. 12 | % * *setMolarMass*: Sets the molar mass of the gas. 13 | % * *setTemperature*: Sets the temperature of the gas. 14 | % 15 | %% Author 16 | % Danilo Cavalcanti 17 | % 18 | %% Version History 19 | % Version 1.00. 20 | % 21 | %% Class Definition 22 | classdef IdealGas < Fluid 23 | %% Public attributes 24 | properties (SetAccess = private, GetAccess = public) 25 | R = 8.3144621; % Universal gas constant (J/(mol*K) 26 | T = 293.15; % Temperature (K) 27 | M = 0.02897; % Molar mass (kg/mol) 28 | end 29 | 30 | %% Constructor method 31 | methods 32 | %------------------------------------------------------------------ 33 | function this = IdealGas(id, viscosity, compressibility) 34 | this = this@Fluid(id); 35 | this.rho = 0.0; 36 | if nargin > 1 37 | this.mu = viscosity; 38 | this.K = compressibility; 39 | end 40 | end 41 | end 42 | %% Public methods 43 | methods 44 | %------------------------------------------------------------------ 45 | % Get the fluid density based on the ideal Gas law 46 | function rho = getDensity(this,pg) 47 | rho = pg * this.M / (this.R * this.T); 48 | end 49 | %------------------------------------------------------------------ 50 | % Set the value of the universal gas constant 51 | function setUniversalGasConstant(this,R) 52 | this.R = R; 53 | end 54 | %------------------------------------------------------------------ 55 | % Set the value of the gas molar mass 56 | function setMolarMass(this,M) 57 | this.M = M; 58 | end 59 | %------------------------------------------------------------------ 60 | % Set the value of the temperature 61 | function setTemperature(this,T) 62 | this.T = T; 63 | end 64 | end 65 | end -------------------------------------------------------------------------------- /src/material/saturationLaw/CapillaryPressureBrooksCorey.m: -------------------------------------------------------------------------------- 1 | %% CapillaryPressureBrooksCorey Class 2 | % This class implements the Brooks-Corey capillary pressure model, which 3 | % is used to compute the saturation degree and its derivative for a porous 4 | % medium. It inherits from the _CapillaryPressure_ base class. 5 | % 6 | % 7 | %% Methods 8 | % * *saturationDegree*: Computes the liquid phase saturation degree based 9 | % on the capillary pressure and the properties of 10 | % the porous medium. 11 | % * *derivativeSaturationDegree*: Computes the derivative of the liquid 12 | % phase saturation degree with respect to 13 | % the capillary pressure. 14 | % 15 | %% Author 16 | % Danilo Cavalcanti 17 | % 18 | %% Version History 19 | % Version 1.00. 20 | % 21 | %% Class Definition 22 | classdef CapillaryPressureBrooksCorey < CapillaryPressure 23 | %% Constructor method 24 | methods 25 | %------------------------------------------------------------------ 26 | function this = CapillaryPressureBrooksCorey() 27 | this = this@CapillaryPressure('brooksCorey'); 28 | end 29 | end 30 | 31 | %% Public methods 32 | methods 33 | 34 | %------------------------------------------------------------------ 35 | % Compute the liquid phase relative permeability 36 | function Sl = saturationDegree(~, pc, porousMedia) 37 | if (pc >= porousMedia.Pb) 38 | Se = (porousMedia.Pb/pc)^porousMedia.lambda; 39 | Sl = Se * (1.0 - porousMedia.Slr - porousMedia.Sgr) + porousMedia.Slr; 40 | else 41 | Sl = 1.0; 42 | end 43 | Sl = max(min(Sl, 1.0 - porousMedia.Sgr - eps), porousMedia.Slr + eps); 44 | end 45 | 46 | %------------------------------------------------------------------ 47 | % Compute the gas phase relative permeability 48 | function dSldpc = derivativeSaturationDegree(this, pc, porousMedia) 49 | % if (pc >= porousMedia.Pb) 50 | % 51 | % else 52 | % dSldpc = 1.0; 53 | % end 54 | Sl = this.saturationDegree(pc, porousMedia); 55 | dPcdSl = (porousMedia.Pb / (porousMedia.lambda * (porousMedia.Slr - Sl))) * ((Sl - porousMedia.Slr)/(1.0 - porousMedia.Sgr - porousMedia.Slr)) ^ (-1.0/porousMedia.lambda); 56 | dSldpc = 1.0 / dPcdSl; 57 | end 58 | 59 | end 60 | end -------------------------------------------------------------------------------- /examples/M/example_m_pressurized_reservoir.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Uniform traction on a plate with isotropic damage model. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | % Set model options 17 | mdl.addPorePressure = true; 18 | 19 | %% MESH 20 | 21 | % Create mesh 22 | Lx = 4000.0; % Horizontal dimension (m) 23 | Ly = 1000.0; % Vertical dimension (m) 24 | Nx = 50; % Number of elements in the x-direction 25 | Ny = 25; % Number of elements in the y-direction 26 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny, [], [], 'ISOQ4', 0.5, 0.7, 0.5, 0.0); 27 | 28 | % Set mesh to model 29 | mdl.setMesh(node, elem); 30 | 31 | %% MATERIALS 32 | 33 | % Earth pressure coefficient 34 | K0 = 0.65; 35 | 36 | % Create porous media 37 | rock = PorousMedia('rock'); 38 | rock.Young = 30.0e+9; % Young modulus (Pa) 39 | rock.nu = K0/(1+K0); % Poisson ratio 40 | 41 | % Set materials to model 42 | mdl.setMaterial(rock); 43 | 44 | %% BOUNDARY CONDITIONS 45 | 46 | % Displacements 47 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 48 | mdl.setDisplacementDirichletBCAtBorder('right', [0.0, NaN]); 49 | mdl.setDisplacementDirichletBCAtBorder('bottom', [NaN, 0.0]); 50 | 51 | % Pressure load 52 | mdl.addLoadAtBorder('top', 2, -70.0e6); 53 | 54 | % Set external pore-pressure 55 | P = 35.0e6 * ones(mdl.nnodes,1); 56 | mdl.setPorePressureField(P); 57 | 58 | %% PROCESS 59 | 60 | % Run analysis 61 | anl = Anl_Linear(); 62 | anl.run(mdl); 63 | 64 | % Update the pressure at the left side 65 | tol = 1.0e-5; 66 | reservoir = isInsideRectangle(mdl.NODE, [0.0-tol,350.0-tol], [0.5*Lx+tol,650.0+tol]); 67 | P(reservoir == 1) = P(reservoir == 1) + 20.0e6; 68 | 69 | % Update pressure at the right side 70 | offset = 100.0; 71 | reservoir = isInsideRectangle(mdl.NODE, [0.5*Lx,350.0+offset-tol], [Lx+tol,650.0+offset+tol]); 72 | P(reservoir == 1) = P(reservoir == 1) + 20.0e6; 73 | mdl.setPorePressureField(P); 74 | 75 | % Run analysis 76 | anl.run(mdl); 77 | 78 | %% POST-PROCESS 79 | 80 | % Print stresses 81 | fprintf("\n\n IP Sxx Syy Szz Sxy\n") 82 | elem = mdl.element(1).type; 83 | for i = 1:elem.nIntPoints 84 | stress = elem.intPoint(i).stress; 85 | fprintf("%2d %+.4e %+.4e %+.4e %+.4e \n",i,stress(1),stress(2),stress(3),stress(4)); 86 | end 87 | 88 | % Plot stresses 89 | mdl.plotField('Sx'); 90 | mdl.plotField('Sy'); 91 | mdl.plotField('Sxy'); 92 | 93 | mdl.plotFieldAlongSegment('Sxy',[0.5*Lx,0.0],[0.5*Lx,Ly],100,'y') 94 | -------------------------------------------------------------------------------- /tests/regression/files/test_h2_buckley_leverett_pc_pg.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Buckley-Leverett problem using the Pc-Pg two-phase flow formulation. 4 | % 5 | % Physics: 6 | % * Two-phase hydraulic (H2) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H2_PcPg(); 15 | 16 | % Set model options 17 | mdl.massLumping = true; % Diagonalize compressibility matrix (mass lumping) 18 | mdl.lumpStrategy = 2; 19 | 20 | %% MESH 21 | 22 | % Create mesh 23 | [node, elem] = regularMesh(301.95, 100.0, 99, 1); 24 | 25 | % Set mesh to model 26 | mdl.setMesh(node, elem); 27 | 28 | %% MATERIALS 29 | 30 | % Create fluids 31 | water = Fluid('water'); 32 | gas = Fluid('gas'); 33 | 34 | % Create porous media 35 | rock = PorousMedia('rock'); 36 | rock.K = 1.0e-7; % Intrinsic permeability (m2) 37 | rock.phi = 0.2; % Porosity 38 | rock.Slr = 0.2; % Residual liquid saturation 39 | rock.Sgr = 0.2; % Residual gas saturation 40 | rock.Pb = 0.0; % Gas-entry pressure 41 | rock.lambda = 2.0; % Curve-fitting parameter 42 | rock.liqRelPermeability = 'BrooksCorey'; % Liquid relative permeability 43 | rock.gasRelPermeability = 'BrooksCorey'; % Gas relative permeability 44 | rock.capillaryPressure = 'UMAT'; % Saturation degree function 45 | 46 | % Set user material values for capillary pressure vs. saturation law 47 | % Pc | Sl 48 | SlPcUMAT = [3.0, 0.2; 49 | 0.0, 0.8]; 50 | rock.setUMATCapillaryPressureCurve(SlPcUMAT); 51 | 52 | % Set materials to model 53 | mdl.setMaterial(rock, water, gas); 54 | 55 | %% BOUNDARY AND INITIAL CONDITIONS 56 | 57 | % Set Dirichlet boundary conditions 58 | mdl.setCapillaryPressureDirichletBCAtBorder('left', 0.230769231); 59 | mdl.setGasPressureDirichletBCAtBorder('left', 200000.230769231); 60 | 61 | % Set initial conditions 62 | mdl.setInitialCapillaryPressureAtDomain(3.0); 63 | mdl.setInitialGasPressureAtDomain(200003.0); 64 | 65 | %% PROCESS 66 | 67 | % Analysis parameters 68 | day = 60*60*24; % Conversion from days to seconds 69 | ti = 0.1*day; % Initial time 70 | dt = 0.1*day; % Time step 71 | tf = 1.0*day; % Final time 72 | dtmax = 0.1*day; % Maximum time step 73 | dtmin = 0.1*day; % Minimum time step 74 | adaptStep = true; % Adaptive step size 75 | 76 | % Run analysis 77 | anl = Anl_Transient("Picard"); 78 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 79 | anl.echo = false; 80 | anl.run(mdl); -------------------------------------------------------------------------------- /tests/regression/files/test_h2_five_spot_pc_pg.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Five-spot corner problem using the Pc-Pg two-phase flow formulation. 4 | % 5 | % Physics: 6 | % * Two-phase hydraulic (H2) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H2_PcPg(); 15 | 16 | % Set model options 17 | mdl.massLumping = true; % Diagonalize compressibility matrix (mass lumping) 18 | mdl.lumpStrategy = 2; 19 | 20 | %% MESH 21 | 22 | % Create mesh 23 | [node, elem] = regularMesh(10.0, 10.0, 20, 20); 24 | 25 | % Set mesh to model 26 | mdl.setMesh(node, elem); 27 | 28 | %% MATERIALS 29 | 30 | % Create fluids 31 | water = Fluid('water'); 32 | gas = Fluid('gas'); 33 | gas.mu = 4.0e-3; % Viscosity (Pa*s) 34 | 35 | % Create porous media 36 | rock = PorousMedia('rock'); 37 | rock.K = 1.0e-13; % Intrinsic permeability (m2) 38 | rock.phi = 0.206; % Porosity 39 | rock.Pb = 1.0e+3; % Gas-entry pressure 40 | rock.lambda = 1.0; % Curve-fitting parameter 41 | rock.m = 2.0; % Expoent for the polynomial relationships 42 | rock.liqRelPermeability = 'PolynomialLiquid'; % Liquid relative permeability 43 | rock.gasRelPermeability = 'PolynomialGas'; % Gas relative permeability 44 | rock.capillaryPressure = 'BrooksCorey'; % Saturation degree function 45 | 46 | % Set materials to model 47 | mdl.setMaterial(rock, water, gas); 48 | 49 | %% BOUNDARY AND INITIAL CONDITIONS 50 | 51 | % Set Dirichlet boundary conditions 52 | mdl.setCapillaryPressureDirichletBCAtPoint([0.0, 0.0], 0.0); 53 | mdl.setCapillaryPressureDirichletBCAtPoint([10.0, 10.0], 105018.5554); 54 | mdl.setGasPressureDirichletBCAtPoint([0.0, 0.0], 1.5e6); 55 | mdl.setGasPressureDirichletBCAtPoint([10.0, 10.0], 1.0e6); 56 | 57 | % Set initial conditions 58 | mdl.setInitialCapillaryPressureAtDomain(105018.5554); 59 | mdl.setInitialGasPressureAtDomain(105018.5554); 60 | 61 | %% PROCESS 62 | 63 | % Analysis parameters 64 | day = 60*60*24; % Conversion from days to seconds 65 | ti = 0.01*day; % Initial time 66 | dt = 0.01*day; % Time step 67 | tf = 0.1*day; % Final time 68 | dtmax = 1.0*day; % Maximum time step 69 | dtmin = 0.001*day; % Minimum time step 70 | adaptStep = true; % Adaptive step size 71 | 72 | % Run analysis 73 | anl = Anl_Transient("Picard"); 74 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 75 | anl.setRelativeConvergenceCriteria(true); 76 | anl.maxIter = 15; 77 | anl.echo = false; 78 | anl.run(mdl); 79 | -------------------------------------------------------------------------------- /examples/M/example_m_partial_tension_q4_discontinuity.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Block crossed by strong discontinuity. Stretching mode. 4 | % 5 | % Reference DOI: 10.1016/j.cma.2009.07.013 6 | % 7 | % Physics: 8 | % * Mechanical (M) 9 | % 10 | % Authors: 11 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 12 | % 13 | %% MODEL 14 | 15 | % Create model 16 | mdl = Model_M(); 17 | 18 | % Set model options 19 | mdl.isPlaneStress = true; 20 | mdl.condenseEnrDofs = false; 21 | mdl.subDivIntegration = true; 22 | mdl.symmetricSDAEFEM = false; 23 | 24 | %% MESH 25 | 26 | % Create mesh 27 | Lx = 2.0e-1; % Horizontal dimension (m) 28 | Ly = 2.0e-1; % Vertical dimension (m) 29 | Nx = 1; % Number of elements in the x-direction 30 | Ny = 1; % Number of elements in the y-direction 31 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 32 | 33 | % Set mesh to model 34 | mdl.setMesh(node,elem); 35 | 36 | %% MATERIALS 37 | 38 | % Create porous media 39 | rock = PorousMedia('rock'); 40 | rock.Young = 30.0e+9; % Young modulus (Pa) 41 | rock.nu = 0.0; % Poisson ratio 42 | 43 | % Set materials to model 44 | mdl.setMaterial(rock); 45 | 46 | %% BOUNDARY CONDITIONS 47 | 48 | % Displacements 49 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, 0.0]); 50 | mdl.setDisplacementDirichletBCAtPoint([2.0e-1,0.0],[0.0,-1.0e-4]); 51 | mdl.setDisplacementDirichletBCAtPoint([2.0e-1,2.0e-1],[0.0,1.0e-4]); 52 | 53 | %% DISCONTINUITIES 54 | 55 | % Create discontinuities 56 | Dx = [1.0e-1; 1.0e-1]; % X-coordinates of polyline defining the fracture 57 | Dy = [0.0e-1; 2.0e-1]; % Y-coordinates of polyline defining the fracture 58 | fracture = Discontinuity([Dx, Dy], true); 59 | 60 | % Set fracture material properties 61 | fracture.cohesiveLaw = 'elastic'; 62 | fracture.initialAperture = 0.0; 63 | fracture.shearStiffness = 0.0; % Pa/m 64 | fracture.normalStiffness = 0.0; % Pa/m 65 | 66 | % Add fractures to model 67 | discontinuityData = struct('addStretchingMode', true, 'addRelRotationMode', true); 68 | mdl.addPreExistingDiscontinuities(fracture, discontinuityData); 69 | 70 | %% PROCESS 71 | 72 | % Run analysis 73 | anl = Anl_Linear(); 74 | anl.run(mdl); 75 | 76 | %% POST-PROCESS 77 | 78 | % Print results to command window 79 | mdl.printResults(); 80 | 81 | % Print stresses 82 | fprintf("\n\n IP Sxx Syy Szz Sxy\n") 83 | elem = mdl.element(1).type; 84 | for i = 1:elem.nIntPoints 85 | stress = elem.intPoint(i).stress; 86 | fprintf("%2d %+.4e %+.4e %+.4e %+.4e \n",i,stress(1),stress(2),stress(3),stress(4)); 87 | end 88 | 89 | % Plot model 90 | mdl.plotField('Ux'); 91 | hold on; 92 | fracture.plotIntersectedGeometry(); 93 | -------------------------------------------------------------------------------- /src/pos/Result.m: -------------------------------------------------------------------------------- 1 | %% Result Class 2 | % This class defines a _Result_ object to use the patch function from 3 | % Matlab to plot the model. 4 | % 5 | %% Methods 6 | % This class provides the following methods: 7 | % 8 | % * *Result*: Constructor that initializes a Result object with the given vertices, faces, vertex data, and data label. 9 | % * *setDataLabel*: Sets the label of the result being plotted. 10 | % * *setVertices*: Updates the vertices of the patches. 11 | % * *setFaces*: Updates the faces of the patches. 12 | % * *setVertexData*: Updates the values associated with the vertices. 13 | % 14 | %% Authors 15 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 16 | % 17 | %% Class Definition 18 | classdef Result < handle 19 | 20 | %% Public attributes 21 | properties 22 | % Patch data 23 | vertices0 = []; % Orginal vertices of the patches 24 | vertices = []; % Vertices of the patches 25 | faces = []; % Faces definitions 26 | vertexData = []; % Values associated to the vertices 27 | dataLabel = ''; % Label of the result being plotted 28 | end 29 | 30 | %% Constructor method 31 | methods 32 | function this = Result(vertices,faces,vertexData,dataLabel) 33 | if nargin > 0 34 | this.vertices0 = vertices; 35 | this.vertices = vertices; 36 | this.faces = faces; 37 | this.vertexData = vertexData; 38 | this.dataLabel = dataLabel; 39 | end 40 | end 41 | end 42 | 43 | %% Public methods 44 | methods 45 | 46 | % ----------------------------------------------------------------- 47 | % Set the label of the result being plotted 48 | function setDataLabel(this, dataLabel) 49 | this.dataLabel = dataLabel; 50 | end 51 | 52 | % ----------------------------------------------------------------- 53 | % Set the vertices of the patches 54 | function setVertices(this, vertices) 55 | this.vertices = vertices; 56 | end 57 | 58 | % ----------------------------------------------------------------- 59 | % Set the faces of the patches 60 | function setFaces(this, faces) 61 | this.faces = faces; 62 | end 63 | 64 | % ----------------------------------------------------------------- 65 | % Set the values of vertices of the patches 66 | function setVertexData(this, vertexData) 67 | this.vertexData = vertexData; 68 | end 69 | 70 | end 71 | end -------------------------------------------------------------------------------- /src/analysis/NonlinearScheme_Newton.m: -------------------------------------------------------------------------------- 1 | %% NonlinearScheme_Newton Class 2 | % This class inherits from the base class 'NonlinearScheme' to implement 3 | % a fully implicit time integration scheme using the Newton-Raphson method for solving nonlinear systems. 4 | % 5 | %% Authors 6 | % * Danilo Cavalcanti 7 | % 8 | %% Class definition 9 | classdef NonlinearScheme_Newton < NonlinearScheme 10 | %% Constructor method 11 | methods 12 | %------------------------------------------------------------------ 13 | function this = NonlinearScheme_Newton() 14 | this = this@NonlinearScheme(); 15 | end 16 | end 17 | 18 | %% Public methods 19 | methods 20 | %------------------------------------------------------------------ 21 | % Assemble the Jacobian matrix and the residual vector. 22 | function [J,r] = assembleLinearSystem(~,C,K,fi,fe,dfidx,x,xOld,dt) 23 | % Residual vector 24 | r = fi + K * x + C * (x - xOld) / dt - fe; 25 | 26 | % Jacobian matrix 27 | J = K + dfidx + C / dt; 28 | end 29 | 30 | %------------------------------------------------------------------ 31 | % Apply boundary conditions to the right-hand side of the system. 32 | function bf = applyBCtoRHS(~,~,b,~,doffree,~) 33 | bf = b(doffree); 34 | end 35 | 36 | %------------------------------------------------------------------ 37 | % Add nodal forces to the right-hand side vector. 38 | function b = addNodalForces(~,b,fe) 39 | b = b - fe; 40 | end 41 | 42 | %------------------------------------------------------------------ 43 | % Evaluate the solution increment and updates the solution vector. 44 | function [X,dx] = eval(~,J,r,X,~,freedof,~) 45 | % Compute increment of variables 46 | dx = -J\r; 47 | 48 | % Update variables 49 | X(freedof) = X(freedof) + dx; 50 | end 51 | 52 | %------------------------------------------------------------------ 53 | % Check for convergence of the nonlinear scheme. 54 | function convFlg = convergence(this,~,XOld,dx,r,~,iter,echo) 55 | normXOld = norm(XOld); 56 | if normXOld < 1.0e-16, normXOld = 1.0; end 57 | if echo 58 | fprintf("\t\t iter.: %3d , ||R|| = %7.3e , ||dx||/||X0|| = %7.3e \n",iter,norm(r),norm(dx)/normXOld); 59 | end 60 | if ((norm(r) < this.tol) || (norm(dx)/normXOld) < this.tol) && (iter > 1) 61 | convFlg = true; 62 | else 63 | convFlg = false; 64 | end 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /examples/HM/example_hm_terzaghi_analytical.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Terzaghi 1D consolidation problem. 4 | % 5 | % References: 6 | % * Nguyen et al (2017). Modelling hydraulic fractures in porous media using flow cohesive interface elements. Eng Geol, 225:68–82. 7 | % * Segura and Carol (2008). Coupled HM analysis using zero-thickness interface elements with double nodes—Part II: Verification and application. Int J Numer Anal Methods Geomech, 32(18):2103–23. 8 | % 9 | % Physics: 10 | % * Single-phase flow hydro-mechanical (HM) 11 | % 12 | % Authors: 13 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 14 | % 15 | clear; clc; % close all 16 | 17 | %% PHYSICAL PARAMETERS 18 | 19 | % Solid parameters 20 | E = 1.0e+6; % Young's modulus (Pa) 21 | nu = 0.3; % Poisson's ratio (-) 22 | n = 0.3; % Porosity (-) 23 | k = 1.15741e-12; % Intrinsic permeability (m^2) 24 | Ks = 1.0e+25; % Solid bulk modulus (Pa) 25 | 26 | % Fluid parameters 27 | muf = 1e-3; % Fluid dynamic viscosity (Pa*s) 28 | 29 | % Porous medium parameters 30 | alpha = 1.0; % Biot coefficient 31 | Sm = 0.0; % Storage coefficient 32 | K = E/3/(1-2*nu); % Bulk modulus (Pa) 33 | G = E/2/(1+nu); % Shear modulus (Pa) 34 | mv = 1 / ((4/3)*G + K); % Confined compressibility (1/Pa) 35 | 36 | % Consolidation coefficient 37 | Cv = k / (muf * (Sm + alpha*alpha * mv)); 38 | 39 | %% PROBLEM PARAMETERS 40 | 41 | % Initial excess pore pressure (Pa) 42 | p0 = 1.0e4; 43 | 44 | % Total thickness of soil layer (m) 45 | H = 1; 46 | 47 | % Consolidation time (s) 48 | t = 100.0; 49 | % t = [43, 100, 262, 302.5, 500]; 50 | 51 | % Number of expansion terms 52 | np = 1000; 53 | 54 | % Depth intervals 55 | dz = 0.001; % Depth increment (m) 56 | z = 0:dz:H; % Depths within soil layer 57 | Z = z/H; % Normalized depth 58 | 59 | %% TERZAGHI SOLUTION 60 | 61 | % Initialize plot 62 | figure; 63 | hold on; 64 | 65 | % Calculate pore pressure profile 66 | for i = 1:length(t) 67 | % Initialize pressure vector 68 | p = zeros(size(z)); 69 | 70 | % Calculate time factor 71 | T = Cv * t(i) / (H^2); 72 | 73 | % Terzaghi's solution 74 | for j = 1:np 75 | M = pi/2*(2*j-1); 76 | p = p + 4/pi * ((-1)^(j-1)/(2*j-1)) * cos(M*Z) * exp(-M*M*T); 77 | end 78 | 79 | % Plot pressure vector 80 | plot(p*p0, z/H, 'LineWidth', 2, 'DisplayName', ['Analytical: t = ',num2str(t(i)), ' s']); 81 | 82 | % Print pressure at bottom 83 | disp(['Pressure at the bottom edge: ', num2str(p0*p(1)) , ' Pa']); 84 | end 85 | 86 | % Formatting 87 | xlabel('Pore Pressure (Pa)'); 88 | ylabel('Y (m)'); 89 | set(gca, 'FontSize', 18) 90 | grid on; 91 | box on; 92 | legend('Location', 'best'); 93 | -------------------------------------------------------------------------------- /examples/H/example_h_fractured_reservoir_cell.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Block crossed by strong discontinuity. 4 | % 5 | % Physics: 6 | % * Single-phase hydraulic (H) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | Lx = 200.0; % Horizontal dimension (m) 20 | Ly = 200.0; % Vertical dimension (m) 21 | Nx = 53; % Number of elements in the x-direction 22 | Ny = 53; % Number of elements in the y-direction 23 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 24 | 25 | % Set mesh to model 26 | mdl.setMesh(node, elem); 27 | 28 | %% MATERIALS 29 | 30 | % Create fluids 31 | water = Fluid('water'); 32 | water.rho = 1.0e+3; % Density (kg/m3) 33 | water.mu = 1.0e-3; % Viscosity (Pa*s) 34 | water.K = 2.2e+9; % Compressibility/Bulk modulus (1/Pa) 35 | 36 | % Create porous media 37 | rock = PorousMedia('rock'); 38 | rock.K = 1.0e-14; % Intrinsic permeability (m2) 39 | rock.phi = 0.25; % Porosity 40 | 41 | % Set materials to model 42 | mdl.setMaterial(rock, water); 43 | 44 | %% BOUNDARY CONDITIONS 45 | 46 | % Set Dirichlet boundary conditions 47 | mdl.setPressureDirichletBCAtBorder('bottom', 0.0); 48 | mdl.setPressureDirichletBCAtBorder('top', 1000000.0); 49 | 50 | %% DISCONTINUITIES 51 | 52 | % loads fracture_data 53 | load('FractureDataReservoirCell.mat'); 54 | 55 | % Number of discontinuities 56 | nd = length(FractureDataReservoirCell); 57 | 58 | % Create discontinuities 59 | fractures(1,nd) = Discontinuity(); 60 | for i = 1:nd 61 | fractures(i) = Discontinuity(FractureDataReservoirCell{i}, true); 62 | end 63 | 64 | % Set fracture material properties 65 | for i = 1:nd 66 | fractures(i).fluid = water; 67 | fractures(i).initialAperture = 1.0e-3; 68 | end 69 | 70 | % Add fractures to model 71 | mdl.addPreExistingDiscontinuities(fractures); 72 | 73 | %% PROCESS 74 | 75 | % Analysis parameters 76 | ti = 1.0; % Initial time 77 | dt = 1.0; % Time step 78 | tf = 1000.0; % Final time 79 | dtmax = 500.0; % Maximum time step 80 | dtmin = 0.001; % Minimum time step 81 | adaptStep = true; % Adaptive step size 82 | 83 | % Run analysis 84 | anl = Anl_Transient("Newton"); 85 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 86 | anl.run(mdl); 87 | 88 | %% POST-PROCESS 89 | 90 | % Print results to command window 91 | mdl.printResults(); 92 | 93 | % Plot model 94 | mdl.plotField('Model'); 95 | colorbar off; hold on; 96 | for i = 1:length(mdl.discontinuitySet) 97 | mdl.discontinuitySet(i).plotIntersectedGeometry(); 98 | end 99 | 100 | % Plot contours 101 | mdl.plotField('Pressure'); 102 | -------------------------------------------------------------------------------- /src/auxiliary/Gmsh2Porouslab.py: -------------------------------------------------------------------------------- 1 | # ============================================================================== 2 | # gmsh2porouslab 3 | # 4 | # This function exports a 2D mesh created in Gmsh to a MATLAB .mat file that is 5 | # compatible with the PorousLab framework. It supports meshes composed of 6 | # multiple element types (e.g., TRI3 and QUAD4), exporting the node coordinates 7 | # and the element connectivity in the expected format. 8 | # 9 | # The exported format includes: 10 | # - node: [N x 2] array with x and y coordinates of mesh nodes 11 | # - elem: {Nelem x 1} cell array, where each cell is a list of node indices 12 | # 13 | # Authors: 14 | # Danilo Cavalcanti (dborges@cimne.upc.edu) 15 | # ============================================================================== 16 | 17 | import numpy as np 18 | import scipy.io 19 | 20 | def gmsh2porouslab(gmsh_model, physical_group_id, output_path="mesh.mat"): 21 | """ 22 | Export Gmsh mesh to PorousLab .mat format with: 23 | - node: [N x 2] array of coordinates 24 | - elem: {Nelem x 1} cell array (each entry is a list of node indices) 25 | 26 | Parameters: 27 | gmsh_model: gmsh.model 28 | physical_group_id: int, physical group ID for the mesh domain 29 | output_path (str): name of the .mat file to export 30 | """ 31 | 32 | # Get the nodes 33 | nodeTags, nodeCoords = gmsh_model.mesh.getNodesForPhysicalGroup(dim=2, tag=physical_group_id) 34 | 35 | # Reshape the node coordinates into a matrix 36 | nodeCoords = nodeCoords.reshape((-1,3)) 37 | 38 | # Convert nodeCoords to a format suitable for MATLAB (e.g., a numpy array) 39 | NODE = np.array(nodeCoords) 40 | NODE = NODE[:, :2] 41 | 42 | # Get the 2D elements 43 | elemTypes, elemTags, elemNodeTags = gmsh_model.mesh.getElements(dim=2, tag=-1) 44 | 45 | # Fill the elem list with the elements connectivity 46 | elem = [] 47 | for etype, elem_connectivity in zip(elemTypes, elemNodeTags): 48 | # Get number of nodes per element 49 | _, _, _, num_nodes_per_elem, *_ = gmsh_model.mesh.getElementProperties(etype) 50 | 51 | # Reshape and map to local indices 52 | elem_connectivity = elem_connectivity.reshape((-1, num_nodes_per_elem)) 53 | 54 | # Append each element as a list (row vector) 55 | for row in elem_connectivity: 56 | elem.append(row.tolist()) 57 | 58 | # Convert to column cell array for MATLAB 59 | ELEM = np.empty((len(elem), 1), dtype=object) 60 | for i, connectivity in enumerate(elem): 61 | ELEM[i, 0] = connectivity 62 | 63 | # Save as .mat file 64 | scipy.io.savemat(output_path, { 65 | "node": NODE, 66 | "elem": ELEM 67 | }) 68 | 69 | print(f"[export_gmsh_to_matlab] Mesh exported to '{output_path}'.") -------------------------------------------------------------------------------- /examples/H2/example_h2_mcwhorter_pc_pg.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % McWhorter and Sunada problem using the Pc-Pg two-phase flow formulation. 4 | % 5 | % References: 6 | % * McWhorter and Sunada (1990). Exact integral solutions for two-phase flow. Water Resour Res, 26(3):399–413. 7 | % 8 | % Physics: 9 | % * Two-phase hydraulic (H2) 10 | % 11 | % Authors: 12 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 13 | % 14 | %% MODEL 15 | 16 | % Create model 17 | mdl = Model_H2_PcPg(); 18 | 19 | % Set model options 20 | mdl.massLumping = true; % Diagonalize compressibility matrix (mass lumping) 21 | mdl.lumpStrategy = 2; 22 | mdl.intOrder = 3; % Integration rule order for the domain 23 | 24 | %% MESH 25 | 26 | % Create mesh 27 | Lx = 2.6; % Horizontal dimension (m) 28 | Ly = 0.5; % Vertical dimension (m) 29 | Nx = 260; % Number of elements in the x-direction 30 | Ny = 1; % Number of elements in the y-direction 31 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 32 | 33 | % Set mesh to model 34 | mdl.setMesh(node, elem); 35 | 36 | %% MATERIALS 37 | 38 | % Create fluids 39 | water = Fluid('water'); 40 | gas = Fluid('gas'); 41 | 42 | % Create porous media 43 | rock = PorousMedia('rock'); 44 | rock.K = 1.0e-10; % Intrinsic permeability (m2) 45 | rock.phi = 0.3; % Porosity 46 | rock.Slr = 0.0; % Residual liquid saturation 47 | rock.Sgr = 0.0; % Residual gas saturation 48 | rock.Pb = 5.0e+3; % Gas-entry pressure 49 | rock.lambda = 2.0; % Curve-fitting parameter 50 | rock.liqRelPermeability = 'BrooksCorey'; % Liquid relative permeability 51 | rock.gasRelPermeability = 'BrooksCorey'; % Gas relative permeability 52 | rock.capillaryPressure = 'BrooksCorey'; % Saturation degree function 53 | 54 | % Set materials to model 55 | mdl.setMaterial(rock, water, gas); 56 | 57 | %% BOUNDARY AND INITIAL CONDITIONS 58 | 59 | % Set Dirichlet boundary conditions 60 | mdl.setCapillaryPressureDirichletBCAtBorder('left', 5.0e+3); 61 | mdl.setGasPressureDirichletBCAtBorder('left', 200.0e+3); 62 | 63 | % Set initial conditions 64 | mdl.setInitialCapillaryPressureAtDomain(50.0e+3); 65 | 66 | %% PROCESS 67 | 68 | % Analysis parameters 69 | ti = 0.1; % Initial time 70 | dt = 0.1; % Time step 71 | tf = 50.0; % Final time 72 | dtmax = 0.1; % Maximum time step 73 | dtmin = 0.0000001; % Minimum time step 74 | adaptStep = true; % Adaptive step size 75 | 76 | % Run analysis 77 | anl = Anl_Transient("Picard"); 78 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 79 | anl.run(mdl); 80 | 81 | %% POST-PROCESS 82 | 83 | % Plot graphs 84 | Xi = [0.0, 0.0]; Xf = [Lx, 0.0]; 85 | mdl.plotFieldAlongSegment('LiquidPressure', Xi, Xf, 500, 'x'); 86 | -------------------------------------------------------------------------------- /tests/regression/files/test_h2_liakopoulos_pc_pg.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % OGS-5 Liakopoulos problem using the Pc-Pg two-phase flow formulation. 4 | % 5 | % Physics: 6 | % * Two-phase hydraulic (H2) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H2_PcPg(); 15 | 16 | % Set model options 17 | mdl.massLumping = true; % Diagonalize compressibility matrix (mass lumping) 18 | mdl.lumpStrategy = 2; 19 | mdl.gravityOn = true; 20 | 21 | %% MESH 22 | 23 | % Create mesh 24 | [node, elem] = regularMesh(0.1, 1.0, 3, 24); 25 | 26 | % Set mesh to model 27 | mdl.setMesh(node, elem); 28 | 29 | %% MATERIALS 30 | 31 | % Create fluids 32 | water = Fluid('water'); 33 | gas = IdealGas('gas'); 34 | gas.mu = 1.8e-5; % Viscosity (Pa*s) 35 | gas.K = 1.0e25; % Compressibility/Bulk modulus (1/Pa) 36 | 37 | % Create porous media 38 | rock = PorousMedia('rock'); 39 | rock.K = 4.5e-13; % Intrinsic permeability (m2) 40 | rock.phi = 0.2975; % Porosity 41 | rock.biot = 1.0; % Biot's coefficient 42 | rock.Ks = 1.0e25; % Solid bulk modulus (Pa) 43 | rock.Slr = 0.0; % Residual liquid saturation 44 | rock.Sgr = 0.2; % Residual gas saturation 45 | rock.Pb = 0.0; % Gas-entry pressure 46 | rock.lambda = 3.0; % Curve-fitting parameter 47 | rock.liqRelPermeability = 'Liakopoulos'; % Liquid relative permeability 48 | rock.gasRelPermeability = 'BrooksCorey'; % Gas relative permeability 49 | rock.capillaryPressure = 'Liakopoulos'; % Saturation degree function 50 | rock.setMinLiquidRelPermeability(0.0001); 51 | rock.setMinGasRelPermeability(0.0001); 52 | 53 | % Set materials to model 54 | mdl.setMaterial(rock, water, gas); 55 | 56 | %% BOUNDARY AND INITIAL CONDITIONS 57 | 58 | % Set Dirichlet boundary conditions 59 | mdl.setCapillaryPressureDirichletBCAtBorder('bottom', 0.0); 60 | mdl.setGasPressureDirichletBCAtBorder('bottom', 101325.0); 61 | mdl.setGasPressureDirichletBCAtBorder('top', 101325.0); 62 | 63 | % Set initial conditions 64 | mdl.setInitialCapillaryPressureAtDomain(0.0); 65 | mdl.setInitialGasPressureAtDomain(101325.0); 66 | 67 | %% PROCESS 68 | 69 | % Analysis parameters 70 | min = 60; % Conversion from days to seconds 71 | ti = 0.001*min; % Initial time 72 | dt = 0.001*min; % Time step 73 | tf = 0.1*min; % Final time 74 | dtmax = 1.0*min; % Maximum time step 75 | dtmin = 0.001*min; % Minimum time step 76 | adaptStep = true; % Adaptive step size 77 | 78 | % Run analysis 79 | anl = Anl_Transient("Newton"); 80 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 81 | anl.echo = false; 82 | anl.run(mdl); -------------------------------------------------------------------------------- /src/mesh/convertToQuadraticMesh.m: -------------------------------------------------------------------------------- 1 | %% convertToQuadraticMesh function 2 | % This function converts a linear mesh into a quadratic mesh. 3 | % 4 | %% Inputs 5 | % * *NODE*: A matrix of size Nx2 containing the x and y coordinates of 6 | % the nodes. Each row represents a node, with the first column 7 | % as the x-coordinate and the second column as the y-coordinate. 8 | % * *ELEM*: A connectivity matrix of size Mx4 (for Q4 elements) or Mx3 9 | % (for T3 elements). Each row represents an element, with 10 | % columns specifying the indices of the nodes that form the 11 | % element. 12 | % 13 | %% Outputs 14 | % * *NODE_quad*: An updated NODE matrix that includes the original nodes 15 | % and the newly created mid-edge nodes. 16 | % * *ELEM_quad*: An updated connectivity matrix that includes the 17 | % quadratic connectivity for each element. 18 | % 19 | %% Author 20 | % Danilo Cavalcanti 21 | % 22 | %% Version History 23 | % Version 1.00. 24 | % 25 | %% Function definition 26 | function [NODE_quad, ELEM_quad] = convertToQuadraticMesh(NODE, ELEM) 27 | % Initialize 28 | num_nodes = size(NODE, 1); 29 | edge_map = containers.Map('KeyType', 'char', 'ValueType', 'double'); 30 | new_nodes = []; 31 | 32 | num_elems = numel(ELEM); 33 | ELEM_quad = cell(num_elems, 1); % Initialize cell for quadratic elements 34 | 35 | for elem_idx = 1:num_elems 36 | elem = ELEM{elem_idx}(:)'; % Ensure row vector 37 | num_nodes_per_elem = numel(elem); 38 | 39 | % Determine edge pairs based on element type 40 | if num_nodes_per_elem == 3 41 | % Triangular element (T3 -> T6) 42 | edge_pairs = [1, 2; 2, 3; 3, 1]; 43 | elseif num_nodes_per_elem == 4 44 | % Quadrilateral element (Q4 -> Q8) 45 | edge_pairs = [1, 2; 2, 3; 3, 4; 4, 1]; 46 | else 47 | error('Unsupported element type. ELEM should have 3 or 4 nodes.'); 48 | end 49 | 50 | new_elem = elem; 51 | 52 | for edge_idx = 1:size(edge_pairs, 1) 53 | n1 = elem(edge_pairs(edge_idx, 1)); 54 | n2 = elem(edge_pairs(edge_idx, 2)); 55 | 56 | edge_key = sprintf('%d-%d', min(n1, n2), max(n1, n2)); 57 | 58 | if isKey(edge_map, edge_key) 59 | mid_node = edge_map(edge_key); 60 | else 61 | mid_coord = (NODE(n1, :) + NODE(n2, :)) / 2; 62 | new_nodes = [new_nodes; mid_coord]; 63 | mid_node = num_nodes + size(new_nodes, 1); 64 | edge_map(edge_key) = mid_node; 65 | end 66 | 67 | new_elem(end + 1) = mid_node; 68 | end 69 | 70 | ELEM_quad{elem_idx} = new_elem; 71 | end 72 | 73 | NODE_quad = [NODE; new_nodes]; 74 | end 75 | -------------------------------------------------------------------------------- /src/physics/M/MaterialDiscontinuity_M.m: -------------------------------------------------------------------------------- 1 | %% MaterialDiscontinuity_M Class 2 | % This class represents a material discontinuity with mechanical and 3 | % constitutive behavior. It provides methods to evaluate the mechanical 4 | % constitutive law, retrieve the number of state variables, and check 5 | % for plastic strain behavior. 6 | % 7 | %% Methods 8 | % * *mechanicalLaw*: Evaluates the mechanical constitutive law at a given 9 | % integration point and returns the stress and material 10 | % stiffness matrix. 11 | % * *getNumberStateVar*: Returns the number of state variables associated 12 | % with the mechanical constitutive law. 13 | % * *hasPlasticStrain*: Checks if the material exhibits elasto-plastic 14 | % behavior. 15 | %% Author 16 | % Danilo Cavalcanti 17 | % 18 | %% Version History 19 | % Version 1.00: Initial version (January 2024). 20 | % 21 | %% Class definition 22 | classdef MaterialDiscontinuity_M < handle 23 | %% Public attributes 24 | properties (SetAccess = public, GetAccess = public) 25 | parameters = []; 26 | mechanical = []; 27 | end 28 | %% Constructor method 29 | methods 30 | %------------------------------------------------------------------ 31 | function this = MaterialDiscontinuity_M(matData) 32 | % Create the material struct 33 | this.parameters = struct( ... 34 | 'initialAperture', matData.initialAperture, ... 35 | 'normalStiffness', matData.normalStiffness, ... 36 | 'shearStiffness', matData.shearStiffness,... 37 | 'contactPenalization',matData.contactPenalization); 38 | % Mechanical constitutive behavior 39 | if strcmp('elastic',matData.cohesiveLaw) 40 | this.mechanical = MechanicalCohesiveLinearElastic(); 41 | end 42 | end 43 | end 44 | %% Public methods 45 | methods 46 | % ----------------------------------------------------------------- 47 | % Evaluate the mechanical constitutive law 48 | function [stress,D] = mechanicalLaw(this,ip) 49 | [stress,D] = this.mechanical.eval(this.parameters,ip); 50 | end 51 | 52 | % ----------------------------------------------------------------- 53 | % Get the number of state variables associated with the mechanical 54 | % constitutive law 55 | function nstVar = getNumberStateVar(this) 56 | nstVar = this.mechanical.nstVar; 57 | end 58 | 59 | % ----------------------------------------------------------------- 60 | % Check if the material is elasto-plastic or not 61 | function flag = hasPlasticStrain(this) 62 | flag = this.mechanical.isElastoPlastic(); 63 | end 64 | 65 | end 66 | end -------------------------------------------------------------------------------- /examples/H2/example_h2_mcwhorter_pl_pg.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % McWhorter and Sunada problem using the Pl-Pg two-phase flow formulation 4 | % 5 | % References: 6 | % * McWhorter and Sunada (1990). Exact integral solutions for two-phase flow. Water Resour Res, 26(3):399–413. 7 | % 8 | % Physics: 9 | % * Two-phase hydraulic (H2) 10 | % 11 | % Authors: 12 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 13 | % 14 | %% MODEL 15 | 16 | % Create model 17 | mdl = Model_H2(); 18 | 19 | % Set model options 20 | mdl.massLumping = true; % Diagonalize compressibility matrix (mass lumping) 21 | mdl.lumpStrategy = 2; 22 | mdl.intOrder = 3; % Integration rule order for the domain 23 | 24 | %% MESH 25 | 26 | % Create mesh 27 | Lx = 2.6; % Horizontal dimension (m) 28 | Ly = 0.5; % Vertical dimension (m) 29 | Nx = 100; % Number of elements in the x-direction 30 | Ny = 1; % Number of elements in the y-direction 31 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 32 | 33 | % Set mesh to model 34 | mdl.setMesh(node, elem); 35 | 36 | %% MATERIALS 37 | 38 | % Create fluids 39 | water = Fluid('water'); 40 | gas = Fluid('gas'); 41 | 42 | % Create porous media 43 | rock = PorousMedia('rock'); 44 | rock.K = 1.0e-10; % Intrinsic permeability (m2) 45 | rock.phi = 0.3; % Porosity 46 | rock.Slr = 0.0; % Residual liquid saturation 47 | rock.Sgr = 0.0; % Residual gas saturation 48 | rock.Pb = 5.0e+3; % Gas-entry pressure 49 | rock.lambda = 2.0; % Curve-fitting parameter 50 | rock.liqRelPermeability = 'BrooksCorey'; % Liquid relative permeability 51 | rock.gasRelPermeability = 'BrooksCorey'; % Gas relative permeability 52 | rock.capillaryPressure = 'BrooksCorey'; % Saturation degree function 53 | 54 | % Set materials to model 55 | mdl.setMaterial(rock, water, gas); 56 | 57 | %% BOUNDARY AND INITIAL CONDITIONS 58 | 59 | % Set Dirichlet boundary conditions 60 | mdl.setPressureDirichletBCAtBorder('left', 195.0e+3); 61 | mdl.setGasPressureDirichletBCAtBorder('left', 200.0e+3); 62 | 63 | % Set initial conditions 64 | mdl.setInitialPressureAtDomain(-50.0e+3); 65 | 66 | %% PROCESS 67 | 68 | % Analysis parameters 69 | ti = 0.1; % Initial time 70 | dt = 0.1; % Time step 71 | tf = 1000; % Final time 72 | dtmax = 10.0; % Maximum time step 73 | dtmin = 0.0000001; % Minimum time step 74 | adaptStep = true; % Adaptive step size 75 | 76 | % Run analysis 77 | anl = Anl_Transient("Newton"); 78 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 79 | anl.maxIter = 10; 80 | anl.run(mdl); 81 | 82 | %% POST-PROCESS 83 | 84 | % Plot contours 85 | mdl.plotField('CapillaryPressure'); 86 | 87 | % Plot graphs 88 | Xi = [0.0, 0.0]; Xf = [Lx, 0.0]; 89 | mdl.plotFieldAlongSegment('LiquidPressure', Xi, Xf, 500, 'x'); 90 | -------------------------------------------------------------------------------- /src/material/saturationLaw/CapillaryPressureLiakopoulos.m: -------------------------------------------------------------------------------- 1 | %% CapillaryPressureLiakopoulos class 2 | % This class implements the capillary pressure-saturation relationship 3 | % based on the Liakopoulos model. It inherits from the _CapillaryPressure_ 4 | % base class and provides methods to compute the saturation degree and 5 | % its derivative with respect to capillary pressure. 6 | % 7 | %% Methods 8 | % * *saturationDegree*: Computes the liquid phase saturation degree Sl 9 | % based on the capillary pressure. Ensures that Sl 10 | % is not less than Slmin. 11 | % * *derivativeSaturationDegree*: Computes the derivative of the liquid 12 | % phase saturation degree with respect to 13 | % the capillary pressure. Ensures that pc 14 | % does not exceed the maximum value 15 | % corresponding to Slmin. 16 | % 17 | %% Author 18 | % Danilo Cavalcanti 19 | % 20 | %% Version History 21 | % Version 1.00. 22 | % 23 | %% Class Definition 24 | classdef CapillaryPressureLiakopoulos < CapillaryPressure 25 | %% Properties 26 | % Parameters taken from OGS-6. 27 | % OGS reference: 28 | % Asadi, R., Ataie-Ashtiani, B. (2015): A Comparison of finite volume 29 | % formulations and coupling strategies for two-phase flow in deforming 30 | % porous media. Comput. Geosci., p. 24ff. 31 | properties (SetAccess = public, GetAccess = public) 32 | a = 1.9722e-11; 33 | b = 2.4279; 34 | Slmin = 0.2; 35 | end 36 | %% Constructor method 37 | methods 38 | %------------------------------------------------------------------ 39 | function this = CapillaryPressureLiakopoulos() 40 | this = this@CapillaryPressure('liakopoulos'); 41 | end 42 | end 43 | 44 | %% Public methods 45 | methods 46 | 47 | %------------------------------------------------------------------ 48 | % Compute the liquid phase relative permeability 49 | function Sl = saturationDegree(this, pc, ~) 50 | if (pc < 0.0) 51 | Sl = 1.0; 52 | else 53 | Sl = 1.0 - this.a * pc^(this.b); 54 | end 55 | Sl = max(Sl, this.Slmin); 56 | end 57 | 58 | %------------------------------------------------------------------ 59 | % Compute the gas phase relative permeability 60 | function dSldpc = derivativeSaturationDegree(this, pc, ~) 61 | if (pc < 0.0) 62 | dSldpc = 0.0; 63 | else 64 | pcmax = ((1.0 - this.Slmin)/this.a)^(1.0/this.b); 65 | pc = min(pc,pcmax); 66 | dSldpc = - this.a * this.b * pc^(this.b - 1.0); 67 | end 68 | end 69 | 70 | end 71 | end -------------------------------------------------------------------------------- /src/material/cohesiveLaw/MechanicalCohesiveLinearElastic.m: -------------------------------------------------------------------------------- 1 | %% MechanicalCohesiveLinearElastic Class 2 | % This class implements a linear elastic cohesive law for mechanical 3 | % materials. It provides methods to compute the stress vector and the 4 | % constitutive matrix based on the material properties and the strain 5 | % state at integration points. 6 | % 7 | %% Methods 8 | % * *eval*: Computes the stress vector and the constitutive matrix for the 9 | % given material and integration point. 10 | % * *isElastoPlastic*: Static method that indicates that the material is 11 | % not elasto-plastic. 12 | % * *elasticConstitutiveMatrix*: Static method that computes the elastic 13 | % constitutive matrix based on the material 14 | % properties and the strain state at the 15 | % integration point. 16 | % 17 | %% Author 18 | % Danilo Cavalcanti 19 | % 20 | %% Version History 21 | % Version 1.00. 22 | % 23 | %% Class Definition 24 | classdef MechanicalCohesiveLinearElastic < handle 25 | %% Public attributes 26 | properties (SetAccess = public, GetAccess = public) 27 | nstVar = 0; % Number of state variables 28 | end 29 | %% Constructor method 30 | methods 31 | %------------------------------------------------------------------ 32 | function this = MechanicalCohesiveLinearElastic() 33 | end 34 | end 35 | 36 | %% Public methods 37 | methods 38 | 39 | %------------------------------------------------------------------ 40 | % Compute the stress vector and the constitutive matrix 41 | function [stress,De] = eval(this,material,ip) 42 | 43 | % Constitutive matrix 44 | De = this.elasticConstitutiveMatrix(material,ip); 45 | 46 | % Stress vector 47 | stress = De * (ip.strain - ip.strainOld) + ip.stressOld; 48 | 49 | end 50 | end 51 | %% Public methods 52 | methods (Static) 53 | %------------------------------------------------------------------ 54 | % Flag to return that the material is not elasto-plastic 55 | function flag = isElastoPlastic() 56 | flag = false; 57 | end 58 | %------------------------------------------------------------------ 59 | % Compute the elastic constitutive matrix 60 | function De = elasticConstitutiveMatrix(material,ip) 61 | 62 | % Elastic material properties 63 | kn = material.normalStiffness; 64 | ks = material.shearStiffness; 65 | 66 | % Normal jump 67 | dn = ip.strain(2); 68 | 69 | % Closure model 70 | if dn < -1.0e-6 71 | kn = kn * 1.0e3; 72 | end 73 | 74 | % Assemble constitutive matrix 75 | De = [ ks 0.0; 76 | 0.0 kn ]; 77 | end 78 | end 79 | end -------------------------------------------------------------------------------- /examples/M/example_m_pressurized_cylinder.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Elastoplastic pressurized cylinder. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | Lx = 1.0; % Horizontal dimension (m) 20 | Ly = 1.0; % Vertical dimension (m) 21 | Nx = 10; % Number of elements in the x-direction 22 | Ny = 10; % Number of elements in the y-direction 23 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 24 | 25 | % Transform to cylindrical coordinates 26 | ri = 0.1; % Internal cylinder radius 27 | re = 0.2; % External cylinder radius 28 | r = ri + node(:, 1) * (re - ri); 29 | theta = node(:, 2) * (pi / 2); 30 | node = [r .* cos(theta), r .* sin(theta)]; 31 | 32 | % Set mesh to model 33 | mdl.setMesh(node, elem); 34 | 35 | %% MATERIALS 36 | 37 | % Create porous media 38 | rock = PorousMedia('rock'); 39 | rock.mechanical = 'vonMises'; % Constitutive law 40 | rock.Young = 2.1e+11; % Young modulus (Pa) 41 | rock.nu = 0.3; % Poisson ratio 42 | rock.sy0 = 2.4e+8; % Initial yield stress (Pa) 43 | rock.Kp = 0.0; % Plastic modulus (Pa) 44 | 45 | % Set materials to model 46 | mdl.setMaterial(rock); 47 | 48 | %% BOUNDARY CONDITIONS 49 | 50 | % Displacements 51 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 52 | mdl.setDisplacementDirichletBCAtBorder('bottom', [NaN, 0.0]); 53 | 54 | % Radius of each node wrt to center at (0,0) 55 | r = sqrt((mdl.NODE(:,1)).^2 + (mdl.NODE(:,2)).^2); 56 | sn = mdl.NODE(:,2) ./ r; 57 | cs = mdl.NODE(:,1) ./ r; 58 | 59 | % Loaded nodes 60 | internalNodes = (r-ri) < eps; 61 | nInternalNodes = sum(internalNodes); 62 | 63 | % Internal pressure (Pa) and Force magnitude 64 | pint = 192.0905814164710e+06; 65 | F0 = (pint*mdl.t*ri*pi/2.0)/(nInternalNodes-1)/2.0; 66 | 67 | % Occurrences of each node 68 | allNodes = cell2mat(mdl.ELEM(:)); 69 | nodeCount = histcounts(allNodes, 1:(size(mdl.NODE,1)+1))'; 70 | 71 | % Apply internal pressure to internal face nodes 72 | mdl.LOAD(internalNodes,:) = F0 * nodeCount(internalNodes) .* [cs(internalNodes) , sn(internalNodes)]; 73 | 74 | %% PROCESS 75 | 76 | % Setup analysis 77 | anl = Anl_NonlinearQuasiStatic('ArcLengthCylControl'); 78 | anl.adjustStep = true; 79 | anl.increment = 0.1; 80 | anl.max_increment = 0.1; 81 | anl.max_lratio = 2.0; 82 | anl.max_step = 100; 83 | anl.max_iter = 100; 84 | anl.trg_iter = 4; 85 | 86 | % Node and DOF used to plot Load Factor vs Displacement 87 | ndId = mdl.closestNodeToPoint([ri, 0.0]); 88 | anl.setPlotDof(ndId, 1); 89 | 90 | % Run analysis 91 | anl.run(mdl); 92 | 93 | %% POST-PROCESS 94 | 95 | % Plot Load Factor vs Displacement 96 | anl.plotCurves(); 97 | 98 | % Plot contours 99 | mdl.plotField('S1'); 100 | mdl.plotField('Sr'); 101 | mdl.plotField('Sx'); 102 | -------------------------------------------------------------------------------- /src/shape/Shape.m: -------------------------------------------------------------------------------- 1 | %% Shape Class 2 | % This in an abstract class that defines an element shape. 3 | % 4 | %% Authors 5 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 6 | % 7 | %% Class Definition 8 | classdef Shape < handle 9 | %% Public properties 10 | properties (SetAccess = public, GetAccess = public) 11 | type = []; 12 | end 13 | 14 | %% Constructor method 15 | methods 16 | %------------------------------------------------------------------ 17 | function this = Shape(type) 18 | if nargin > 0 19 | this.type = type; 20 | end 21 | end 22 | end 23 | 24 | %% Abstract methods 25 | methods (Abstract) 26 | %------------------------------------------------------------------ 27 | % Evaluate shape function at a given point. 28 | N = shapeFnc(this,Xn) 29 | 30 | %------------------------------------------------------------------ 31 | % Get shape function matrix. 32 | N = shapeFncMtrx(this,Xn) 33 | 34 | %------------------------------------------------------------------ 35 | % Get shape function derivatives matrix. 36 | dNdxi = shapeFncDrv(this,Xn) 37 | 38 | %------------------------------------------------------------------ 39 | % Compute jacobian matrix. 40 | J = JacobianMtrx(this,X,Xn) 41 | 42 | %------------------------------------------------------------------ 43 | % Compute the determinant of the jacobian. 44 | detJ = detJacobian(this,X,Xn) 45 | 46 | %------------------------------------------------------------------ 47 | % Transform point coordinates from natural coordinate system to 48 | % global cartesian coordinate system. 49 | X = coordNaturalToCartesian(this,NODE,Xn) 50 | 51 | %------------------------------------------------------------------ 52 | % Transform point coordinates from global cartesian coordinate system to 53 | % natural coordinate system. 54 | Xn = coordCartesianToNatural(this,NODE,X) 55 | 56 | %------------------------------------------------------------------ 57 | % Get integration points. 58 | [X,W,n] = getIntegrationPoints(this,intOrder,elem) 59 | end 60 | 61 | %% Public methods 62 | methods 63 | %------------------------------------------------------------------ 64 | % Compute shape centroid. 65 | function Xc = computeCentroid(~,NODE) 66 | x = NODE(1:3,1); 67 | y = NODE(1:3,2); 68 | polyin = polyshape({x},{y}); 69 | [xc,yc] = centroid(polyin); 70 | Xc = [xc yc]; 71 | end 72 | 73 | %------------------------------------------------------------------ 74 | % Compute the axisymmetric factor. 75 | function af = axisSymmetricFactor(~,N,X) 76 | r = N*X(:,1); 77 | af = 2.0 * r * pi; 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PorousLab 2 | 3 |

4 | 5 | [![Release][release-image]][release-link] 6 | [![License][license-image]][license-link] 7 | [![Contributing][contributing-image]][contributing-link] 8 | 9 | **PorousLab** is a MATLAB framework based on the Finite Element Method (FEM) for solving multiphysics problems, mainly in the context of geomechanics and fractured porous media. 10 | 11 | ## Table of Contents 12 | - [Main Features](#main-features) 13 | - [How to Contribute](#how-to-contribute) 14 | - [How to Cite](#how-to-cite) 15 | - [Authorship](#authorship) 16 | - [Acknowledgement](#acknowledgement) 17 | - [License](#license) 18 | 19 | ## Main Features 20 | 21 | Check out the [wiki][wiki_link] page. 22 | 23 | ## How to Contribute 24 | 25 | Please check the [contribution guidelines][contribute_link]. 26 | 27 | ## How to Cite 28 | 29 | If you use this software in your work, please cite it using the metadata indicated in this [file][citation_link]. 30 | 31 | ## Authorship 32 | 33 | **Danilo Cavalcanti** () 34 | 35 | - International Center for Numerical Methods in Engineering ([CIMNE][cimne_website])
36 | - Polytechnic University of Catalonia ([Barcelona Tech - UPC][upc_website])
37 | - Pontifical Catholic University of Rio de Janeiro ([PUC-Rio][puc_website]) 38 | 39 |

40 | 41 |       42 | 43 |       44 | 45 |

46 | 47 | ## Acknowledgement 48 | 49 | PorousLab was developed in the context of SECCO2 project under the Grant TED2021-130510A-I00 funded by MCIN/AEI/10.13039/501100011033 and by the "European Union NextGenerationEU/PRTR”. 50 | 51 |

52 | 53 | ## License 54 | 55 | PorousLab is released under the [MIT license][mit_license_link]. 56 | It allows the program to be freely used by anyone for modification, private use, commercial use, and distribution, only requiring preservation of copyright and license notices. 57 | No liability and warranty are provided. 58 | 59 | [release-image]: https://img.shields.io/badge/release-1.0.0-green.svg?style=flat 60 | [release-link]: https://github.com/dbcavalcanti/porousLab/releases 61 | [license-image]: https://img.shields.io/badge/license-MIT-green.svg?style=flat 62 | [license-link]: LICENSE 63 | [contributing-image]: https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg 64 | [contributing-link]: CONTRIBUTING.md 65 | [wiki_link]: https://github.com/dbcavalcanti/porousLab/wiki 66 | [contribute_link]: CONTRIBUTING.md 67 | [citation_link]: CITATION.cff 68 | [cimne_website]: https://www.cimne.com/ 69 | [upc_website]: https://camins.upc.edu/ 70 | [puc_website]: https://www.puc-rio.br/english/ 71 | [mit_license_link]: https://choosealicense.com/licenses/mit/ 72 | -------------------------------------------------------------------------------- /examples/H2/example_h2_five_spot_pc_pg.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Five-spot corner problem using the Pc-Pg two-phase flow formulation. 4 | % 5 | % Physics: 6 | % * Two-phase hydraulic (H2) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H2_PcPg(); 15 | 16 | % Set model options 17 | mdl.massLumping = true; % Diagonalize compressibility matrix (mass lumping) 18 | mdl.lumpStrategy = 2; 19 | 20 | %% MESH 21 | 22 | % Create mesh 23 | Lx = 10.0; % Horizontal dimension (m) 24 | Ly = 10.0; % Vertical dimension (m) 25 | Nx = 50; % Number of elements in the x-direction 26 | Ny = 50; % Number of elements in the y-direction 27 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 28 | 29 | % Set mesh to model 30 | mdl.setMesh(node, elem); 31 | 32 | %% MATERIALS 33 | 34 | % Create fluids 35 | water = Fluid('water'); 36 | gas = Fluid('gas'); 37 | gas.mu = 4.0e-3; % Viscosity (Pa*s) 38 | 39 | % Create porous media 40 | rock = PorousMedia('rock'); 41 | rock.K = 1.0e-13; % Intrinsic permeability (m2) 42 | rock.phi = 0.206; % Porosity 43 | rock.Pb = 1.0e+3; % Gas-entry pressure 44 | rock.lambda = 1.0; % Curve-fitting parameter 45 | rock.m = 2.0; % Expoent for the polynomial relationships 46 | rock.liqRelPermeability = 'PolynomialLiquid'; % Liquid relative permeability 47 | rock.gasRelPermeability = 'PolynomialGas'; % Gas relative permeability 48 | rock.capillaryPressure = 'BrooksCorey'; % Saturation degree function 49 | 50 | % Set materials to model 51 | mdl.setMaterial(rock, water, gas); 52 | 53 | %% BOUNDARY AND INITIAL CONDITIONS 54 | 55 | % Set Dirichlet boundary conditions 56 | mdl.setCapillaryPressureDirichletBCAtPoint([0.0, 0.0], 0.0); 57 | mdl.setCapillaryPressureDirichletBCAtPoint([Lx, Ly], 105018.5554); 58 | mdl.setGasPressureDirichletBCAtPoint([0.0, 0.0], 1.5e6); 59 | mdl.setGasPressureDirichletBCAtPoint([Lx, Ly], 1.0e6); 60 | 61 | % Set initial conditions 62 | mdl.setInitialCapillaryPressureAtDomain(105018.5554); 63 | mdl.setInitialGasPressureAtDomain(105018.5554); 64 | 65 | %% PROCESS 66 | 67 | % Analysis parameters 68 | day = 60*60*24; % Conversion from days to seconds 69 | ti = 0.01*day; % Initial time 70 | dt = 0.01*day; % Time step 71 | tf = 10.0*day; % Final time 72 | dtmax = 1.0*day; % Maximum time step 73 | dtmin = 0.001*day; % Minimum time step 74 | adaptStep = true; % Adaptive step size 75 | 76 | % Run analysis 77 | anl = Anl_Transient("Picard"); 78 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 79 | anl.setRelativeConvergenceCriteria(true); 80 | anl.maxIter = 15; 81 | anl.run(mdl); 82 | 83 | %% POST-PROCESS 84 | 85 | % Plot contours 86 | mdl.plotField('LiquidSaturation'); 87 | mdl.plotField('GasSaturation'); 88 | 89 | % Plot graphs 90 | Xi = [0.0, 0.0]; Xf = [Lx, Ly]; 91 | mdl.plotFieldAlongSegment('LiquidPressure', Xi, Xf, 500, 'x'); 92 | -------------------------------------------------------------------------------- /examples/M/example_m_porepressure_discontinuity.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Uniform traction on a plate with isotropic damage model. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | % Set model options 17 | mdl.condenseEnrDofs = false; 18 | mdl.addPorePressure = true; 19 | mdl.subDivIntegration = true; 20 | mdl.symmetricSDAEFEM = true; 21 | 22 | %% MESH 23 | 24 | % Create mesh 25 | Lx = 2.0e-1; % Horizontal dimension (m) 26 | Ly = 2.0e-1; % Vertical dimension (m) 27 | Nx = 1; % Number of elements in the x-direction 28 | Ny = 1; % Number of elements in the y-direction 29 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 30 | 31 | % Set mesh to model 32 | mdl.setMesh(node, elem); 33 | 34 | %% MATERIALS 35 | 36 | % Create porous media 37 | rock = PorousMedia('rock'); 38 | rock.Young = 30.0e+9; % Young modulus (Pa) 39 | rock.nu = 0.2; % Poisson ratio 40 | 41 | % Set materials to model 42 | mdl.setMaterial(rock); 43 | 44 | %% BOUNDARY CONDITIONS 45 | 46 | % Displacements 47 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 48 | mdl.setDisplacementDirichletBCAtBorder('right', [0.0, NaN]); 49 | mdl.setDisplacementDirichletBCAtBorder('bottom', [NaN, 0.0]); 50 | 51 | % Set external pore-pressure 52 | % P = 10 * [0;1;0;1]; 53 | P = 10 * [1;0;1;0]; 54 | % P = 10 * [1;1;1;1]; 55 | mdl.setPorePressureField(P); 56 | 57 | %% DISCONTINUITIES 58 | 59 | % Create discontinuities 60 | Xd = [ 0.0 , 0.5*Ly; 61 | Lx , 0.5*Ly ]; 62 | fault = Discontinuity(Xd, true); 63 | 64 | % Set fracture material properties 65 | fault.cohesiveLaw = 'elastic'; 66 | fault.shearStiffness = 1.0e15; % Pa/m 67 | fault.normalStiffness = 1.0e15; % Pa/m 68 | 69 | % Add fractures to model 70 | discontinuityData = struct('addTangentialStretchingMode', true, 'addNormalStretchingMode', true, 'addRelRotationMode', false); 71 | mdl.addPreExistingDiscontinuities(fault, discontinuityData); 72 | 73 | % Set pressure jump at the discontinuities 74 | nDiscontinuities = mdl.getNumberOfDiscontinuities(); 75 | for i = 1:nDiscontinuities 76 | nDiscontinuitySeg = mdl.discontinuitySet(i).getNumberOfDiscontinuitySegments(); 77 | for j = 1:nDiscontinuitySeg 78 | mdl.discontinuitySet(i).segment(j).DP = -10; 79 | end 80 | end 81 | 82 | %% PROCESS 83 | 84 | % Run analysis 85 | anl = Anl_Linear(); 86 | anl.run(mdl); 87 | 88 | %% POST-PROCESS 89 | 90 | % Print stresses 91 | fprintf("\n\n IP Sxx Syy Szz Sxy\n") 92 | elem = mdl.element(1).type; 93 | for i = 1:elem.nIntPoints 94 | stress = elem.intPoint(i).stress; 95 | fprintf("%2d %+.4e %+.4e %+.4e %+.4e \n",i,stress(1),stress(2),stress(3),stress(4)); 96 | end 97 | 98 | % Plot stresses 99 | mdl.plotField('Sx'); 100 | mdl.plotField('Sy'); 101 | mdl.plotField('Sxy'); 102 | mdl.plotFieldAlongDiscontinuiy('Sn',1,'x') 103 | -------------------------------------------------------------------------------- /examples/M/example_m_pressurized_cylinder_asymptotic.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Elastoplastic pressurized cylinder. 4 | % 5 | % Physics: 6 | % * Mechanical (M) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_M(); 15 | 16 | %% MESH 17 | 18 | % Create mesh 19 | Lx = 1.0; % Horizontal dimension (m) 20 | Ly = 1.0; % Vertical dimension (m) 21 | Nx = 10; % Number of elements in the x-direction 22 | Ny = 10; % Number of elements in the y-direction 23 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 24 | 25 | % Transform to cylindrical coordinates 26 | ri = 0.1; % Internal cylinder radius 27 | re = 0.2; % External cylinder radius 28 | r = ri + node(:, 1) * (re - ri); 29 | theta = node(:, 2) * (pi / 2); 30 | node = [r .* cos(theta), r .* sin(theta)]; 31 | 32 | % Set mesh to model 33 | mdl.setMesh(node, elem); 34 | 35 | %% MATERIALS 36 | 37 | % Create porous media 38 | rock = PorousMedia('rock'); 39 | rock.mechanical = 'nonlinearAsymptotic'; % Constitutive law 40 | rock.asympt = 'vonMises'; % Asymptotic model 41 | rock.Young = 2.1e+11; % Young modulus (Pa) 42 | rock.nu = 0.3; % Poisson ratio 43 | rock.sy0 = 2.4e+8; % Initial yield stress (Pa) 44 | rock.Kp = 0.0; % Plastic modulus (Pa) 45 | rock.tauy = 2.4e+8 / sqrt(3.0); 46 | rock.eref = 0.0001; 47 | 48 | % Set materials to model 49 | mdl.setMaterial(rock); 50 | 51 | %% BOUNDARY CONDITIONS 52 | 53 | % Displacements 54 | mdl.setDisplacementDirichletBCAtBorder('left', [0.0, NaN]); 55 | mdl.setDisplacementDirichletBCAtBorder('bottom', [NaN, 0.0]); 56 | 57 | % Radius of each node wrt to center at (0,0) 58 | r = sqrt((mdl.NODE(:,1)).^2 + (mdl.NODE(:,2)).^2); 59 | sn = mdl.NODE(:,2) ./ r; 60 | cs = mdl.NODE(:,1) ./ r; 61 | 62 | % Loaded nodes 63 | internalNodes = (r-ri) < eps; 64 | nInternalNodes = sum(internalNodes); 65 | 66 | % Internal pressure (Pa) and Force magnitude 67 | pint = 192.0905814164710e+06; 68 | F0 = (pint*mdl.t*ri*pi/2.0)/(nInternalNodes-1)/2.0; 69 | 70 | % Occurrences of each node 71 | allNodes = cell2mat(mdl.ELEM(:)); 72 | nodeCount = histcounts(allNodes, 1:(size(mdl.NODE,1)+1))'; 73 | 74 | % Apply internal pressure to internal face nodes 75 | mdl.LOAD(internalNodes,:) = F0 * nodeCount(internalNodes) .* [cs(internalNodes) , sn(internalNodes)]; 76 | 77 | %% PROCESS 78 | 79 | % Setup analysis 80 | anl = Anl_NonlinearQuasiStatic('ArcLengthCylControl'); 81 | anl.adjustStep = true; 82 | anl.increment = 0.1; 83 | anl.max_lratio = 2.0; 84 | anl.max_step = 100; 85 | anl.max_iter = 100; 86 | anl.trg_iter = 20; 87 | 88 | % Node and DOF used to plot Load Factor vs Displacement 89 | ndId = mdl.closestNodeToPoint([ri, 0.0]); 90 | anl.setPlotDof(ndId, 1); 91 | 92 | % Run analysis 93 | anl.run(mdl); 94 | 95 | %% POST-PROCESS 96 | 97 | % Plot Load Factor vs Displacement 98 | anl.plotCurves(); 99 | 100 | % Plot contours 101 | mdl.plotField('S1'); 102 | mdl.plotField('Sr'); 103 | mdl.plotField('Sx'); 104 | -------------------------------------------------------------------------------- /examples/H2/example_h2_buckley_leverett_pl_pg.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Buckley-Leverett problem using the Pl-Pg two-phase flow formulation. 4 | % 5 | % Physics: 6 | % * Two-phase hydraulic (H2) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H2(); 15 | 16 | % Set model options 17 | mdl.massLumping = true; % Diagonalize compressibility matrix (mass lumping) 18 | mdl.lumpStrategy = 2; 19 | 20 | %% MESH 21 | 22 | % Create mesh 23 | Lx = 301.95; % Horizontal dimension (m) 24 | Ly = 100.00; % Vertical dimension (m) 25 | Nx = 99; % Number of elements in the x-direction 26 | Ny = 1; % Number of elements in the y-direction 27 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 28 | 29 | % Set mesh to model 30 | mdl.setMesh(node, elem); 31 | 32 | %% MATERIALS 33 | 34 | % Create fluids 35 | water = Fluid('water'); 36 | gas = Fluid('gas'); 37 | 38 | % Create porous media 39 | rock = PorousMedia('rock'); 40 | rock.K = 1.0e-7; % Intrinsic permeability (m2) 41 | rock.phi = 0.2; % Porosity 42 | rock.Slr = 0.2; % Residual liquid saturation 43 | rock.Sgr = 0.2; % Residual gas saturation 44 | rock.Pb = 0.0; % Gas-entry pressure 45 | rock.lambda = 2.0; % Curve-fitting parameter 46 | rock.liqRelPermeability = 'BrooksCorey'; % Liquid relative permeability 47 | rock.gasRelPermeability = 'BrooksCorey'; % Gas relative permeability 48 | rock.capillaryPressure = 'UMAT'; % Saturation degree function 49 | 50 | % Set user material values for capillary pressure vs. saturation law 51 | % Pc | Sl 52 | SlPcUMAT = [3.0, 0.2; 53 | 0.0, 0.8]; 54 | rock.setUMATCapillaryPressureCurve(SlPcUMAT); 55 | 56 | % Set materials to model 57 | mdl.setMaterial(rock, water, gas); 58 | 59 | %% BOUNDARY AND INITIAL CONDITIONS 60 | 61 | % Set Dirichlet boundary conditions 62 | mdl.setPressureDirichletBCAtBorder('left', 200000.0); 63 | mdl.setGasPressureDirichletBCAtBorder('left', 200000.230769231); 64 | 65 | % Set initial conditions 66 | mdl.setInitialPressureAtDomain(200000.0); 67 | mdl.setInitialGasPressureAtDomain(200003.0); 68 | 69 | %% PROCESS 70 | 71 | % Analysis parameters 72 | day = 60*60*24; % Conversion from days to seconds 73 | ti = 0.1*day; % Initial time 74 | dt = 0.1*day; % Time step 75 | tf = 50.0*day; % Final time 76 | dtmax = 0.1*day; % Maximum time step 77 | dtmin = 0.1*day; % Minimum time step 78 | adaptStep = true; % Adaptive step size 79 | 80 | % Run analysis 81 | anl = Anl_Transient("Picard"); 82 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 83 | anl.run(mdl); 84 | 85 | %% POST-PROCESS 86 | 87 | % Plot contours 88 | mdl.plotField('CapillaryPressure'); 89 | mdl.plotField('GasPressure'); 90 | 91 | % Plot graphs 92 | Xi = [0.0, 0.0]; Xf = [Lx, 0.0]; 93 | mdl.plotFieldAlongSegment('LiquidPressure', Xi, Xf, 500, 'x'); 94 | mdl.plotFieldAlongSegment('CapillaryPressure', Xi, Xf, 500, 'x'); 95 | mdl.plotFieldAlongSegment('GasPressure', Xi, Xf, 500, 'x'); 96 | -------------------------------------------------------------------------------- /examples/H2/example_h2_buckley_leverett_pc_pg.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % Buckley-Leverett problem using the Pc-Pg two-phase flow formulation. 4 | % 5 | % Physics: 6 | % * Two-phase hydraulic (H2) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H2_PcPg(); 15 | 16 | % Set model options 17 | mdl.massLumping = true; % Diagonalize compressibility matrix (mass lumping) 18 | mdl.lumpStrategy = 2; 19 | 20 | %% MESH 21 | 22 | % Create mesh 23 | Lx = 301.95; % Horizontal dimension (m) 24 | Ly = 100.00; % Vertical dimension (m) 25 | Nx = 99; % Number of elements in the x-direction 26 | Ny = 1; % Number of elements in the y-direction 27 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 28 | 29 | % Set mesh to model 30 | mdl.setMesh(node, elem); 31 | 32 | %% MATERIALS 33 | 34 | % Create fluids 35 | water = Fluid('water'); 36 | gas = Fluid('gas'); 37 | 38 | % Create porous media 39 | rock = PorousMedia('rock'); 40 | rock.K = 1.0e-7; % Intrinsic permeability (m2) 41 | rock.phi = 0.2; % Porosity 42 | rock.Slr = 0.2; % Residual liquid saturation 43 | rock.Sgr = 0.2; % Residual gas saturation 44 | rock.Pb = 0.0; % Gas-entry pressure 45 | rock.lambda = 2.0; % Curve-fitting parameter 46 | rock.liqRelPermeability = 'BrooksCorey'; % Liquid relative permeability 47 | rock.gasRelPermeability = 'BrooksCorey'; % Gas relative permeability 48 | rock.capillaryPressure = 'UMAT'; % Saturation degree function 49 | 50 | % Set user material values for capillary pressure vs. saturation law 51 | % Pc | Sl 52 | SlPcUMAT = [3.0, 0.2; 53 | 0.0, 0.8]; 54 | rock.setUMATCapillaryPressureCurve(SlPcUMAT); 55 | 56 | % Set materials to model 57 | mdl.setMaterial(rock, water, gas); 58 | 59 | %% BOUNDARY AND INITIAL CONDITIONS 60 | 61 | % Set Dirichlet boundary conditions 62 | mdl.setCapillaryPressureDirichletBCAtBorder('left', 0.230769231); 63 | mdl.setGasPressureDirichletBCAtBorder('left', 200000.230769231); 64 | 65 | % Set initial conditions 66 | mdl.setInitialCapillaryPressureAtDomain(3.0); 67 | mdl.setInitialGasPressureAtDomain(200003.0); 68 | 69 | %% PROCESS 70 | 71 | % Analysis parameters 72 | day = 60*60*24; % Conversion from days to seconds 73 | ti = 0.1*day; % Initial time 74 | dt = 0.1*day; % Time step 75 | tf = 50.0*day; % Final time 76 | dtmax = 0.1*day; % Maximum time step 77 | dtmin = 0.1*day; % Minimum time step 78 | adaptStep = true; % Adaptive step size 79 | 80 | % Run analysis 81 | anl = Anl_Transient("Picard"); 82 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 83 | anl.run(mdl); 84 | 85 | %% POST-PROCESS 86 | 87 | % Plot contours 88 | mdl.plotField('CapillaryPressure'); 89 | mdl.plotField('GasPressure'); 90 | 91 | % Plot graphs 92 | Xi = [0.0, 0.0]; Xf = [Lx, 0.0]; 93 | mdl.plotFieldAlongSegment('LiquidPressure', Xi, Xf, 500, 'x'); 94 | mdl.plotFieldAlongSegment('CapillaryPressure', Xi, Xf, 500, 'x'); 95 | mdl.plotFieldAlongSegment('GasPressure', Xi, Xf, 500, 'x'); 96 | -------------------------------------------------------------------------------- /src/physics/M/Material_M.m: -------------------------------------------------------------------------------- 1 | %% Material_M Class 2 | % This class represents a material model that combines porous media 3 | % properties with mechanical constitutive behavior. It provides methods to 4 | % evaluate the mechanical constitutive law, retrieve the number of state 5 | % variables, and check for plastic strain behavior. 6 | % 7 | %% Methods 8 | % * *mechanicalLaw*: Evaluates the mechanical constitutive law at a given 9 | % integration point to return the stress tensor and the 10 | % material stiffness matrix. 11 | % * *getNumberStateVar*: Returns the number of state variables associated 12 | % with the mechanical constitutive law. 13 | % * *hasPlasticStrain*: Checks if the material exhibits elasto-plastic 14 | % behavior. 15 | % 16 | %% Author 17 | % Danilo Cavalcanti 18 | % 19 | %% Version History 20 | % Version 1.00: Initial version (January 2024). 21 | % 22 | %% Class definition 23 | classdef Material_M < handle 24 | %% Public attributes 25 | properties (SetAccess = public, GetAccess = public) 26 | porousMedia = PorousMedia(); 27 | mechanical = []; 28 | end 29 | %% Constructor method 30 | methods 31 | %------------------------------------------------------------------ 32 | function this = Material_M(matData,lc) 33 | this.porousMedia = matData.porousMedia; 34 | % Mechanical constitutive behavior 35 | if strcmp('elastic',matData.porousMedia.mechanical) 36 | this.mechanical = MechanicalLinearElastic(); 37 | elseif strcmp('vonMises',matData.porousMedia.mechanical) 38 | this.mechanical = MechanicalElastoPlasticVonMises(); 39 | elseif strcmp('druckerPrager',matData.porousMedia.mechanical) 40 | this.mechanical = MechanicalElastoPlasticDruckerPrager(); 41 | elseif strcmp('elasticDruckerPrager',matData.porousMedia.mechanical) 42 | this.mechanical = MechanicalNonlinearElasticDruckerPrager(); 43 | elseif strcmp('nonlinearAsymptotic',matData.porousMedia.mechanical) 44 | this.mechanical = MechanicalNonlinearAsymptotic(); 45 | elseif strcmp('isoDamage',matData.porousMedia.mechanical) 46 | this.mechanical = MechanicalIsotropicDamage(lc); 47 | end 48 | end 49 | end 50 | %% Public methods 51 | methods 52 | % ----------------------------------------------------------------- 53 | % Evaluate the mechanical constitutive law 54 | function [stress,D] = mechanicalLaw(this,ip) 55 | [stress,D] = this.mechanical.eval(this.porousMedia,ip); 56 | end 57 | 58 | % ----------------------------------------------------------------- 59 | % Get the number of state variables associated with the mechanical 60 | % constitutive law 61 | function nstVar = getNumberStateVar(this) 62 | nstVar = this.mechanical.nstVar; 63 | end 64 | 65 | % ----------------------------------------------------------------- 66 | % Checks if the material exhibits elasto-plastic behaviour 67 | function flag = hasPlasticStrain(this) 68 | flag = this.mechanical.isElastoPlastic(); 69 | end 70 | 71 | end 72 | end -------------------------------------------------------------------------------- /examples/H2/example_h2_liakopoulos_pc_pg.m: -------------------------------------------------------------------------------- 1 | %% DESCRIPTION 2 | % 3 | % OGS-5 Liakopoulos problem using the Pc-Pg two-phase flow formulation. 4 | % 5 | % Physics: 6 | % * Two-phase hydraulic (H2) 7 | % 8 | % Authors: 9 | % * Danilo Cavalcanti (dborges@cimne.upc.edu) 10 | % 11 | %% MODEL 12 | 13 | % Create model 14 | mdl = Model_H2_PcPg(); 15 | 16 | % Set model options 17 | mdl.massLumping = true; % Diagonalize compressibility matrix (mass lumping) 18 | mdl.lumpStrategy = 2; 19 | mdl.gravityOn = true; 20 | 21 | %% MESH 22 | 23 | % Create mesh 24 | Lx = 0.1; % Horizontal dimension (m) 25 | Ly = 1.0; % Vertical dimension (m) 26 | Nx = 3; % Number of elements in the x-direction 27 | Ny = 24; % Number of elements in the y-direction 28 | [node, elem] = regularMesh(Lx, Ly, Nx, Ny); 29 | 30 | % Set mesh to model 31 | mdl.setMesh(node, elem); 32 | 33 | %% MATERIALS 34 | 35 | % Create fluids 36 | water = Fluid('water'); 37 | gas = IdealGas('gas'); 38 | gas.mu = 1.8e-5; % Viscosity (Pa*s) 39 | gas.K = 1.0e25; % Compressibility/Bulk modulus (1/Pa) 40 | 41 | % Create porous media 42 | rock = PorousMedia('rock'); 43 | rock.K = 4.5e-13; % Intrinsic permeability (m2) 44 | rock.phi = 0.2975; % Porosity 45 | rock.biot = 1.0; % Biot's coefficient 46 | rock.Ks = 1.0e25; % Solid bulk modulus (Pa) 47 | rock.Slr = 0.0; % Residual liquid saturation 48 | rock.Sgr = 0.2; % Residual gas saturation 49 | rock.Pb = 0.0; % Gas-entry pressure 50 | rock.lambda = 3.0; % Curve-fitting parameter 51 | rock.liqRelPermeability = 'Liakopoulos'; % Liquid relative permeability 52 | rock.gasRelPermeability = 'BrooksCorey'; % Gas relative permeability 53 | rock.capillaryPressure = 'Liakopoulos'; % Saturation degree function 54 | rock.setMinLiquidRelPermeability(0.0001); 55 | rock.setMinGasRelPermeability(0.0001); 56 | 57 | % Set materials to model 58 | mdl.setMaterial(rock, water, gas); 59 | 60 | %% BOUNDARY AND INITIAL CONDITIONS 61 | 62 | % Set Dirichlet boundary conditions 63 | mdl.setCapillaryPressureDirichletBCAtBorder('bottom', 0.0); 64 | mdl.setGasPressureDirichletBCAtBorder('bottom', 101325.0); 65 | mdl.setGasPressureDirichletBCAtBorder('top', 101325.0); 66 | 67 | % Set initial conditions 68 | mdl.setInitialCapillaryPressureAtDomain(0.0); 69 | mdl.setInitialGasPressureAtDomain(101325.0); 70 | 71 | %% PROCESS 72 | 73 | % Analysis parameters 74 | min = 60; % Conversion from days to seconds 75 | ti = 0.001*min; % Initial time 76 | dt = 0.001*min; % Time step 77 | tf = 5.0*min; % Final time 78 | dtmax = 1.0*min; % Maximum time step 79 | dtmin = 0.001*min; % Minimum time step 80 | adaptStep = true; % Adaptive step size 81 | 82 | % Run analysis 83 | anl = Anl_Transient("Newton"); 84 | anl.setUpTransientSolver(ti, dt, tf, dtmax, dtmin, adaptStep); 85 | anl.run(mdl); 86 | 87 | %% POST-PROCESS 88 | 89 | % Plot contours 90 | mdl.plotField('CapillaryPressure'); 91 | mdl.plotField('GasPressure'); 92 | 93 | % Plot graphs 94 | Xi = [0.0, 0.0]; Xf = [0.0, Ly]; 95 | mdl.plotFieldAlongSegment('LiquidPressure', Xi, Xf, 500, 'y'); 96 | mdl.plotFieldAlongSegment('CapillaryPressure', Xi, Xf, 500, 'y'); 97 | mdl.plotFieldAlongSegment('GasPressure', Xi, Xf, 500, 'y'); 98 | --------------------------------------------------------------------------------