导出test_mql总闭包关键序列
This commit is contained in:
1 parent
958d813300
commit
6953c864c4
2 files changed
+231
No files matched your search
@@ -3879,6 +3879,33 @@ _ELASTIC_ENDSTOP_FORCE_BINDINGS = (
|
||||
)
|
||||
|
||||
|
||||
def _default_full_state_data_paths() -> tuple[str, ...]:
|
||||
chamber_paths: list[str] = []
|
||||
piston_paths: list[str] = []
|
||||
for _mass_alias, piston_alias, chamber_field in _PISTON_FORCE_BINDINGS:
|
||||
chamber_alias = _PNCH012_ALIAS_BY_SNAPSHOT_FIELD[chamber_field]
|
||||
chamber_paths.extend([f"press@{chamber_alias}", f"vol@{chamber_alias}"])
|
||||
piston_paths.extend([f"vol1@{piston_alias}", f"vvol1@{piston_alias}"])
|
||||
mass_paths = [
|
||||
f"{signal}@mass_friction_endstops_{index}"
|
||||
for index in range(10, 20)
|
||||
for signal in ("x1", "v1", "acc1")
|
||||
]
|
||||
return tuple([*chamber_paths, *piston_paths, *mass_paths])
|
||||
|
||||
|
||||
_PNCH012_ALIAS_BY_SNAPSHOT_FIELD = {
|
||||
"p4_port3_remote_primary_chamber": "pn_c1_8",
|
||||
"p4_primary_chamber": "pn_c1_9",
|
||||
"p4_port1_remote_primary_chamber": "pn_c1_10",
|
||||
"p4_port1_far_primary_chamber": "pn_c1_11",
|
||||
"p4_port1_next_primary_chamber": "pn_c1_12",
|
||||
"p4_bridge_primary_chamber": "pn_c1_13",
|
||||
"p4_port3_next_primary_chamber": "pn_c1_14",
|
||||
"p4_port3_far_primary_chamber": "pn_c1_15",
|
||||
}
|
||||
|
||||
|
||||
class TestMqlFullStateClosure:
|
||||
def __init__(self, *, pneumatic_closure: object, mechanical_closure: object) -> None:
|
||||
self.pneumatic_closure = pneumatic_closure
|
||||
@@ -3961,6 +3988,116 @@ class TestMqlFullStateClosure:
|
||||
),
|
||||
)
|
||||
|
||||
def data_path_values(
|
||||
self,
|
||||
*,
|
||||
time_s: float,
|
||||
state_vector: list[float],
|
||||
data_paths: tuple[str, ...] | list[str] | None = None,
|
||||
) -> dict[str, float]:
|
||||
from PythonModels.systems.test_mql_pneumatic import pressure_to_amesim_gauge_pa
|
||||
|
||||
selected_paths = tuple(data_paths) if data_paths is not None else _default_full_state_data_paths()
|
||||
snapshot = self.snapshot(state_vector)
|
||||
rhs = self.rhs_at(time_s, state_vector)
|
||||
chamber_properties_by_alias = {}
|
||||
chamber_by_alias = {}
|
||||
for _mass_alias, _piston_alias, chamber_field in _PISTON_FORCE_BINDINGS:
|
||||
chamber = getattr(self.pneumatic_closure.components, chamber_field)
|
||||
chamber_by_alias[chamber.name] = chamber
|
||||
chamber_properties_by_alias[chamber.name] = getattr(snapshot.pneumatic, chamber_field)
|
||||
|
||||
state_by_alias = {state.alias: state for state in snapshot.mechanical.states}
|
||||
acceleration_by_mass_alias = {
|
||||
alias: rhs[self.pneumatic_state_count + 2 * index]
|
||||
for index, alias in enumerate(self.mechanical_closure.mass_aliases)
|
||||
}
|
||||
values_by_data_path = {}
|
||||
for data_path in selected_paths:
|
||||
signal, alias = self._split_data_path(data_path)
|
||||
if alias in chamber_properties_by_alias:
|
||||
chamber_properties = chamber_properties_by_alias[alias]
|
||||
chamber = chamber_by_alias[alias]
|
||||
if signal == "press":
|
||||
values_by_data_path[data_path] = pressure_to_amesim_gauge_pa(
|
||||
chamber_properties.p
|
||||
)
|
||||
elif signal == "temp":
|
||||
values_by_data_path[data_path] = chamber_properties.T
|
||||
elif signal == "vol":
|
||||
values_by_data_path[data_path] = chamber.volume_cm3()
|
||||
else:
|
||||
raise KeyError(data_path)
|
||||
elif alias in self.mechanical_closure.assembly.pistons:
|
||||
piston = self.mechanical_closure.assembly.pistons[alias]
|
||||
kinematics = snapshot.mechanical.piston_kinematics_by_alias[alias]
|
||||
geometry = piston.geometry()
|
||||
if signal == "vol1":
|
||||
values_by_data_path[data_path] = geometry.chamber_volume_cm3(
|
||||
kinematics.port_3_displacement_m,
|
||||
kinematics.port_2_displacement_m,
|
||||
)
|
||||
elif signal == "vvol1":
|
||||
values_by_data_path[data_path] = geometry.chamber_volume_rate_l_min(
|
||||
kinematics.port_3_velocity_m_s,
|
||||
kinematics.port_2_velocity_m_s,
|
||||
)
|
||||
elif signal == "length":
|
||||
values_by_data_path[data_path] = geometry.chamber_length_mm(
|
||||
kinematics.port_3_displacement_m,
|
||||
kinematics.port_2_displacement_m,
|
||||
)
|
||||
elif signal == "x4":
|
||||
values_by_data_path[data_path] = kinematics.port_3_displacement_m
|
||||
elif signal == "x5":
|
||||
values_by_data_path[data_path] = kinematics.port_2_displacement_m
|
||||
elif signal == "v4":
|
||||
values_by_data_path[data_path] = kinematics.port_3_velocity_m_s
|
||||
elif signal == "v5":
|
||||
values_by_data_path[data_path] = kinematics.port_2_velocity_m_s
|
||||
else:
|
||||
raise KeyError(data_path)
|
||||
elif alias in state_by_alias:
|
||||
mass_state = state_by_alias[alias]
|
||||
if signal == "x1":
|
||||
values_by_data_path[data_path] = mass_state.displacement_m
|
||||
elif signal == "v1":
|
||||
values_by_data_path[data_path] = mass_state.velocity_m_s
|
||||
elif signal == "acc1":
|
||||
values_by_data_path[data_path] = acceleration_by_mass_alias[alias]
|
||||
else:
|
||||
raise KeyError(data_path)
|
||||
else:
|
||||
raise KeyError(data_path)
|
||||
return values_by_data_path
|
||||
|
||||
def data_path_series(
|
||||
self,
|
||||
*,
|
||||
times: tuple[float, ...] | list[float],
|
||||
state_rows: list[list[float]],
|
||||
data_paths: tuple[str, ...] | list[str] | None = None,
|
||||
) -> dict[str, list[float]]:
|
||||
selected_paths = tuple(data_paths) if data_paths is not None else _default_full_state_data_paths()
|
||||
series = {data_path: [] for data_path in selected_paths}
|
||||
for sample_index, time_value in enumerate(times):
|
||||
state_vector = [row[sample_index] for row in state_rows]
|
||||
values = self.data_path_values(
|
||||
time_s=float(time_value),
|
||||
state_vector=state_vector,
|
||||
data_paths=selected_paths,
|
||||
)
|
||||
for data_path in selected_paths:
|
||||
series[data_path].append(values[data_path])
|
||||
return series
|
||||
|
||||
@staticmethod
|
||||
def _split_data_path(data_path: str) -> tuple[str, str]:
|
||||
if "@" not in data_path:
|
||||
raise KeyError(data_path)
|
||||
signal, alias = data_path.split("@", 1)
|
||||
return signal, alias
|
||||
|
||||
def _force_by_mass_alias(
|
||||
self,
|
||||
time_s: float,
|
||||
@@ -4406,6 +4543,43 @@ class TestMqlSystem:
|
||||
t_eval=t_eval,
|
||||
)
|
||||
|
||||
def simulate_full_state_series_from_spec(
|
||||
self,
|
||||
spec,
|
||||
*,
|
||||
inlet_node_pressure_pa: float,
|
||||
resistance_boundary_pressure_pa: float,
|
||||
inlet_node_temperature_k: float = 293.15,
|
||||
resistance_boundary_temperature_k: float = 293.15,
|
||||
config: SolveIVPConfig | None = None,
|
||||
t_eval: list[float] | None = None,
|
||||
data_paths: tuple[str, ...] | list[str] | None = None,
|
||||
) -> TestMqlSimulationResult:
|
||||
closure = self.full_state_closure_from_spec(
|
||||
spec,
|
||||
inlet_node_pressure_pa=inlet_node_pressure_pa,
|
||||
resistance_boundary_pressure_pa=resistance_boundary_pressure_pa,
|
||||
inlet_node_temperature_k=inlet_node_temperature_k,
|
||||
resistance_boundary_temperature_k=resistance_boundary_temperature_k,
|
||||
)
|
||||
solution = integrate_ode(
|
||||
rhs=lambda t, state: closure.rhs_at(t, state),
|
||||
initial_state=closure.initial_state_vector(),
|
||||
config=config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5),
|
||||
t_eval=t_eval,
|
||||
)
|
||||
times = [float(value) for value in solution.t]
|
||||
state_rows = [list(row) for row in solution.y]
|
||||
series = {
|
||||
"time": times,
|
||||
**closure.data_path_series(
|
||||
times=times,
|
||||
state_rows=state_rows,
|
||||
data_paths=data_paths,
|
||||
),
|
||||
}
|
||||
return TestMqlSimulationResult(t=times, y=state_rows, series=series)
|
||||
|
||||
@staticmethod
|
||||
def pneumatic_branch_spec(
|
||||
*,
|
||||
|
||||
Reference in new issue
Block a user