增加可选性能埋点并完成物性效率评估

This commit is contained in:
ljz committed 2026-08-16 17:46:04 +08:00
1 parent 4e0b9fd8cc
commit 57b459bc72
21 files changed
+2029 -179

No files matched your search

+155 -130
View File
@@ -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,
)