|
|
|
@ -19,7 +19,9 @@
|
|
|
|
from __future__ import annotations
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
import argparse
|
|
|
|
|
|
|
|
import csv
|
|
|
|
import json
|
|
|
|
import json
|
|
|
|
|
|
|
|
import math
|
|
|
|
import sys
|
|
|
|
import sys
|
|
|
|
from collections import Counter
|
|
|
|
from collections import Counter
|
|
|
|
from pathlib import Path
|
|
|
|
from pathlib import Path
|
|
|
|
@ -35,8 +37,9 @@ from src.common.experiment_paths import config_for_stage, normalize_tag
|
|
|
|
from src.data.curve_processing import (
|
|
|
|
from src.data.curve_processing import (
|
|
|
|
clean_curve_for_dataset,
|
|
|
|
clean_curve_for_dataset,
|
|
|
|
is_valid_curve,
|
|
|
|
is_valid_curve,
|
|
|
|
resample_curve_to_features_with_time,
|
|
|
|
resample_curve_to_features_with_time_and_mask,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
from src.data.dataset_generation import _sample_schedule_family_random as sample_schedule_family_random
|
|
|
|
from src.data.params import Params, Schedule, generate_params_dataset
|
|
|
|
from src.data.params import Params, Schedule, generate_params_dataset
|
|
|
|
from src.data.runner_client import CppRunner, read_result_bin
|
|
|
|
from src.data.runner_client import CppRunner, read_result_bin
|
|
|
|
from src.data.schedule_features import (
|
|
|
|
from src.data.schedule_features import (
|
|
|
|
@ -63,36 +66,6 @@ SCHEDULE_META_NAMES = [
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _pick_mixture(rng: np.random.RandomState, items: list[dict]) -> dict:
|
|
|
|
|
|
|
|
"""按配置中的概率权重从多个采样组件里抽取一个组件。"""
|
|
|
|
|
|
|
|
probs = np.asarray([float(it.get("prob", 0.0)) for it in items], dtype=np.float64)
|
|
|
|
|
|
|
|
s = float(np.sum(probs))
|
|
|
|
|
|
|
|
if s <= 0:
|
|
|
|
|
|
|
|
return items[int(rng.randint(0, len(items)))]
|
|
|
|
|
|
|
|
probs = probs / s
|
|
|
|
|
|
|
|
u = float(rng.rand())
|
|
|
|
|
|
|
|
c = 0.0
|
|
|
|
|
|
|
|
for it, p in zip(items, probs):
|
|
|
|
|
|
|
|
c += float(p)
|
|
|
|
|
|
|
|
if u <= c:
|
|
|
|
|
|
|
|
return it
|
|
|
|
|
|
|
|
return items[-1]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _normalize_durations_to_total(dt: np.ndarray, total: float, min_dt: float) -> np.ndarray:
|
|
|
|
|
|
|
|
"""在满足最小时长约束的前提下,将各段时长缩放到指定总时长。"""
|
|
|
|
|
|
|
|
dt = np.maximum(dt.astype(np.float64), float(min_dt))
|
|
|
|
|
|
|
|
s = float(np.sum(dt))
|
|
|
|
|
|
|
|
total = max(float(total), float(min_dt) * float(len(dt)))
|
|
|
|
|
|
|
|
if s <= 0:
|
|
|
|
|
|
|
|
return np.full_like(dt, total / len(dt))
|
|
|
|
|
|
|
|
dt = dt * (total / s)
|
|
|
|
|
|
|
|
dt = np.maximum(dt, float(min_dt))
|
|
|
|
|
|
|
|
diff = total - float(np.sum(dt))
|
|
|
|
|
|
|
|
dt[-1] += diff
|
|
|
|
|
|
|
|
return np.maximum(dt, float(min_dt))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _family_id_map(cfg: Config) -> dict[str, int]:
|
|
|
|
def _family_id_map(cfg: Config) -> dict[str, int]:
|
|
|
|
"""把流量制度族名称映射为整数 id,便于写入模型特征和元数据。"""
|
|
|
|
"""把流量制度族名称映射为整数 id,便于写入模型特征和元数据。"""
|
|
|
|
mode = str(cfg.raw["schedule"]["generation_mode"]).lower()
|
|
|
|
mode = str(cfg.raw["schedule"]["generation_mode"]).lower()
|
|
|
|
@ -184,59 +157,12 @@ def _sample_schedule_family_random(
|
|
|
|
rng: np.random.RandomState,
|
|
|
|
rng: np.random.RandomState,
|
|
|
|
family_override: str | None = None,
|
|
|
|
family_override: str | None = None,
|
|
|
|
) -> tuple[list[float], list[float], dict]:
|
|
|
|
) -> tuple[list[float], list[float], dict]:
|
|
|
|
"""按 family_random 配置随机生成不同类别的生产/关井制度。"""
|
|
|
|
"""复用正式数据生成器,使局部数据与普通数据的流量制度分布保持一致。"""
|
|
|
|
fcfg = cfg.raw["schedule"]["family_random"]
|
|
|
|
return sample_schedule_family_random(
|
|
|
|
if family_override is None:
|
|
|
|
cfg,
|
|
|
|
fam = _pick_mixture(rng, fcfg["families"])
|
|
|
|
rng,
|
|
|
|
fam_name = str(fam.get("name", "inc_tail_shutin")).lower()
|
|
|
|
family_override=family_override,
|
|
|
|
else:
|
|
|
|
)
|
|
|
|
fam_name = str(family_override).lower()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
n_lo, n_hi = fcfg["n_prod_sections_range"]
|
|
|
|
|
|
|
|
n_prod = int(rng.randint(int(n_lo), int(n_hi) + 1))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prod_total_lo, prod_total_hi = fcfg["prod_total_time_range"]
|
|
|
|
|
|
|
|
prod_total = float(prod_total_lo + rng.rand() * (prod_total_hi - prod_total_lo))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mu = float(fcfg["duration_lognormal_mu"])
|
|
|
|
|
|
|
|
sigma = float(fcfg["duration_lognormal_sigma"])
|
|
|
|
|
|
|
|
dt_prod = rng.lognormal(mean=mu, sigma=sigma, size=n_prod).astype(np.float64)
|
|
|
|
|
|
|
|
dt_prod = _normalize_durations_to_total(dt_prod, total=prod_total, min_dt=0.05)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
q_lo, q_hi = fcfg["q_range"]
|
|
|
|
|
|
|
|
q0 = float(q_lo + rng.rand() * (q_hi - q_lo))
|
|
|
|
|
|
|
|
max_rel_step = float(fcfg["max_rel_step"])
|
|
|
|
|
|
|
|
mult_noise_sigma = float(fcfg["mult_noise_sigma"])
|
|
|
|
|
|
|
|
step_jump_lo, step_jump_hi = fcfg["step_jump_rel_range"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
q_prod = np.zeros((n_prod,), dtype=np.float64)
|
|
|
|
|
|
|
|
q_prod[0] = q0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if fam_name == "inc_tail_shutin":
|
|
|
|
|
|
|
|
for i in range(1, n_prod):
|
|
|
|
|
|
|
|
q_prod[i] = q_prod[i - 1] * rng.uniform(1.02, max_rel_step)
|
|
|
|
|
|
|
|
q_prod = np.maximum.accumulate(q_prod)
|
|
|
|
|
|
|
|
elif fam_name == "dec_tail_shutin":
|
|
|
|
|
|
|
|
for i in range(1, n_prod):
|
|
|
|
|
|
|
|
q_prod[i] = max(q_prod[i - 1] * rng.uniform(1.0 / max_rel_step, 0.98), q_lo)
|
|
|
|
|
|
|
|
q_prod = np.minimum.accumulate(q_prod)
|
|
|
|
|
|
|
|
elif fam_name == "mild_step_tail_shutin":
|
|
|
|
|
|
|
|
q_prod[:] = q0
|
|
|
|
|
|
|
|
jump_idx = int(rng.randint(1, max(2, n_prod)))
|
|
|
|
|
|
|
|
q_prod[jump_idx:] *= float(rng.uniform(step_jump_lo, step_jump_hi))
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
for i in range(1, n_prod):
|
|
|
|
|
|
|
|
rel = rng.uniform(1.0 / max_rel_step, max_rel_step)
|
|
|
|
|
|
|
|
rel = 1.0 + 0.15 * (rel - 1.0)
|
|
|
|
|
|
|
|
q_prod[i] = q_prod[i - 1] * rel
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if mult_noise_sigma > 0:
|
|
|
|
|
|
|
|
q_prod *= np.exp(rng.normal(loc=0.0, scale=mult_noise_sigma, size=n_prod))
|
|
|
|
|
|
|
|
q_prod = np.clip(q_prod, q_lo, q_hi)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
shut_lo, shut_hi = fcfg["shutin_dt_range"]
|
|
|
|
|
|
|
|
dt_shut = float(shut_lo + rng.rand() * (shut_hi - shut_lo))
|
|
|
|
|
|
|
|
return dt_prod.tolist() + [dt_shut], q_prod.tolist() + [0.0], {"family_name": fam_name}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def sample_schedule_by_mode(
|
|
|
|
def sample_schedule_by_mode(
|
|
|
|
@ -275,6 +201,7 @@ def parse_args() -> argparse.Namespace:
|
|
|
|
"""解析自动拟合邻域数据生成所需的锚点数量、扰动尺度和输出路径。"""
|
|
|
|
"""解析自动拟合邻域数据生成所需的锚点数量、扰动尺度和输出路径。"""
|
|
|
|
parser = argparse.ArgumentParser(description="Generate anchor-neighborhood autofit dataset for generalized local ranking")
|
|
|
|
parser = argparse.ArgumentParser(description="Generate anchor-neighborhood autofit dataset for generalized local ranking")
|
|
|
|
parser.add_argument("--config", type=str, default=None)
|
|
|
|
parser.add_argument("--config", type=str, default=None)
|
|
|
|
|
|
|
|
parser.add_argument("--dataset-case", type=str, default=None)
|
|
|
|
parser.add_argument(
|
|
|
|
parser.add_argument(
|
|
|
|
"--stage",
|
|
|
|
"--stage",
|
|
|
|
choices=[
|
|
|
|
choices=[
|
|
|
|
@ -292,6 +219,13 @@ def parse_args() -> argparse.Namespace:
|
|
|
|
parser.add_argument("--neighbors-per-anchor", type=int, default=24)
|
|
|
|
parser.add_argument("--neighbors-per-anchor", type=int, default=24)
|
|
|
|
parser.add_argument("--max-attempts-factor", type=int, default=4)
|
|
|
|
parser.add_argument("--max-attempts-factor", type=int, default=4)
|
|
|
|
parser.add_argument("--anchor-max-attempts-factor", type=int, default=5)
|
|
|
|
parser.add_argument("--anchor-max-attempts-factor", type=int, default=5)
|
|
|
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
|
|
|
"--trace-csv",
|
|
|
|
|
|
|
|
type=str,
|
|
|
|
|
|
|
|
default=None,
|
|
|
|
|
|
|
|
help="Optional full-solver PSO trace used to seed representative anchor locations",
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
parser.add_argument("--trace-anchor-count", type=int, default=16)
|
|
|
|
parser.add_argument("--seed", type=int, default=42)
|
|
|
|
parser.add_argument("--seed", type=int, default=42)
|
|
|
|
parser.add_argument("--span-frac", type=float, default=0.08)
|
|
|
|
parser.add_argument("--span-frac", type=float, default=0.08)
|
|
|
|
parser.add_argument(
|
|
|
|
parser.add_argument(
|
|
|
|
@ -311,6 +245,18 @@ def parse_args() -> argparse.Namespace:
|
|
|
|
)
|
|
|
|
)
|
|
|
|
parser.add_argument("--solver-timeout", type=int, default=120)
|
|
|
|
parser.add_argument("--solver-timeout", type=int, default=120)
|
|
|
|
parser.add_argument("--well-index", type=int, default=0)
|
|
|
|
parser.add_argument("--well-index", type=int, default=0)
|
|
|
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
|
|
|
"--fixed-cf",
|
|
|
|
|
|
|
|
type=float,
|
|
|
|
|
|
|
|
default=None,
|
|
|
|
|
|
|
|
help="Fix Cf for every anchor and neighbor, e.g. 0.0003 for the current T5 fit",
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
|
|
|
"--schedule-mode",
|
|
|
|
|
|
|
|
choices=["fixed_case", "case_neighborhood", "family_random"],
|
|
|
|
|
|
|
|
default=None,
|
|
|
|
|
|
|
|
help="Override schedule.generation_mode from the YAML config",
|
|
|
|
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
parser.add_argument(
|
|
|
|
"--use-runner-server",
|
|
|
|
"--use-runner-server",
|
|
|
|
action="store_true",
|
|
|
|
action="store_true",
|
|
|
|
@ -342,7 +288,18 @@ def resolve_config(args: argparse.Namespace) -> Config:
|
|
|
|
config_path = args.config
|
|
|
|
config_path = args.config
|
|
|
|
if config_path is None:
|
|
|
|
if config_path is None:
|
|
|
|
config_path = str(config_for_stage(args.stage) or Path("configs/data_gen_family_random.yaml"))
|
|
|
|
config_path = str(config_for_stage(args.stage) or Path("configs/data_gen_family_random.yaml"))
|
|
|
|
return Config(config_path)
|
|
|
|
cfg = Config(config_path, dataset_case=args.dataset_case)
|
|
|
|
|
|
|
|
if cfg.dataset_cases and args.dataset_case is None:
|
|
|
|
|
|
|
|
available = ", ".join(str(case.get("name")) for case in cfg.dataset_cases)
|
|
|
|
|
|
|
|
raise ValueError(f"--dataset-case is required for this config; available cases: {available}")
|
|
|
|
|
|
|
|
if args.fixed_cf is not None:
|
|
|
|
|
|
|
|
cfg.raw["params"].setdefault("fixed_params", {})["Cf"] = {
|
|
|
|
|
|
|
|
"enabled": True,
|
|
|
|
|
|
|
|
"value": float(args.fixed_cf),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if args.schedule_mode is not None:
|
|
|
|
|
|
|
|
cfg.raw["schedule"]["generation_mode"] = str(args.schedule_mode)
|
|
|
|
|
|
|
|
return cfg
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def resolve_output_path(cfg: Config, args: argparse.Namespace) -> Path:
|
|
|
|
def resolve_output_path(cfg: Config, args: argparse.Namespace) -> Path:
|
|
|
|
@ -372,7 +329,7 @@ def run_solver_and_extract_curve(
|
|
|
|
params: Params,
|
|
|
|
params: Params,
|
|
|
|
well_index: int,
|
|
|
|
well_index: int,
|
|
|
|
timeout: int,
|
|
|
|
timeout: int,
|
|
|
|
) -> tuple[np.ndarray, np.ndarray, dict]:
|
|
|
|
) -> tuple[np.ndarray, np.ndarray, np.ndarray, dict]:
|
|
|
|
"""调用 C++ 求解器运行一次正演,并把双对数输出重采样为模型曲线向量。"""
|
|
|
|
"""调用 C++ 求解器运行一次正演,并把双对数输出重采样为模型曲线向量。"""
|
|
|
|
ok = runner.run_simulation(params, timeout=timeout, override_schedule=params.schedule, include_schedule=True)
|
|
|
|
ok = runner.run_simulation(params, timeout=timeout, override_schedule=params.schedule, include_schedule=True)
|
|
|
|
result = read_result_bin(runner.result_bin) if runner.result_bin.exists() else None
|
|
|
|
result = read_result_bin(runner.result_bin) if runner.result_bin.exists() else None
|
|
|
|
@ -397,7 +354,12 @@ def run_solver_and_extract_curve(
|
|
|
|
if not valid:
|
|
|
|
if not valid:
|
|
|
|
raise RuntimeError(f"curve_invalid_{reason}")
|
|
|
|
raise RuntimeError(f"curve_invalid_{reason}")
|
|
|
|
|
|
|
|
|
|
|
|
curve_feat, curve_time = resample_curve_to_features_with_time(cfg, t_clean, p_clean, d_clean)
|
|
|
|
curve_feat, curve_time, curve_valid_mask = resample_curve_to_features_with_time_and_mask(
|
|
|
|
|
|
|
|
cfg,
|
|
|
|
|
|
|
|
t_clean,
|
|
|
|
|
|
|
|
p_clean,
|
|
|
|
|
|
|
|
d_clean,
|
|
|
|
|
|
|
|
)
|
|
|
|
raw = {
|
|
|
|
raw = {
|
|
|
|
"t": t_clean.tolist(),
|
|
|
|
"t": t_clean.tolist(),
|
|
|
|
"p": p_clean.tolist(),
|
|
|
|
"p": p_clean.tolist(),
|
|
|
|
@ -405,24 +367,123 @@ def run_solver_and_extract_curve(
|
|
|
|
"n_steps": int(result["nSteps"]),
|
|
|
|
"n_steps": int(result["nSteps"]),
|
|
|
|
"n_wells": int(result["nWells"]),
|
|
|
|
"n_wells": int(result["nWells"]),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return curve_feat, curve_time, raw
|
|
|
|
return curve_feat, curve_time, curve_valid_mask, raw
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def params_to_array(params: Params) -> np.ndarray:
|
|
|
|
def model_param_names(cfg: Config) -> list[str]:
|
|
|
|
"""按固定参数顺序把 Params 对象转换成数值数组。"""
|
|
|
|
"""返回H5中保存并交给模型的原始参数列顺序。"""
|
|
|
|
return np.asarray(
|
|
|
|
return list(
|
|
|
|
[params.k, params.skin, params.wellboreC, params.phi, params.h, params.Ct, params.Cf],
|
|
|
|
cfg.raw["params"].get(
|
|
|
|
dtype=np.float32,
|
|
|
|
"model_param_names",
|
|
|
|
|
|
|
|
cfg.raw["params"]["all_physical_param_names"],
|
|
|
|
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def params_to_model_array(cfg: Config, params: Params) -> np.ndarray:
|
|
|
|
|
|
|
|
"""按当前模型列顺序写参数;Ct仍保留在Params中供求解器使用。"""
|
|
|
|
|
|
|
|
values: list[float] = []
|
|
|
|
|
|
|
|
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 contains solverType but the selected case has no solver_type")
|
|
|
|
|
|
|
|
values.append(float(solver_type))
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
if not hasattr(params, name):
|
|
|
|
|
|
|
|
raise ValueError(f"Unsupported model parameter column: {name}")
|
|
|
|
|
|
|
|
values.append(float(getattr(params, name)))
|
|
|
|
|
|
|
|
return np.asarray(values, dtype=np.float32)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def load_trace_anchor_params(cfg: Config, trace_csv: str | None, count: int) -> list[Params]:
|
|
|
|
|
|
|
|
"""从全求解trace选择各代最优点和目标值分位点作为重点锚点。"""
|
|
|
|
|
|
|
|
if trace_csv is None or int(count) <= 0:
|
|
|
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rows: list[dict] = []
|
|
|
|
|
|
|
|
with Path(trace_csv).open("r", newline="", encoding="utf-8-sig") as f:
|
|
|
|
|
|
|
|
for row in csv.DictReader(f):
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
objective = float(row.get("solver_objective", "nan"))
|
|
|
|
|
|
|
|
generation = int(row.get("generation", -1))
|
|
|
|
|
|
|
|
success = str(row.get("solver_success", "")) == "1"
|
|
|
|
|
|
|
|
if row.get("phase") != "particle_solver" or not success or not math.isfinite(objective):
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
values = {}
|
|
|
|
|
|
|
|
for name in cfg.raw["params"]["all_physical_param_names"]:
|
|
|
|
|
|
|
|
fixed = _fixed_param_value(cfg, name)
|
|
|
|
|
|
|
|
value = fixed if fixed is not None else float(row[name])
|
|
|
|
|
|
|
|
lo, hi = map(float, cfg.raw["params"]["ranges"][name])
|
|
|
|
|
|
|
|
values[name] = float(np.clip(value, lo, hi))
|
|
|
|
|
|
|
|
rows.append(
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"generation": generation,
|
|
|
|
|
|
|
|
"objective": objective,
|
|
|
|
|
|
|
|
"params": Params(**values),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
except (KeyError, TypeError, ValueError):
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not rows:
|
|
|
|
|
|
|
|
raise ValueError(f"No valid full-solver particle rows found in trace: {trace_csv}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
best_by_generation: dict[int, dict] = {}
|
|
|
|
|
|
|
|
for row in rows:
|
|
|
|
|
|
|
|
generation = int(row["generation"])
|
|
|
|
|
|
|
|
current = best_by_generation.get(generation)
|
|
|
|
|
|
|
|
if current is None or float(row["objective"]) < float(current["objective"]):
|
|
|
|
|
|
|
|
best_by_generation[generation] = row
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
selected: list[Params] = []
|
|
|
|
|
|
|
|
seen: set[tuple[float, ...]] = set()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add(row: dict) -> None:
|
|
|
|
|
|
|
|
params = row["params"]
|
|
|
|
|
|
|
|
key = tuple(
|
|
|
|
|
|
|
|
round(float(getattr(params, name)), 12)
|
|
|
|
|
|
|
|
for name in cfg.raw["params"]["all_physical_param_names"]
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
if key not in seen and len(selected) < int(count):
|
|
|
|
|
|
|
|
seen.add(key)
|
|
|
|
|
|
|
|
selected.append(params)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
generation_best_rows = [best_by_generation[key] for key in sorted(best_by_generation)]
|
|
|
|
|
|
|
|
if len(generation_best_rows) > int(count):
|
|
|
|
|
|
|
|
positions = np.linspace(0, len(generation_best_rows) - 1, num=int(count), dtype=np.int64)
|
|
|
|
|
|
|
|
generation_best_rows = [generation_best_rows[int(pos)] for pos in positions]
|
|
|
|
|
|
|
|
for row in generation_best_rows:
|
|
|
|
|
|
|
|
add(row)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
objective_rows = sorted(rows, key=lambda row: float(row["objective"]))
|
|
|
|
|
|
|
|
remaining = int(count) - len(selected)
|
|
|
|
|
|
|
|
if remaining > 0:
|
|
|
|
|
|
|
|
positions = np.linspace(0, len(objective_rows) - 1, num=max(remaining, 1), dtype=np.int64)
|
|
|
|
|
|
|
|
for pos in positions:
|
|
|
|
|
|
|
|
add(objective_rows[int(pos)])
|
|
|
|
|
|
|
|
for row in objective_rows:
|
|
|
|
|
|
|
|
add(row)
|
|
|
|
|
|
|
|
if len(selected) >= int(count):
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
return selected
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def sample_anchor_params_and_schedule(
|
|
|
|
def sample_anchor_params_and_schedule(
|
|
|
|
cfg: Config,
|
|
|
|
cfg: Config,
|
|
|
|
rng: np.random.RandomState,
|
|
|
|
rng: np.random.RandomState,
|
|
|
|
family_override: str | None = None,
|
|
|
|
family_override: str | None = None,
|
|
|
|
|
|
|
|
anchor_params: Params | None = None,
|
|
|
|
) -> tuple[Params, np.ndarray, str]:
|
|
|
|
) -> tuple[Params, np.ndarray, str]:
|
|
|
|
"""为一个锚点同时采样物理参数和流量制度,作为后续邻域搜索中心。"""
|
|
|
|
"""为一个锚点同时采样物理参数和流量制度,作为后续邻域搜索中心。"""
|
|
|
|
params = generate_params_dataset(cfg, n_samples=1, method="sobol", random_seed=int(rng.randint(0, 2**31 - 1)))[0]
|
|
|
|
params = anchor_params
|
|
|
|
|
|
|
|
if params is None:
|
|
|
|
|
|
|
|
params = generate_params_dataset(
|
|
|
|
|
|
|
|
cfg,
|
|
|
|
|
|
|
|
n_samples=1,
|
|
|
|
|
|
|
|
method=cfg.raw["params"].get("sampling_method", "sobol"),
|
|
|
|
|
|
|
|
random_seed=int(rng.randint(0, 2**31 - 1)),
|
|
|
|
|
|
|
|
)[0]
|
|
|
|
timeQ, q, sched_info = sample_schedule_by_mode(cfg, rng, family_override=family_override)
|
|
|
|
timeQ, q, sched_info = sample_schedule_by_mode(cfg, rng, family_override=family_override)
|
|
|
|
section_indices = _resolve_section_indices(cfg, timeQ, q, rng)
|
|
|
|
section_indices = _resolve_section_indices(cfg, timeQ, q, rng)
|
|
|
|
sec = int(section_indices[int(rng.randint(0, len(section_indices)))])
|
|
|
|
sec = int(section_indices[int(rng.randint(0, len(section_indices)))])
|
|
|
|
@ -588,11 +649,11 @@ def select_objective_stratified_indices(objectives: np.ndarray, k: int, objectiv
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def select_multiscale_rows(
|
|
|
|
def select_multiscale_rows(
|
|
|
|
rows: list[tuple[np.ndarray, np.ndarray, dict[str, float], float, np.ndarray]],
|
|
|
|
rows: list[tuple[np.ndarray, np.ndarray, dict[str, float], float, np.ndarray, np.ndarray]],
|
|
|
|
k: int,
|
|
|
|
k: int,
|
|
|
|
objective_bins: int,
|
|
|
|
objective_bins: int,
|
|
|
|
span_fracs: list[float],
|
|
|
|
span_fracs: list[float],
|
|
|
|
) -> list[tuple[np.ndarray, np.ndarray, dict[str, float], float, np.ndarray]]:
|
|
|
|
) -> list[tuple[np.ndarray, np.ndarray, dict[str, float], float, np.ndarray, np.ndarray]]:
|
|
|
|
"""从不同扰动尺度的候选中挑选代表性行,形成多尺度邻域数据。"""
|
|
|
|
"""从不同扰动尺度的候选中挑选代表性行,形成多尺度邻域数据。"""
|
|
|
|
if len(rows) <= k or len(span_fracs) <= 1:
|
|
|
|
if len(rows) <= k or len(span_fracs) <= 1:
|
|
|
|
indices = select_objective_stratified_indices(
|
|
|
|
indices = select_objective_stratified_indices(
|
|
|
|
@ -658,19 +719,24 @@ def build_span_targets(total_keep: int, span_fracs: list[float]) -> dict[float,
|
|
|
|
|
|
|
|
|
|
|
|
def create_output_file(
|
|
|
|
def create_output_file(
|
|
|
|
output_path: Path,
|
|
|
|
output_path: Path,
|
|
|
|
param_dim: int,
|
|
|
|
param_names: list[str],
|
|
|
|
schedule_dim: int,
|
|
|
|
schedule_dim: int,
|
|
|
|
curve_dim: int,
|
|
|
|
curve_dim: int,
|
|
|
|
span_fracs: list[float],
|
|
|
|
span_fracs: list[float],
|
|
|
|
search_names: list[str],
|
|
|
|
search_names: list[str],
|
|
|
|
|
|
|
|
dataset_case: str | None,
|
|
|
|
|
|
|
|
solver_type: int | None,
|
|
|
|
) -> h5py.File:
|
|
|
|
) -> h5py.File:
|
|
|
|
"""创建邻域 HDF5 文件,并初始化锚点、候选、曲线和元数据数据集。"""
|
|
|
|
"""创建邻域 HDF5 文件,并初始化锚点、候选、曲线和元数据数据集。"""
|
|
|
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
f = h5py.File(output_path, "w")
|
|
|
|
f = h5py.File(output_path, "w")
|
|
|
|
f.attrs["param_names"] = np.asarray(["k", "skin", "wellboreC", "phi", "h", "Ct", "Cf"], dtype="S")
|
|
|
|
param_dim = len(param_names)
|
|
|
|
|
|
|
|
f.attrs["param_names"] = np.asarray(param_names, dtype="S")
|
|
|
|
f.attrs["schedule_meta_names"] = np.asarray(SCHEDULE_META_NAMES, dtype="S")
|
|
|
|
f.attrs["schedule_meta_names"] = np.asarray(SCHEDULE_META_NAMES, dtype="S")
|
|
|
|
f.attrs["span_fracs"] = np.asarray(span_fracs, dtype=np.float32)
|
|
|
|
f.attrs["span_fracs"] = np.asarray(span_fracs, dtype=np.float32)
|
|
|
|
f.attrs["search_param_names"] = np.asarray(search_names, dtype="S")
|
|
|
|
f.attrs["search_param_names"] = np.asarray(search_names, dtype="S")
|
|
|
|
|
|
|
|
f.attrs["dataset_case"] = "" if dataset_case is None else str(dataset_case)
|
|
|
|
|
|
|
|
f.attrs["solver_type"] = -1 if solver_type is None else int(solver_type)
|
|
|
|
|
|
|
|
|
|
|
|
n_anchors = 0
|
|
|
|
n_anchors = 0
|
|
|
|
n_neighbors = 0
|
|
|
|
n_neighbors = 0
|
|
|
|
@ -680,6 +746,7 @@ def create_output_file(
|
|
|
|
n_time_points = int(curve_dim // 2)
|
|
|
|
n_time_points = int(curve_dim // 2)
|
|
|
|
f.create_dataset("anchor_curve", shape=(0, curve_dim), maxshape=(None, curve_dim), dtype=np.float32, chunks=(64, curve_dim))
|
|
|
|
f.create_dataset("anchor_curve", shape=(0, curve_dim), maxshape=(None, curve_dim), dtype=np.float32, chunks=(64, curve_dim))
|
|
|
|
f.create_dataset("anchor_curve_time", shape=(0, n_time_points), maxshape=(None, n_time_points), dtype=np.float32, chunks=(64, n_time_points))
|
|
|
|
f.create_dataset("anchor_curve_time", shape=(0, n_time_points), maxshape=(None, n_time_points), dtype=np.float32, chunks=(64, n_time_points))
|
|
|
|
|
|
|
|
f.create_dataset("anchor_curve_valid_mask", shape=(0, n_time_points), maxshape=(None, n_time_points), dtype=np.uint8, chunks=(64, n_time_points))
|
|
|
|
f.create_dataset("anchor_schedule_meta", shape=(0, len(SCHEDULE_META_NAMES)), maxshape=(None, len(SCHEDULE_META_NAMES)), dtype=np.float32, chunks=(64, len(SCHEDULE_META_NAMES)))
|
|
|
|
f.create_dataset("anchor_schedule_meta", shape=(0, len(SCHEDULE_META_NAMES)), maxshape=(None, len(SCHEDULE_META_NAMES)), dtype=np.float32, chunks=(64, len(SCHEDULE_META_NAMES)))
|
|
|
|
f.create_dataset("anchor_family_name", shape=(0,), maxshape=(None,), dtype=h5py.string_dtype(encoding="utf-8"), chunks=(64,))
|
|
|
|
f.create_dataset("anchor_family_name", shape=(0,), maxshape=(None,), dtype=h5py.string_dtype(encoding="utf-8"), chunks=(64,))
|
|
|
|
f.create_dataset("anchor_section_index", shape=(0,), maxshape=(None,), dtype=np.int32, chunks=(64,))
|
|
|
|
f.create_dataset("anchor_section_index", shape=(0,), maxshape=(None,), dtype=np.int32, chunks=(64,))
|
|
|
|
@ -690,6 +757,7 @@ def create_output_file(
|
|
|
|
f.create_dataset("neighbor_params", shape=(0, param_dim), maxshape=(None, param_dim), dtype=np.float32, chunks=(256, param_dim))
|
|
|
|
f.create_dataset("neighbor_params", shape=(0, param_dim), maxshape=(None, param_dim), dtype=np.float32, chunks=(256, param_dim))
|
|
|
|
f.create_dataset("neighbor_curve", shape=(0, curve_dim), maxshape=(None, curve_dim), dtype=np.float32, chunks=(256, curve_dim))
|
|
|
|
f.create_dataset("neighbor_curve", shape=(0, curve_dim), maxshape=(None, curve_dim), dtype=np.float32, chunks=(256, curve_dim))
|
|
|
|
f.create_dataset("neighbor_curve_time", shape=(0, n_time_points), maxshape=(None, n_time_points), dtype=np.float32, chunks=(256, n_time_points))
|
|
|
|
f.create_dataset("neighbor_curve_time", shape=(0, n_time_points), maxshape=(None, n_time_points), dtype=np.float32, chunks=(256, n_time_points))
|
|
|
|
|
|
|
|
f.create_dataset("neighbor_curve_valid_mask", shape=(0, n_time_points), maxshape=(None, n_time_points), dtype=np.uint8, chunks=(256, n_time_points))
|
|
|
|
f.create_dataset("neighbor_objective", shape=(0,), maxshape=(None,), dtype=np.float32, chunks=(256,))
|
|
|
|
f.create_dataset("neighbor_objective", shape=(0,), maxshape=(None,), dtype=np.float32, chunks=(256,))
|
|
|
|
f.create_dataset("neighbor_objective_p", shape=(0,), maxshape=(None,), dtype=np.float32, chunks=(256,))
|
|
|
|
f.create_dataset("neighbor_objective_p", shape=(0,), maxshape=(None,), dtype=np.float32, chunks=(256,))
|
|
|
|
f.create_dataset("neighbor_objective_d", shape=(0,), maxshape=(None,), dtype=np.float32, chunks=(256,))
|
|
|
|
f.create_dataset("neighbor_objective_d", shape=(0,), maxshape=(None,), dtype=np.float32, chunks=(256,))
|
|
|
|
@ -705,6 +773,7 @@ def append_anchor(
|
|
|
|
schedule_vec: np.ndarray,
|
|
|
|
schedule_vec: np.ndarray,
|
|
|
|
curve: np.ndarray,
|
|
|
|
curve: np.ndarray,
|
|
|
|
curve_time: np.ndarray,
|
|
|
|
curve_time: np.ndarray,
|
|
|
|
|
|
|
|
curve_valid_mask: np.ndarray,
|
|
|
|
schedule_meta: np.ndarray,
|
|
|
|
schedule_meta: np.ndarray,
|
|
|
|
family_name: str,
|
|
|
|
family_name: str,
|
|
|
|
section_index: int,
|
|
|
|
section_index: int,
|
|
|
|
@ -719,6 +788,7 @@ def append_anchor(
|
|
|
|
("anchor_schedule", schedule_vec.reshape(1, -1)),
|
|
|
|
("anchor_schedule", schedule_vec.reshape(1, -1)),
|
|
|
|
("anchor_curve", curve.reshape(1, -1)),
|
|
|
|
("anchor_curve", curve.reshape(1, -1)),
|
|
|
|
("anchor_curve_time", curve_time.reshape(1, -1)),
|
|
|
|
("anchor_curve_time", curve_time.reshape(1, -1)),
|
|
|
|
|
|
|
|
("anchor_curve_valid_mask", curve_valid_mask.reshape(1, -1)),
|
|
|
|
("anchor_schedule_meta", schedule_meta.reshape(1, -1)),
|
|
|
|
("anchor_schedule_meta", schedule_meta.reshape(1, -1)),
|
|
|
|
]:
|
|
|
|
]:
|
|
|
|
ds = f[name]
|
|
|
|
ds = f[name]
|
|
|
|
@ -743,6 +813,7 @@ def append_neighbors(
|
|
|
|
params_list: list[np.ndarray],
|
|
|
|
params_list: list[np.ndarray],
|
|
|
|
curve_list: list[np.ndarray],
|
|
|
|
curve_list: list[np.ndarray],
|
|
|
|
curve_time_list: list[np.ndarray],
|
|
|
|
curve_time_list: list[np.ndarray],
|
|
|
|
|
|
|
|
curve_valid_mask_list: list[np.ndarray],
|
|
|
|
obj_list: list[dict[str, float]],
|
|
|
|
obj_list: list[dict[str, float]],
|
|
|
|
span_frac_list: list[float],
|
|
|
|
span_frac_list: list[float],
|
|
|
|
) -> None:
|
|
|
|
) -> None:
|
|
|
|
@ -767,6 +838,7 @@ def append_neighbors(
|
|
|
|
resize_2d("neighbor_params")[start:end] = np.stack(params_list, axis=0).astype(np.float32)
|
|
|
|
resize_2d("neighbor_params")[start:end] = np.stack(params_list, axis=0).astype(np.float32)
|
|
|
|
resize_2d("neighbor_curve")[start:end] = np.stack(curve_list, axis=0).astype(np.float32)
|
|
|
|
resize_2d("neighbor_curve")[start:end] = np.stack(curve_list, axis=0).astype(np.float32)
|
|
|
|
resize_2d("neighbor_curve_time")[start:end] = np.stack(curve_time_list, axis=0).astype(np.float32)
|
|
|
|
resize_2d("neighbor_curve_time")[start:end] = np.stack(curve_time_list, axis=0).astype(np.float32)
|
|
|
|
|
|
|
|
resize_2d("neighbor_curve_valid_mask")[start:end] = np.stack(curve_valid_mask_list, axis=0).astype(np.uint8)
|
|
|
|
resize_1d("neighbor_objective")[start:end] = np.asarray([x["dual_log_objective"] for x in obj_list], dtype=np.float32)
|
|
|
|
resize_1d("neighbor_objective")[start:end] = np.asarray([x["dual_log_objective"] for x in obj_list], dtype=np.float32)
|
|
|
|
resize_1d("neighbor_objective_p")[start:end] = np.asarray([x["log_pressure_objective"] for x in obj_list], dtype=np.float32)
|
|
|
|
resize_1d("neighbor_objective_p")[start:end] = np.asarray([x["log_pressure_objective"] for x in obj_list], dtype=np.float32)
|
|
|
|
resize_1d("neighbor_objective_d")[start:end] = np.asarray([x["log_derivative_objective"] for x in obj_list], dtype=np.float32)
|
|
|
|
resize_1d("neighbor_objective_d")[start:end] = np.asarray([x["log_derivative_objective"] for x in obj_list], dtype=np.float32)
|
|
|
|
@ -786,16 +858,18 @@ def main() -> None:
|
|
|
|
if use_schedule_meta_features(cfg):
|
|
|
|
if use_schedule_meta_features(cfg):
|
|
|
|
schedule_dim += len(schedule_meta_feature_names(cfg))
|
|
|
|
schedule_dim += len(schedule_meta_feature_names(cfg))
|
|
|
|
curve_dim = int(cfg.curve_dim)
|
|
|
|
curve_dim = int(cfg.curve_dim)
|
|
|
|
param_dim = len(cfg.raw["params"]["all_physical_param_names"])
|
|
|
|
output_param_names = model_param_names(cfg)
|
|
|
|
local_search_names = search_param_names(cfg)
|
|
|
|
local_search_names = search_param_names(cfg)
|
|
|
|
|
|
|
|
|
|
|
|
f = create_output_file(
|
|
|
|
f = create_output_file(
|
|
|
|
output_path,
|
|
|
|
output_path,
|
|
|
|
param_dim=param_dim,
|
|
|
|
param_names=output_param_names,
|
|
|
|
schedule_dim=schedule_dim,
|
|
|
|
schedule_dim=schedule_dim,
|
|
|
|
curve_dim=curve_dim,
|
|
|
|
curve_dim=curve_dim,
|
|
|
|
span_fracs=span_fracs,
|
|
|
|
span_fracs=span_fracs,
|
|
|
|
search_names=local_search_names,
|
|
|
|
search_names=local_search_names,
|
|
|
|
|
|
|
|
dataset_case=cfg.dataset_case,
|
|
|
|
|
|
|
|
solver_type=cfg.get("solver_type", default=None),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
summary = {
|
|
|
|
summary = {
|
|
|
|
"config_path": str(cfg.path),
|
|
|
|
"config_path": str(cfg.path),
|
|
|
|
@ -809,6 +883,13 @@ def main() -> None:
|
|
|
|
"use_runner_server": bool(args.use_runner_server),
|
|
|
|
"use_runner_server": bool(args.use_runner_server),
|
|
|
|
"max_perturbed_dims": int(args.max_perturbed_dims),
|
|
|
|
"max_perturbed_dims": int(args.max_perturbed_dims),
|
|
|
|
"search_param_names": local_search_names,
|
|
|
|
"search_param_names": local_search_names,
|
|
|
|
|
|
|
|
"model_param_names": output_param_names,
|
|
|
|
|
|
|
|
"dataset_case": cfg.dataset_case,
|
|
|
|
|
|
|
|
"solver_type": cfg.get("solver_type", default=None),
|
|
|
|
|
|
|
|
"fixed_cf": _fixed_param_value(cfg, "Cf"),
|
|
|
|
|
|
|
|
"schedule_mode": str(cfg.raw["schedule"]["generation_mode"]),
|
|
|
|
|
|
|
|
"trace_csv": None if args.trace_csv is None else str(Path(args.trace_csv).resolve()),
|
|
|
|
|
|
|
|
"trace_anchor_count_requested": int(args.trace_anchor_count),
|
|
|
|
"objective_bins": int(args.objective_bins),
|
|
|
|
"objective_bins": int(args.objective_bins),
|
|
|
|
"anchor_fail_reasons": Counter(),
|
|
|
|
"anchor_fail_reasons": Counter(),
|
|
|
|
"neighbor_fail_reasons": Counter(),
|
|
|
|
"neighbor_fail_reasons": Counter(),
|
|
|
|
@ -819,14 +900,38 @@ def main() -> None:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
anchor_attempts = 0
|
|
|
|
|
|
|
|
max_anchor_attempts = max(int(args.n_anchors), int(args.n_anchors) * int(args.anchor_max_attempts_factor))
|
|
|
|
max_anchor_attempts = max(int(args.n_anchors), int(args.n_anchors) * int(args.anchor_max_attempts_factor))
|
|
|
|
|
|
|
|
trace_anchor_params = load_trace_anchor_params(
|
|
|
|
|
|
|
|
cfg,
|
|
|
|
|
|
|
|
trace_csv=args.trace_csv,
|
|
|
|
|
|
|
|
count=min(max(int(args.trace_anchor_count), 0), int(args.n_anchors)),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
global_anchor_count = max_anchor_attempts - len(trace_anchor_params)
|
|
|
|
|
|
|
|
global_anchor_params = generate_params_dataset(
|
|
|
|
|
|
|
|
cfg,
|
|
|
|
|
|
|
|
n_samples=global_anchor_count,
|
|
|
|
|
|
|
|
method=cfg.raw["params"].get("sampling_method", "sobol"),
|
|
|
|
|
|
|
|
random_seed=int(args.seed),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
anchor_param_candidates = trace_anchor_params + global_anchor_params
|
|
|
|
|
|
|
|
if len(anchor_param_candidates) < max_anchor_attempts:
|
|
|
|
|
|
|
|
raise RuntimeError(
|
|
|
|
|
|
|
|
f"Only {len(anchor_param_candidates)} unique anchor parameters were generated; "
|
|
|
|
|
|
|
|
f"expected {max_anchor_attempts}"
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
anchor_attempts = 0
|
|
|
|
|
|
|
|
summary["trace_anchor_count_loaded"] = int(len(trace_anchor_params))
|
|
|
|
family_plan = build_family_plan(cfg, int(args.n_anchors), balance_families=bool(args.balance_families))
|
|
|
|
family_plan = build_family_plan(cfg, int(args.n_anchors), balance_families=bool(args.balance_families))
|
|
|
|
while int(f.attrs["n_anchors"]) < int(args.n_anchors) and anchor_attempts < max_anchor_attempts:
|
|
|
|
while int(f.attrs["n_anchors"]) < int(args.n_anchors) and anchor_attempts < max_anchor_attempts:
|
|
|
|
anchor_idx = anchor_attempts
|
|
|
|
anchor_idx = anchor_attempts
|
|
|
|
anchor_attempts += 1
|
|
|
|
anchor_attempts += 1
|
|
|
|
target_family = family_plan[int(f.attrs["n_anchors"])] if family_plan else None
|
|
|
|
target_family = family_plan[int(f.attrs["n_anchors"])] if family_plan else None
|
|
|
|
anchor_params, schedule_meta, family_name = sample_anchor_params_and_schedule(cfg, rng, family_override=target_family)
|
|
|
|
anchor_params, schedule_meta, family_name = sample_anchor_params_and_schedule(
|
|
|
|
|
|
|
|
cfg,
|
|
|
|
|
|
|
|
rng,
|
|
|
|
|
|
|
|
family_override=target_family,
|
|
|
|
|
|
|
|
anchor_params=anchor_param_candidates[anchor_idx],
|
|
|
|
|
|
|
|
)
|
|
|
|
summary["family_counter_attempted"][family_name] += 1
|
|
|
|
summary["family_counter_attempted"][family_name] += 1
|
|
|
|
|
|
|
|
|
|
|
|
anchor_runner = CppRunner(
|
|
|
|
anchor_runner = CppRunner(
|
|
|
|
@ -836,7 +941,7 @@ def main() -> None:
|
|
|
|
use_server=bool(args.use_runner_server),
|
|
|
|
use_server=bool(args.use_runner_server),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
anchor_curve, anchor_curve_time, _ = run_solver_and_extract_curve(
|
|
|
|
anchor_curve, anchor_curve_time, anchor_curve_valid_mask, _ = run_solver_and_extract_curve(
|
|
|
|
runner=anchor_runner,
|
|
|
|
runner=anchor_runner,
|
|
|
|
cfg=cfg,
|
|
|
|
cfg=cfg,
|
|
|
|
params=anchor_params,
|
|
|
|
params=anchor_params,
|
|
|
|
@ -856,10 +961,11 @@ def main() -> None:
|
|
|
|
)
|
|
|
|
)
|
|
|
|
anchor_id = append_anchor(
|
|
|
|
anchor_id = append_anchor(
|
|
|
|
f=f,
|
|
|
|
f=f,
|
|
|
|
anchor_params=params_to_array(anchor_params),
|
|
|
|
anchor_params=params_to_model_array(cfg, anchor_params),
|
|
|
|
schedule_vec=schedule_vec,
|
|
|
|
schedule_vec=schedule_vec,
|
|
|
|
curve=anchor_curve,
|
|
|
|
curve=anchor_curve,
|
|
|
|
curve_time=anchor_curve_time,
|
|
|
|
curve_time=anchor_curve_time,
|
|
|
|
|
|
|
|
curve_valid_mask=anchor_curve_valid_mask,
|
|
|
|
schedule_meta=schedule_meta,
|
|
|
|
schedule_meta=schedule_meta,
|
|
|
|
family_name=family_name,
|
|
|
|
family_name=family_name,
|
|
|
|
section_index=int(anchor_params.schedule.sectionIndex),
|
|
|
|
section_index=int(anchor_params.schedule.sectionIndex),
|
|
|
|
@ -874,7 +980,7 @@ def main() -> None:
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
valid_neighbor_rows: list[
|
|
|
|
valid_neighbor_rows: list[
|
|
|
|
tuple[np.ndarray, np.ndarray, dict[str, float], float, np.ndarray]
|
|
|
|
tuple[np.ndarray, np.ndarray, dict[str, float], float, np.ndarray, np.ndarray]
|
|
|
|
] = []
|
|
|
|
] = []
|
|
|
|
valid_span_counter: Counter[str] = Counter()
|
|
|
|
valid_span_counter: Counter[str] = Counter()
|
|
|
|
max_attempts = max(
|
|
|
|
max_attempts = max(
|
|
|
|
@ -901,25 +1007,46 @@ def main() -> None:
|
|
|
|
max_perturbed_dims=int(args.max_perturbed_dims),
|
|
|
|
max_perturbed_dims=int(args.max_perturbed_dims),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
cand_curve, cand_curve_time, _ = run_solver_and_extract_curve(
|
|
|
|
cand_curve, cand_curve_time, cand_curve_valid_mask, _ = run_solver_and_extract_curve(
|
|
|
|
runner=anchor_runner,
|
|
|
|
runner=anchor_runner,
|
|
|
|
cfg=cfg,
|
|
|
|
cfg=cfg,
|
|
|
|
params=cand,
|
|
|
|
params=cand,
|
|
|
|
well_index=int(args.well_index),
|
|
|
|
well_index=int(args.well_index),
|
|
|
|
timeout=int(args.solver_timeout),
|
|
|
|
timeout=int(args.solver_timeout),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
common_mask = anchor_curve_valid_mask.astype(bool) & cand_curve_valid_mask.astype(bool)
|
|
|
|
n_time_points = curve_dim // 2
|
|
|
|
n_time_points = curve_dim // 2
|
|
|
|
obj = dual_log_objective(anchor_curve, cand_curve, {"parts": [
|
|
|
|
anchor_common = np.concatenate(
|
|
|
|
{"name": "log_pressure", "start": 0, "end": n_time_points},
|
|
|
|
[
|
|
|
|
{"name": "log_derivative", "start": n_time_points, "end": curve_dim},
|
|
|
|
anchor_curve[:n_time_points][common_mask],
|
|
|
|
]})
|
|
|
|
anchor_curve[n_time_points:][common_mask],
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
cand_common = np.concatenate(
|
|
|
|
|
|
|
|
[
|
|
|
|
|
|
|
|
cand_curve[:n_time_points][common_mask],
|
|
|
|
|
|
|
|
cand_curve[n_time_points:][common_mask],
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
n_common = int(np.sum(common_mask))
|
|
|
|
|
|
|
|
obj = dual_log_objective(
|
|
|
|
|
|
|
|
anchor_common,
|
|
|
|
|
|
|
|
cand_common,
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"parts": [
|
|
|
|
|
|
|
|
{"name": "log_pressure", "start": 0, "end": n_common},
|
|
|
|
|
|
|
|
{"name": "log_derivative", "start": n_common, "end": 2 * n_common},
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
)
|
|
|
|
valid_neighbor_rows.append(
|
|
|
|
valid_neighbor_rows.append(
|
|
|
|
(
|
|
|
|
(
|
|
|
|
params_to_array(cand),
|
|
|
|
params_to_model_array(cfg, cand),
|
|
|
|
cand_curve.astype(np.float32),
|
|
|
|
cand_curve.astype(np.float32),
|
|
|
|
obj,
|
|
|
|
obj,
|
|
|
|
span_frac,
|
|
|
|
span_frac,
|
|
|
|
cand_curve_time.astype(np.float32),
|
|
|
|
cand_curve_time.astype(np.float32),
|
|
|
|
|
|
|
|
cand_curve_valid_mask.astype(np.uint8),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
summary["neighbor_span_counter_valid"][f"{span_frac:g}"] += 1
|
|
|
|
summary["neighbor_span_counter_valid"][f"{span_frac:g}"] += 1
|
|
|
|
@ -963,6 +1090,7 @@ def main() -> None:
|
|
|
|
neighbor_obj_rows = [x[2] for x in selected_rows]
|
|
|
|
neighbor_obj_rows = [x[2] for x in selected_rows]
|
|
|
|
neighbor_span_rows = [float(x[3]) for x in selected_rows]
|
|
|
|
neighbor_span_rows = [float(x[3]) for x in selected_rows]
|
|
|
|
neighbor_curve_time_rows = [x[4] for x in selected_rows]
|
|
|
|
neighbor_curve_time_rows = [x[4] for x in selected_rows]
|
|
|
|
|
|
|
|
neighbor_curve_valid_mask_rows = [x[5] for x in selected_rows]
|
|
|
|
for span_frac in neighbor_span_rows:
|
|
|
|
for span_frac in neighbor_span_rows:
|
|
|
|
summary["neighbor_span_counter_kept"][f"{span_frac:g}"] += 1
|
|
|
|
summary["neighbor_span_counter_kept"][f"{span_frac:g}"] += 1
|
|
|
|
|
|
|
|
|
|
|
|
@ -973,6 +1101,7 @@ def main() -> None:
|
|
|
|
params_list=neighbor_params_rows,
|
|
|
|
params_list=neighbor_params_rows,
|
|
|
|
curve_list=neighbor_curve_rows,
|
|
|
|
curve_list=neighbor_curve_rows,
|
|
|
|
curve_time_list=neighbor_curve_time_rows,
|
|
|
|
curve_time_list=neighbor_curve_time_rows,
|
|
|
|
|
|
|
|
curve_valid_mask_list=neighbor_curve_valid_mask_rows,
|
|
|
|
obj_list=neighbor_obj_rows,
|
|
|
|
obj_list=neighbor_obj_rows,
|
|
|
|
span_frac_list=neighbor_span_rows,
|
|
|
|
span_frac_list=neighbor_span_rows,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|