JavaProjectRepo/异步推理并保存结果.md
2026-03-20 19:00:16 +08:00

49 lines
3.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 异步推理并保存结果 (SimInferService 流程解析)
在仿真计算完成后,系统需要将每一步的计算结果发送给 Python 推理服务,以预测关键指标(如 Keff。这个过程由 `SimInferService``DeviceInferService` 协同完成。
## 1. 推理数据不是一次性全部发送
**核心结论:** 并不是把所有结果封装为一个大 Request 调用一次推理接口,而是**进行了精细的多级分组后,分别调用推理接口**。
因为不同的设备、不同的材料、以及用户为设备配置的不同算法,都对应着不同的**模型文件Pipeline/Model**。一次推理请求只能加载一个模型文件,所以必须将必须使用同一模型的数据分在同一批次发送。
## 2. 数据转换与分组流程
整个流程分为两部分:在 `SimInferService` 中进行一级分组,然后在 `DeviceInferService` 中进行二级和三级分组。
### 2.1 第一级分组:按设备类型 (DeviceType) 分组
**位置:** `SimInferService.asyncInferAndSave`
1. **展平时间轴 (Flatten Timeline)**:仿真引擎返回的 `SimContext` 是按时间步Step组织的。代码首先遍历每个时间步将散落的属性如液位、浓度`unitId` 聚合。
2. **注入元数据**:通过 `SimUnit`,将静态属性(如设备固有的直径、高度)以及新加入的 `materialType`(如 U, Pu合并到设备的属性集合中生成 `DeviceStepInfo` 对象。
3. **一级分组**:将所有时间步的 `DeviceStepInfo` 根据 **设备类型 (`deviceType`)** 放入 `Map<String, List<DeviceStepInfo>> groupedDevices` 中。
- *例如:所有的 CylindricalTank 数据在一组AnnularTank 在另一组。*
### 2.2 第二级分组:按算法类型 (AlgorithmType) 分组
**位置:** `DeviceInferService.processDeviceInference`
1. **读取配置**:获取全局配置的算法(如 GPR以及针对特定设备独立配置的算法`deviceAlgoConfig`)。
2. **二级分组**:在某一个设备类型(如 CylindricalTank的数据列表中进一步按 **算法类型 (`algoType`)** 分组。
- *例如CylindricalTank 组被拆分为 -> 使用 GPR 算法的批次、使用 MLP 算法的批次。*
### 2.3 第三级分组:按材料类型 (MaterialType) 分组
**位置:** `DeviceInferService.processDeviceInference`
1. **三级分组**:在特定的算法批次中,进一步按 **材料类型 (`materialType`)** 分组。
- *例如:使用 GPR 的 CylindricalTank 批次被拆分为 -> 材料为 U 的批次、材料为 Pu 的批次。*
## 3. 发起推理请求
经过上述三级分组后,我们得到了一个**高度同质化**的数据批次。对于每一个这样的最终批次:
1. **查询模型**:调用 `algorithmModelService.getCurrentModelPath(algoType, deviceType, materialType)`。因为这三个维度相同,所以它们一定使用同一个物理模型文件(`.pkl`)。
2. **构建 Request**:将这批数据(包含所有相关设备在所有时间步的状态)组装成一个 `InferRequest`
3. **发起调用**:向 Python 服务发送 HTTP POST 请求 `/v1/infer`
4. **入库保存**Python 返回每个设备在每个时间步的预测结果(如 `keff`Java 端解析这些结果并批量保存到 `scenario_result` 表中。
## 4. 异常与状态管理
- 整个过程是加上了 `@Async` 异步执行的,不会阻塞前端获取基础仿真数据。
- 如果某一个批次因为找不到模型(例如上述终端日志中 `GPR + CylindricalTank + U` 的模型未配置),代码会记录错误并标记 `hasAnyError = true`,然后跳过该批次(`continue`)。
- **兜底机制**:如果所有的批次都失败或找不到模型(`!hasAnySuccess && hasAnyError`),会抛出 `RuntimeException`。这会被外层 `SimInferService` 捕获,并将该情景的状态更新为 **"3" (失败)**。