Files
3D_EDFM_SIM-X/docs/开发者快速入门.md
2026-03-23 14:38:09 +08:00

9.8 KiB

EDFM Simulator 开发者快速入门

1. 先明确当前主线

这个项目当前的正式 GUI 路线是:

  • 界面文件:gui_support/app/EDFM_Simulator_App.mlapp
  • 控制器:gui_support/app/EDFMAppController.m
  • 统一运行入口:gui_support/runtime/run_case.m

早期 .m 版界面:

  • gui_support/app/EDFMSimulatorApp.m

现在只应视为历史过渡版本,不应再作为主要开发方向。

如果后续要继续开发,请默认以:

  • .mlapp + controller

为主线。

2. 当前架构怎么理解

建议把项目拆成三层理解。

第一层:界面层

正式界面在:

  • EDFM_Simulator_App.mlapp

你导出的可读版本在:

  • gui_support/app/edfm_simulator_app.txt

这一层主要负责:

  • 组件摆放
  • 组件命名
  • 回调入口

第二层:控制器层

控制器文件:

  • gui_support/app/EDFMAppController.m

这一层主要负责:

  • startup 初始化
  • 模板加载
  • 导入/导出配置
  • 导入/导出结果
  • UI 到 config 的写回
  • config 到 UI 的回填
  • 调用 run_case(config)
  • 更新结果页
  • 处理 wells 页表格逻辑

第三层:后端运行层

统一运行入口:

  • gui_support/runtime/run_case.m

这一层负责:

  • 根据 config 构造运行所需参数
  • 调用网格、裂缝、流体、井、schedule 相关逻辑
  • 最终调用原始求解器

3. 开发时应遵循的原则

以后开发尽量遵循下面的分工。

.mlapp 负责什么

  • 负责界面布局
  • 负责组件名称
  • 负责简单回调入口

EDFMAppController.m 负责什么

  • 负责业务逻辑
  • 负责数据同步
  • 负责调用后端

run_case.m 负责什么

  • 负责统一组织求解流程
  • 负责把 config 真正转换成后端求解器输入

简化理解就是:

  • .mlapp 负责“长什么样”
  • controller 负责“点了之后做什么”
  • run_case 负责“真正怎么算”

4. 当前 .mlapp 已经具备什么

根据你导出的 edfm_simulator_app.txt,当前 .mlapp 已经不是空壳,而是已经完成了较完整的绑定:

  • 已有 Controller EDFMAppController
  • 已有 startupFcn
  • startup 时会执行:
app.Controller = EDFMAppController(app);
app.Controller.startup();
  • 顶部按钮已绑定到 controller
  • results 页按钮已绑定到 controller
  • wells 页表格增删与选中已绑定到 controller
  • 各类绘图参数变化已绑定到 controller

这意味着当前开发重点不应再是“重新解释 .m 版怎么跑”,而应是:

  • 继续完善 .mlapp 布局
  • 保持组件名稳定
  • EDFMAppController.m 中补逻辑

5. App Designer 中最常见的组件

下面只讲和当前 .mlapp 直接相关的组件。

uidropdown

下拉框,用于:

  • 模板选择
  • 模型选择
  • 绘图选项选择

常见属性:

  • Items
  • Value
  • ValueChangedFcn

uibutton

按钮,用于:

  • 加载模板
  • 导入导出
  • 运行
  • 绘图
  • 表格行增删

常见属性:

  • Text
  • ButtonPushedFcn

uitable

表格控件,当前项目非常关键,尤其在 Wells 页。

当前主要有:

  • Well1Table
  • Well2Table
  • ScheduleTable
  • FractureWellLocationTable

常见属性:

  • Data
  • ColumnName
  • RowName
  • ColumnEditable
  • CellSelectionCallback

uitextarea

多行文本框,当前仍大量用于输入 MATLAB 表达式,如:

  • 数组
  • 矩阵
  • cell
  • 边界与裂缝文本数据

uieditfield

数值编辑框,用于:

  • 求解器参数
  • 初始条件
  • 部分单值参数

uiaxes

绘图区,用于展示:

  • 时间步图
  • Newtons vs Time
  • 部分结果图

6. 回调函数怎么理解

回调函数就是用户操作组件时触发的函数。

在当前 .mlapp 主线下,推荐让回调函数保持很薄,只做“转发”。

例如按钮回调:

function onRun(app, event)
    app.Controller.runCurrentConfig();
end

这种写法的好处是:

  • .mlapp 内代码简单
  • 业务逻辑集中在 controller
  • 后续换布局时不容易把逻辑打散

7. startup 机制

当前 .mlapp 的关键启动逻辑是:

function startupFcn(app)
    app.Controller = EDFMAppController(app);
    app.Controller.startup();
end

App 创建完成后,runStartupFcn(app, @startupFcn) 会触发这段逻辑。

它的作用是:

  1. 给 app 挂上 controller
  2. 初始化下拉框
  3. 设置表格
  4. 加载默认模板
  5. 刷新界面

如果启动后界面不正常,先查这条链路,而不是先去看求解器。

8. 组件名为什么这么重要

EDFMAppController.m 大量依赖组件名访问控件,例如:

obj.App.(propName)

这意味着:

  • 组件名一旦变了
  • controller 里对应逻辑就可能失效

所以在 App Designer 里改界面时,第一原则是:

  • 不要随意修改已有组件名

如果确实要改名,必须同步修改 controller 中所有相关引用。

9. 修改界面的正确方式

9.1 纯布局修改

如果只是改:

  • 位置
  • 大小
  • 标签文字
  • 页签布局

那么直接在 App Designer 中改 .mlapp 即可。

这种修改通常不需要动 controller。

9.2 新增一个控件

如果新增了一个输入控件,通常要做四件事。

第一步:在 .mlapp 中添加控件

例如增加:

  • 一个下拉框
  • 一个按钮
  • 一个数值框

第二步:给它起稳定名字

命名风格建议沿用现有项目,例如:

  • MyNewDropDown
  • MyNewButton
  • MyNewEditField

第三步:添加回调

例如按钮:

function MyNewButtonPushed(app, event)
    app.Controller.doSomething();
end

第四步:在 controller 中补逻辑

这是关键步骤,不要把逻辑只写在 .mlapp 里。

10. 新增一个参数字段时怎么改

假设新增一个参数,推荐按下面顺序。

1. 先决定它在 config 中的位置

例如:

  • config.solver.xxx
  • config.wells.xxx
  • config.flow.multi_component.xxx

2. 修改默认配置

编辑:

  • gui_support/config/create_empty_config.m

3. 修改模板

编辑:

  • gui_support/templates/load_case_template_case01.m
  • 其他需要的 caseXX

4. 在 .mlapp 中增加控件

并给出稳定组件名。

5. 在 controller 中补两处

必须同时补:

  • refreshUIFromConfig()
  • pushUIToConfig()

这两个函数分别负责:

  • config -> UI
  • UI -> config

如果只改一边,参数就会出现“显示了但不会保存”或者“保存了但不会显示”的问题。

6. 如果运行要用到,再改 run_case.m

只有到这一步,才去改后端运行逻辑。

11. 如何实现一个完整功能

这里给一个适用于本项目的通用开发流程。

第一步:先明确功能边界

先回答这几个问题:

  • 用户从哪个页面进入
  • 输入是什么
  • 点击哪个按钮
  • 结果显示在哪里

第二步:落到统一 config

不要直接从控件把值硬塞到求解器里,优先让它进入统一 config

第三步:补齐 UI 和 config 的双向同步

需要改:

  • .mlapp
  • refreshUIFromConfig()
  • pushUIToConfig()

第四步:补齐运行逻辑

需要改:

  • run_case.m
  • 以及必要的后端函数

第五步:补齐结果显示

如果功能有结果输出,还需要改:

  • refreshResults()
  • 结果页控件
  • 可能的绘图逻辑

12. Wells 页是当前最需要小心的地方

当前 Wells 页已经从原来“纯文本输入”往 uitable 方向演进,这是比较正确的方向。

开发时重点注意三件事。

1. 表头要明确

当前 controller 已统一设置这些表的 ColumnName

如果你在 .mlapp 中重建表格或改字段,记得同步更新 controller 中的表头配置。

2. 默认行也要同步

新增表格字段后,还要同步修改:

  • getDefaultRowForTable()

否则新增行时默认数据长度会不匹配。

3. 注意字符串和数值混合解析

例如 ScheduleTable 既有:

  • 井名
  • open/close
  • inj/pro
  • 数值
  • 可能为空的项

所以改表结构时,需要同步考虑:

  • setTableValue
  • getTableValue
  • parseUITableData
  • parseTableCell

13. 开发者在 App Designer 中最常见的修改场景

场景一:改一个按钮文字

直接在 App Designer 中改 Text 即可。

场景二:改布局

直接在 App Designer 中调整控件位置、网格和页签。

场景三:加一个按钮

推荐做法:

  1. .mlapp 里加按钮
  2. 生成回调函数
  3. 回调函数里调用 controller
  4. 在 controller 实现业务逻辑

场景四:加一个新表字段

推荐做法:

  1. 先改 .mlapp 里的表展示
  2. 再改 controller 表头
  3. 再改默认行
  4. 再改 config 和模板
  5. 最后确认后端是否需要这个字段

14. 现在不推荐的做法

以下做法不推荐继续扩大。

1. 继续把主逻辑写回 .m 版老界面

因为项目主线已经切到 .mlapp

2. 在 .mlapp 回调里直接堆业务逻辑

因为这样会让界面代码越来越难维护。

3. 改了组件名但不改 controller

这会直接导致绑定失效。

15. 当前最值得先看的文件

如果你是新接手开发者,建议按下面顺序看代码。

  1. gui_support/app/edfm_simulator_app.txt
  2. gui_support/app/EDFMAppController.m
  3. gui_support/config/create_empty_config.m
  4. gui_support/templates/load_case_template_case01.m
  5. gui_support/runtime/run_case.m
  6. 对应算例目录下的 main1.m

这个顺序能最快建立“界面字段 -> config -> 后端”的对应关系。

16. 一句最实用的开发建议

以后每次开发,都先问自己三件事:

  1. 这个改动在 .mlapp 里对应哪个组件
  2. 这个组件在 config 里对应哪个字段
  3. 这个字段在 run_case 或后端里最终去哪儿

只要这三层关系始终清楚,项目就不会乱。