初版gui

This commit is contained in:
xinxiao
2026-03-16 16:57:25 +08:00
parent 748c50fb44
commit 0e8421ec4f
19 changed files with 3467 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
# App Quickstart
## Launch
From MATLAB, open the app with:
```matlab
launch_edfm_simulator_app
```
File:
- `gui_support/app/launch_edfm_simulator_app.m`
## Current Scope
The app currently provides:
- tab layout by Part
- template loading
- config import/export as MAT
- result import/export as MAT
- unified run entry through `run_case(config)`
- run log capture
- basic result summary and plotting
## Current Editing Style
For large arrays and cell data, the app currently uses MATLAB literal text areas.
Examples:
- numeric arrays: `[1 2 3]`
- matrices: `[1 2; 3 4]`
- cell arrays: `{'w1', 1, [1 1 1], 0.089, 0, 1}`
This keeps the first App Designer style version flexible while the parameter schema is still being stabilized.
## Notes
- The flow models are mutually exclusive.
- The GUI only uses the active `flow_model` branch at runtime.
- The current result page is a first-pass implementation.
- The current app class is written in App Designer style (`matlab.apps.AppBase`) as a text `.m` class instead of a binary `.mlapp`.
+90
View File
@@ -0,0 +1,90 @@
# Case Template Summary
This file captures the first-pass differences among the 7 existing example cases.
The goal is to turn these into GUI presets later instead of keeping 7 separate hard-coded entry scripts.
## Shared Structure
All current example `main1.m` scripts follow the same 8-part flow:
1. model selection
2. matrix grid definition
3. fracture input
4. discretization
5. flow model and initial state
6. well and schedule
7. solver setup
8. execution
## Template Summary
| Case | Folder | Grid | Grid Model | Flow Model | Fracture Wells | Schedule Phases | Notes |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 1 | `算例1-组分流-不规则非均质计算域` | `20 x 10 x 1` | SP | Multi-component | 1 | 3 | Component transport, surfactant/salt injection |
| 2 | `算例2-组分流-无效网格` | `20 x 20 x 3` | SP | Multi-component | 1 | 3 | Similar to case 1, but multi-layer and invalid-grid theme |
| 3 | `算例3-单重双重离散裂缝混合模型` | `20 x 10 x 1` | DP | Multi-component | 1 | 3 | Dual-medium setup |
| 4 | `算例4-气水两相流-压力导数曲线` | `20 x 10 x 1` | SP | Gas-water | 1 | 5 | Pressure derivative style schedule with very small early timesteps |
| 5 | `算例5-油水两相流-注焖采` | `20 x 10 x 1` | SP | Oil-water | 1 | 3 | Injection-soak-production schedule |
| 6 | `算例6-油水两相流-直井注压裂水平井采` | `20 x 10 x 2` | SP | Oil-water | 1 | 1 | Contains both conventional wells and fracture well |
| 7 | `算例7-油水两相流-不同裂缝制度不同` | `20 x 10 x 1` | SP | Oil-water | 6 | 4 | Multiple fracture-well controls with different stages |
## Key Template Differences
### Grid
- Most cases use `dx = 50 * ones(1, 20)`.
- Most cases use `dy = 50 * ones(1, 10)`.
- `dz` differs by case:
- case 1: 1 layer
- case 2: 3 layers
- case 3: 1 layer
- case 4: 1 layer
- case 5: 1 layer
- case 6: 2 layers
- case 7: 1 layer
### Discretization
- Cases 1, 2, 4, 5, 6, 7 use single-medium mode.
- Case 3 uses dual-medium mode.
### Flow Physics
- Cases 1, 2, 3 use multi-component flow.
- Case 4 uses gas-water flow.
- Cases 5, 6, 7 use oil-water flow.
### Wells
- Cases 1 to 5 mainly define fracture well completions through `welloc`.
- Case 6 includes conventional wells in `well1` plus one fracture well in `well2`.
- Case 7 splits six fracture locations into six separately controlled fracture wells.
### Schedule
- Cases 1, 2, 3: 3-stage schedule
- Case 4: 5-stage schedule with aggressive timestep ramping
- Case 5: 3-stage schedule
- Case 6: 1-stage schedule
- Case 7: 4-stage schedule
## Preset Design Recommendation
Later, each GUI preset should contain:
- display name
- source folder
- default `config`
- supported flow model
- supported grid model
- notes for the result page
Suggested preset IDs:
- `case01_multicomponent_irregular`
- `case02_multicomponent_invalid_grid`
- `case03_multicomponent_dp`
- `case04_gas_water_pressure_derivative`
- `case05_oil_water_huff_n_puff`
- `case06_oil_water_vertical_inj_fractured_horizontal_prod`
- `case07_oil_water_multi_fracture_regimes`
+386
View File
@@ -0,0 +1,386 @@
# GUI Parameter And Run Architecture
## Decision
Use MATLAB `struct` as the primary runtime and persistence format.
Reasons:
- App Designer works naturally with nested `struct` data.
- Existing solver code already expects MATLAB variables and structs, not object models.
- `struct` avoids unnecessary conversion while the GUI is being built.
- JSON can still be added later as an optional export/import layer.
Recommended flow:
1. Load a case template into `config` as a MATLAB struct.
2. Let the GUI edit `config`.
3. Save or load `config` directly as MATLAB data first.
4. Convert `config` into solver inputs through a single entry point later: `run_case(config)`.
## Unified Config Layout
The GUI should be built around the following top-level fields:
```matlab
config.meta
config.model
config.grid
config.fracture
config.discretization
config.flow
config.initial
config.wells
config.schedule
config.solver
config.output
```
## Part Mapping
The existing `main1.m` scripts are structurally consistent and map well to the GUI:
1. `model`: model selection
2. `grid`: matrix grid definition
3. `fracture`: fracture input and geometry
4. `discretization`: SP/DP discretization and medium setup
5. `flow` + `initial`: flow model, PVT, relative permeability, initial state
6. `wells` + `schedule`: wells, perforations, stage schedule
7. `solver`: nonlinear and timestep controls
8. `output`: run execution and result presentation
## Parameter Layers
The previous inventory mixed together direct inputs and fields created during preprocessing.
The GUI should distinguish them explicitly.
### Layer A: Editable Input Parameters
These are the parameters the GUI should expose directly or through advanced panels.
### Layer B: Derived Or Runtime Fields
These are generated by preprocessing, discretization, solver assembly, or postprocessing.
They should usually be displayed or logged, but not edited directly.
## Core Parameter Inventory
This is the revised first-pass grouping of parameters already identified in the repository.
### `meta`
- `case_name`
- `case_id`
- `description`
- `source_case_folder`
- `created_from_template`
- `version`
### `model`
- `modelflag`
- `grid_model`
- `flow_model`
Known values:
- `modelflag`: currently fixed to classical EDFM in all 7 examples
- `grid_model`: `1` single-medium, `2` dual-medium
- `flow_model`: `1` gas-water, `2` oil-water, `3` multi-component
### `grid`
Editable inputs:
- `dx`
- `dy`
- `dz`
- `nx`
- `ny`
- `nz`
- `NTG`
Derived by `GridProp_pre` and later preprocessing:
- `coordinates`
- `nodes`
- `nP`
- `nmc`
- `dxv`
- `dyv`
- `dzv`
- `vm`
- `zm`
- `xrao`
- `yrao`
- `zrao`
- `cell_mid_coords`
Important correction:
- `boundary` is not defined in `GridProp_pre.m`.
- In case 1 it is defined in `grid_discretization_SP_model.m`.
- This means geometric grid size and reservoir validity boundary are separate parameter groups and should not be merged.
### `fracture`
- `input_style`
- `input_content`
- `f`
- `fellip`
- `fractureLines`
- `fractureHeights`
- `flowBarrierFlags`
- `frac_information`
- `nf`
Observed input modes:
- Engineering input table
- Vector input
- 2D line input
- Reserved `.fab` import mode
### `discretization`
Editable inputs:
- `grid_model`
- `boundary`
- `invalid_layer`
- `valid_grids` generation rule
- matrix permeability definition rule
- matrix porosity definition rule
- matrix reference pressure `prpor`
- matrix compressibility `cpor`
- rock density `rock_density`
- fracture permeability `Kf`
- fracture aperture `Wf`
- fracture porosity `Porf`
- fracture reference pressure `prporf`
- fracture compressibility `cporf`
- `stress_factor_fracture`
- `stress_factor_matrix`
- `stress_factor_ref_pressure`
- dual-medium only:
- `kx_matrixLayer`
- `ky_matrixLayer`
- `kz_matrixLayer`
- `pori_matrixLayer`
- `sigma`
Observed editable rock-property expressions in current cases:
- case 1 SP:
- polygon `boundary`
- `kx/ky/kz` as spatial functions of `cell_mid_coords`
- `pori` as spatial function of `cell_mid_coords`
- cases 2/4/6:
- constant matrix properties
- `invalid_layer` controls inactive layers
- cases 5/7:
- constant matrix properties, different values from cases 2/4/6
- case 3 DP:
- fracture-layer permeability set
- matrix-layer permeability set
- matrix-layer porosity
- shape factor `sigma`
Derived fields:
- fracture-matrix discretization result
- fracture-fracture discretization result
- EDFM connection data
- operator generation inputs for `OperatorRS`
- runtime fields added onto `r`, including `rock_density`, `valid_grids`, stress-factor fields, and dual-medium derived fields
### `flow`
Shared categories:
- phase density
- reference pressure
- formation volume factor
- compressibility
- viscosity
- viscosity-pressure coefficient
- capillary pressure switch
- non-Darcy coefficient
- threshold pressure gradient
- matrix relative permeability table
- fracture relative permeability table
Additional note:
- Many of these are hidden inside helper files such as `gas_water_flow.m`, `oil_water_flow.m`, and `multi_component_flow.m`, so they must be treated as editable physics parameters even though they are not visible in `main1.m`.
Gas-water specific:
- `gas_prop.VL`
- `gas_prop.PL`
- `gas_prop.Kn`
- `gas_prop.Kn_modified_factor`
- `gas_prop.beta_non_Darcy_flow`
- `density_g_sc`
- `gas_model`
- gas PVT table or generated PVT parameters
Oil-water specific:
- `density_o_sc`
- `oil_model`
- oil PVT table or generated PVT parameters
Multi-component specific:
- `Ds`
- `Db`
- adsorption table `c_ca_table`
- chemistry parameters `R`, `Vm`, `Temperature`, `chemistry_cof`
- dynamic relative permeability tables `cs_Nc`, `kr_nosurf`, `kr_surf`, `PC`
- fracture counterparts of the same tables
- `number_state_variables`
### `initial`
Gas-water and oil-water:
- `P`
- `Sw`
Multi-component:
- `P`
- `Sw`
- `Cs`
- `Cb`
### `wells`
Conventional well definition:
- `well1`
- well name
- perforation count
- perforation grid indices
- wellbore radius
- skin
- well type
Fracture-well definition:
- `num_fracture_wells`
- `welloc`
- `perfnum`
- `well2`
Combined runtime well structure:
- `Wellc`
### `schedule`
- `number_phases`
- `well_schedules`
- `time`
- `dtmax`
- `dtmin`
Per-row schedule fields observed:
- well name
- well state
- well role
- control mode
- target value 1
- target value 2
- optional `Cs_inj`
- optional `Cb_inj`
### `solver`
- `yitap`
- `yitas`
- `omega`
- `Nmax`
- `epsave`
- `epsmax`
### `output`
Runtime outputs observed:
- `Times`
- `OutputRs`
- `Wellpara`
- `trun`
Useful progress fields for the future GUI:
- current stage index
- current simulation time
- current `dt`
- Newton iteration count
- cumulative linear solve time
- cumulative Jacobian assembly time
## Preset Strategy
The seven example folders should be treated as presets, not as independent long-term entry points.
Recommended future structure:
- `load_case_template(1)` ... `load_case_template(7)`
- each template returns a complete `config`
- GUI edits the `config`
- `run_case(config)` executes the solver
This avoids binding the GUI to seven different hard-coded scripts.
## Run Page Scope
Pause and abort are explicitly deferred for now.
Current target for the run page:
- show active case name
- show active stage
- show current simulation time
- show current timestep
- show Newton count
- show text log
- optionally plot selected well response during run
The existing solver already prints progress with `fprintf`, but the proper GUI solution will be to add a progress callback later.
## File-Level Sources Confirmed So Far
Primary input sources already confirmed:
- `main1.m`
- `GridProp_pre.m`
- `grid_discretization_SP_model.m`
- `grid_discretization_DP_model.m`
- `preprocess_heterogeneous.m`
- `gas_water_flow.m`
- `oil_water_flow.m`
- `multi_component_flow.m`
This matters because not all user-facing parameters live in `main1.m`.
The parameter registry must therefore be built from the full call chain, not from entry scripts only.
## Next Implementation Steps
1. Build a complete field-level parameter registry file from the 7 case folders.
2. Keep `create_empty_config` as the primary configuration skeleton.
3. Use `run_case(config)` as the single runtime entry point for all three flow models.
4. Build App Designer pages around model-specific parameter panels.
## Runtime Status
Current runtime direction:
- `run_case(config)` is now the unified execution entry.
- `flow_model` is treated as mutually exclusive.
- GUI should only show the active model's parameter set.
- Non-active model parameters should remain hidden and unused.
+351
View File
@@ -0,0 +1,351 @@
# Parameter Registry
This registry maps the current hard-coded parameters to a unified `config` structure.
It is intentionally field-oriented so the future GUI can be built against a stable schema.
## Conventions
- `Config Path`: target field in the unified config
- `Source Variable`: current variable name in code
- `Source File`: current MATLAB file where the parameter is defined
- `Cases`: which example folders currently use the field
- `Editable`: whether the GUI should expose the field
- `Notes`: behavior, enum meaning, or shape
## Meta
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `meta.case_name` | none | template-level | all | yes | Display name |
| `meta.case_id` | none | template-level | all | yes | Stable preset ID |
| `meta.description` | none | template-level | all | yes | Free text |
| `meta.source_case_folder` | folder name | template-level | all | no | Traceability |
| `meta.created_from_template` | none | template-level | all | no | Preset source |
| `meta.version` | none | config system | all | no | Schema version |
## Model
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `model.modelflag` | `modelflag` | `main1.m` | 1-7 | yes | Current examples use `1` |
| `model.grid_model` | `grid_model` | `main1.m` | 1-7 | yes | `1` SP, `2` DP |
| `model.flow_model` | `flow_model` | `main1.m` | 1-7 | yes | `1` gas-water, `2` oil-water, `3` multi-component |
## Grid Geometry
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `grid.dx` | `dx` | `main1.m` | 1-7 | yes | Vector |
| `grid.dy` | `dy` | `main1.m` | 1-7 | yes | Vector |
| `grid.dz` | `dz` | `main1.m` | 1-7 | yes | Vector |
| `grid.nx` | `nx` | `main1.m` | 1-7 | no | Derived from `dx` |
| `grid.ny` | `ny` | `main1.m` | 1-7 | no | Derived from `dy` |
| `grid.nz` | `nz` | `main1.m` | 1-7 | no | Derived from `dz` |
| `grid.NTG` | `NTG` | `main1.m` | 1-7 | no | Array sized `nx*ny*nz` |
Derived fields produced by `GridProp_pre.m`:
- `grid.coordinates`
- `grid.nodes`
- `grid.nP`
- `grid.nmc`
- `grid.dxv`
- `grid.dyv`
- `grid.dzv`
- `grid.zm`
- `grid.vm`
- `grid.xrao`
- `grid.yrao`
- `grid.zrao`
- `grid.cell_mid_coords`
## Fracture Input
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `fracture.input_style` | `input_style` | `main1.m` | 1-7 | yes | 1 engineering, 2 vector, 3 2D lines, 4 fab reserved |
| `fracture.input_content` | `input_content` | `main1.m` | 1-7 | yes | Engineering fracture table |
| `fracture.f` | `f` | `main1.m` / helper outputs | 1-7 | advanced | Vector fracture representation |
| `fracture.fellip` | `fellip` | `main1.m` / helper outputs | 1-7 | advanced | Elliptic fractures |
| `fracture.fractureLines` | `fractureLines` | `main1.m` | 1-7 | yes | Used in mode 3 |
| `fracture.fractureHeights` | `fractureHeights` | `main1.m` | 1-7 | yes | Used in mode 3 |
| `fracture.flowBarrierFlags` | `flowBarrierFlags` | `main1.m` | 1-7 | yes | Optional |
| `fracture.frac_information` | `frac_information` | helper outputs | 1-7 | no | Generated by helper functions |
| `fracture.nf` | `nf` | `main1.m` | 1-7 | no | Derived fracture count |
## Discretization Selection
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `discretization.mode` | `grid_model` | `main1.m` | 1-7 | yes | Mirrors `model.grid_model` |
| `discretization.use_operator` | implicit | `main1.m` | 1-7 | no | `OperatorRS` is always called currently |
## SP Rock And Boundary Parameters
These are critical editable parameters and were previously undercounted.
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `discretization.sp.boundary_polygon` | `boundary` | `grid_discretization_SP_model.m` | 1 | yes | Irregular domain polygon |
| `discretization.sp.invalid_layer` | `invalid_layer` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Layer indices disabled from simulation |
| `discretization.sp.valid_grids` | `valid_grids` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | no | Derived from boundary/layers |
| `discretization.sp.matrix.kx` | `kx` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Array or generated field |
| `discretization.sp.matrix.ky` | `ky` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Array or generated field |
| `discretization.sp.matrix.kz` | `kz` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Array or generated field |
| `discretization.sp.matrix.pori` | `pori` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Array or generated field |
| `discretization.sp.matrix.prpor` | `prpor` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Matrix reference pressure |
| `discretization.sp.matrix.cpor` | `cpor` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Matrix compressibility |
| `discretization.sp.matrix.rock_density` | `rock_density` / `density_rock` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Naming is inconsistent across cases |
| `discretization.sp.fracture.Kf` | `Kf` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Fracture permeability |
| `discretization.sp.fracture.Wf` | `Wf` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Fracture aperture |
| `discretization.sp.fracture.Porf` | `Porf` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Fracture porosity |
| `discretization.sp.fracture.prporf` | `prporf` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Fracture reference pressure |
| `discretization.sp.fracture.cporf` | `cporf` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Fracture compressibility |
| `discretization.sp.stress.fracture_factor` | `stress_factor_fracture` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Stress sensitivity |
| `discretization.sp.stress.matrix_factor` | `stress_factor_matrix` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Stress sensitivity |
| `discretization.sp.stress.ref_pressure` | `stress_factor_ref_pressure` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Reference pressure |
| `discretization.sp.stress.Rpt` | `Rpt` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Unknown |
| `discretization.sp.stress.cf` | `cf` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Unknown |
| `discretization.sp.stress.ca` | `ca` | `grid_discretization_SP_model.m` | 1,2,4,5,6,7 | yes | Unknown |
Case-specific notes:
- Case 1 uses spatial functions and an irregular polygon boundary.
- Cases 2 and 4 use `invalid_layer` to deactivate the second layer when applicable.
- Cases 5 and 7 use different constant matrix properties than cases 2, 4, and 6.
## DP Rock Parameters
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `discretization.dp.fracture_layer.kx` | `kx` | `grid_discretization_DP_model.m` | 3 | yes | Dual-medium fracture layer |
| `discretization.dp.fracture_layer.ky` | `ky` | `grid_discretization_DP_model.m` | 3 | yes | Dual-medium fracture layer |
| `discretization.dp.fracture_layer.kz` | `kz` | `grid_discretization_DP_model.m` | 3 | yes | Dual-medium fracture layer |
| `discretization.dp.fracture_layer.pori` | `pori` | `grid_discretization_DP_model.m` | 3 | no | Dual-medium fracture layer porosity |
| `discretization.dp.matrix_layer.kx` | `kx_matrixLayer` | `grid_discretization_DP_model.m` | 3 | yes | Matrix layer permeability |
| `discretization.dp.matrix_layer.ky` | `ky_matrixLayer` | `grid_discretization_DP_model.m` | 3 | yes | Matrix layer permeability |
| `discretization.dp.matrix_layer.kz` | `kz_matrixLayer` | `grid_discretization_DP_model.m` | 3 | yes | Matrix layer permeability |
| `discretization.dp.matrix_layer.pori` | `pori_matrixLayer` | `grid_discretization_DP_model.m` | 3 | yes | Matrix layer porosity |
| `discretization.dp.shape_factor` | `sigma` | `grid_discretization_DP_model.m` | 3 | yes | Interporosity shape factor |
| `discretization.dp.valid_grids` | `valid_grids` | `grid_discretization_DP_model.m` | 3 | no | All ones in current example |
| `discretization.dp.NTG` | `NTG` | `grid_discretization_DP_model.m` | 3 | yes | Reassigned in file |
| `discretization.dp.prpor` | `prpor` | `grid_discretization_DP_model.m` | 3 | yes | Reference pressure |
| `discretization.dp.cpor` | `cpor` | `grid_discretization_DP_model.m` | 3 | yes | Compressibility |
| `discretization.dp.fracture.Kf` | `Kf` | `grid_discretization_DP_model.m` | 3 | yes | Fracture permeability |
| `discretization.dp.fracture.Wf` | `Wf` | `grid_discretization_DP_model.m` | 3 | yes | Fracture aperture |
| `discretization.dp.fracture.Porf` | `Porf` | `grid_discretization_DP_model.m` | 3 | yes | Fracture porosity |
| `discretization.dp.fracture.prporf` | `prporf` | `grid_discretization_DP_model.m` | 3 | yes | Fracture reference pressure |
| `discretization.dp.fracture.cporf` | `cporf` | `grid_discretization_DP_model.m` | 3 | yes | Fracture compressibility |
| `discretization.dp.stress.fracture_factor` | `stress_factor_fracture` | `grid_discretization_DP_model.m` | 3 | yes | Stress sensitivity |
| `discretization.dp.stress.matrix_factor` | `stress_factor_matrix` | `grid_discretization_DP_model.m` | 3 | yes | Stress sensitivity |
| `discretization.dp.stress.ref_pressure` | `stress_factor_ref_pressure` | `grid_discretization_DP_model.m` | 3 | yes | Reference pressure |
| `discretization.dp.rock_density` | `rock_density` | `grid_discretization_DP_model.m` | 3 | yes | Rock density |
| `discretization.dp.Rpt` | `Rpt` | `grid_discretization_DP_model.m` | 3 | yes | Unknown |
| `discretization.dp.cf` | `cf` | `grid_discretization_DP_model.m` | 3 | yes | Unknown |
| `discretization.dp.ca` | `ca` | `grid_discretization_DP_model.m` | 3 | yes | Unknown |
## Flow: Gas-Water
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `flow.gas_water.gas_prop.VL` | `gas_prop.VL` | `gas_water_flow.m` | 4 | yes | Langmuir volume |
| `flow.gas_water.gas_prop.PL` | `gas_prop.PL` | `gas_water_flow.m` | 4 | yes | Langmuir pressure |
| `flow.gas_water.gas_prop.Kn` | `gas_prop.Kn` | `gas_water_flow.m` | 4 | yes | Knudsen number |
| `flow.gas_water.gas_prop.Kn_modified_factor` | `gas_prop.Kn_modified_factor` | `gas_water_flow.m` | 4 | no | Derived |
| `flow.gas_water.gas_prop.beta_non_darcy_flow` | `gas_prop.beta_non_Darcy_flow` | `gas_water_flow.m` | 4 | yes | High-velocity term |
| `flow.gas_water.p_grad_threshold` | `p_grad_threshold` | `gas_water_flow.m` | 4 | yes | Threshold pressure gradient |
| `flow.gas_water.density_g_sc` | `density_g_sc` | `gas_water_flow.m` | 4 | yes | Gas density at standard conditions |
| `flow.gas_water.density_w_sc` | `density_w_sc` | `gas_water_flow.m` | 4 | yes | Water density at standard conditions |
| `flow.gas_water.gas_model` | `gas_model` | `gas_water_flow.m` | 4 | yes | 1 generated PVT, 2 tabulated PVT |
| `flow.gas_water.prg` | `prg` | `gas_water_flow.m` | 4 | yes | Only in model 1 |
| `flow.gas_water.Bgi` | `Bgi` | `gas_water_flow.m` | 4 | yes | Only in model 1 |
| `flow.gas_water.cg` | `cg` | `gas_water_flow.m` | 4 | yes | Only in model 1 |
| `flow.gas_water.vgi` | `vgi` | `gas_water_flow.m` | 4 | yes | Only in model 1 |
| `flow.gas_water.cvg` | `cvg` | `gas_water_flow.m` | 4 | yes | Only in model 1 |
| `flow.gas_water.Ppr` | `Ppr` | `gas_water_flow.m` | 4 | yes | Table or generated |
| `flow.gas_water.BG` | `BG` | `gas_water_flow.m` | 4 | yes | Table or generated |
| `flow.gas_water.MUG` | `MUG` | `gas_water_flow.m` | 4 | yes | Table or generated |
| `flow.gas_water.prw` | `prw` | `gas_water_flow.m` | 4 | yes | Water reference pressure |
| `flow.gas_water.Bwi` | `Bwi` | `gas_water_flow.m` | 4 | yes | Water volume factor |
| `flow.gas_water.cw` | `cw` | `gas_water_flow.m` | 4 | yes | Water compressibility |
| `flow.gas_water.vwi` | `vwi` | `gas_water_flow.m` | 4 | yes | Water viscosity |
| `flow.gas_water.cvw` | `cvw` | `gas_water_flow.m` | 4 | yes | Water viscosity-pressure coefficient |
| `flow.gas_water.ifpcgl` | `ifpcgl` | `gas_water_flow.m` | 4 | yes | Capillary pressure switch |
| `flow.gas_water.matrix_relperm_table` | `RPGW` | `gas_water_flow.m` | 4 | yes | Matrix table |
| `flow.gas_water.fracture_relperm_table` | `PRF` | `gas_water_flow.m` | 4 | yes | Fracture table |
## Flow: Oil-Water
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `flow.oil_water.density_o_sc` | `density_o_sc` | `oil_water_flow.m` | 5,6,7 | yes | Oil density |
| `flow.oil_water.density_w_sc` | `density_w_sc` | `oil_water_flow.m` | 5,6,7 | yes | Water density |
| `flow.oil_water.oil_model` | `oil_model` | `oil_water_flow.m` | 5,6,7 | yes | 1 generated PVT, 2 tabulated |
| `flow.oil_water.pro` | `pro` | `oil_water_flow.m` | 5,6,7 | yes | Oil ref pressure |
| `flow.oil_water.Boi` | `Boi` | `oil_water_flow.m` | 5,6,7 | yes | Oil volume factor |
| `flow.oil_water.co` | `co` | `oil_water_flow.m` | 5,6,7 | yes | Oil compressibility |
| `flow.oil_water.voi` | `voi` | `oil_water_flow.m` | 5,6,7 | yes | Oil viscosity |
| `flow.oil_water.cvo` | `cvo` | `oil_water_flow.m` | 5,6,7 | yes | Oil viscosity-pressure coefficient |
| `flow.oil_water.Ppr` | `Ppr` | `oil_water_flow.m` | 5,6,7 | yes | Table or generated |
| `flow.oil_water.BO` | `BO` | `oil_water_flow.m` | 5,6,7 | yes | Table or generated |
| `flow.oil_water.MUO` | `MUO` | `oil_water_flow.m` | 5,6,7 | yes | Table or generated |
| `flow.oil_water.prw` | `prw` | `oil_water_flow.m` | 5,6,7 | yes | Water ref pressure |
| `flow.oil_water.Bwi` | `Bwi` | `oil_water_flow.m` | 5,6,7 | yes | Water volume factor |
| `flow.oil_water.cw` | `cw` | `oil_water_flow.m` | 5,6,7 | yes | Water compressibility |
| `flow.oil_water.vwi` | `vwi` | `oil_water_flow.m` | 5,6,7 | yes | Water viscosity |
| `flow.oil_water.cvw` | `cvw` | `oil_water_flow.m` | 5,6,7 | yes | Water viscosity-pressure coefficient |
| `flow.oil_water.ifpcow` | `ifpcow` | `oil_water_flow.m` | 5,6,7 | yes | Capillary pressure switch |
| `flow.oil_water.matrix_relperm_table` | `PRM` | `oil_water_flow.m` | 5,6,7 | yes | Matrix table |
| `flow.oil_water.fracture_relperm_table` | `PRF` | `oil_water_flow.m` | 5,6,7 | yes | Fracture table |
| `flow.oil_water.beta_non_darcy_flow` | `beta_non_Darcy_flow` | `oil_water_flow.m` | 5,6,7 | yes | Non-Darcy coefficient |
| `flow.oil_water.p_grad_threshold` | `p_grad_threshold` | `oil_water_flow.m` | 5,6,7 | yes | Threshold gradient |
## Flow: Multi-Component
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `flow.multi_component.Ds` | `Ds` | `multi_component_flow.m` | 1,2,3 | yes | Surfactant diffusion |
| `flow.multi_component.Db` | `Db` | `multi_component_flow.m` | 1,2,3 | yes | Salt diffusion |
| `flow.multi_component.c_ca_table` | `c_ca_table` | `multi_component_flow.m` | 1,2,3 | yes | Adsorption table |
| `flow.multi_component.cs_data` | `cs_data` | `multi_component_flow.m` | 1,2,3 | no | Derived from table |
| `flow.multi_component.cb_data` | `cb_data` | `multi_component_flow.m` | 1,2,3 | no | Derived from table |
| `flow.multi_component.csa_data` | `csa_data` | `multi_component_flow.m` | 1,2,3 | no | Derived from table |
| `flow.multi_component.cba_data` | `cba_data` | `multi_component_flow.m` | 1,2,3 | no | Derived from table |
| `flow.multi_component.R` | `R` | `multi_component_flow.m` | 1,2,3 | yes | Chemistry constant |
| `flow.multi_component.Vm` | `Vm` | `multi_component_flow.m` | 1,2,3 | yes | Molar volume |
| `flow.multi_component.Temperature` | `Temperature` | `multi_component_flow.m` | 1,2,3 | yes | Temperature |
| `flow.multi_component.chemistry_cof` | `chemistry_cof` | `multi_component_flow.m` | 1,2,3 | no | Derived |
| `flow.multi_component.x_matrix!!!!` | `xm` | `multi_component_flow.m` | 1,2,3 | yes | Chemistry activity factor for matrix cells |
| `flow.multi_component.x_fracture!!!` | `xf` | `multi_component_flow.m` | 1,2,3 | yes | Chemistry activity factor for fracture cells |
| `flow.multi_component.cs_Nc` | `cs_Nc` | `multi_component_flow.m` | 1,2,3 | yes | Dynamic relative permeability mapping |
| `flow.multi_component.Nc_nosurf` | `Nc_nosurf` | `multi_component_flow.m` | 1,2,3 | no | Derived |
| `flow.multi_component.Nc_surf` | `Nc_surf` | `multi_component_flow.m` | 1,2,3 | no | Derived |
| `flow.multi_component.kr_nosurf` | `kr_nosurf` | `multi_component_flow.m` | 1,2,3 | yes | Relative permeability table |
| `flow.multi_component.kr_surf` | `kr_surf` | `multi_component_flow.m` | 1,2,3 | yes | Relative permeability table |
| `flow.multi_component.PC` | `PC` | `multi_component_flow.m` | 1,2,3 | yes | Capillary pressure table |
| `flow.multi_component.cs_Nc_fracture` | `cs_Nc_fracture` | `multi_component_flow.m` | 1,2,3 | yes | Fracture table |
| `flow.multi_component.kr_nosurf_fracture` | `kr_nosurf_fracture` | `multi_component_flow.m` | 1,2,3 | yes | Fracture table |
| `flow.multi_component.kr_surf_fracture` | `kr_surf_fracture` | `multi_component_flow.m` | 1,2,3 | yes | Fracture table |
| `flow.multi_component.PC_fracture` | `PC_fracture` | `multi_component_flow.m` | 1,2,3 | yes | Fracture capillary table |
| `flow.multi_component.ifpcgl` | `ifpcgl` | `multi_component_flow.m` | 1,2,3 | yes | Capillary pressure switch |
| `flow.multi_component.p_grad_threshold` | `p_grad_threshold` | `multi_component_flow.m` | 1,2,3 | yes | Threshold gradient |
| `flow.multi_component.gas_prop.VL` | `gas_prop.VL` | `multi_component_flow.m` | 1,2,3 | yes | Often zero for oil-like use |
| `flow.multi_component.gas_prop.PL` | `gas_prop.PL` | `multi_component_flow.m` | 1,2,3 | yes | Langmuir pressure |
| `flow.multi_component.gas_prop.Kn` | `gas_prop.Kn` | `multi_component_flow.m` | 1,2,3 | yes | Knudsen number |
| `flow.multi_component.gas_prop.Kn_modified_factor` | `gas_prop.Kn_modified_factor` | `multi_component_flow.m` | 1,2,3 | no | Derived |
| `flow.multi_component.gas_prop.stress_factor_fracture` | `gas_prop.stress_factor_fracture` | `multi_component_flow.m` | 1,2,3 | yes | Present in case-specific flow files |
| `flow.multi_component.gas_prop.stress_factor_matrix` | `gas_prop.stress_factor_matrix` | `multi_component_flow.m` | 1,2,3 | yes | Present in case-specific flow files |
| `flow.multi_component.gas_prop.stress_factor_ref_pressure` | `gas_prop.stress_factor_ref_pressure` | `multi_component_flow.m` | 1,2,3 | yes | Present in case-specific flow files |
| `flow.multi_component.gas_prop.beta_non_darcy_flow` | `gas_prop.beta_non_Darcy_flow` | `multi_component_flow.m` | 1,2,3 | yes | Non-Darcy coefficient |
| `flow.multi_component.density_g_sc` | `density_g_sc` | `multi_component_flow.m` | 1,2,3 | yes | Standard density |
| `flow.multi_component.gas_model` | `gas_model` | `multi_component_flow.m` | 1,2,3 | yes | 1 generated, 2 tabulated |
| `flow.multi_component.prg` | `prg` | `multi_component_flow.m` | 1,2,3 | yes | Ref pressure |
| `flow.multi_component.Bgi` | `Bgi` | `multi_component_flow.m` | 1,2,3 | yes | Volume factor |
| `flow.multi_component.cg` | `cg` | `multi_component_flow.m` | 1,2,3 | yes | Compressibility |
| `flow.multi_component.vgi` | `vgi` | `multi_component_flow.m` | 1,2,3 | yes | Viscosity |
| `flow.multi_component.cvg` | `cvg` | `multi_component_flow.m` | 1,2,3 | yes | Viscosity-pressure coefficient |
| `flow.multi_component.Ppr` | `Ppr` | `multi_component_flow.m` | 1,2,3 | yes | Table or generated |
| `flow.multi_component.BG` | `BG` | `multi_component_flow.m` | 1,2,3 | yes | Table or generated |
| `flow.multi_component.MUG` | `MUG` | `multi_component_flow.m` | 1,2,3 | yes | Table or generated |
| `flow.multi_component.density_w_sc` | `density_w_sc` | `multi_component_flow.m` | 1,2,3 | yes | Water density |
| `flow.multi_component.prw` | `prw` | `multi_component_flow.m` | 1,2,3 | yes | Water ref pressure |
| `flow.multi_component.Bwi` | `Bwi` | `multi_component_flow.m` | 1,2,3 | yes | Water volume factor |
| `flow.multi_component.cw` | `cw` | `multi_component_flow.m` | 1,2,3 | yes | Water compressibility |
| `flow.multi_component.vwi` | `vwi` | `multi_component_flow.m` | 1,2,3 | yes | Water viscosity |
| `flow.multi_component.cvw` | `cvw` | `multi_component_flow.m` | 1,2,3 | yes | Water viscosity-pressure coefficient |
| `flow.multi_component.number_state_variables` | `number_state_variables` | `multi_component_flow.m` | 1,2,3 | no | Fixed as 4 in current code |
## Initial Conditions
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `initial.pressure` | `P` | flow files | 1-7 | yes | Initial pressure array |
| `initial.sw` | `Sw` | flow files | 1-7 | yes | Initial water saturation array |
| `initial.cs` | `Cs` | `multi_component_flow.m` | 1,2,3 | yes | Initial surfactant concentration |
| `initial.cb` | `Cb` | `multi_component_flow.m` | 1,2,3 | yes | Initial salt concentration |
## Wells
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `wells.well1` | `well1` | `main1.m` | 1-7 | yes | Conventional wells table |
| `wells.num_fracture_wells` | `num_fracture_wells` | `main1.m` | 1-7 | yes | Count |
| `wells.welloc` | `welloc` | `main1.m` | 1-7 | yes | Fracture well coordinates |
| `wells.perfnum` | `perfnum` | helper output | 1-7 | no | Derived from `findWelloc` |
| `wells.well2` | `well2` | `main1.m` | 1-7 | yes | Fracture-well table |
| `wells.Wellc` | `Wellc` | helper output | 1-7 | no | Combined runtime structure |
Conventional well row shape:
- well name
- perforation count
- perforation grid index matrix
- well radius
- skin
- well type
Fracture-well row shape:
- well name
- perforation count
- perforation indices
- well radius
- skin
- well type
## Schedule
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `schedule.number_phases` | `number_phases` | `main1.m` | 1-7 | yes | Stage count |
| `schedule.well_schedules` | `well_schedules` | `main1.m` | 1-7 | yes | Per-stage control rows |
| `schedule.time` | `time` | `main1.m` | 1-7 | yes | Stage duration vector |
| `schedule.dtmax` | `dtmax` | `main1.m` | 1-7 | yes | Max timestep per stage |
| `schedule.dtmin` | `dtmin` | `main1.m` | 1-7 | yes | Min timestep per stage |
Schedule row fields observed:
- well name
- well state
- well role
- control mode
- target value 1
- target value 2
- optional `Cs_inj`
- optional `Cb_inj`
## Solver
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `solver.yitap` | `yitap` | `main1.m` | 1-7 | yes | Adaptive timestep control |
| `solver.yitas` | `yitas` | `main1.m` | 1-7 | yes | Adaptive timestep control |
| `solver.omega` | `omega` | `main1.m` | 1-7 | yes | Adaptive timestep control |
| `solver.Nmax` | `Nmax` | `main1.m` | 1-7 | yes | Max Newton iterations |
| `solver.epsave` | `epsave` | `main1.m` | 1-7 | yes | Average residual tolerance |
| `solver.epsmax` | `epsmax` | `main1.m` | 1-7 | yes | Max residual tolerance |
## Runtime / Output
| Config Path | Source Variable | Source File | Cases | Editable | Notes |
| --- | --- | --- | --- | --- | --- |
| `output.result_name` | none | future GUI | all | yes | Result label |
| `output.save_input_path` | none | future GUI | all | yes | Save location |
| `output.save_result_path` | none | future GUI | all | yes | Save location |
| `output.plot_requests` | none | future GUI | all | yes | Requested result plots |
Runtime-only outputs:
- `Times`
- `OutputRs`
- `Wellpara`
- `trun`
## Known Inconsistencies To Normalize
- `rock_density` and `density_rock` are both used in SP discretization files.
- Some fields are editable expressions in one case and constant arrays in another, especially `kx`, `ky`, `kz`, and `pori`.
- `boundary` exists in case 1 but not in the other SP examples.
- DP mode introduces extra fields absent from SP mode.
These inconsistencies are exactly why the GUI must be built on a normalized `config` instead of the raw scripts.
+369
View File
@@ -0,0 +1,369 @@
# EDFM GUI Project Status Overview
## Project Goal
Build a MATLAB GUI for the existing EDFM simulator so that users can:
- edit simulation parameters through a graphical interface
- load and save input configurations
- run the solver from the GUI
- view run status and basic results
- import and export results
- eventually call existing plotting functions from the result page
The current solver code already exists.
The main work is:
1. extracting and organizing parameters from the existing case scripts and helper files
2. building a GUI around a unified configuration format and runtime entry point
## Functional Scope Agreed So Far
### GUI Structure
The GUI should be organized by the `Part1` to `Part8` logic already present in the case `main1.m` files.
Recommended page split:
- `Part1 模型`
- `Part2 网格`
- `Part3 裂缝`
- `Part4 离散化/岩性`
- `Part5 流动模型`
- `Part6 井与制度`
- `Part7 求解器`
- `结果`
There is also a top toolbar for:
- template loading
- config import/export
- run
- result import/export
### Data Management
The main editable runtime format is now defined as MATLAB `struct`.
Current persistence direction:
- config import/export: `.mat`
- result import/export: `.mat`
JSON is not the current priority.
It can be added later if needed.
### Runtime Model Handling
The three flow models are mutually exclusive:
- `1`: gas-water
- `2`: oil-water
- `3`: multi-component
The GUI should only show the active flow model's parameters.
Inactive model parameters should not be shown or used during runtime.
## What Has Been Completed
## 1. Parameter extraction and organization
The repository has been reviewed across:
- all 7 example case folders
- `main1.m`
- `GridProp_pre.m`
- `grid_discretization_SP_model.m`
- `grid_discretization_DP_model.m`
- `gas_water_flow.m`
- `oil_water_flow.m`
- `multi_component_flow.m`
- solver entry and main runtime functions
Completed documents:
- [`gui_parameter_plan.md`](C:\Users\Administrator\Videos\3D_EDFM_simulator_20260305\docs\gui_parameter_plan.md)
- [`case_template_summary.md`](C:\Users\Administrator\Videos\3D_EDFM_simulator_20260305\docs\case_template_summary.md)
- [`parameter_registry.md`](C:\Users\Administrator\Videos\3D_EDFM_simulator_20260305\docs\parameter_registry.md)
These already cover:
- overall GUI architecture
- 7-case summary
- field-level parameter registry
- separation of editable parameters and derived runtime fields
## 2. Unified config skeleton
Created:
- [`create_empty_config.m`](C:\Users\Administrator\Videos\3D_EDFM_simulator_20260305\gui_support\config\create_empty_config.m)
Current config structure includes:
- `meta`
- `model`
- `grid`
- `fracture`
- `discretization`
- `flow`
- `initial`
- `wells`
- `schedule`
- `solver`
- `output`
It now includes all major editable parameter groups identified so far.
## 3. Config and result MAT import/export helpers
Created:
- [`load_config_mat.m`](C:\Users\Administrator\Videos\3D_EDFM_simulator_20260305\gui_support\config\load_config_mat.m)
- [`save_config_mat.m`](C:\Users\Administrator\Videos\3D_EDFM_simulator_20260305\gui_support\config\save_config_mat.m)
- [`load_results_mat.m`](C:\Users\Administrator\Videos\3D_EDFM_simulator_20260305\gui_support\results\load_results_mat.m)
- [`save_results_mat.m`](C:\Users\Administrator\Videos\3D_EDFM_simulator_20260305\gui_support\results\save_results_mat.m)
## 4. Unified runtime entry point
Created:
- [`run_case.m`](C:\Users\Administrator\Videos\3D_EDFM_simulator_20260305\gui_support\runtime\run_case.m)
This is now the intended runtime entry point instead of calling each case's `main1.m` directly.
Current status:
- grid preprocessing is routed through unified config
- fracture inputs are routed through unified config
- well and schedule setup are routed through unified config
- solver invocation is routed through unified config
- all three `flow_model` branches are now supported through the unified runtime path
## 5. First template support
Created:
- [`load_case_template.m`](C:\Users\Administrator\Videos\3D_EDFM_simulator_20260305\gui_support\templates\load_case_template.m)
- [`load_case_template_case01.m`](C:\Users\Administrator\Videos\3D_EDFM_simulator_20260305\gui_support\templates\load_case_template_case01.m)
Current template coverage:
- `case01`
This is enough to validate the unified config and runtime direction, but not yet enough for final GUI delivery.
## 6. App Designer direction clarified
Important conclusion:
- a pure `.m` app class is not the right final form for this project if the user wants to edit the GUI in MATLAB App Designer
- the final GUI should be built as a real `.mlapp`
- the current recommended workflow is:
- manually draw the layout in App Designer
- keep stable component names
- then bind code to those components
## What Still Needs To Be Done
## 1. Draw the real `.mlapp` interface
This is the next main task.
Need to complete:
- top toolbar
- all main tabs
- model-specific sub-tabs or dynamic sections
- all editable controls
- result page layout
The drawing guide has been prepared conceptually, but the actual `.mlapp` still needs to be built manually in App Designer.
## 2. Bind `.mlapp` code to existing backend
After the UI is drawn, code still needs to be connected for:
- startup default config loading
- template switching
- config import/export
- result import/export
- reading values from controls into `config`
- writing `config` back into controls
- calling `run_case(config)`
- refreshing result plots
## 3. Expand template coverage
Currently only `case01` has a template loader.
Still needed:
- `case02`
- `case03`
- `case04`
- `case05`
- `case06`
- `case07`
These should eventually all become presets in the GUI.
## 4. Strengthen flow-model config coverage
The unified runtime path now supports all three model branches, but more practical work is still needed:
- make sure default template values are complete for each model
- validate that GUI fields map cleanly to backend config fields
- ensure inactive model fields do not interfere with execution
## 5. Improve editing experience for complex parameters
Right now, many large arrays or nested cell structures are still best represented as text expressions.
This is acceptable for early integration but not ideal for end users.
Likely future upgrades:
- use `UITable` for well definitions
- use `UITable` for schedules
- use `UITable` for fracture engineering input
- use dedicated table editors for relperm/PVT/adsorption data
## 6. Results page enhancement
The final result page should support:
- summary text
- well response curves
- Newton-vs-time or runtime diagnostics
- 2D and 3D plots
- selected existing post-processing functions
This is only partially addressed so far.
## Hard Parts
## 1. Parameters are not only in `main1.m`
This is the biggest structural difficulty.
Important parameters are scattered across:
- case `main1.m`
- grid preprocessing files
- SP/DP discretization files
- physics setup files
- solver-related helper files
This makes GUI extraction error-prone if only entry scripts are inspected.
## 2. Same function names appear in multiple case folders
Several case folders contain same-named files such as:
- `grid_discretization_SP_model.m`
- `multi_component_flow.m`
This means runtime path resolution can break if the working directory or MATLAB path is not controlled carefully.
The current backend addresses this by resolving case folders explicitly before running.
## 3. MATLAB App Designer is not Qt-style UI-file driven
Unlike Qt `.ui`, MATLAB `.mlapp` is not a simple open text UI definition format.
This means:
- generating App Designer GUI purely by external text editing is unreliable
- manual drawing inside App Designer is the safer workflow
## 4. Complex data entry is awkward in basic controls
Several parameters are naturally tabular or nested:
- fracture engineering input
- well definitions
- well schedules
- relperm tables
- adsorption tables
These need careful component choice.
If handled with only `TextArea`, the app will work but will not be user-friendly.
## 5. Encoding and Chinese path issues
Some files and folders contain Chinese names.
Some comments also appear to have encoding issues.
Risks:
- MATLAB string/path handling may be fine, but external tooling and generated code may display garbage text
- hardcoding such paths in generated code is risky
ASCII-safe identifiers and runtime folder resolution are preferred where possible.
## Easy-To-Break Areas
## 1. Component naming drift
If the `.mlapp` component names are changed casually after backend code is written, callbacks and data binding will break quickly.
Recommendation:
- finalize component names early
- keep names stable
## 2. Array/cell parsing from UI text
If text areas are used for MATLAB expressions, malformed input can break parsing.
Examples:
- missing brackets
- malformed cell arrays
- inconsistent row widths
Recommendation:
- use text areas only as an intermediate step
- replace key inputs with `UITable` later
## 3. Flow-model mutual exclusivity
Gas-water, oil-water, and multi-component are mutually exclusive.
If the GUI keeps unrelated fields visible and active, users may edit values that are silently ignored or accidentally used.
Recommendation:
- show only the active model section
- hide or disable the others
## 4. Schedule and well table consistency
The solver expects consistent relations among:
- `well1`
- `welloc`
- `well2`
- `well_schedules`
- `time`
- `dtmin`
- `dtmax`
If the user edits one without updating the others, runtime errors are likely.
## 5. Case-specific discretization assumptions
Case 1 includes irregular boundary polygon logic.
Case 3 uses DP-specific fields.
Other cases use different rock defaults.
If the GUI over-generalizes too early, it may hide case-specific assumptions that are required for correct runs.
## Recommended Next Step
The highest-value next step is:
1. manually build the `.mlapp` layout in App Designer
2. keep component names fixed
3. then connect each page to the existing backend functions and config structure
That is the safest path to a maintainable App Designer application.
+332
View File
@@ -0,0 +1,332 @@
classdef EDFMSimulatorApp < matlab.apps.AppBase
properties (Access = public)
UIFigure matlab.ui.Figure
end
properties (Access = private)
UI struct
Config struct
Results struct
end
methods (Access = private)
function startup(app)
app.Config = load_case_template('case01');
app.Results = struct();
app.refreshUIFromConfig();
app.appendLog('Loaded default template: case01');
app.updateStatus('Ready');
end
function createComponents(app)
app.UIFigure = uifigure('Visible', 'off', 'Name', 'EDFM Simulator App');
app.UIFigure.Position = [100 100 1500 900];
root = uigridlayout(app.UIFigure, [2 1]);
root.RowHeight = {44, '1x'};
top = uigridlayout(root, [1 9]);
top.ColumnWidth = {140, 110, 110, 110, 90, 110, 110, '1x', 180};
app.UI.TemplateDropDown = uidropdown(top, 'Items', {'case01'}, 'Value', 'case01');
app.UI.TemplateDropDown.Layout.Column = 1;
app.UI.LoadTemplateButton = uibutton(top, 'push', 'Text', 'Load Template', ...
'ButtonPushedFcn', @(~,~) app.onLoadTemplate());
app.UI.LoadTemplateButton.Layout.Column = 2;
app.UI.ImportConfigButton = uibutton(top, 'push', 'Text', 'Import Config', ...
'ButtonPushedFcn', @(~,~) app.onImportConfig());
app.UI.ImportConfigButton.Layout.Column = 3;
app.UI.ExportConfigButton = uibutton(top, 'push', 'Text', 'Export Config', ...
'ButtonPushedFcn', @(~,~) app.onExportConfig());
app.UI.ExportConfigButton.Layout.Column = 4;
app.UI.RunButton = uibutton(top, 'push', 'Text', 'Run', ...
'ButtonPushedFcn', @(~,~) app.onRun());
app.UI.RunButton.Layout.Column = 5;
app.UI.ImportResultButton = uibutton(top, 'push', 'Text', 'Import Result', ...
'ButtonPushedFcn', @(~,~) app.onImportResult());
app.UI.ImportResultButton.Layout.Column = 6;
app.UI.ExportResultButton = uibutton(top, 'push', 'Text', 'Export Result', ...
'ButtonPushedFcn', @(~,~) app.onExportResult());
app.UI.ExportResultButton.Layout.Column = 7;
app.UI.StatusLabel = uilabel(top, 'Text', 'Status: Ready', 'HorizontalAlignment', 'right');
app.UI.StatusLabel.Layout.Column = 9;
tabs = uitabgroup(root);
tabs.Layout.Row = 2;
app.UI.Tabs = tabs;
app.UI.Part1Tab = uitab(tabs, 'Title', 'Part1 Model');
app.UI.Part2Tab = uitab(tabs, 'Title', 'Part2 Grid');
app.UI.Part3Tab = uitab(tabs, 'Title', 'Part3 Fracture');
app.UI.Part4Tab = uitab(tabs, 'Title', 'Part4 Discretization');
app.UI.Part5Tab = uitab(tabs, 'Title', 'Part5 Flow');
app.UI.Part6Tab = uitab(tabs, 'Title', 'Part6 Wells');
app.UI.Part7Tab = uitab(tabs, 'Title', 'Part7 Solver');
app.UI.RunTab = uitab(tabs, 'Title', 'Run');
app.UI.ResultTab = uitab(tabs, 'Title', 'Results');
app.buildPart1();
app.buildPart2();
app.buildPart3();
app.buildPart4();
app.buildPart5();
app.buildPart6();
app.buildPart7();
app.buildRunTab();
app.buildResultTab();
app.UIFigure.Visible = 'on';
end
function buildPart1(app)
g = uigridlayout(app.UI.Part1Tab, [4 2]); g.RowHeight = {30,30,30,'1x'}; g.ColumnWidth = {160,'1x'};
uilabel(g, 'Text', 'Model Flag'); app.UI.ModelFlag = uidropdown(g, 'Items', {'1'}); app.UI.ModelFlag.Layout.Column = 2;
lbl = uilabel(g, 'Text', 'Grid Model'); lbl.Layout.Row = 2; lbl.Layout.Column = 1;
app.UI.GridModel = uidropdown(g, 'Items', {'1','2'}); app.UI.GridModel.Layout.Row = 2; app.UI.GridModel.Layout.Column = 2;
lbl = uilabel(g, 'Text', 'Flow Model'); lbl.Layout.Row = 3; lbl.Layout.Column = 1;
app.UI.FlowModel = uidropdown(g, 'Items', {'1','2','3'}); app.UI.FlowModel.Layout.Row = 3; app.UI.FlowModel.Layout.Column = 2;
end
function buildPart2(app)
g = uigridlayout(app.UI.Part2Tab, [4 2]); g.ColumnWidth = {130,'1x'}; g.RowHeight = {100,100,100,'1x'};
app.createAreaField(g, 1, 'dx', 'Dx');
app.createAreaField(g, 2, 'dy', 'Dy');
app.createAreaField(g, 3, 'dz', 'Dz');
app.createAreaField(g, 4, 'ntg', 'NTG');
end
function buildPart3(app)
g = uigridlayout(app.UI.Part3Tab, [5 2]); g.ColumnWidth = {160,'1x'}; g.RowHeight = {30,120,120,120,80};
uilabel(g, 'Text', 'Input Style'); app.UI.InputStyle = uidropdown(g, 'Items', {'1','2','3','4'}); app.UI.InputStyle.Layout.Column = 2;
app.createAreaField(g, 2, 'fractureInput', 'Input Content');
app.createAreaField(g, 3, 'fractureLines', 'Fracture Lines');
app.createAreaField(g, 4, 'fractureHeights', 'Fracture Heights');
app.createAreaField(g, 5, 'flowBarrier', 'Flow Barrier Flags');
end
function buildPart4(app)
g = uigridlayout(app.UI.Part4Tab, [7 2]); g.ColumnWidth = {180,'1x'}; g.RowHeight = {90,60,70,70,70,30,'1x'};
app.createAreaField(g, 1, 'boundary', 'Boundary Polygon');
app.createAreaField(g, 2, 'invalidLayer', 'Invalid Layer');
app.createAreaField(g, 3, 'matrixKx', 'Matrix kx');
app.createAreaField(g, 4, 'matrixKy', 'Matrix ky');
app.createAreaField(g, 5, 'matrixKz', 'Matrix kz');
app.createAreaField(g, 6, 'matrixPori', 'Matrix pori');
panel = uipanel(g); panel.Layout.Row = 7; panel.Layout.Column = 2; sub = uigridlayout(panel, [1 6]);
uilabel(sub, 'Text', 'prpor'); app.UI.MatrixPrpor = uieditfield(sub, 'numeric');
uilabel(sub, 'Text', 'cpor'); app.UI.MatrixCpor = uieditfield(sub, 'numeric');
uilabel(sub, 'Text', 'rho'); app.UI.RockDensity = uieditfield(sub, 'numeric');
end
function buildPart5(app)
g = uigridlayout(app.UI.Part5Tab, [3 1]); g.RowHeight = {100,'1x',120};
init = uipanel(g, 'Title', 'Initial State'); initg = uigridlayout(init, [2 4]);
uilabel(initg, 'Text', 'Pressure'); uilabel(initg, 'Text', 'Sw'); uilabel(initg, 'Text', 'Cs'); uilabel(initg, 'Text', 'Cb');
app.UI.InitialPressure = uieditfield(initg, 'numeric'); app.UI.InitialPressure.Layout.Row = 2;
app.UI.InitialSw = uieditfield(initg, 'numeric'); app.UI.InitialSw.Layout.Row = 2;
app.UI.InitialCs = uieditfield(initg, 'numeric'); app.UI.InitialCs.Layout.Row = 2;
app.UI.InitialCb = uieditfield(initg, 'numeric'); app.UI.InitialCb.Layout.Row = 2;
subtabs = uitabgroup(g);
app.UI.GasTab = uitab(subtabs, 'Title', 'Gas-Water');
app.UI.OilTab = uitab(subtabs, 'Title', 'Oil-Water');
app.UI.MultiTab = uitab(subtabs, 'Title', 'Multi-Component');
app.UI.GasArea = uitextarea(uigridlayout(app.UI.GasTab, [1 1]));
app.UI.OilArea = uitextarea(uigridlayout(app.UI.OilTab, [1 1]));
mg = uigridlayout(app.UI.MultiTab, [2 3]);
app.UI.MultiAdsorption = uitextarea(mg); app.UI.MultiNc = uitextarea(mg); app.UI.MultiPc = uitextarea(mg);
app.UI.MultiKrNoSurf = uitextarea(mg); app.UI.MultiKrSurf = uitextarea(mg); app.UI.MultiNote = uitextarea(mg, 'Editable', 'off', 'Value', {'Active flow model only.'});
hint = uitextarea(g, 'Editable', 'off', 'Value', {'Flow models are mutually exclusive.', 'Only the selected model will be used at run time.'});
hint.Layout.Row = 3;
end
function buildPart6(app)
g = uigridlayout(app.UI.Part6Tab, [4 2]); g.ColumnWidth = {160,'1x'}; g.RowHeight = {110,110,140,'1x'};
app.createAreaField(g, 1, 'well1', 'Well1');
app.createAreaField(g, 2, 'welloc', 'Well Locations');
app.createAreaField(g, 3, 'well2', 'Well2');
p = uipanel(g); p.Layout.Row = 4; p.Layout.Column = 2; sub = uigridlayout(p, [1 4]);
app.UI.ScheduleArea = uitextarea(sub); app.UI.TimeArea = uitextarea(sub); app.UI.DtMinArea = uitextarea(sub); app.UI.DtMaxArea = uitextarea(sub);
lbl = uilabel(g, 'Text', 'Schedule / Time / dt'); lbl.Layout.Row = 4; lbl.Layout.Column = 1;
end
function buildPart7(app)
g = uigridlayout(app.UI.Part7Tab, [2 6]);
names = {'YitaP','YitaS','Omega','Nmax','EpsAve','EpsMax'};
for i = 1:numel(names)
lbl = uilabel(g, 'Text', names{i}); lbl.Layout.Row = 1; lbl.Layout.Column = i;
app.UI.(names{i}) = uieditfield(g, 'numeric');
app.UI.(names{i}).Layout.Row = 2; app.UI.(names{i}).Layout.Column = i;
end
end
function buildRunTab(app)
g = uigridlayout(app.UI.RunTab, [2 1]); g.RowHeight = {40,'1x'};
uibutton(g, 'push', 'Text', 'Run Current Config', 'ButtonPushedFcn', @(~,~) app.onRun());
app.UI.RunLog = uitextarea(g, 'Editable', 'off'); app.UI.RunLog.Layout.Row = 2;
end
function buildResultTab(app)
g = uigridlayout(app.UI.ResultTab, [1 2]); g.ColumnWidth = {360,'1x'};
app.UI.ResultSummary = uitextarea(g, 'Editable', 'off');
app.UI.ResultAxes = uiaxes(g); title(app.UI.ResultAxes, 'Results');
end
function createAreaField(app, parent, row, field_name, label_text)
lbl = uilabel(parent, 'Text', label_text);
lbl.Layout.Row = row;
lbl.Layout.Column = 1;
app.UI.(field_name) = uitextarea(parent);
app.UI.(field_name).Layout.Row = row;
app.UI.(field_name).Layout.Column = 2;
end
function onLoadTemplate(app)
app.Config = load_case_template(app.UI.TemplateDropDown.Value);
app.refreshUIFromConfig();
app.appendLog(['Loaded template: ', app.UI.TemplateDropDown.Value]);
app.updateStatus('Template loaded');
end
function onImportConfig(app)
[f, p] = uigetfile('*.mat', 'Import Config'); if isequal(f, 0), return; end
app.Config = load_config_mat(fullfile(p, f));
app.refreshUIFromConfig();
app.appendLog(['Imported config: ', fullfile(p, f)]);
app.updateStatus('Config imported');
end
function onExportConfig(app)
app.pushUIToConfig();
[f, p] = uiputfile('*.mat', 'Export Config', 'config.mat'); if isequal(f, 0), return; end
save_config_mat(app.Config, fullfile(p, f));
app.appendLog(['Exported config: ', fullfile(p, f)]);
app.updateStatus('Config exported');
end
function onImportResult(app)
[f, p] = uigetfile('*.mat', 'Import Result'); if isequal(f, 0), return; end
app.Results = load_results_mat(fullfile(p, f));
app.refreshResults();
app.updateStatus('Result imported');
end
function onExportResult(app)
if isempty(fieldnames(app.Results)), uialert(app.UIFigure, 'No results available.', 'Export Result'); return; end
[f, p] = uiputfile('*.mat', 'Export Result', 'results.mat'); if isequal(f, 0), return; end
save_results_mat(app.Results, fullfile(p, f));
app.appendLog(['Exported result: ', fullfile(p, f)]);
app.updateStatus('Result exported');
end
function onRun(app)
app.pushUIToConfig();
app.updateStatus('Running');
app.appendLog('Run started');
drawnow;
try
log_text = evalc('[r, Times, OutputRs, Wellpara, trun] = run_case(app.Config);');
app.Results = struct('r', r, 'Times', Times, 'OutputRs', {OutputRs}, 'Wellpara', {Wellpara}, 'trun', trun, 'captured_log', log_text);
app.appendLog(log_text);
app.refreshResults();
app.UI.Tabs.SelectedTab = app.UI.ResultTab;
app.updateStatus('Run completed');
catch ME
app.appendLog(getReport(ME, 'extended', 'hyperlinks', 'off'));
app.updateStatus('Run failed');
uialert(app.UIFigure, ME.message, 'Run Failed');
end
end
function refreshUIFromConfig(app)
c = app.Config;
app.UI.ModelFlag.Value = string(c.model.modelflag);
app.UI.GridModel.Value = string(c.model.grid_model);
app.UI.FlowModel.Value = string(c.model.flow_model);
app.UI.Dx.Value = splitlines(app.toExpr(c.grid.dx)); app.UI.Dy.Value = splitlines(app.toExpr(c.grid.dy)); app.UI.Dz.Value = splitlines(app.toExpr(c.grid.dz)); app.UI.Ntg.Value = splitlines(app.toExpr(c.grid.NTG));
app.UI.InputStyle.Value = string(c.fracture.input_style); app.UI.fractureInput.Value = splitlines(app.toExpr(c.fracture.input_content)); app.UI.fractureLines.Value = splitlines(app.toExpr(c.fracture.fractureLines)); app.UI.fractureHeights.Value = splitlines(app.toExpr(c.fracture.fractureHeights)); app.UI.flowBarrier.Value = splitlines(app.toExpr(c.fracture.flowBarrierFlags));
app.UI.boundary.Value = splitlines(app.toExpr(c.discretization.sp.boundary_polygon)); app.UI.invalidLayer.Value = splitlines(app.toExpr(c.discretization.sp.invalid_layer)); app.UI.matrixKx.Value = splitlines(app.toExpr(c.discretization.sp.matrix.kx)); app.UI.matrixKy.Value = splitlines(app.toExpr(c.discretization.sp.matrix.ky)); app.UI.matrixKz.Value = splitlines(app.toExpr(c.discretization.sp.matrix.kz)); app.UI.matrixPori.Value = splitlines(app.toExpr(c.discretization.sp.matrix.pori));
app.UI.MatrixPrpor.Value = c.discretization.sp.matrix.prpor; app.UI.MatrixCpor.Value = c.discretization.sp.matrix.cpor; app.UI.RockDensity.Value = c.discretization.sp.matrix.rock_density;
app.UI.GasArea.Value = splitlines(app.toExpr(c.flow.gas_water.matrix_relperm_table)); app.UI.OilArea.Value = splitlines(app.toExpr(c.flow.oil_water.matrix_relperm_table)); app.UI.MultiAdsorption.Value = splitlines(app.toExpr(c.flow.multi_component.c_ca_table)); app.UI.MultiNc.Value = splitlines(app.toExpr(c.flow.multi_component.cs_Nc)); app.UI.MultiPc.Value = splitlines(app.toExpr(c.flow.multi_component.PC)); app.UI.MultiKrNoSurf.Value = splitlines(app.toExpr(c.flow.multi_component.kr_nosurf)); app.UI.MultiKrSurf.Value = splitlines(app.toExpr(c.flow.multi_component.kr_surf));
app.UI.InitialPressure.Value = app.scalarValue(c.initial.pressure); app.UI.InitialSw.Value = app.scalarValue(c.initial.sw); app.UI.InitialCs.Value = app.scalarValue(c.initial.cs); app.UI.InitialCb.Value = app.scalarValue(c.initial.cb);
app.UI.well1.Value = splitlines(app.toExpr(c.wells.well1)); app.UI.welloc.Value = splitlines(app.toExpr(c.wells.welloc)); app.UI.well2.Value = splitlines(app.toExpr(c.wells.well2)); app.UI.ScheduleArea.Value = splitlines(app.toExpr(c.schedule.well_schedules)); app.UI.TimeArea.Value = splitlines(app.toExpr(c.schedule.time)); app.UI.DtMinArea.Value = splitlines(app.toExpr(c.schedule.dtmin)); app.UI.DtMaxArea.Value = splitlines(app.toExpr(c.schedule.dtmax));
app.UI.YitaP.Value = c.solver.yitap; app.UI.YitaS.Value = c.solver.yitas; app.UI.Omega.Value = c.solver.omega; app.UI.Nmax.Value = c.solver.Nmax; app.UI.EpsAve.Value = c.solver.epsave; app.UI.EpsMax.Value = c.solver.epsmax;
end
function pushUIToConfig(app)
c = app.Config;
c.model.modelflag = str2double(app.UI.ModelFlag.Value); c.model.grid_model = str2double(app.UI.GridModel.Value); c.model.flow_model = str2double(app.UI.FlowModel.Value);
c.grid.dx = app.parseExpr(app.UI.Dx.Value); c.grid.dy = app.parseExpr(app.UI.Dy.Value); c.grid.dz = app.parseExpr(app.UI.Dz.Value); c.grid.NTG = app.parseExpr(app.UI.Ntg.Value); c.grid.nx = numel(c.grid.dx); c.grid.ny = numel(c.grid.dy); c.grid.nz = numel(c.grid.dz);
c.fracture.input_style = str2double(app.UI.InputStyle.Value); c.fracture.input_content = app.parseExpr(app.UI.fractureInput.Value); c.fracture.fractureLines = app.parseExpr(app.UI.fractureLines.Value); c.fracture.fractureHeights = app.parseExpr(app.UI.fractureHeights.Value); c.fracture.flowBarrierFlags = app.parseExpr(app.UI.flowBarrier.Value);
c.discretization.sp.boundary_polygon = app.parseExpr(app.UI.boundary.Value); c.discretization.sp.invalid_layer = app.parseExpr(app.UI.invalidLayer.Value); c.discretization.sp.matrix.kx = app.parseExpr(app.UI.matrixKx.Value); c.discretization.sp.matrix.ky = app.parseExpr(app.UI.matrixKy.Value); c.discretization.sp.matrix.kz = app.parseExpr(app.UI.matrixKz.Value); c.discretization.sp.matrix.pori = app.parseExpr(app.UI.matrixPori.Value); c.discretization.sp.matrix.prpor = app.UI.MatrixPrpor.Value; c.discretization.sp.matrix.cpor = app.UI.MatrixCpor.Value; c.discretization.sp.matrix.rock_density = app.UI.RockDensity.Value;
c.flow.gas_water.matrix_relperm_table = app.parseExpr(app.UI.GasArea.Value); c.flow.oil_water.matrix_relperm_table = app.parseExpr(app.UI.OilArea.Value); c.flow.multi_component.c_ca_table = app.parseExpr(app.UI.MultiAdsorption.Value); c.flow.multi_component.cs_Nc = app.parseExpr(app.UI.MultiNc.Value); c.flow.multi_component.PC = app.parseExpr(app.UI.MultiPc.Value); c.flow.multi_component.kr_nosurf = app.parseExpr(app.UI.MultiKrNoSurf.Value); c.flow.multi_component.kr_surf = app.parseExpr(app.UI.MultiKrSurf.Value);
c.initial.pressure = app.UI.InitialPressure.Value; c.initial.sw = app.UI.InitialSw.Value; c.initial.cs = app.UI.InitialCs.Value; c.initial.cb = app.UI.InitialCb.Value;
c.wells.well1 = app.parseExpr(app.UI.well1.Value); c.wells.welloc = app.parseExpr(app.UI.welloc.Value); c.wells.num_fracture_wells = numel(c.wells.welloc); c.wells.well2 = app.parseExpr(app.UI.well2.Value);
c.schedule.well_schedules = app.parseExpr(app.UI.ScheduleArea.Value); c.schedule.time = app.parseExpr(app.UI.TimeArea.Value); c.schedule.dtmin = app.parseExpr(app.UI.DtMinArea.Value); c.schedule.dtmax = app.parseExpr(app.UI.DtMaxArea.Value); c.schedule.number_phases = size(c.schedule.well_schedules, 1);
c.solver.yitap = app.UI.YitaP.Value; c.solver.yitas = app.UI.YitaS.Value; c.solver.omega = app.UI.Omega.Value; c.solver.Nmax = app.UI.Nmax.Value; c.solver.epsave = app.UI.EpsAve.Value; c.solver.epsmax = app.UI.EpsMax.Value;
app.Config = c;
end
function refreshResults(app)
if isempty(fieldnames(app.Results)), app.UI.ResultSummary.Value = {'No results loaded.'}; cla(app.UI.ResultAxes); return; end
summary = {};
if isfield(app.Results, 'Times'), summary{end+1} = ['Time steps: ', num2str(numel(app.Results.Times))]; end %#ok<AGROW>
if isfield(app.Results, 'trun') && isstruct(app.Results.trun)
if isfield(app.Results.trun, 'run_time'), summary{end+1} = ['Run time: ', num2str(app.Results.trun.run_time)]; end %#ok<AGROW>
if isfield(app.Results.trun, 'Newton_step'), summary{end+1} = ['Newton steps: ', num2str(app.Results.trun.Newton_step)]; end %#ok<AGROW>
end
app.UI.ResultSummary.Value = summary;
cla(app.UI.ResultAxes);
if isfield(app.Results, 'trun') && isfield(app.Results.trun, 'Newtons_vs_time') && ~isempty(app.Results.trun.Newtons_vs_time)
plot(app.UI.ResultAxes, app.Results.trun.Newtons_vs_time(:,1), app.Results.trun.Newtons_vs_time(:,2), '-o'); title(app.UI.ResultAxes, 'Newtons vs Time'); xlabel(app.UI.ResultAxes, 'Time'); ylabel(app.UI.ResultAxes, 'Newton Count');
elseif isfield(app.Results, 'Times') && ~isempty(app.Results.Times)
plot(app.UI.ResultAxes, app.Results.Times, 1:numel(app.Results.Times), '-o'); title(app.UI.ResultAxes, 'Time Step Index'); xlabel(app.UI.ResultAxes, 'Time'); ylabel(app.UI.ResultAxes, 'Step');
end
end
function appendLog(app, txt)
lines = string(txt); lines = splitlines(lines);
current = string(app.UI.RunLog.Value);
if isequal(current, ""), app.UI.RunLog.Value = cellstr(lines); else, app.UI.RunLog.Value = cellstr([current; lines]); end
end
function updateStatus(app, txt)
app.UI.StatusLabel.Text = ['Status: ', txt];
end
function out = parseExpr(app, lines) %#ok<INUSL>
txt = strtrim(strjoin(string(lines), newline));
if txt == "", out = []; else, out = eval(txt); end %#ok<EVLDIR>
end
function txt = toExpr(app, value) %#ok<INUSL>
if isempty(value), txt = '[]'; return; end
if isnumeric(value) || islogical(value), txt = mat2str(value); return; end
if ischar(value), txt = ['''', strrep(value, '''', ''''''), '''']; return; end
if isstring(value) && isscalar(value), txt = ['''', strrep(char(value), '''', ''''''), '''']; return; end
if iscell(value)
rows = cell(size(value,1),1);
for i = 1:size(value,1)
cols = cell(1,size(value,2));
for j = 1:size(value,2), cols{j} = app.toExpr(value{i,j}); end
rows{i} = strjoin(cols, ', ');
end
txt = ['{', strjoin(rows, [';', newline]), '}']; return;
end
txt = evalc('disp(value)');
end
function value = scalarValue(app, raw) %#ok<INUSL>
if isempty(raw), value = 0; elseif isscalar(raw), value = raw; else, value = raw(1); end
end
end
methods (Access = public)
function app = EDFMSimulatorApp()
createComponents(app);
registerApp(app, app.UIFigure);
runStartupFcn(app, @(~,~) app.startup());
end
function delete(app)
delete(app.UIFigure);
end
end
end
+917
View File
@@ -0,0 +1,917 @@
classdef EDFM_Simulator_App < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
MainGrid matlab.ui.container.GridLayout
TopGrid matlab.ui.container.GridLayout
TemplateDropDown matlab.ui.control.DropDown
LoadTemplateButton matlab.ui.control.Button
ImportConfigButton matlab.ui.control.Button
ExportConfigButton matlab.ui.control.Button
RunButton matlab.ui.control.Button
ImportResultButton matlab.ui.control.Button
ExportResultButton matlab.ui.control.Button
StatusLabel matlab.ui.control.Label
MainTabGroup matlab.ui.container.TabGroup
Part1Tab matlab.ui.container.Tab
Part2Tab matlab.ui.container.Tab
Part3Tab matlab.ui.container.Tab
Part4Tab matlab.ui.container.Tab
Part5Tab matlab.ui.container.Tab
Part6Tab matlab.ui.container.Tab
Part7Tab matlab.ui.container.Tab
RunTab matlab.ui.container.Tab
ResultTab matlab.ui.container.Tab
Part1Grid matlab.ui.container.GridLayout
ModelFlagLabel matlab.ui.control.Label
ModelFlagDropDown matlab.ui.control.DropDown
GridModelLabel matlab.ui.control.Label
GridModelDropDown matlab.ui.control.DropDown
FlowModelLabel matlab.ui.control.Label
FlowModelDropDown matlab.ui.control.DropDown
Part2Grid matlab.ui.container.GridLayout
DxLabel matlab.ui.control.Label
DxTextArea matlab.ui.control.TextArea
DyLabel matlab.ui.control.Label
DyTextArea matlab.ui.control.TextArea
DzLabel matlab.ui.control.Label
DzTextArea matlab.ui.control.TextArea
NTGLabel matlab.ui.control.Label
NTGTextArea matlab.ui.control.TextArea
Part3Grid matlab.ui.container.GridLayout
FractureInputStyleLabel matlab.ui.control.Label
FractureInputStyleDropDown matlab.ui.control.DropDown
FractureInputLabel matlab.ui.control.Label
FractureInputTextArea matlab.ui.control.TextArea
FractureLinesLabel matlab.ui.control.Label
FractureLinesTextArea matlab.ui.control.TextArea
FractureHeightsLabel matlab.ui.control.Label
FractureHeightsTextArea matlab.ui.control.TextArea
FlowBarrierFlagsLabel matlab.ui.control.Label
FlowBarrierFlagsTextArea matlab.ui.control.TextArea
Part4Grid matlab.ui.container.GridLayout
BoundaryLabel matlab.ui.control.Label
BoundaryTextArea matlab.ui.control.TextArea
InvalidLayerLabel matlab.ui.control.Label
InvalidLayerTextArea matlab.ui.control.TextArea
MatrixKxLabel matlab.ui.control.Label
MatrixKxTextArea matlab.ui.control.TextArea
MatrixKyLabel matlab.ui.control.Label
MatrixKyTextArea matlab.ui.control.TextArea
MatrixKzLabel matlab.ui.control.Label
MatrixKzTextArea matlab.ui.control.TextArea
MatrixPoriLabel matlab.ui.control.Label
MatrixPoriTextArea matlab.ui.control.TextArea
MatrixPrporLabel matlab.ui.control.Label
MatrixPrporField matlab.ui.control.NumericEditField
MatrixCporLabel matlab.ui.control.Label
MatrixCporField matlab.ui.control.NumericEditField
RockDensityLabel matlab.ui.control.Label
RockDensityField matlab.ui.control.NumericEditField
FractureKfLabel matlab.ui.control.Label
FractureKfTextArea matlab.ui.control.TextArea
FractureWfLabel matlab.ui.control.Label
FractureWfTextArea matlab.ui.control.TextArea
FracturePorfLabel matlab.ui.control.Label
FracturePorfTextArea matlab.ui.control.TextArea
Part5Grid matlab.ui.container.GridLayout
InitialPanel matlab.ui.container.Panel
InitialGrid matlab.ui.container.GridLayout
InitialPressureLabel matlab.ui.control.Label
InitialPressureField matlab.ui.control.NumericEditField
InitialSwLabel matlab.ui.control.Label
InitialSwField matlab.ui.control.NumericEditField
InitialCsLabel matlab.ui.control.Label
InitialCsField matlab.ui.control.NumericEditField
InitialCbLabel matlab.ui.control.Label
InitialCbField matlab.ui.control.NumericEditField
FlowSubTabGroup matlab.ui.container.TabGroup
GasWaterTab matlab.ui.container.Tab
OilWaterTab matlab.ui.container.Tab
MultiComponentTab matlab.ui.container.Tab
GasWaterGrid matlab.ui.container.GridLayout
GasRelPermLabel matlab.ui.control.Label
GasRelPermTextArea matlab.ui.control.TextArea
GasPVTLabel matlab.ui.control.Label
GasPVTTextArea matlab.ui.control.TextArea
OilWaterGrid matlab.ui.container.GridLayout
OilRelPermLabel matlab.ui.control.Label
OilRelPermTextArea matlab.ui.control.TextArea
OilPVTLabel matlab.ui.control.Label
OilPVTTextArea matlab.ui.control.TextArea
MultiComponentGrid matlab.ui.container.GridLayout
AdsorptionLabel matlab.ui.control.Label
AdsorptionTextArea matlab.ui.control.TextArea
NcTableLabel matlab.ui.control.Label
NcTableTextArea matlab.ui.control.TextArea
KrNoSurfLabel matlab.ui.control.Label
KrNoSurfTextArea matlab.ui.control.TextArea
KrSurfLabel matlab.ui.control.Label
KrSurfTextArea matlab.ui.control.TextArea
PcTableLabel matlab.ui.control.Label
PcTableTextArea matlab.ui.control.TextArea
Part6Grid matlab.ui.container.GridLayout
Well1Label matlab.ui.control.Label
Well1Table matlab.ui.control.Table
FractureWellLocationLabel matlab.ui.control.Label
FractureWellLocationTable matlab.ui.control.Table
Well2Label matlab.ui.control.Label
Well2Table matlab.ui.control.Table
ScheduleLabel matlab.ui.control.Label
ScheduleTable matlab.ui.control.Table
TimeLabel matlab.ui.control.Label
TimeTextArea matlab.ui.control.TextArea
DtMinLabel matlab.ui.control.Label
DtMinTextArea matlab.ui.control.TextArea
DtMaxLabel matlab.ui.control.Label
DtMaxTextArea matlab.ui.control.TextArea
Part7Grid matlab.ui.container.GridLayout
YitaPLabel matlab.ui.control.Label
YitaPField matlab.ui.control.NumericEditField
YitaSLabel matlab.ui.control.Label
YitaSField matlab.ui.control.NumericEditField
OmegaLabel matlab.ui.control.Label
OmegaField matlab.ui.control.NumericEditField
NmaxLabel matlab.ui.control.Label
NmaxField matlab.ui.control.NumericEditField
EpsAveLabel matlab.ui.control.Label
EpsAveField matlab.ui.control.NumericEditField
EpsMaxLabel matlab.ui.control.Label
EpsMaxField matlab.ui.control.NumericEditField
RunGrid matlab.ui.container.GridLayout
RunCurrentConfigButton matlab.ui.control.Button
CurrentStageLabel matlab.ui.control.Label
CurrentTimeLabel matlab.ui.control.Label
CurrentDtLabel matlab.ui.control.Label
RunLogTextArea matlab.ui.control.TextArea
ResultGrid matlab.ui.container.GridLayout
ResultLeftGrid matlab.ui.container.GridLayout
ResultSummaryLabel matlab.ui.control.Label
ResultSummaryTextArea matlab.ui.control.TextArea
ResultTypeLabel matlab.ui.control.Label
ResultTypeDropDown matlab.ui.control.DropDown
PlotResultButton matlab.ui.control.Button
ResultAxes matlab.ui.control.UIAxes
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure and hide until all components are created
app.UIFigure = uifigure('Visible', 'off');
app.UIFigure.Position = [100 100 1500 920];
app.UIFigure.Name = 'EDFM Simulator App';
% Create MainGrid
app.MainGrid = uigridlayout(app.UIFigure);
app.MainGrid.ColumnWidth = {'1x'};
app.MainGrid.RowHeight = {48, '1x'};
app.MainGrid.Padding = [8 8 8 8];
% Create TopGrid
app.TopGrid = uigridlayout(app.MainGrid);
app.TopGrid.Layout.Row = 1;
app.TopGrid.Layout.Column = 1;
app.TopGrid.RowHeight = {'1x'};
app.TopGrid.ColumnWidth = {140, 110, 110, 110, 90, 110, 110, '1x', 180};
app.TopGrid.ColumnSpacing = 8;
app.TopGrid.Padding = [0 0 0 0];
% Create top controls
app.TemplateDropDown = uidropdown(app.TopGrid);
app.TemplateDropDown.Layout.Row = 1;
app.TemplateDropDown.Layout.Column = 1;
app.TemplateDropDown.Items = {'case01'};
app.TemplateDropDown.Value = 'case01';
app.LoadTemplateButton = uibutton(app.TopGrid, 'push');
app.LoadTemplateButton.Layout.Row = 1;
app.LoadTemplateButton.Layout.Column = 2;
app.LoadTemplateButton.Text = 'Load Template';
app.ImportConfigButton = uibutton(app.TopGrid, 'push');
app.ImportConfigButton.Layout.Row = 1;
app.ImportConfigButton.Layout.Column = 3;
app.ImportConfigButton.Text = 'Import Config';
app.ExportConfigButton = uibutton(app.TopGrid, 'push');
app.ExportConfigButton.Layout.Row = 1;
app.ExportConfigButton.Layout.Column = 4;
app.ExportConfigButton.Text = 'Export Config';
app.RunButton = uibutton(app.TopGrid, 'push');
app.RunButton.Layout.Row = 1;
app.RunButton.Layout.Column = 5;
app.RunButton.Text = 'Run';
app.ImportResultButton = uibutton(app.TopGrid, 'push');
app.ImportResultButton.Layout.Row = 1;
app.ImportResultButton.Layout.Column = 6;
app.ImportResultButton.Text = 'Import Result';
app.ExportResultButton = uibutton(app.TopGrid, 'push');
app.ExportResultButton.Layout.Row = 1;
app.ExportResultButton.Layout.Column = 7;
app.ExportResultButton.Text = 'Export Result';
app.StatusLabel = uilabel(app.TopGrid);
app.StatusLabel.Layout.Row = 1;
app.StatusLabel.Layout.Column = 9;
app.StatusLabel.HorizontalAlignment = 'right';
app.StatusLabel.Text = 'Status: Ready';
% Create MainTabGroup
app.MainTabGroup = uitabgroup(app.MainGrid);
app.MainTabGroup.Layout.Row = 2;
app.MainTabGroup.Layout.Column = 1;
% Create tabs
app.Part1Tab = uitab(app.MainTabGroup);
app.Part1Tab.Title = 'Part1 Model';
app.Part2Tab = uitab(app.MainTabGroup);
app.Part2Tab.Title = 'Part2 Grid';
app.Part3Tab = uitab(app.MainTabGroup);
app.Part3Tab.Title = 'Part3 Fracture';
app.Part4Tab = uitab(app.MainTabGroup);
app.Part4Tab.Title = 'Part4 Discretization';
app.Part5Tab = uitab(app.MainTabGroup);
app.Part5Tab.Title = 'Part5 Flow';
app.Part6Tab = uitab(app.MainTabGroup);
app.Part6Tab.Title = 'Part6 Wells';
app.Part7Tab = uitab(app.MainTabGroup);
app.Part7Tab.Title = 'Part7 Solver';
app.RunTab = uitab(app.MainTabGroup);
app.RunTab.Title = 'Run';
app.ResultTab = uitab(app.MainTabGroup);
app.ResultTab.Title = 'Results';
% ---------------- Part1 ----------------
app.Part1Grid = uigridlayout(app.Part1Tab);
app.Part1Grid.ColumnWidth = {180, '1x'};
app.Part1Grid.RowHeight = {32, 32, 32, '1x'};
app.Part1Grid.Padding = [12 12 12 12];
app.ModelFlagLabel = uilabel(app.Part1Grid);
app.ModelFlagLabel.Layout.Row = 1;
app.ModelFlagLabel.Layout.Column = 1;
app.ModelFlagLabel.Text = 'Model Flag';
app.ModelFlagDropDown = uidropdown(app.Part1Grid);
app.ModelFlagDropDown.Layout.Row = 1;
app.ModelFlagDropDown.Layout.Column = 2;
app.ModelFlagDropDown.Items = {'1'};
app.ModelFlagDropDown.Value = '1';
app.GridModelLabel = uilabel(app.Part1Grid);
app.GridModelLabel.Layout.Row = 2;
app.GridModelLabel.Layout.Column = 1;
app.GridModelLabel.Text = 'Grid Model';
app.GridModelDropDown = uidropdown(app.Part1Grid);
app.GridModelDropDown.Layout.Row = 2;
app.GridModelDropDown.Layout.Column = 2;
app.GridModelDropDown.Items = {'1', '2'};
app.GridModelDropDown.Value = '1';
app.FlowModelLabel = uilabel(app.Part1Grid);
app.FlowModelLabel.Layout.Row = 3;
app.FlowModelLabel.Layout.Column = 1;
app.FlowModelLabel.Text = 'Flow Model';
app.FlowModelDropDown = uidropdown(app.Part1Grid);
app.FlowModelDropDown.Layout.Row = 3;
app.FlowModelDropDown.Layout.Column = 2;
app.FlowModelDropDown.Items = {'1', '2', '3'};
app.FlowModelDropDown.Value = '3';
% ---------------- Part2 ----------------
app.Part2Grid = uigridlayout(app.Part2Tab);
app.Part2Grid.ColumnWidth = {140, '1x'};
app.Part2Grid.RowHeight = {110, 110, 110, '1x'};
app.Part2Grid.Padding = [12 12 12 12];
app.DxLabel = uilabel(app.Part2Grid);
app.DxLabel.Layout.Row = 1;
app.DxLabel.Layout.Column = 1;
app.DxLabel.Text = 'dx';
app.DxTextArea = uitextarea(app.Part2Grid);
app.DxTextArea.Layout.Row = 1;
app.DxTextArea.Layout.Column = 2;
app.DyLabel = uilabel(app.Part2Grid);
app.DyLabel.Layout.Row = 2;
app.DyLabel.Layout.Column = 1;
app.DyLabel.Text = 'dy';
app.DyTextArea = uitextarea(app.Part2Grid);
app.DyTextArea.Layout.Row = 2;
app.DyTextArea.Layout.Column = 2;
app.DzLabel = uilabel(app.Part2Grid);
app.DzLabel.Layout.Row = 3;
app.DzLabel.Layout.Column = 1;
app.DzLabel.Text = 'dz';
app.DzTextArea = uitextarea(app.Part2Grid);
app.DzTextArea.Layout.Row = 3;
app.DzTextArea.Layout.Column = 2;
app.NTGLabel = uilabel(app.Part2Grid);
app.NTGLabel.Layout.Row = 4;
app.NTGLabel.Layout.Column = 1;
app.NTGLabel.Text = 'NTG';
app.NTGTextArea = uitextarea(app.Part2Grid);
app.NTGTextArea.Layout.Row = 4;
app.NTGTextArea.Layout.Column = 2;
% ---------------- Part3 ----------------
app.Part3Grid = uigridlayout(app.Part3Tab);
app.Part3Grid.ColumnWidth = {170, '1x'};
app.Part3Grid.RowHeight = {32, 120, 120, 120, 90};
app.Part3Grid.Padding = [12 12 12 12];
app.FractureInputStyleLabel = uilabel(app.Part3Grid);
app.FractureInputStyleLabel.Layout.Row = 1;
app.FractureInputStyleLabel.Layout.Column = 1;
app.FractureInputStyleLabel.Text = 'Input Style';
app.FractureInputStyleDropDown = uidropdown(app.Part3Grid);
app.FractureInputStyleDropDown.Layout.Row = 1;
app.FractureInputStyleDropDown.Layout.Column = 2;
app.FractureInputStyleDropDown.Items = {'1', '2', '3', '4'};
app.FractureInputStyleDropDown.Value = '1';
app.FractureInputLabel = uilabel(app.Part3Grid);
app.FractureInputLabel.Layout.Row = 2;
app.FractureInputLabel.Layout.Column = 1;
app.FractureInputLabel.Text = 'Input Content';
app.FractureInputTextArea = uitextarea(app.Part3Grid);
app.FractureInputTextArea.Layout.Row = 2;
app.FractureInputTextArea.Layout.Column = 2;
app.FractureLinesLabel = uilabel(app.Part3Grid);
app.FractureLinesLabel.Layout.Row = 3;
app.FractureLinesLabel.Layout.Column = 1;
app.FractureLinesLabel.Text = 'Fracture Lines';
app.FractureLinesTextArea = uitextarea(app.Part3Grid);
app.FractureLinesTextArea.Layout.Row = 3;
app.FractureLinesTextArea.Layout.Column = 2;
app.FractureHeightsLabel = uilabel(app.Part3Grid);
app.FractureHeightsLabel.Layout.Row = 4;
app.FractureHeightsLabel.Layout.Column = 1;
app.FractureHeightsLabel.Text = 'Fracture Heights';
app.FractureHeightsTextArea = uitextarea(app.Part3Grid);
app.FractureHeightsTextArea.Layout.Row = 4;
app.FractureHeightsTextArea.Layout.Column = 2;
app.FlowBarrierFlagsLabel = uilabel(app.Part3Grid);
app.FlowBarrierFlagsLabel.Layout.Row = 5;
app.FlowBarrierFlagsLabel.Layout.Column = 1;
app.FlowBarrierFlagsLabel.Text = 'Flow Barrier Flags';
app.FlowBarrierFlagsTextArea = uitextarea(app.Part3Grid);
app.FlowBarrierFlagsTextArea.Layout.Row = 5;
app.FlowBarrierFlagsTextArea.Layout.Column = 2;
% ---------------- Part4 ----------------
app.Part4Grid = uigridlayout(app.Part4Tab);
app.Part4Grid.ColumnWidth = {180, '1x', 180, '1x'};
app.Part4Grid.RowHeight = {90, 60, 90, 90, 90, 32, '1x'};
app.Part4Grid.Padding = [12 12 12 12];
app.BoundaryLabel = uilabel(app.Part4Grid);
app.BoundaryLabel.Layout.Row = 1;
app.BoundaryLabel.Layout.Column = 1;
app.BoundaryLabel.Text = 'Boundary Polygon';
app.BoundaryTextArea = uitextarea(app.Part4Grid);
app.BoundaryTextArea.Layout.Row = 1;
app.BoundaryTextArea.Layout.Column = [2 4];
app.InvalidLayerLabel = uilabel(app.Part4Grid);
app.InvalidLayerLabel.Layout.Row = 2;
app.InvalidLayerLabel.Layout.Column = 1;
app.InvalidLayerLabel.Text = 'Invalid Layer';
app.InvalidLayerTextArea = uitextarea(app.Part4Grid);
app.InvalidLayerTextArea.Layout.Row = 2;
app.InvalidLayerTextArea.Layout.Column = [2 4];
app.MatrixKxLabel = uilabel(app.Part4Grid);
app.MatrixKxLabel.Layout.Row = 3;
app.MatrixKxLabel.Layout.Column = 1;
app.MatrixKxLabel.Text = 'Matrix kx';
app.MatrixKxTextArea = uitextarea(app.Part4Grid);
app.MatrixKxTextArea.Layout.Row = 3;
app.MatrixKxTextArea.Layout.Column = 2;
app.MatrixKyLabel = uilabel(app.Part4Grid);
app.MatrixKyLabel.Layout.Row = 3;
app.MatrixKyLabel.Layout.Column = 3;
app.MatrixKyLabel.Text = 'Matrix ky';
app.MatrixKyTextArea = uitextarea(app.Part4Grid);
app.MatrixKyTextArea.Layout.Row = 3;
app.MatrixKyTextArea.Layout.Column = 4;
app.MatrixKzLabel = uilabel(app.Part4Grid);
app.MatrixKzLabel.Layout.Row = 4;
app.MatrixKzLabel.Layout.Column = 1;
app.MatrixKzLabel.Text = 'Matrix kz';
app.MatrixKzTextArea = uitextarea(app.Part4Grid);
app.MatrixKzTextArea.Layout.Row = 4;
app.MatrixKzTextArea.Layout.Column = 2;
app.MatrixPoriLabel = uilabel(app.Part4Grid);
app.MatrixPoriLabel.Layout.Row = 4;
app.MatrixPoriLabel.Layout.Column = 3;
app.MatrixPoriLabel.Text = 'Matrix pori';
app.MatrixPoriTextArea = uitextarea(app.Part4Grid);
app.MatrixPoriTextArea.Layout.Row = 4;
app.MatrixPoriTextArea.Layout.Column = 4;
app.FractureKfLabel = uilabel(app.Part4Grid);
app.FractureKfLabel.Layout.Row = 5;
app.FractureKfLabel.Layout.Column = 1;
app.FractureKfLabel.Text = 'Fracture Kf';
app.FractureKfTextArea = uitextarea(app.Part4Grid);
app.FractureKfTextArea.Layout.Row = 5;
app.FractureKfTextArea.Layout.Column = 2;
app.FractureWfLabel = uilabel(app.Part4Grid);
app.FractureWfLabel.Layout.Row = 5;
app.FractureWfLabel.Layout.Column = 3;
app.FractureWfLabel.Text = 'Fracture Wf';
app.FractureWfTextArea = uitextarea(app.Part4Grid);
app.FractureWfTextArea.Layout.Row = 5;
app.FractureWfTextArea.Layout.Column = 4;
app.MatrixPrporLabel = uilabel(app.Part4Grid);
app.MatrixPrporLabel.Layout.Row = 6;
app.MatrixPrporLabel.Layout.Column = 1;
app.MatrixPrporLabel.Text = 'Matrix prpor';
app.MatrixPrporField = uieditfield(app.Part4Grid, 'numeric');
app.MatrixPrporField.Layout.Row = 6;
app.MatrixPrporField.Layout.Column = 2;
app.MatrixCporLabel = uilabel(app.Part4Grid);
app.MatrixCporLabel.Layout.Row = 6;
app.MatrixCporLabel.Layout.Column = 3;
app.MatrixCporLabel.Text = 'Matrix cpor';
app.MatrixCporField = uieditfield(app.Part4Grid, 'numeric');
app.MatrixCporField.Layout.Row = 6;
app.MatrixCporField.Layout.Column = 4;
app.RockDensityLabel = uilabel(app.Part4Grid);
app.RockDensityLabel.Layout.Row = 7;
app.RockDensityLabel.Layout.Column = 1;
app.RockDensityLabel.Text = 'Rock Density';
app.RockDensityField = uieditfield(app.Part4Grid, 'numeric');
app.RockDensityField.Layout.Row = 7;
app.RockDensityField.Layout.Column = 2;
app.FracturePorfLabel = uilabel(app.Part4Grid);
app.FracturePorfLabel.Layout.Row = 7;
app.FracturePorfLabel.Layout.Column = 3;
app.FracturePorfLabel.Text = 'Fracture Porf';
app.FracturePorfTextArea = uitextarea(app.Part4Grid);
app.FracturePorfTextArea.Layout.Row = 7;
app.FracturePorfTextArea.Layout.Column = 4;
% ---------------- Part5 ----------------
app.Part5Grid = uigridlayout(app.Part5Tab);
app.Part5Grid.ColumnWidth = {'1x'};
app.Part5Grid.RowHeight = {110, '1x'};
app.Part5Grid.Padding = [12 12 12 12];
app.InitialPanel = uipanel(app.Part5Grid);
app.InitialPanel.Layout.Row = 1;
app.InitialPanel.Layout.Column = 1;
app.InitialPanel.Title = 'Initial State';
app.InitialGrid = uigridlayout(app.InitialPanel);
app.InitialGrid.ColumnWidth = {120, 120, 120, 120};
app.InitialGrid.RowHeight = {26, 32};
app.InitialPressureLabel = uilabel(app.InitialGrid);
app.InitialPressureLabel.Layout.Row = 1;
app.InitialPressureLabel.Layout.Column = 1;
app.InitialPressureLabel.Text = 'Pressure';
app.InitialPressureField = uieditfield(app.InitialGrid, 'numeric');
app.InitialPressureField.Layout.Row = 2;
app.InitialPressureField.Layout.Column = 1;
app.InitialSwLabel = uilabel(app.InitialGrid);
app.InitialSwLabel.Layout.Row = 1;
app.InitialSwLabel.Layout.Column = 2;
app.InitialSwLabel.Text = 'Sw';
app.InitialSwField = uieditfield(app.InitialGrid, 'numeric');
app.InitialSwField.Layout.Row = 2;
app.InitialSwField.Layout.Column = 2;
app.InitialCsLabel = uilabel(app.InitialGrid);
app.InitialCsLabel.Layout.Row = 1;
app.InitialCsLabel.Layout.Column = 3;
app.InitialCsLabel.Text = 'Cs';
app.InitialCsField = uieditfield(app.InitialGrid, 'numeric');
app.InitialCsField.Layout.Row = 2;
app.InitialCsField.Layout.Column = 3;
app.InitialCbLabel = uilabel(app.InitialGrid);
app.InitialCbLabel.Layout.Row = 1;
app.InitialCbLabel.Layout.Column = 4;
app.InitialCbLabel.Text = 'Cb';
app.InitialCbField = uieditfield(app.InitialGrid, 'numeric');
app.InitialCbField.Layout.Row = 2;
app.InitialCbField.Layout.Column = 4;
app.FlowSubTabGroup = uitabgroup(app.Part5Grid);
app.FlowSubTabGroup.Layout.Row = 2;
app.FlowSubTabGroup.Layout.Column = 1;
app.GasWaterTab = uitab(app.FlowSubTabGroup);
app.GasWaterTab.Title = 'Gas-Water';
app.OilWaterTab = uitab(app.FlowSubTabGroup);
app.OilWaterTab.Title = 'Oil-Water';
app.MultiComponentTab = uitab(app.FlowSubTabGroup);
app.MultiComponentTab.Title = 'Multi-Component';
app.GasWaterGrid = uigridlayout(app.GasWaterTab);
app.GasWaterGrid.ColumnWidth = {180, '1x'};
app.GasWaterGrid.RowHeight = {140, '1x'};
app.GasWaterGrid.Padding = [12 12 12 12];
app.GasRelPermLabel = uilabel(app.GasWaterGrid);
app.GasRelPermLabel.Layout.Row = 1;
app.GasRelPermLabel.Layout.Column = 1;
app.GasRelPermLabel.Text = 'Gas RelPerm Table';
app.GasRelPermTextArea = uitextarea(app.GasWaterGrid);
app.GasRelPermTextArea.Layout.Row = 1;
app.GasRelPermTextArea.Layout.Column = 2;
app.GasPVTLabel = uilabel(app.GasWaterGrid);
app.GasPVTLabel.Layout.Row = 2;
app.GasPVTLabel.Layout.Column = 1;
app.GasPVTLabel.Text = 'Gas PVT Text';
app.GasPVTTextArea = uitextarea(app.GasWaterGrid);
app.GasPVTTextArea.Layout.Row = 2;
app.GasPVTTextArea.Layout.Column = 2;
app.OilWaterGrid = uigridlayout(app.OilWaterTab);
app.OilWaterGrid.ColumnWidth = {180, '1x'};
app.OilWaterGrid.RowHeight = {140, '1x'};
app.OilWaterGrid.Padding = [12 12 12 12];
app.OilRelPermLabel = uilabel(app.OilWaterGrid);
app.OilRelPermLabel.Layout.Row = 1;
app.OilRelPermLabel.Layout.Column = 1;
app.OilRelPermLabel.Text = 'Oil RelPerm Table';
app.OilRelPermTextArea = uitextarea(app.OilWaterGrid);
app.OilRelPermTextArea.Layout.Row = 1;
app.OilRelPermTextArea.Layout.Column = 2;
app.OilPVTLabel = uilabel(app.OilWaterGrid);
app.OilPVTLabel.Layout.Row = 2;
app.OilPVTLabel.Layout.Column = 1;
app.OilPVTLabel.Text = 'Oil PVT Text';
app.OilPVTTextArea = uitextarea(app.OilWaterGrid);
app.OilPVTTextArea.Layout.Row = 2;
app.OilPVTTextArea.Layout.Column = 2;
app.MultiComponentGrid = uigridlayout(app.MultiComponentTab);
app.MultiComponentGrid.ColumnWidth = {180, '1x', 180, '1x'};
app.MultiComponentGrid.RowHeight = {120, 120, 120};
app.MultiComponentGrid.Padding = [12 12 12 12];
app.AdsorptionLabel = uilabel(app.MultiComponentGrid);
app.AdsorptionLabel.Layout.Row = 1;
app.AdsorptionLabel.Layout.Column = 1;
app.AdsorptionLabel.Text = 'Adsorption Table';
app.AdsorptionTextArea = uitextarea(app.MultiComponentGrid);
app.AdsorptionTextArea.Layout.Row = 1;
app.AdsorptionTextArea.Layout.Column = 2;
app.NcTableLabel = uilabel(app.MultiComponentGrid);
app.NcTableLabel.Layout.Row = 1;
app.NcTableLabel.Layout.Column = 3;
app.NcTableLabel.Text = 'Nc Table';
app.NcTableTextArea = uitextarea(app.MultiComponentGrid);
app.NcTableTextArea.Layout.Row = 1;
app.NcTableTextArea.Layout.Column = 4;
app.KrNoSurfLabel = uilabel(app.MultiComponentGrid);
app.KrNoSurfLabel.Layout.Row = 2;
app.KrNoSurfLabel.Layout.Column = 1;
app.KrNoSurfLabel.Text = 'Kr No Surf';
app.KrNoSurfTextArea = uitextarea(app.MultiComponentGrid);
app.KrNoSurfTextArea.Layout.Row = 2;
app.KrNoSurfTextArea.Layout.Column = 2;
app.KrSurfLabel = uilabel(app.MultiComponentGrid);
app.KrSurfLabel.Layout.Row = 2;
app.KrSurfLabel.Layout.Column = 3;
app.KrSurfLabel.Text = 'Kr Surf';
app.KrSurfTextArea = uitextarea(app.MultiComponentGrid);
app.KrSurfTextArea.Layout.Row = 2;
app.KrSurfTextArea.Layout.Column = 4;
app.PcTableLabel = uilabel(app.MultiComponentGrid);
app.PcTableLabel.Layout.Row = 3;
app.PcTableLabel.Layout.Column = 1;
app.PcTableLabel.Text = 'Pc Table';
app.PcTableTextArea = uitextarea(app.MultiComponentGrid);
app.PcTableTextArea.Layout.Row = 3;
app.PcTableTextArea.Layout.Column = [2 4];
% ---------------- Part6 ----------------
app.Part6Grid = uigridlayout(app.Part6Tab);
app.Part6Grid.ColumnWidth = {180, '1x'};
app.Part6Grid.RowHeight = {120, 120, 120, 160, 80, 80, '1x'};
app.Part6Grid.Padding = [12 12 12 12];
app.Well1Label = uilabel(app.Part6Grid);
app.Well1Label.Layout.Row = 1;
app.Well1Label.Layout.Column = 1;
app.Well1Label.Text = 'Well1';
app.Well1Table = uitable(app.Part6Grid);
app.Well1Table.Layout.Row = 1;
app.Well1Table.Layout.Column = 2;
app.FractureWellLocationLabel = uilabel(app.Part6Grid);
app.FractureWellLocationLabel.Layout.Row = 2;
app.FractureWellLocationLabel.Layout.Column = 1;
app.FractureWellLocationLabel.Text = 'Fracture Well Locations';
app.FractureWellLocationTable = uitable(app.Part6Grid);
app.FractureWellLocationTable.Layout.Row = 2;
app.FractureWellLocationTable.Layout.Column = 2;
app.Well2Label = uilabel(app.Part6Grid);
app.Well2Label.Layout.Row = 3;
app.Well2Label.Layout.Column = 1;
app.Well2Label.Text = 'Well2';
app.Well2Table = uitable(app.Part6Grid);
app.Well2Table.Layout.Row = 3;
app.Well2Table.Layout.Column = 2;
app.ScheduleLabel = uilabel(app.Part6Grid);
app.ScheduleLabel.Layout.Row = 4;
app.ScheduleLabel.Layout.Column = 1;
app.ScheduleLabel.Text = 'Schedule';
app.ScheduleTable = uitable(app.Part6Grid);
app.ScheduleTable.Layout.Row = 4;
app.ScheduleTable.Layout.Column = 2;
app.TimeLabel = uilabel(app.Part6Grid);
app.TimeLabel.Layout.Row = 5;
app.TimeLabel.Layout.Column = 1;
app.TimeLabel.Text = 'Time';
app.TimeTextArea = uitextarea(app.Part6Grid);
app.TimeTextArea.Layout.Row = 5;
app.TimeTextArea.Layout.Column = 2;
app.DtMinLabel = uilabel(app.Part6Grid);
app.DtMinLabel.Layout.Row = 6;
app.DtMinLabel.Layout.Column = 1;
app.DtMinLabel.Text = 'dtmin';
app.DtMinTextArea = uitextarea(app.Part6Grid);
app.DtMinTextArea.Layout.Row = 6;
app.DtMinTextArea.Layout.Column = 2;
app.DtMaxLabel = uilabel(app.Part6Grid);
app.DtMaxLabel.Layout.Row = 7;
app.DtMaxLabel.Layout.Column = 1;
app.DtMaxLabel.Text = 'dtmax';
app.DtMaxTextArea = uitextarea(app.Part6Grid);
app.DtMaxTextArea.Layout.Row = 7;
app.DtMaxTextArea.Layout.Column = 2;
% ---------------- Part7 ----------------
app.Part7Grid = uigridlayout(app.Part7Tab);
app.Part7Grid.ColumnWidth = {100, 100, 100, 100, 100, 100};
app.Part7Grid.RowHeight = {26, 32, '1x'};
app.Part7Grid.Padding = [12 12 12 12];
app.YitaPLabel = uilabel(app.Part7Grid);
app.YitaPLabel.Layout.Row = 1;
app.YitaPLabel.Layout.Column = 1;
app.YitaPLabel.Text = 'yitap';
app.YitaPField = uieditfield(app.Part7Grid, 'numeric');
app.YitaPField.Layout.Row = 2;
app.YitaPField.Layout.Column = 1;
app.YitaSLabel = uilabel(app.Part7Grid);
app.YitaSLabel.Layout.Row = 1;
app.YitaSLabel.Layout.Column = 2;
app.YitaSLabel.Text = 'yitas';
app.YitaSField = uieditfield(app.Part7Grid, 'numeric');
app.YitaSField.Layout.Row = 2;
app.YitaSField.Layout.Column = 2;
app.OmegaLabel = uilabel(app.Part7Grid);
app.OmegaLabel.Layout.Row = 1;
app.OmegaLabel.Layout.Column = 3;
app.OmegaLabel.Text = 'omega';
app.OmegaField = uieditfield(app.Part7Grid, 'numeric');
app.OmegaField.Layout.Row = 2;
app.OmegaField.Layout.Column = 3;
app.NmaxLabel = uilabel(app.Part7Grid);
app.NmaxLabel.Layout.Row = 1;
app.NmaxLabel.Layout.Column = 4;
app.NmaxLabel.Text = 'Nmax';
app.NmaxField = uieditfield(app.Part7Grid, 'numeric');
app.NmaxField.Layout.Row = 2;
app.NmaxField.Layout.Column = 4;
app.EpsAveLabel = uilabel(app.Part7Grid);
app.EpsAveLabel.Layout.Row = 1;
app.EpsAveLabel.Layout.Column = 5;
app.EpsAveLabel.Text = 'epsave';
app.EpsAveField = uieditfield(app.Part7Grid, 'numeric');
app.EpsAveField.Layout.Row = 2;
app.EpsAveField.Layout.Column = 5;
app.EpsMaxLabel = uilabel(app.Part7Grid);
app.EpsMaxLabel.Layout.Row = 1;
app.EpsMaxLabel.Layout.Column = 6;
app.EpsMaxLabel.Text = 'epsmax';
app.EpsMaxField = uieditfield(app.Part7Grid, 'numeric');
app.EpsMaxField.Layout.Row = 2;
app.EpsMaxField.Layout.Column = 6;
% ---------------- RunTab ----------------
app.RunGrid = uigridlayout(app.RunTab);
app.RunGrid.ColumnWidth = {140, 180, 180, '1x'};
app.RunGrid.RowHeight = {36, '1x'};
app.RunGrid.Padding = [12 12 12 12];
app.RunCurrentConfigButton = uibutton(app.RunGrid, 'push');
app.RunCurrentConfigButton.Layout.Row = 1;
app.RunCurrentConfigButton.Layout.Column = 1;
app.RunCurrentConfigButton.Text = 'Run Current Config';
app.CurrentStageLabel = uilabel(app.RunGrid);
app.CurrentStageLabel.Layout.Row = 1;
app.CurrentStageLabel.Layout.Column = 2;
app.CurrentStageLabel.Text = 'Stage: -';
app.CurrentTimeLabel = uilabel(app.RunGrid);
app.CurrentTimeLabel.Layout.Row = 1;
app.CurrentTimeLabel.Layout.Column = 3;
app.CurrentTimeLabel.Text = 'Time: -';
app.CurrentDtLabel = uilabel(app.RunGrid);
app.CurrentDtLabel.Layout.Row = 1;
app.CurrentDtLabel.Layout.Column = 4;
app.CurrentDtLabel.Text = 'dt: -';
app.RunLogTextArea = uitextarea(app.RunGrid);
app.RunLogTextArea.Layout.Row = 2;
app.RunLogTextArea.Layout.Column = [1 4];
app.RunLogTextArea.Editable = 'off';
% ---------------- ResultTab ----------------
app.ResultGrid = uigridlayout(app.ResultTab);
app.ResultGrid.ColumnWidth = {360, '1x'};
app.ResultGrid.RowHeight = {'1x'};
app.ResultGrid.Padding = [12 12 12 12];
app.ResultLeftGrid = uigridlayout(app.ResultGrid);
app.ResultLeftGrid.Layout.Row = 1;
app.ResultLeftGrid.Layout.Column = 1;
app.ResultLeftGrid.ColumnWidth = {'1x'};
app.ResultLeftGrid.RowHeight = {24, 180, 24, 32, 36, '1x'};
app.ResultSummaryLabel = uilabel(app.ResultLeftGrid);
app.ResultSummaryLabel.Layout.Row = 1;
app.ResultSummaryLabel.Layout.Column = 1;
app.ResultSummaryLabel.Text = 'Result Summary';
app.ResultSummaryTextArea = uitextarea(app.ResultLeftGrid);
app.ResultSummaryTextArea.Layout.Row = 2;
app.ResultSummaryTextArea.Layout.Column = 1;
app.ResultSummaryTextArea.Editable = 'off';
app.ResultTypeLabel = uilabel(app.ResultLeftGrid);
app.ResultTypeLabel.Layout.Row = 3;
app.ResultTypeLabel.Layout.Column = 1;
app.ResultTypeLabel.Text = 'Result Type';
app.ResultTypeDropDown = uidropdown(app.ResultLeftGrid);
app.ResultTypeDropDown.Layout.Row = 4;
app.ResultTypeDropDown.Layout.Column = 1;
app.ResultTypeDropDown.Items = {'Time Steps', 'Newtons vs Time'};
app.ResultTypeDropDown.Value = 'Time Steps';
app.PlotResultButton = uibutton(app.ResultLeftGrid, 'push');
app.PlotResultButton.Layout.Row = 5;
app.PlotResultButton.Layout.Column = 1;
app.PlotResultButton.Text = 'Plot Result';
app.ResultAxes = uiaxes(app.ResultGrid);
app.ResultAxes.Layout.Row = 1;
app.ResultAxes.Layout.Column = 2;
title(app.ResultAxes, 'Results');
xlabel(app.ResultAxes, 'X');
ylabel(app.ResultAxes, 'Y');
% Show the figure after all components are created
app.UIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = EDFM_Simulator_App
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end
end
Binary file not shown.
@@ -0,0 +1,5 @@
function app = launch_edfm_simulator_app()
%LAUNCH_EDFM_SIMULATOR_APP Launch the EDFM Simulator App.
startup;
app = EDFMSimulatorApp();
+248
View File
@@ -0,0 +1,248 @@
function config = create_empty_config()
%CREATE_EMPTY_CONFIG Create a unified GUI/runtime config skeleton.
config = struct();
config.meta = struct( ...
'case_name', '', ...
'case_id', '', ...
'description', '', ...
'source_case_folder', '', ...
'created_from_template', '', ...
'version', '0.1');
config.model = struct( ...
'modelflag', 1, ...
'grid_model', 1, ...
'flow_model', 1);
config.grid = struct( ...
'dx', [], ...
'dy', [], ...
'dz', [], ...
'nx', 0, ...
'ny', 0, ...
'nz', 0, ...
'NTG', [], ...
'coordinates', [], ...
'nodes', [], ...
'nP', 0, ...
'nmc', 0, ...
'dxv', [], ...
'dyv', [], ...
'dzv', [], ...
'zm', [], ...
'vm', [], ...
'xrao', [], ...
'yrao', [], ...
'zrao', [], ...
'cell_mid_coords', []);
config.fracture = struct( ...
'input_style', 1, ...
'input_content', {{}}, ...
'f', [], ...
'fellip', [], ...
'fractureLines', [], ...
'fractureHeights', [], ...
'flowBarrierFlags', [], ...
'frac_information', [], ...
'nf', 0);
config.discretization = struct( ...
'mode', 1, ...
'use_operator', true, ...
'sp', struct( ...
'boundary_polygon', [], ...
'invalid_layer', [], ...
'valid_grids', [], ...
'matrix', struct( ...
'kx', [], ...
'ky', [], ...
'kz', [], ...
'pori', [], ...
'prpor', 20, ...
'cpor', 1.0e-5, ...
'rock_density', 2700), ...
'fracture', struct( ...
'Kf', [], ...
'Wf', [], ...
'Porf', [], ...
'prporf', 20, ...
'cporf', 1.0e-5), ...
'stress', struct( ...
'fracture_factor', 0, ...
'matrix_factor', 0, ...
'ref_pressure', 20)), ...
'dp', struct( ...
'valid_grids', [], ...
'NTG', [], ...
'prpor', 20, ...
'cpor', 1.0e-5, ...
'rock_density', 2700, ...
'fracture_layer', struct( ...
'kx', [], ...
'ky', [], ...
'kz', [], ...
'pori', []), ...
'matrix_layer', struct( ...
'kx', [], ...
'ky', [], ...
'kz', [], ...
'pori', []), ...
'shape_factor', [], ...
'fracture', struct( ...
'Kf', [], ...
'Wf', [], ...
'Porf', [], ...
'prporf', 20, ...
'cporf', 1.0e-5), ...
'stress', struct( ...
'fracture_factor', 0, ...
'matrix_factor', 0, ...
'ref_pressure', 20)), ...
'notes', '');
config.flow = struct( ...
'gas_water', struct( ...
'gas_prop', struct( ...
'VL', 0, ...
'PL', 0, ...
'Kn', 0, ...
'Kn_modified_factor', 1, ...
'beta_non_darcy_flow', 0), ...
'p_grad_threshold', 0, ...
'density_g_sc', 0, ...
'density_w_sc', 1000, ...
'gas_model', 1, ...
'prg', [], ...
'Bgi', [], ...
'cg', [], ...
'vgi', [], ...
'cvg', [], ...
'Ppr', [], ...
'BG', [], ...
'MUG', [], ...
'prw', [], ...
'Bwi', [], ...
'cw', [], ...
'vwi', [], ...
'cvw', [], ...
'ifpcgl', 0, ...
'Ppr', [], ...
'BG', [], ...
'MUG', [], ...
'matrix_relperm_table', [], ...
'fracture_relperm_table', []), ...
'oil_water', struct( ...
'density_o_sc', 0, ...
'density_w_sc', 1000, ...
'oil_model', 1, ...
'pro', [], ...
'Boi', [], ...
'co', [], ...
'voi', [], ...
'cvo', [], ...
'Ppr', [], ...
'BO', [], ...
'MUO', [], ...
'prw', [], ...
'Bwi', [], ...
'cw', [], ...
'vwi', [], ...
'cvw', [], ...
'ifpcow', 0, ...
'Ppr', [], ...
'BO', [], ...
'MUO', [], ...
'matrix_relperm_table', [], ...
'fracture_relperm_table', [], ...
'beta_non_darcy_flow', 0, ...
'p_grad_threshold', 0), ...
'multi_component', struct( ...
'Ds', [], ...
'Db', [], ...
'c_ca_table', [], ...
'cs_data', [], ...
'cb_data', [], ...
'csa_data', [], ...
'cba_data', [], ...
'R', [], ...
'Vm', [], ...
'Temperature', [], ...
'chemistry_cof', [], ...
'x_matrix', 0.9, ...
'x_fracture', 1.0, ...
'cs_Nc', [], ...
'Nc_nosurf', [], ...
'Nc_surf', [], ...
'kr_nosurf', [], ...
'kr_surf', [], ...
'PC', [], ...
'cs_Nc_fracture', [], ...
'kr_nosurf_fracture', [], ...
'kr_surf_fracture', [], ...
'PC_fracture', [], ...
'ifpcgl', 0, ...
'p_grad_threshold', 0, ...
'gas_prop', struct( ...
'VL', 0, ...
'PL', 0, ...
'Kn', 0, ...
'Kn_modified_factor', 1, ...
'stress_factor_fracture', 0, ...
'stress_factor_matrix', 0, ...
'stress_factor_ref_pressure', 20, ...
'beta_non_darcy_flow', 0), ...
'density_g_sc', 0, ...
'density_w_sc', 1000, ...
'gas_model', 1, ...
'prg', [], ...
'Bgi', [], ...
'cg', [], ...
'vgi', [], ...
'cvg', [], ...
'Ppr', [], ...
'BG', [], ...
'MUG', [], ...
'prw', [], ...
'Bwi', [], ...
'cw', [], ...
'vwi', [], ...
'cvw', [], ...
'number_state_variables', 4));
config.initial = struct( ...
'pressure', [], ...
'sw', [], ...
'cs', [], ...
'cb', []);
config.wells = struct( ...
'well1', {{}}, ...
'num_fracture_wells', 0, ...
'welloc', {{}}, ...
'perfnum', {{}}, ...
'well2', {{}}, ...
'Wellc', []);
config.schedule = struct( ...
'number_phases', 0, ...
'well_schedules', {{}}, ...
'time', [], ...
'dtmax', [], ...
'dtmin', []);
config.solver = struct( ...
'yitap', 5, ...
'yitas', 0.04, ...
'omega', 0.5, ...
'Nmax', 50, ...
'epsave', 1e-6, ...
'epsmax', 1e-6);
config.output = struct( ...
'save_input_path', '', ...
'save_result_path', '', ...
'result_name', '', ...
'plot_requests', {{}});
+13
View File
@@ -0,0 +1,13 @@
function config = load_config_json(file_path)
%LOAD_CONFIG_JSON Load a config struct from a JSON file.
arguments
file_path (1,:) char
end
if ~exist(file_path, 'file')
error('load_config_json:FileNotFound', 'Config file not found: %s', file_path);
end
json_text = fileread(file_path);
config = jsondecode(json_text);
+18
View File
@@ -0,0 +1,18 @@
function config = load_config_mat(file_path)
%LOAD_CONFIG_MAT Load config struct from a MAT file.
arguments
file_path (1,:) char
end
if ~exist(file_path, 'file')
error('load_config_mat:FileNotFound', 'Config file not found: %s', file_path);
end
data = load(file_path, '-mat');
if ~isfield(data, 'config')
error('load_config_mat:MissingConfigVariable', ...
'MAT file does not contain variable ''config'': %s', file_path);
end
config = data.config;
+21
View File
@@ -0,0 +1,21 @@
function save_config_json(config, file_path)
%SAVE_CONFIG_JSON Save a config struct to a JSON file.
arguments
config (1,1) struct
file_path (1,:) char
end
folder_path = fileparts(file_path);
if ~isempty(folder_path) && ~exist(folder_path, 'dir')
mkdir(folder_path);
end
json_text = jsonencode(config, PrettyPrint=true);
fid = fopen(file_path, 'w');
if fid == -1
error('save_config_json:FileOpenFailed', 'Cannot open file: %s', file_path);
end
cleanup_obj = onCleanup(@() fclose(fid));
fprintf(fid, '%s', json_text);
+14
View File
@@ -0,0 +1,14 @@
function save_config_mat(config, file_path)
%SAVE_CONFIG_MAT Save config struct to a MAT file.
arguments
config (1,1) struct
file_path (1,:) char
end
folder_path = fileparts(file_path);
if ~isempty(folder_path) && ~exist(folder_path, 'dir')
mkdir(folder_path);
end
save(file_path, 'config', '-mat');
+18
View File
@@ -0,0 +1,18 @@
function results = load_results_mat(file_path)
%LOAD_RESULTS_MAT Load results struct from a MAT file.
arguments
file_path (1,:) char
end
if ~exist(file_path, 'file')
error('load_results_mat:FileNotFound', 'Results file not found: %s', file_path);
end
data = load(file_path, '-mat');
if ~isfield(data, 'results')
error('load_results_mat:MissingResultsVariable', ...
'MAT file does not contain variable ''results'': %s', file_path);
end
results = data.results;
+14
View File
@@ -0,0 +1,14 @@
function save_results_mat(results, file_path)
%SAVE_RESULTS_MAT Save results struct to a MAT file.
arguments
results (1,1) struct
file_path (1,:) char
end
folder_path = fileparts(file_path);
if ~isempty(folder_path) && ~exist(folder_path, 'dir')
mkdir(folder_path);
end
save(file_path, 'results', '-mat');
+413
View File
@@ -0,0 +1,413 @@
function [r, Times, OutputRs, Wellpara, trun] = run_case(config)
%RUN_CASE Execute a simulation from unified config.
%
% This is the first migration step from hard-coded main1.m scripts toward a
% unified GUI entry point. The current implementation is intended to
% reproduce case-template runs while the remaining flow-model internals are
% still being normalized.
arguments
config (1,1) struct
end
project_root = fileparts(fileparts(fileparts(mfilename('fullpath'))));
source_case_folder = resolve_source_case_folder(project_root, config.meta);
if isempty(source_case_folder)
error('run_case:MissingSourceCaseFolder', ...
'config.meta.source_case_folder is required.');
end
if ~isfolder(source_case_folder)
error('run_case:SourceCaseFolderNotFound', ...
'Source case folder not found: %s', source_case_folder);
end
addpath(genpath(project_root));
old_dir = pwd;
cleanup_obj = onCleanup(@() cd(old_dir));
cd(source_case_folder);
overall_tic = tic;
config.grid.nx = numel(config.grid.dx);
config.grid.ny = numel(config.grid.dy);
config.grid.nz = numel(config.grid.dz);
r = GridProp_pre( ...
config.grid.dx, ...
config.grid.dy, ...
config.grid.dz, ...
config.grid.nx, ...
config.grid.ny, ...
config.grid.nz, ...
config.grid.NTG);
[f, fellip, frac_information, nf] = build_fracture_inputs(config.fracture);
modelflag = config.model.modelflag;
grid_model = config.model.grid_model;
flow_model = config.model.flow_model;
if grid_model == 1
r = grid_discretization_SP_model(modelflag, r, f, frac_information, fellip, nf);
elseif grid_model == 2
r = grid_discretization_DP_model(modelflag, r, f, frac_information, fellip, nf);
else
error('run_case:UnsupportedGridModel', 'Unsupported grid model: %d', grid_model);
end
os = OperatorRS(r.N, r.nex, r.nc);
[fluid_model, state0] = build_flow_inputs(flow_model, r, config);
well1 = handle_well1(config.wells.well1, r);
[well2, welloc] = build_fracture_wells(config.wells, r);
Wellc = handle_well1_well2(well1, well2, welloc, r);
[Times, OutputRs, Wellpara, trun] = solver_NR( ...
r, ...
flow_model, ...
fluid_model, ...
os, ...
state0, ...
config.solver.yitap, ...
config.solver.yitas, ...
config.solver.omega, ...
config.solver.Nmax, ...
config.solver.epsave, ...
config.solver.epsmax, ...
config.schedule.dtmin, ...
config.schedule.dtmax, ...
Wellc, ...
config.schedule.time, ...
config.schedule.well_schedules);
trun.run_time = toc(overall_tic);
end
function source_case_folder = resolve_source_case_folder(project_root, meta_config)
source_case_folder = meta_config.source_case_folder;
if isfolder(source_case_folder)
return;
end
case_id = lower(string(meta_config.case_id));
switch case_id
case "case01"
source_case_folder = find_case_folder_by_index(project_root, 1);
otherwise
if isempty(source_case_folder) || startsWith(string(source_case_folder), "CASE")
source_case_folder = '';
end
end
end
function source_case_folder = find_case_folder_by_index(project_root, case_index)
folder_candidates = dir(fullfile(project_root, sprintf('*%d-*', case_index)));
folder_candidates = folder_candidates([folder_candidates.isdir]);
if isempty(folder_candidates)
source_case_folder = '';
else
source_case_folder = fullfile(project_root, folder_candidates(1).name);
end
end
function [f, fellip, frac_information, nf] = build_fracture_inputs(fracture_config)
input_style = fracture_config.input_style;
switch input_style
case 1
[f, fellip] = sort_fracture(fracture_config.input_content);
m = size(f, 1);
n = size(fellip, 1);
nf = (m + n) / 5;
frac_information = fractureInformation_input_engineering_vector( ...
f, fellip, fracture_config.flowBarrierFlags);
case 2
f = fracture_config.f;
fellip = fracture_config.fellip;
m = size(f, 1);
n = size(fellip, 1);
nf = (m + n) / 5;
frac_information = fractureInformation_input_engineering_vector(f, fellip);
case 3
fellip = fracture_config.fellip;
[f, frac_information] = input_fracture_2D( ...
fracture_config.fractureLines, ...
fracture_config.fractureHeights, ...
fracture_config.flowBarrierFlags);
m = size(f, 1);
n = size(fellip, 1);
nf = (m + n) / 5;
otherwise
error('run_case:UnsupportedFractureInputStyle', ...
'Unsupported fracture input style: %d', input_style);
end
end
function [fluid_model, state0] = build_flow_inputs(flow_model, r, config)
switch flow_model
case 1
if has_complete_gas_water_config(config.flow.gas_water)
[fluid_model, state0] = build_gas_water_flow_from_config( ...
config.flow.gas_water, config.initial, r);
else
[fluid_model, state0] = gas_water_flow(r);
end
case 2
if has_complete_oil_water_config(config.flow.oil_water)
[fluid_model, state0] = build_oil_water_flow_from_config( ...
config.flow.oil_water, config.initial, r);
else
[fluid_model, state0] = oil_water_flow(r);
end
case 3
if has_complete_multicomponent_config(config.flow.multi_component)
[fluid_model, state0] = build_multi_component_flow_from_config( ...
config.flow.multi_component, config.initial, r);
else
[fluid_model, state0] = multi_component_flow(r);
end
otherwise
error('run_case:UnsupportedFlowModel', ...
'Unsupported flow model: %d', flow_model);
end
end
function tf = has_complete_gas_water_config(gw)
required_fields = { ...
'density_g_sc', 'density_w_sc', 'gas_model', 'prw', 'Bwi', 'cw', ...
'vwi', 'cvw', 'ifpcgl', 'matrix_relperm_table', 'fracture_relperm_table', ...
'p_grad_threshold'};
tf = true;
for i = 1:numel(required_fields)
field_name = required_fields{i};
if ~isfield(gw, field_name) || isempty(gw.(field_name))
tf = false;
return;
end
end
if ~isfield(gw, 'gas_prop') || isempty(gw.gas_prop)
tf = false;
return;
end
if gw.gas_model == 1
tf = all(isfield(gw, {'prg', 'Bgi', 'cg', 'vgi', 'cvg'})) && ...
~isempty(gw.prg) && ~isempty(gw.Bgi) && ~isempty(gw.cg) && ...
~isempty(gw.vgi) && ~isempty(gw.cvg);
else
tf = all(isfield(gw, {'Ppr', 'BG', 'MUG'})) && ...
~isempty(gw.Ppr) && ~isempty(gw.BG) && ~isempty(gw.MUG);
end
end
function tf = has_complete_oil_water_config(ow)
required_fields = { ...
'density_o_sc', 'density_w_sc', 'oil_model', 'prw', 'Bwi', 'cw', ...
'vwi', 'cvw', 'ifpcow', 'matrix_relperm_table', 'fracture_relperm_table', ...
'beta_non_darcy_flow', 'p_grad_threshold'};
tf = true;
for i = 1:numel(required_fields)
field_name = required_fields{i};
if ~isfield(ow, field_name) || isempty(ow.(field_name))
tf = false;
return;
end
end
if ow.oil_model == 1
tf = all(isfield(ow, {'pro', 'Boi', 'co', 'voi', 'cvo'})) && ...
~isempty(ow.pro) && ~isempty(ow.Boi) && ~isempty(ow.co) && ...
~isempty(ow.voi) && ~isempty(ow.cvo);
else
tf = all(isfield(ow, {'Ppr', 'BO', 'MUO'})) && ...
~isempty(ow.Ppr) && ~isempty(ow.BO) && ~isempty(ow.MUO);
end
end
function [f, state0] = build_gas_water_flow_from_config(gw, initial_config, r)
if gw.gas_model == 1
[Ppr, BG, MUG] = cal_gas_prop(gw.prg, gw.Bgi, gw.cg, gw.vgi, gw.cvg);
else
Ppr = gw.Ppr;
BG = gw.BG;
MUG = gw.MUG;
end
matrix_table = gw.matrix_relperm_table;
fracture_table = gw.fracture_relperm_table;
f = fluidPVT_gas_water_flow( ...
Ppr, BG, MUG, gw.Bwi, gw.prw, gw.cw, gw.vwi, gw.cvw, ...
matrix_table(:, 1), matrix_table(:, 3), matrix_table(:, 2), matrix_table(:, 4), ...
fracture_table(:, 1), fracture_table(:, 3), fracture_table(:, 2), fracture_table(:, 4), ...
gw.density_g_sc, gw.ifpcgl, r.rpt);
gas_prop = gw.gas_prop;
c1 = 1;
c2 = 8 / 9;
gas_prop.Kn_modified_factor = 1 + 8 * c1 * gas_prop.Kn + 16 * c2 * gas_prop.Kn^2;
f.Dwsi = gw.density_w_sc;
f.Dgsi = gw.density_g_sc;
f.gas_prop = gas_prop;
f.p_grad_threshold = gw.p_grad_threshold;
total_cells = r.nmc + r.nfc;
pressure0 = expand_initial_value(initial_config.pressure, total_cells);
sw0 = expand_initial_value(initial_config.sw, total_cells);
state0 = initialRS_gas_water_flow(pressure0, sw0);
end
function [f, state0] = build_oil_water_flow_from_config(ow, initial_config, r)
if ow.oil_model == 1
[Ppr, BO, MUO] = cal_oil_prop(ow.pro, ow.Boi, ow.co, ow.voi, ow.cvo);
else
Ppr = ow.Ppr;
BO = ow.BO;
MUO = ow.MUO;
end
matrix_table = ow.matrix_relperm_table;
fracture_table = ow.fracture_relperm_table;
f = fluidPVT_oil_water_flow( ...
Ppr, BO, MUO, ow.Bwi, ow.prw, ow.cw, ow.vwi, ow.cvw, ...
matrix_table(:, 1), matrix_table(:, 3), matrix_table(:, 2), matrix_table(:, 4), ...
fracture_table(:, 1), fracture_table(:, 3), fracture_table(:, 2), fracture_table(:, 4), ...
ow.density_o_sc, ow.ifpcow, r.rpt);
f.beta_non_Darcy_flow = ow.beta_non_darcy_flow;
f.Dwsi = ow.density_w_sc;
f.Dosi = ow.density_o_sc;
f.p_grad_threshold = ow.p_grad_threshold;
total_cells = r.nmc + r.nfc;
pressure0 = expand_initial_value(initial_config.pressure, total_cells);
sw0 = expand_initial_value(initial_config.sw, total_cells);
state0 = initialRS_oil_water_flow(pressure0, sw0);
end
function tf = has_complete_multicomponent_config(mc)
required_fields = { ...
'Ds', 'Db', 'c_ca_table', 'R', 'Vm', 'Temperature', ...
'cs_Nc', 'kr_nosurf', 'kr_surf', 'PC', ...
'cs_Nc_fracture', 'kr_nosurf_fracture', 'kr_surf_fracture', 'PC_fracture', ...
'density_g_sc', 'density_w_sc', 'gas_model', 'prw', 'Bwi', 'cw', 'vwi', 'cvw'};
tf = true;
for i = 1:numel(required_fields)
field_name = required_fields{i};
if ~isfield(mc, field_name) || isempty(mc.(field_name))
tf = false;
return;
end
end
if ~isfield(mc, 'gas_prop') || isempty(mc.gas_prop)
tf = false;
return;
end
if mc.gas_model == 1
tf = all(isfield(mc, {'prg', 'Bgi', 'cg', 'vgi', 'cvg'})) && ...
~isempty(mc.prg) && ~isempty(mc.Bgi) && ~isempty(mc.cg) && ...
~isempty(mc.vgi) && ~isempty(mc.cvg);
else
tf = all(isfield(mc, {'Ppr', 'BG', 'MUG'})) && ...
~isempty(mc.Ppr) && ~isempty(mc.BG) && ~isempty(mc.MUG);
end
end
function [f, state0] = build_multi_component_flow_from_config(mc, initial_config, r)
cs_data = mc.c_ca_table(:, 1);
cb_data = mc.c_ca_table(:, 1);
csa_data = mc.c_ca_table(:, 2) * 1e-3;
cba_data = mc.c_ca_table(:, 3) * 1e-3;
Nc_nosurf = min(mc.cs_Nc(:, 2));
Nc_surf = max(mc.cs_Nc(:, 2));
if mc.gas_model == 1
[Ppr, BG, MUG] = cal_gas_prop(mc.prg, mc.Bgi, mc.cg, mc.vgi, mc.cvg);
else
Ppr = mc.Ppr;
BG = mc.BG;
MUG = mc.MUG;
end
f = fluidPVT_new( ...
Ppr, BG, MUG, mc.Bwi, mc.prw, mc.cw, mc.vwi, mc.cvw, ...
mc.ifpcgl, r.rpt, cs_data, csa_data, cb_data, cba_data, ...
mc.cs_Nc, Nc_nosurf, Nc_surf, mc.kr_nosurf, mc.kr_surf, mc.PC, ...
mc.cs_Nc_fracture, mc.kr_nosurf_fracture, mc.kr_surf_fracture, mc.PC_fracture);
gas_prop = mc.gas_prop;
c1 = 1;
c2 = 8 / 9;
gas_prop.Kn_modified_factor = 1 + 8 * c1 * gas_prop.Kn + 16 * c2 * gas_prop.Kn^2;
f.Dwsi = mc.density_w_sc;
f.Dgsi = mc.density_g_sc;
f.gas_prop = gas_prop;
f.Ds = mc.Ds;
f.Db = mc.Db;
f.chemistry_cof = mc.R * mc.Temperature / mc.Vm * 1e-3 / 10;
f.p_grad_threshold = mc.p_grad_threshold;
f.number_state_variables = mc.number_state_variables;
total_cells = r.nmc + r.nfc;
matrix_x = default_if_empty(mc, 'x_matrix', 0.9);
fracture_x = default_if_empty(mc, 'x_fracture', 1.0);
f.x_total = [matrix_x * ones(r.nmc, 1); fracture_x * ones(r.nfc, 1)];
f.chemistry_potential = f.chemistry_cof * log(f.x_total);
pressure0 = expand_initial_value(initial_config.pressure, total_cells);
sw0 = expand_initial_value(initial_config.sw, total_cells);
cs0 = expand_initial_value(initial_config.cs, total_cells);
cb0 = expand_initial_value(initial_config.cb, total_cells);
state0 = initialRS(pressure0, sw0, cs0, cb0);
end
function value = expand_initial_value(raw_value, total_cells)
if isscalar(raw_value)
value = raw_value * ones(total_cells, 1);
else
value = raw_value;
end
end
function value = default_if_empty(s, field_name, fallback)
if isfield(s, field_name) && ~isempty(s.(field_name))
value = s.(field_name);
else
value = fallback;
end
end
function [well2, welloc] = build_fracture_wells(wells_config, r)
num_fracture_wells = wells_config.num_fracture_wells;
welloc = wells_config.welloc;
perfnum = cell(num_fracture_wells, 1);
for i = 1:num_fracture_wells
perfnum{i, 1} = findWelloc(r, welloc{i, 1});
end
well2 = cell(num_fracture_wells, 6);
for i = 1:num_fracture_wells
if numel(wells_config.well2) >= i && ~isempty(wells_config.well2{i, 1})
well2(i, :) = wells_config.well2(i, :);
well2{i, 2} = length(perfnum{i, 1});
well2{i, 3} = perfnum{i, 1};
else
well2(i, :) = {sprintf('wf%d', i), length(perfnum{i, 1}), perfnum{i, 1}, 0.178/2, 0, 4};
end
end
end
@@ -0,0 +1,25 @@
function config = load_case_template(case_id)
%LOAD_CASE_TEMPLATE Load a predefined case template into unified config.
arguments
case_id
end
case_key = normalize_case_id(case_id);
switch case_key
case "case01"
config = load_case_template_case01();
otherwise
error('load_case_template:UnsupportedCase', ...
'Unsupported case template: %s', string(case_key));
end
end
function case_key = normalize_case_id(case_id)
if isnumeric(case_id)
case_key = "case" + compose("%02d", case_id);
else
case_key = lower(string(case_id));
end
end
@@ -0,0 +1,189 @@
function config = load_case_template_case01()
%LOAD_CASE_TEMPLATE_CASE01 Build config for case 1.
config = create_empty_config();
config.meta.case_name = 'case01_multicomponent_irregular_domain';
config.meta.case_id = 'case01';
config.meta.description = 'Multicomponent flow with irregular heterogeneous domain';
config.meta.source_case_folder = 'CASE01_FOLDER';
config.meta.created_from_template = 'case01';
config.model.modelflag = 1;
config.model.grid_model = 1;
config.model.flow_model = 3;
config.grid.dx = 50 * ones(1, 20);
config.grid.dy = 50 * ones(1, 10);
config.grid.dz = 10 * ones(1, 1);
config.grid.nx = numel(config.grid.dx);
config.grid.ny = numel(config.grid.dy);
config.grid.nz = numel(config.grid.dz);
config.grid.NTG = ones(config.grid.nx * config.grid.ny * config.grid.nz, 1);
config.fracture.input_style = 1;
config.fracture.input_content = {
[255,255,5],90,90,0,200,10,1;
[305,255,5],90,90,0,200,10,1;
[355,255,5],90,90,0,200,10,1;
[405,255,5],90,90,0,200,10,1;
[455,255,5],90,90,0,200,10,1;
[505,255,5],90,90,0,200,10,1;
[555,255,5],90,90,0,200,10,1;
[605,255,5],90,90,0,200,10,1;
[655,255,5],90,90,0,200,10,1;
[705,255,5],90,90,0,200,10,1;
[755,255,5],90,90,0,200,10,1;
};
config.fracture.flowBarrierFlags = [];
config.discretization.mode = 1;
config.discretization.sp.boundary_polygon = [
0,100;
800,50;
1000,150;
1000,350;
800,450;
0,400;
0,100];
config.discretization.sp.invalid_layer = [];
config.discretization.sp.matrix.prpor = 20;
config.discretization.sp.matrix.cpor = 1.0e-5;
config.discretization.sp.matrix.rock_density = 2700;
config.discretization.sp.fracture.prporf = 20;
config.discretization.sp.fracture.cporf = 1.0e-5;
config.discretization.sp.stress.fracture_factor = 0.0;
config.discretization.sp.stress.matrix_factor = 0.0;
config.discretization.sp.stress.ref_pressure = 20;
config.flow.multi_component.Ds = 0.76e-9;
config.flow.multi_component.Db = 2.2e-9;
config.flow.multi_component.c_ca_table = [
0 0 0;
0.05 1 0.075;
0.1 1.75 0.125;
0.2 3 0.2;
0.5 4.35 0.325;
1 4.55 0.365];
config.flow.multi_component.R = 0.008314;
config.flow.multi_component.Vm = 18.02e-6;
config.flow.multi_component.Temperature = 293.15;
config.flow.multi_component.x_matrix = 0.9;
config.flow.multi_component.x_fracture = 1.0;
config.flow.multi_component.cs_Nc = [
0 1.6e-6 30;
0.1 9.5e-6 10;
0.2 2.5e-5 4;
0.5 5.8e-5 1.4;
1 8.2e-5 1;
2 8.8e-5 0.75];
config.flow.multi_component.kr_nosurf = [
0 0 0.64;
0.25 0 0.64;
0.30 0.072 0.6;
0.40 0.14 0.56;
0.50 0.26 0.48;
0.60 0.4 0.38;
0.70 0.56 0.26;
0.85 0.88 0;
1 0.88 0];
config.flow.multi_component.kr_surf = [
0 0 0.6;
0.18 0 0.6;
0.25 0.056 0.56;
0.30 0.1 0.52;
0.40 0.19 0.42;
0.50 0.29 0.3;
0.60 0.37 0.19;
0.75 0.46 0;
1 0.46 0];
config.flow.multi_component.PC = [
0 3.8916;
0.2 3.8916;
0.316 0.5796;
0.435 0.3724;
0.562 0.2425;
0.614 0.0608;
0.702 0.0372;
0.812 0.0137;
0.875 0.0104;
0.906 0.009;
0.937 0.0075;
0.969 0.0059;
1 0];
config.flow.multi_component.cs_Nc_fracture = config.flow.multi_component.cs_Nc;
config.flow.multi_component.kr_nosurf_fracture = config.flow.multi_component.kr_nosurf;
config.flow.multi_component.kr_surf_fracture = config.flow.multi_component.kr_surf;
config.flow.multi_component.PC_fracture = config.flow.multi_component.PC;
config.flow.multi_component.ifpcgl = 0;
config.flow.multi_component.p_grad_threshold = 0.01;
config.flow.multi_component.gas_prop.VL = 0.0;
config.flow.multi_component.gas_prop.PL = 3.5;
config.flow.multi_component.gas_prop.Kn = 0;
config.flow.multi_component.gas_prop.stress_factor_fracture = 0.0;
config.flow.multi_component.gas_prop.stress_factor_matrix = 0.0;
config.flow.multi_component.gas_prop.stress_factor_ref_pressure = 20;
config.flow.multi_component.gas_prop.beta_non_darcy_flow = 0;
config.flow.multi_component.density_g_sc = 800;
config.flow.multi_component.gas_model = 1;
config.flow.multi_component.prg = 20;
config.flow.multi_component.Bgi = 1;
config.flow.multi_component.cg = 5e-4;
config.flow.multi_component.vgi = 6;
config.flow.multi_component.cvg = 0;
config.flow.multi_component.density_w_sc = 1000;
config.flow.multi_component.prw = 20;
config.flow.multi_component.Bwi = 1.0;
config.flow.multi_component.cw = 4.0e-4;
config.flow.multi_component.vwi = 1;
config.flow.multi_component.cvw = 0;
config.flow.multi_component.number_state_variables = 4;
config.initial.pressure = 20;
config.initial.sw = 0.2;
config.initial.cs = 0.0;
config.initial.cb = 0.0;
config.wells.well1 = {};
config.wells.num_fracture_wells = 1;
config.wells.welloc = {
[
255,255,5;
305,255,5;
355,255,5;
405,255,5;
455,255,5;
505,255,5;
555,255,5;
605,255,5;
655,255,5;
705,255,5;
755,255,5
]};
config.wells.well2 = {
'w1', 0, [], 0.178/2, 0, 4
};
config.schedule.number_phases = 3;
config.schedule.time = [10; 30; 200];
config.schedule.dtmax = [0.1; 0.5; 0.5];
config.schedule.dtmin = [0.001; 0.001; 0.001];
config.schedule.well_schedules = {
{
'w1','open','inj','const_pwf',40,40,'Cs_inj',0.5,'Cb_inj',1
};
{
'w1','open','pro','const_q',0,0
};
{
'w1','open','pro','const_pwf',10,10
}};
config.solver.yitap = 5;
config.solver.yitas = 0.04;
config.solver.omega = 0.5;
config.solver.Nmax = 50;
config.solver.epsave = 1e-6;
config.solver.epsmax = 1e-6;
config.output.result_name = 'case01_default_run';