初版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
+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';