From 9276c1ef3265493220d9f7c7752e3540af2494df Mon Sep 17 00:00:00 2001 From: xinxiao Date: Tue, 17 Mar 2026 11:05:57 +0800 Subject: [PATCH] fix parse bug --- core functions/preprocess/Ulit/dinterptable.m | 28 +++++ gui_support/app/EDFMAppController.m | 106 ++++++++++++++++-- gui_support/runtime/run_case.m | 22 +++- .../templates/load_case_template_case01.m | 2 +- 4 files changed, 149 insertions(+), 9 deletions(-) diff --git a/core functions/preprocess/Ulit/dinterptable.m b/core functions/preprocess/Ulit/dinterptable.m index 9179021..6d0a528 100644 --- a/core functions/preprocess/Ulit/dinterptable.m +++ b/core functions/preprocess/Ulit/dinterptable.m @@ -7,7 +7,35 @@ function h = dinterptable(X, Y, u) % b(b == 0) = 1; % b(b == n) = n - 1; % h = DYDX(b); +X = X(:); +Y = Y(:); +u = u(:); + +if numel(X) ~= numel(Y) + error('dinterptable:SizeMismatch', ... + 'X and Y must have the same length. Got %d and %d.', numel(X), numel(Y)); +end +if any(~isfinite(X)) || any(~isfinite(Y)) + error('dinterptable:InvalidTable', ... + 'Interpolation table contains NaN or Inf.'); +end +if any(diff(X) < 0) + error('dinterptable:NonMonotonicX', ... + 'Interpolation table X must be nondecreasing.'); +end + DYDX = diff(Y) ./ diff(X); DYDX = DYDX([1, 1:end, end]); [~, b] = histc(u, [-inf;X;inf]); + +invalid_mask = ~isfinite(u) | b < 1 | b > numel(DYDX); +if any(invalid_mask) + bad_values = u(invalid_mask); + bad_preview = bad_values(1:min(5, numel(bad_values))); + error('dinterptable:InvalidQuery', ... + ['Interpolation query contains invalid values. ' ... + 'num_bad=%d, sample=%s, X_range=[%g, %g], Y_range=[%g, %g].'], ... + numel(bad_values), mat2str(bad_preview.'), X(1), X(end), min(Y), max(Y)); +end + h = reshape(DYDX(b), [], 1); diff --git a/gui_support/app/EDFMAppController.m b/gui_support/app/EDFMAppController.m index 392e274..306ab1d 100644 --- a/gui_support/app/EDFMAppController.m +++ b/gui_support/app/EDFMAppController.m @@ -96,10 +96,15 @@ classdef EDFMAppController < handle obj.setRunProgress('Completed'); obj.setStatus('Run completed'); catch ME - obj.appendLog(getReport(ME, 'extended', 'hyperlinks', 'off')); + errorReport = getReport(ME, 'extended', 'hyperlinks', 'off'); + errorSummary = obj.formatExceptionSummary(ME); + obj.publishExceptionToBase(ME, errorReport); + fprintf(2, '\n[EDFM GUI Run Error]\n%s\n', errorReport); + obj.appendLog(errorSummary); + obj.appendLog(errorReport); obj.setRunProgress('Failed'); obj.setStatus('Run failed'); - uialert(obj.App.UIFigure, ME.message, 'Run Failed'); + uialert(obj.App.UIFigure, errorSummary, 'Run Failed', 'Interpreter', 'none'); end end @@ -319,9 +324,9 @@ classdef EDFMAppController < handle obj.setNumericFieldValue('MCcvwEditField', obj.firstScalar(c.flow.multi_component.cvw)); obj.setTableValue('Well1Table', c.wells.well1); - obj.setTableValue('FractureWellLocationTable', c.wells.welloc{1}); + obj.setTableValue('FractureWellLocationTable', obj.unwrapFirstCell(c.wells.welloc)); obj.setTableValue('Well2Table', c.wells.well2); - obj.setTableValue('ScheduleTable', c.schedule.well_schedules{1}); + obj.setTableValue('ScheduleTable', obj.unwrapFirstCell(c.schedule.well_schedules)); obj.setTextAreaExpr('TimeTextArea', c.schedule.time); obj.setTextAreaExpr('DtMinTextArea', c.schedule.dtmin); obj.setTextAreaExpr('DtMaxTextArea', c.schedule.dtmax); @@ -442,11 +447,15 @@ classdef EDFMAppController < handle c.flow.multi_component.cvw = obj.getNumericFieldValue('MCcvwEditField', c.flow.multi_component.cvw); c.wells.well1 = obj.getTableValue('Well1Table', c.wells.well1); - c.wells.welloc = obj.getTableValue('FractureWellLocationTable', c.wells.welloc); + fractureWellLocation = obj.getNumericTableValue( ... + 'FractureWellLocationTable', obj.unwrapFirstCell(c.wells.welloc)); + c.wells.welloc = obj.replaceFirstCell(c.wells.welloc, fractureWellLocation); c.wells.num_fracture_wells = numel(c.wells.welloc); c.wells.well2 = obj.getTableValue('Well2Table', c.wells.well2); - c.schedule.well_schedules = obj.getTableValue('ScheduleTable', c.schedule.well_schedules); + firstPhaseSchedule = obj.getTableValue( ... + 'ScheduleTable', obj.unwrapFirstCell(c.schedule.well_schedules)); + c.schedule.well_schedules = obj.replaceFirstCell(c.schedule.well_schedules, firstPhaseSchedule); c.schedule.number_phases = numel(c.schedule.well_schedules); c.schedule.time = obj.getTextAreaExpr('TimeTextArea', c.schedule.time); c.schedule.dtmin = obj.getTextAreaExpr('DtMinTextArea', c.schedule.dtmin); @@ -631,7 +640,7 @@ classdef EDFMAppController < handle return; end value = obj.App.(propName).Value; - if isempty(value) + if isempty(value) || (isnumeric(value) && isscalar(value) && ~isfinite(value)) value = fallback; end end @@ -687,6 +696,27 @@ classdef EDFMAppController < handle end end + function value = getNumericTableValue(obj, propName, fallback) + value = obj.getTableValue(propName, fallback); + if isempty(value) + return; + end + if isnumeric(value) + return; + end + if iscell(value) + try + value = cellfun(@obj.convertTableCellToDouble, value); + catch ME + error('EDFMAppController:NumericTableParseError', ... + 'Failed to parse %s as a numeric table. %s', propName, ME.message); + end + return; + end + error('EDFMAppController:NumericTableTypeError', ... + 'Unsupported table data type for %s: %s', propName, class(value)); + end + function setEditableState(obj, propName, isEnabled) if ~isprop(obj.App, propName) return; @@ -704,6 +734,68 @@ classdef EDFMAppController < handle end end + function textValue = formatExceptionSummary(~, ME) + lines = { + sprintf('Error: %s', ME.message) + sprintf('Identifier: %s', ME.identifier) + }; + if ~isempty(ME.stack) + topFrame = ME.stack(1); + lines{end + 1} = sprintf('Location: %s (line %d)', topFrame.name, topFrame.line); %#ok + lines{end + 1} = sprintf('File: %s', topFrame.file); %#ok + end + textValue = strjoin(lines, newline); + end + + function publishExceptionToBase(obj, ME, errorReport) + assignin('base', 'edfm_last_run_error', ME); + assignin('base', 'edfm_last_run_error_report', errorReport); + assignin('base', 'edfm_last_run_config', obj.Config); + end + + function value = unwrapFirstCell(~, rawValue) + if iscell(rawValue) && ~isempty(rawValue) + value = rawValue{1}; + else + value = rawValue; + end + end + + function values = replaceFirstCell(~, existingValues, firstValue) + if isempty(existingValues) + values = {firstValue}; + return; + end + if ~iscell(existingValues) + values = {firstValue}; + return; + end + values = existingValues; + values{1} = firstValue; + end + + function value = convertTableCellToDouble(~, cellValue) + if isnumeric(cellValue) && isscalar(cellValue) + value = double(cellValue); + return; + end + if islogical(cellValue) && isscalar(cellValue) + value = double(cellValue); + return; + end + if isstring(cellValue) && isscalar(cellValue) + cellValue = char(cellValue); + end + if ischar(cellValue) + parsedValue = str2double(strtrim(cellValue)); + if ~isnan(parsedValue) + value = parsedValue; + return; + end + end + error('Cell value "%s" is not a scalar numeric entry.', string(cellValue)); + end + function value = firstScalar(~, rawValue) if isempty(rawValue) value = 0; diff --git a/gui_support/runtime/run_case.m b/gui_support/runtime/run_case.m index 01d8eef..01ba6d0 100644 --- a/gui_support/runtime/run_case.m +++ b/gui_support/runtime/run_case.m @@ -352,6 +352,11 @@ 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; +if isfield(gas_prop, 'beta_non_darcy_flow') && ~isfield(gas_prop, 'beta_non_Darcy_flow') + gas_prop.beta_non_Darcy_flow = gas_prop.beta_non_darcy_flow; +elseif ~isfield(gas_prop, 'beta_non_Darcy_flow') + gas_prop.beta_non_Darcy_flow = 0; +end f.Dwsi = mc.density_w_sc; f.Dgsi = mc.density_g_sc; @@ -371,7 +376,7 @@ 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); +cb0 = expand_initial_value(sanitize_positive_initial_value(initial_config.cb, 50.0), total_cells); state0 = initialRS(pressure0, sw0, cs0, cb0); end @@ -383,6 +388,21 @@ else end end +function value = sanitize_positive_initial_value(raw_value, fallback) +if isempty(raw_value) + value = fallback; + return; +end + +value = raw_value; +invalid_mask = ~isfinite(value) | value <= 0; +if all(invalid_mask(:)) + value = fallback; +elseif any(invalid_mask(:)) + value(invalid_mask) = fallback; +end +end + function value = default_if_empty(s, field_name, fallback) if isfield(s, field_name) && ~isempty(s.(field_name)) value = s.(field_name); diff --git a/gui_support/templates/load_case_template_case01.m b/gui_support/templates/load_case_template_case01.m index 48b78ba..26ce86e 100644 --- a/gui_support/templates/load_case_template_case01.m +++ b/gui_support/templates/load_case_template_case01.m @@ -142,7 +142,7 @@ 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.initial.cb = 50.0; config.wells.well1 = {}; config.wells.num_fracture_wells = 1;