增加可选性能埋点并完成物性效率评估
This commit is contained in:
1 parent
4e0b9fd8cc
commit
57b459bc72
21 files changed
+2029
-179
No files matched your search
+155
-130
@@ -7,6 +7,7 @@ from typing import Literal
|
||||
|
||||
from app.simulation.core.base import DynamicComponent
|
||||
from app.simulation.core.metadata import ResultVariableMetadata
|
||||
from app.simulation.performance import performance_span, profile_phase
|
||||
from app.simulation.solvers.algebraic import PressureFlowSolver
|
||||
from app.simulation.solvers.mechanical import (
|
||||
MechanicalConstraintGroup,
|
||||
@@ -337,6 +338,7 @@ def simulation_sample_times(
|
||||
class GenericFluidSystem:
|
||||
"""Topology-driven, semi-explicit fluid simulation for registered components."""
|
||||
|
||||
@profile_phase("simulation.system_construction")
|
||||
def __init__(self, network: SimulationNetwork) -> None:
|
||||
issues = simulation_preparation_issues(network)
|
||||
if issues:
|
||||
@@ -465,14 +467,18 @@ class GenericFluidSystem:
|
||||
"colorGroupCount": group_count,
|
||||
}
|
||||
|
||||
@profile_phase(
|
||||
"simulation.closure",
|
||||
minimum_mode="audit",
|
||||
reset_property_shadow=True,
|
||||
)
|
||||
def _close_current_state(self, time: float) -> dict[str, dict[str, float]]:
|
||||
signal = self.signal_resolver.solve(time)
|
||||
self.signal_propagation_count += signal.propagated
|
||||
self.pressure_flow_solver.propagate_equal_efforts(("x", "v"))
|
||||
pneumatic_volume = self.pneumatic_volume_resolver.solve()
|
||||
self.pneumatic_volume_propagation_count += pneumatic_volume.propagated
|
||||
for component in self.dynamic_components:
|
||||
component.refresh_thermodynamic_ports()
|
||||
self._refresh_dynamic_components()
|
||||
algebraic = self.pressure_flow_solver.solve(
|
||||
effort_variables=("p",),
|
||||
)
|
||||
@@ -549,18 +555,31 @@ class GenericFluidSystem:
|
||||
)
|
||||
return connected_h
|
||||
|
||||
@profile_phase("simulation.refresh", minimum_mode="audit")
|
||||
def _refresh_dynamic_components(self) -> None:
|
||||
for component in self.dynamic_components:
|
||||
component.refresh_thermodynamic_ports()
|
||||
|
||||
@profile_phase("simulation.derivatives", minimum_mode="audit")
|
||||
def _state_derivatives(
|
||||
self,
|
||||
connected_h: dict[str, dict[str, float]],
|
||||
) -> list[float]:
|
||||
return self.pneumatic_storage_reducer.coupled_derivatives(
|
||||
self.mechanical_state_reducer.state_derivatives(connected_h)
|
||||
)
|
||||
|
||||
def consistent_initial_state_vector(self, time: float = 0.0) -> list[float]:
|
||||
state = self.initial_state_vector()
|
||||
self.apply_state_vector(state)
|
||||
self._close_current_state(time)
|
||||
return state
|
||||
|
||||
@profile_phase("simulation.rhs", minimum_mode="audit")
|
||||
def rhs(self, _time: float, state_vector: list[float]) -> list[float]:
|
||||
self.apply_state_vector(state_vector)
|
||||
connected_h = self._close_current_state(_time)
|
||||
return self.pneumatic_storage_reducer.coupled_derivatives(
|
||||
self.mechanical_state_reducer.state_derivatives(connected_h)
|
||||
)
|
||||
return self._state_derivatives(connected_h)
|
||||
|
||||
def _append_current_state(self, series: dict[str, list[float]]) -> None:
|
||||
for component in self.network.components.values():
|
||||
@@ -603,20 +622,26 @@ class GenericFluidSystem:
|
||||
progress_callback(last_reported_progress, phase)
|
||||
|
||||
report_progress(0.0, "initializing", force=True)
|
||||
integration_config = config
|
||||
if isinstance(config.atol, (int, float)):
|
||||
integration_config = replace(
|
||||
config,
|
||||
atol=self.mechanical_state_reducer.absolute_tolerances(
|
||||
float(config.atol)
|
||||
),
|
||||
with performance_span("simulation.sample_initialization"):
|
||||
integration_config = config
|
||||
if isinstance(config.atol, (int, float)):
|
||||
integration_config = replace(
|
||||
config,
|
||||
atol=self.mechanical_state_reducer.absolute_tolerances(
|
||||
float(config.atol)
|
||||
),
|
||||
)
|
||||
t_eval = simulation_sample_times(config, sample_step)
|
||||
signal_event_times = self.signal_resolver.event_times(
|
||||
config.t_start,
|
||||
config.t_stop,
|
||||
)
|
||||
initial_state = self.consistent_initial_state_vector(config.t_start)
|
||||
jac_sparsity = (
|
||||
self.jacobian_sparsity()
|
||||
if integration_config.method in {"BDF", "Radau"}
|
||||
else None
|
||||
)
|
||||
t_eval = simulation_sample_times(config, sample_step)
|
||||
signal_event_times = self.signal_resolver.event_times(
|
||||
config.t_start,
|
||||
config.t_stop,
|
||||
)
|
||||
initial_state = self.consistent_initial_state_vector(config.t_start)
|
||||
report_progress(0.0, "integrating", force=True)
|
||||
duration = config.t_stop - config.t_start
|
||||
furthest_solver_time = config.t_start
|
||||
@@ -651,11 +676,7 @@ class GenericFluidSystem:
|
||||
if self.mechanical_state_reducer.has_state_events
|
||||
else None
|
||||
),
|
||||
jac_sparsity=(
|
||||
self.jacobian_sparsity()
|
||||
if integration_config.method in {"BDF", "Radau"}
|
||||
else None
|
||||
),
|
||||
jac_sparsity=jac_sparsity,
|
||||
)
|
||||
if isinstance(solution, ODESolution):
|
||||
run_status: SimulationRunStatus = solution.status
|
||||
@@ -719,112 +740,116 @@ class GenericFluidSystem:
|
||||
for segment in solver_segment_diagnostics
|
||||
)
|
||||
|
||||
series: dict[str, list[float]] = {"time": []}
|
||||
postprocessing_error: Exception | None = None
|
||||
self.mechanical_state_reducer.reset_constraint_modes()
|
||||
for time_index in range(len(times)):
|
||||
if (
|
||||
run_status == "completed"
|
||||
and cancel_check is not None
|
||||
and cancel_check()
|
||||
):
|
||||
run_status = "cancelled"
|
||||
result_message = "Simulation was stopped while preparing partial results."
|
||||
break
|
||||
state = [
|
||||
float(solution.y[state_index][time_index])
|
||||
for state_index in range(len(solution.y))
|
||||
]
|
||||
try:
|
||||
self.apply_state_vector(state)
|
||||
self._close_current_state(times[time_index])
|
||||
self._append_current_state(series)
|
||||
series["time"].append(times[time_index])
|
||||
except Exception as exc:
|
||||
run_status = "failed"
|
||||
result_message = str(exc)
|
||||
postprocessing_error = exc
|
||||
break
|
||||
if len(series["time"]) < 2:
|
||||
if postprocessing_error is not None:
|
||||
raise postprocessing_error
|
||||
if integration_error is not None:
|
||||
raise integration_error
|
||||
with performance_span("simulation.postprocessing"):
|
||||
series: dict[str, list[float]] = {"time": []}
|
||||
postprocessing_error: Exception | None = None
|
||||
self.mechanical_state_reducer.reset_constraint_modes()
|
||||
for time_index in range(len(times)):
|
||||
if (
|
||||
run_status == "completed"
|
||||
and cancel_check is not None
|
||||
and cancel_check()
|
||||
):
|
||||
run_status = "cancelled"
|
||||
result_message = (
|
||||
"Simulation was stopped while preparing partial results."
|
||||
)
|
||||
break
|
||||
state = [
|
||||
float(solution.y[state_index][time_index])
|
||||
for state_index in range(len(solution.y))
|
||||
]
|
||||
try:
|
||||
self.apply_state_vector(state)
|
||||
self._close_current_state(times[time_index])
|
||||
self._append_current_state(series)
|
||||
series["time"].append(times[time_index])
|
||||
except Exception as exc:
|
||||
run_status = "failed"
|
||||
result_message = str(exc)
|
||||
postprocessing_error = exc
|
||||
break
|
||||
if len(series["time"]) < 2:
|
||||
if postprocessing_error is not None:
|
||||
raise postprocessing_error
|
||||
if integration_error is not None:
|
||||
raise integration_error
|
||||
|
||||
final = {
|
||||
key: values[-1]
|
||||
for key, values in series.items()
|
||||
if key != "time" and values
|
||||
}
|
||||
diagnostics = {
|
||||
"integration": {
|
||||
"method": integration_config.method,
|
||||
"jacobianSparsity": jacobian_diagnostics,
|
||||
"segmentCount": len(solver_segment_diagnostics),
|
||||
"segments": solver_segment_diagnostics,
|
||||
"totals": solver_totals,
|
||||
},
|
||||
"pressureFlow": {
|
||||
"solveCount": self.algebraic_solve_count,
|
||||
"maxScaledResidual": self.max_algebraic_residual,
|
||||
"maxEvaluationsPerSolve": self.max_algebraic_evaluations,
|
||||
"last": (
|
||||
self.pressure_flow_solver.last_diagnostics.as_dict()
|
||||
if self.pressure_flow_solver.last_diagnostics is not None
|
||||
else None
|
||||
with performance_span("simulation.result_assembly"):
|
||||
final = {
|
||||
key: values[-1]
|
||||
for key, values in series.items()
|
||||
if key != "time" and values
|
||||
}
|
||||
diagnostics = {
|
||||
"integration": {
|
||||
"method": integration_config.method,
|
||||
"jacobianSparsity": jacobian_diagnostics,
|
||||
"segmentCount": len(solver_segment_diagnostics),
|
||||
"segments": solver_segment_diagnostics,
|
||||
"totals": solver_totals,
|
||||
},
|
||||
"pressureFlow": {
|
||||
"solveCount": self.algebraic_solve_count,
|
||||
"maxScaledResidual": self.max_algebraic_residual,
|
||||
"maxEvaluationsPerSolve": self.max_algebraic_evaluations,
|
||||
"last": (
|
||||
self.pressure_flow_solver.last_diagnostics.as_dict()
|
||||
if self.pressure_flow_solver.last_diagnostics is not None
|
||||
else None
|
||||
),
|
||||
},
|
||||
"stream": {
|
||||
"maxIterationsPerSolve": self.max_stream_iterations,
|
||||
"maxThermofluidIterations": self.max_thermofluid_iterations,
|
||||
"last": (
|
||||
self.stream_resolver.last_diagnostics.as_dict()
|
||||
if self.stream_resolver.last_diagnostics is not None
|
||||
else None
|
||||
),
|
||||
},
|
||||
"signal": {
|
||||
"propagations": self.signal_propagation_count,
|
||||
"eventTimes": list(signal_event_times),
|
||||
"last": (
|
||||
self.signal_resolver.last_diagnostics.as_dict()
|
||||
if self.signal_resolver.last_diagnostics is not None
|
||||
else None
|
||||
),
|
||||
},
|
||||
"pneumaticVolume": {
|
||||
"propagations": self.pneumatic_volume_propagation_count,
|
||||
"last": (
|
||||
self.pneumatic_volume_resolver.last_diagnostics.as_dict()
|
||||
if self.pneumatic_volume_resolver.last_diagnostics is not None
|
||||
else None
|
||||
),
|
||||
},
|
||||
"stateCount": len(initial_state),
|
||||
"sampleCount": len(series["time"]),
|
||||
}
|
||||
variables = tuple(
|
||||
variable
|
||||
for variable in self.network.result_variable_metadata()
|
||||
if variable.key in series
|
||||
)
|
||||
report_progress(
|
||||
1.0 if run_status == "completed" else max(0.0, last_reported_progress),
|
||||
"complete" if run_status == "completed" else run_status,
|
||||
force=True,
|
||||
)
|
||||
return GenericSimulationResult(
|
||||
success=run_status == "completed" and bool(solution.success),
|
||||
status=run_status,
|
||||
message=result_message,
|
||||
simulated_until=(
|
||||
float(series["time"][-1])
|
||||
if series["time"]
|
||||
else float(config.t_start)
|
||||
),
|
||||
},
|
||||
"stream": {
|
||||
"maxIterationsPerSolve": self.max_stream_iterations,
|
||||
"maxThermofluidIterations": self.max_thermofluid_iterations,
|
||||
"last": (
|
||||
self.stream_resolver.last_diagnostics.as_dict()
|
||||
if self.stream_resolver.last_diagnostics is not None
|
||||
else None
|
||||
),
|
||||
},
|
||||
"signal": {
|
||||
"propagations": self.signal_propagation_count,
|
||||
"eventTimes": list(signal_event_times),
|
||||
"last": (
|
||||
self.signal_resolver.last_diagnostics.as_dict()
|
||||
if self.signal_resolver.last_diagnostics is not None
|
||||
else None
|
||||
),
|
||||
},
|
||||
"pneumaticVolume": {
|
||||
"propagations": self.pneumatic_volume_propagation_count,
|
||||
"last": (
|
||||
self.pneumatic_volume_resolver.last_diagnostics.as_dict()
|
||||
if self.pneumatic_volume_resolver.last_diagnostics is not None
|
||||
else None
|
||||
),
|
||||
},
|
||||
"stateCount": len(initial_state),
|
||||
"sampleCount": len(series["time"]),
|
||||
}
|
||||
variables = tuple(
|
||||
variable
|
||||
for variable in self.network.result_variable_metadata()
|
||||
if variable.key in series
|
||||
)
|
||||
report_progress(
|
||||
1.0 if run_status == "completed" else max(0.0, last_reported_progress),
|
||||
"complete" if run_status == "completed" else run_status,
|
||||
force=True,
|
||||
)
|
||||
return GenericSimulationResult(
|
||||
success=run_status == "completed" and bool(solution.success),
|
||||
status=run_status,
|
||||
message=result_message,
|
||||
simulated_until=(
|
||||
float(series["time"][-1])
|
||||
if series["time"]
|
||||
else float(config.t_start)
|
||||
),
|
||||
requested_stop_time=float(config.t_stop),
|
||||
variables=variables,
|
||||
series=series,
|
||||
final=final,
|
||||
diagnostics=diagnostics,
|
||||
)
|
||||
requested_stop_time=float(config.t_stop),
|
||||
variables=variables,
|
||||
series=series,
|
||||
final=final,
|
||||
diagnostics=diagnostics,
|
||||
)
|
||||
Reference in new issue
Block a user