|
|
|
|
@ -59,6 +59,7 @@ from src.data.params import Params, Schedule, generate_params_dataset, write_par
|
|
|
|
|
from src.data.schedule_encoding import encode_schedule_to_timegrid
|
|
|
|
|
|
|
|
|
|
_WORKER_CFG_PATH: Optional[str] = None
|
|
|
|
|
_WORKER_DATASET_CASE: Optional[str] = None
|
|
|
|
|
_WORKDIR: Optional[Path] = None
|
|
|
|
|
_PARAMS_BIN: Optional[Path] = None
|
|
|
|
|
_RESULT_BIN: Optional[Path] = None
|
|
|
|
|
@ -72,6 +73,26 @@ def _seed32(x: int) -> int:
|
|
|
|
|
return int(x) & 0xFFFFFFFF
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _model_param_names(cfg: Config) -> list[str]:
|
|
|
|
|
"""返回写入H5并交给代理模型的参数列,允许与求解器完整参数不同。"""
|
|
|
|
|
params_cfg = cfg.raw["params"]
|
|
|
|
|
return list(params_cfg.get("model_param_names", params_cfg["all_physical_param_names"]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _build_model_param_vector(cfg: Config, params: Params) -> np.ndarray:
|
|
|
|
|
"""构造模型参数向量;solverType来自当前dataset case,Ct仍只传给求解器。"""
|
|
|
|
|
values = []
|
|
|
|
|
for name in _model_param_names(cfg):
|
|
|
|
|
if name == "solverType":
|
|
|
|
|
solver_type = cfg.get("solver_type", default=None)
|
|
|
|
|
if solver_type is None:
|
|
|
|
|
raise ValueError("model_param_names包含solverType,但当前case未配置solver_type")
|
|
|
|
|
values.append(float(solver_type))
|
|
|
|
|
else:
|
|
|
|
|
values.append(float(getattr(params, name)))
|
|
|
|
|
return np.asarray(values, dtype=np.float32)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _read_result_bin(result_bin_path: Path) -> Optional[Dict[str, Any]]:
|
|
|
|
|
"""读取 C++ 求解器输出的二进制结果文件,并解析时间、压力和双对数曲线。"""
|
|
|
|
|
try:
|
|
|
|
|
@ -378,12 +399,13 @@ def _resolve_section_indices(cfg: Config, timeQ, q, rng):
|
|
|
|
|
raise ValueError(f"Unknown section_policy.mode: {mode}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _init_process_worker(cfg_path: str):
|
|
|
|
|
def _init_process_worker(cfg_path: str, dataset_case: str | None):
|
|
|
|
|
"""初始化并行工作进程中的全局配置、临时目录和求解器路径。"""
|
|
|
|
|
global _WORKER_CFG_PATH, _WORKDIR, _PARAMS_BIN, _RESULT_BIN, _SUBPROC_ENV
|
|
|
|
|
global _WORKER_CFG_PATH, _WORKER_DATASET_CASE, _WORKDIR, _PARAMS_BIN, _RESULT_BIN, _SUBPROC_ENV
|
|
|
|
|
|
|
|
|
|
_WORKER_CFG_PATH = cfg_path
|
|
|
|
|
cfg = Config(cfg_path)
|
|
|
|
|
_WORKER_DATASET_CASE = dataset_case
|
|
|
|
|
cfg = Config(cfg_path, dataset_case=dataset_case)
|
|
|
|
|
cfg.ensure_dirs()
|
|
|
|
|
|
|
|
|
|
base_worker_dir = cfg.paths.temp_dir / "parallel_workers"
|
|
|
|
|
@ -405,7 +427,7 @@ def _init_process_worker(cfg_path: str):
|
|
|
|
|
def _worker_simulate_parallel(args):
|
|
|
|
|
"""在工作进程中写入参数、调用求解器、清洗曲线并返回一个训练样本。"""
|
|
|
|
|
task_idx, params_dict = args
|
|
|
|
|
cfg = Config(_WORKER_CFG_PATH)
|
|
|
|
|
cfg = Config(_WORKER_CFG_PATH, dataset_case=_WORKER_DATASET_CASE)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# 子进程之间不共享 Python 对象,这里从可序列化字典重建 Params/Schedule。
|
|
|
|
|
@ -486,10 +508,7 @@ def _worker_simulate_parallel(args):
|
|
|
|
|
n_sections=len(sch.timeQ),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
params_vec = np.asarray(
|
|
|
|
|
[float(getattr(p, name)) for name in cfg.raw["params"]["all_physical_param_names"]],
|
|
|
|
|
dtype=np.float32,
|
|
|
|
|
)
|
|
|
|
|
params_vec = _build_model_param_vector(cfg, p)
|
|
|
|
|
|
|
|
|
|
schedule_parts = [
|
|
|
|
|
np.asarray(enc.x_sched, dtype=np.float32).reshape(-1),
|
|
|
|
|
@ -662,7 +681,12 @@ class ParallelDatasetGenerator:
|
|
|
|
|
"""执行并行数据生成主循环,直到收集到目标数量的有效样本。"""
|
|
|
|
|
try:
|
|
|
|
|
result = subprocess.run(
|
|
|
|
|
[str(self.cfg.training_exe)],
|
|
|
|
|
[
|
|
|
|
|
str(self.cfg.training_exe),
|
|
|
|
|
str(self.cfg.scene_bin),
|
|
|
|
|
str(self.cfg.dataset_bin),
|
|
|
|
|
str(self.cfg.grid_cache_bin),
|
|
|
|
|
],
|
|
|
|
|
cwd=str(self.cfg.training_exe.parent),
|
|
|
|
|
timeout=60,
|
|
|
|
|
stdout=subprocess.DEVNULL,
|
|
|
|
|
@ -674,12 +698,6 @@ class ParallelDatasetGenerator:
|
|
|
|
|
if result.returncode == 0 and self.cfg.dataset_bin.exists():
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
fallback = self.cfg.training_exe.parent / "dataset.bin"
|
|
|
|
|
if result.returncode == 0 and fallback.exists():
|
|
|
|
|
self.cfg.dataset_bin.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
shutil.copy2(fallback, self.cfg.dataset_bin)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
except Exception:
|
|
|
|
|
return False
|
|
|
|
|
@ -718,7 +736,7 @@ class ParallelDatasetGenerator:
|
|
|
|
|
sched_dim = n_u_points * n_channels + cfg.sec_feat_dim
|
|
|
|
|
if bool(cfg.raw.get("schedule", {}).get("use_metadata_features_for_model", False)):
|
|
|
|
|
sched_dim += len(cfg.raw.get("schedule", {}).get("metadata_features_for_model", []) or [])
|
|
|
|
|
param_names = list(cfg.raw["params"]["all_physical_param_names"])
|
|
|
|
|
param_names = _model_param_names(cfg)
|
|
|
|
|
param_dim = len(param_names)
|
|
|
|
|
|
|
|
|
|
# HDF5 布局与正演模型输入输出一致:
|
|
|
|
|
@ -856,7 +874,7 @@ class ParallelDatasetGenerator:
|
|
|
|
|
with ProcessPoolExecutor(
|
|
|
|
|
max_workers=self.n_workers,
|
|
|
|
|
initializer=_init_process_worker,
|
|
|
|
|
initargs=(str(cfg.path),),
|
|
|
|
|
initargs=(str(cfg.path), cfg.dataset_case),
|
|
|
|
|
) as executor:
|
|
|
|
|
task_iter = iter(tasks)
|
|
|
|
|
in_flight = deque()
|
|
|
|
|
|