完成求解器雅可比矩阵首轮优化,增加更新目录,整理了文档文件夹,增加了服务启动脚本
This commit is contained in:
1 parent
6bb0591d32
commit
16a7eb2d6c
48 files changed
+8172
-217
No files matched your search
@@ -12,6 +12,7 @@ CancellationCheck = Callable[[], bool]
|
||||
AcceptedStepCallback = Callable[[float], None]
|
||||
IntegrationStatus = Literal["completed", "cancelled", "failed"]
|
||||
DenseState = Callable[[float], list[float]]
|
||||
JacobianCallable = Callable[[float, object], object]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -30,7 +31,9 @@ StateTransitionHandler = Callable[
|
||||
_MAX_STATE_TRANSITIONS_AT_SAME_TIME = 64
|
||||
|
||||
|
||||
class _IntegrationCancelled(Exception):
|
||||
class IntegrationCancelled(Exception):
|
||||
"""Internal control-flow signal shared by RHS and Jacobian evaluation."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
@@ -59,9 +62,19 @@ class SolverSegmentDiagnostics:
|
||||
solver_start_count: int = 0
|
||||
state_transition_count: int = 0
|
||||
recoverable_retry_count: int = 0
|
||||
jacobian_evaluation_count: int = 0
|
||||
jacobian_full_build_count: int = 0
|
||||
jacobian_secant_reuse_count: int = 0
|
||||
jacobian_audit_failure_count: int = 0
|
||||
finite_difference_rhs_evaluation_count: int = 0
|
||||
jacobian_base_rhs_evaluation_count: int = 0
|
||||
jacobian_jv_audit_rhs_evaluation_count: int = 0
|
||||
exact_column_build_count: int = 0
|
||||
exact_column_fallback_count: int = 0
|
||||
jacobian_assembly_seconds: float = 0.0
|
||||
|
||||
def as_dict(self) -> dict[str, float | int]:
|
||||
return {
|
||||
result: dict[str, float | int] = {
|
||||
"startTime": self.start_time,
|
||||
"requestedStopTime": self.requested_stop_time,
|
||||
"simulatedUntil": self.simulated_until,
|
||||
@@ -73,6 +86,61 @@ class SolverSegmentDiagnostics:
|
||||
"stateTransitionCount": self.state_transition_count,
|
||||
"recoverableRetryCount": self.recoverable_retry_count,
|
||||
}
|
||||
if (
|
||||
self.jacobian_evaluation_count
|
||||
or self.finite_difference_rhs_evaluation_count
|
||||
or self.jacobian_assembly_seconds
|
||||
):
|
||||
result.update(
|
||||
{
|
||||
"jacobianEvaluationCount": self.jacobian_evaluation_count,
|
||||
"jacobianFullBuildCount": self.jacobian_full_build_count,
|
||||
"jacobianSecantReuseCount": self.jacobian_secant_reuse_count,
|
||||
"jacobianAuditFailureCount": self.jacobian_audit_failure_count,
|
||||
"finiteDifferenceRhsEvaluationCount": (
|
||||
self.finite_difference_rhs_evaluation_count
|
||||
),
|
||||
"jacobianBaseRhsEvaluationCount": (
|
||||
self.jacobian_base_rhs_evaluation_count
|
||||
),
|
||||
"jacobianJvAuditRhsEvaluationCount": (
|
||||
self.jacobian_jv_audit_rhs_evaluation_count
|
||||
),
|
||||
"exactColumnBuildCount": self.exact_column_build_count,
|
||||
"exactColumnFallbackCount": (
|
||||
self.exact_column_fallback_count
|
||||
),
|
||||
"jacobianAssemblySeconds": self.jacobian_assembly_seconds,
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
_JACOBIAN_DIAGNOSTIC_KEYS = (
|
||||
"jacobianEvaluationCount",
|
||||
"fullBuildCount",
|
||||
"secantReuseCount",
|
||||
"auditFailureCount",
|
||||
"finiteDifferenceRhsEvaluationCount",
|
||||
"baseRhsEvaluationCount",
|
||||
"jvAuditEvaluationCount",
|
||||
"exactColumnBuildCount",
|
||||
"exactColumnFallbackCount",
|
||||
"assemblySeconds",
|
||||
)
|
||||
|
||||
|
||||
def _jacobian_diagnostic_snapshot(
|
||||
jac: JacobianCallable | None,
|
||||
) -> dict[str, float]:
|
||||
diagnostics = getattr(jac, "diagnostics", None)
|
||||
if diagnostics is None:
|
||||
return {key: 0.0 for key in _JACOBIAN_DIAGNOSTIC_KEYS}
|
||||
values = diagnostics()
|
||||
return {
|
||||
key: float(values.get(key, 0.0))
|
||||
for key in _JACOBIAN_DIAGNOSTIC_KEYS
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -309,7 +377,7 @@ def _runge_kutta_4(
|
||||
for target_time in t_eval[1:]:
|
||||
while current_time < target_time:
|
||||
if cancel_check is not None and cancel_check():
|
||||
raise _IntegrationCancelled
|
||||
raise IntegrationCancelled
|
||||
dt = min(config.max_step, target_time - current_time)
|
||||
k1 = rhs(current_time, state)
|
||||
k2 = rhs(current_time + 0.5 * dt, _vector_add(state, k1, 0.5 * dt))
|
||||
@@ -374,7 +442,7 @@ def _runge_kutta_4(
|
||||
report_step(current_time)
|
||||
|
||||
_append_solution_sample(times, states, target_time, state)
|
||||
except _IntegrationCancelled:
|
||||
except IntegrationCancelled:
|
||||
status = "cancelled"
|
||||
message = "Simulation was stopped before reaching the requested end time."
|
||||
_append_solution_sample(times, states, current_time, state)
|
||||
@@ -451,7 +519,7 @@ def _runge_kutta_4_segmented(
|
||||
nonlocal current_time, last_transition, same_time_transition_count, state
|
||||
while current_time < target_time:
|
||||
if cancel_check is not None and cancel_check():
|
||||
raise _IntegrationCancelled
|
||||
raise IntegrationCancelled
|
||||
dt = min(config.max_step, target_time - current_time)
|
||||
k1 = rhs(current_time, state)
|
||||
k2 = rhs(
|
||||
@@ -565,7 +633,7 @@ def _runge_kutta_4_segmented(
|
||||
sample_time = float(sample_times[sample_index])
|
||||
_append_solution_sample(times, states, sample_time, state)
|
||||
sample_index += 1
|
||||
except _IntegrationCancelled:
|
||||
except IntegrationCancelled:
|
||||
status = "cancelled"
|
||||
message = "Simulation was stopped before reaching the requested end time."
|
||||
_append_solution_sample(times, states, current_time, state)
|
||||
@@ -595,6 +663,7 @@ def _integrate_scipy_stepwise(
|
||||
breakpoints: Sequence[float] = (),
|
||||
state_transition_handler: StateTransitionHandler | None = None,
|
||||
jac_sparsity=None,
|
||||
jac: JacobianCallable | None = None,
|
||||
) -> ODESolution:
|
||||
"""Initial stepwise integration path for breakpoints and state resets.
|
||||
|
||||
@@ -617,6 +686,7 @@ def _integrate_scipy_stepwise(
|
||||
solver_type = solver_types.get(config.method)
|
||||
if solver_type is None:
|
||||
raise ValueError(f"Unsupported integration method: {config.method}")
|
||||
implicit_jac = jac if config.method in {"BDF", "Radau"} else None
|
||||
|
||||
times = [float(config.t_start)]
|
||||
states = [[float(value)] for value in initial_state]
|
||||
@@ -632,8 +702,13 @@ def _integrate_scipy_stepwise(
|
||||
|
||||
def cancellable_rhs(time, state):
|
||||
if cancel_check():
|
||||
raise _IntegrationCancelled
|
||||
return rhs(float(time), [float(value) for value in state])
|
||||
raise IntegrationCancelled
|
||||
normalized_state = [float(value) for value in state]
|
||||
derivative = rhs(float(time), normalized_state)
|
||||
observer = getattr(implicit_jac, "observe", None)
|
||||
if observer is not None:
|
||||
observer(float(time), normalized_state, derivative)
|
||||
return derivative
|
||||
|
||||
status: IntegrationStatus = "completed"
|
||||
message = "The solver successfully reached the end of the integration interval."
|
||||
@@ -683,6 +758,7 @@ def _integrate_scipy_stepwise(
|
||||
segment_solver_starts = 0
|
||||
segment_state_transitions = 0
|
||||
segment_recoverable_retries = 0
|
||||
jacobian_work_start = _jacobian_diagnostic_snapshot(implicit_jac)
|
||||
|
||||
while has_integration_interval and last_accepted_time < integration_end:
|
||||
if cancel_check():
|
||||
@@ -695,8 +771,11 @@ def _integrate_scipy_stepwise(
|
||||
"atol": config.atol,
|
||||
"max_step": segment_max_step,
|
||||
}
|
||||
if jac_sparsity is not None and config.method in {"BDF", "Radau"}:
|
||||
solver_options["jac_sparsity"] = jac_sparsity
|
||||
if config.method in {"BDF", "Radau"}:
|
||||
if implicit_jac is not None:
|
||||
solver_options["jac"] = implicit_jac
|
||||
elif jac_sparsity is not None:
|
||||
solver_options["jac_sparsity"] = jac_sparsity
|
||||
requested_first_step = (
|
||||
0.1 * segment_max_step
|
||||
if last_recoverable_error is not None
|
||||
@@ -709,6 +788,9 @@ def _integrate_scipy_stepwise(
|
||||
)
|
||||
|
||||
try:
|
||||
start_segment = getattr(implicit_jac, "start_segment", None)
|
||||
if start_segment is not None:
|
||||
start_segment()
|
||||
solver = solver_type(
|
||||
cancellable_rhs,
|
||||
last_accepted_time,
|
||||
@@ -716,7 +798,7 @@ def _integrate_scipy_stepwise(
|
||||
integration_end,
|
||||
**solver_options,
|
||||
)
|
||||
except _IntegrationCancelled:
|
||||
except IntegrationCancelled:
|
||||
status = "cancelled"
|
||||
message = cancellation_message()
|
||||
break
|
||||
@@ -755,7 +837,7 @@ def _integrate_scipy_stepwise(
|
||||
step_start_state = list(last_accepted_state)
|
||||
try:
|
||||
step_message = solver.step()
|
||||
except _IntegrationCancelled:
|
||||
except IntegrationCancelled:
|
||||
status = "cancelled"
|
||||
message = (
|
||||
"Simulation was stopped before reaching the requested end time."
|
||||
@@ -957,6 +1039,11 @@ def _integrate_scipy_stepwise(
|
||||
if not restart_at_transition:
|
||||
break
|
||||
|
||||
jacobian_work_end = _jacobian_diagnostic_snapshot(implicit_jac)
|
||||
jacobian_work = {
|
||||
key: jacobian_work_end[key] - jacobian_work_start[key]
|
||||
for key in _JACOBIAN_DIAGNOSTIC_KEYS
|
||||
}
|
||||
solver_segments.append(
|
||||
SolverSegmentDiagnostics(
|
||||
start_time=float(segment_start_time),
|
||||
@@ -971,6 +1058,34 @@ def _integrate_scipy_stepwise(
|
||||
solver_start_count=segment_solver_starts,
|
||||
state_transition_count=segment_state_transitions,
|
||||
recoverable_retry_count=segment_recoverable_retries,
|
||||
jacobian_evaluation_count=int(
|
||||
jacobian_work["jacobianEvaluationCount"]
|
||||
),
|
||||
jacobian_full_build_count=int(
|
||||
jacobian_work["fullBuildCount"]
|
||||
),
|
||||
jacobian_secant_reuse_count=int(
|
||||
jacobian_work["secantReuseCount"]
|
||||
),
|
||||
jacobian_audit_failure_count=int(
|
||||
jacobian_work["auditFailureCount"]
|
||||
),
|
||||
finite_difference_rhs_evaluation_count=int(
|
||||
jacobian_work["finiteDifferenceRhsEvaluationCount"]
|
||||
),
|
||||
jacobian_base_rhs_evaluation_count=int(
|
||||
jacobian_work["baseRhsEvaluationCount"]
|
||||
),
|
||||
jacobian_jv_audit_rhs_evaluation_count=int(
|
||||
jacobian_work["jvAuditEvaluationCount"]
|
||||
),
|
||||
exact_column_build_count=int(
|
||||
jacobian_work["exactColumnBuildCount"]
|
||||
),
|
||||
exact_column_fallback_count=int(
|
||||
jacobian_work["exactColumnFallbackCount"]
|
||||
),
|
||||
jacobian_assembly_seconds=jacobian_work["assemblySeconds"],
|
||||
)
|
||||
)
|
||||
if status != "completed":
|
||||
@@ -1034,6 +1149,7 @@ def integrate_ode(
|
||||
breakpoints: Sequence[float] | None = None,
|
||||
state_transition_handler: StateTransitionHandler | None = None,
|
||||
jac_sparsity=None,
|
||||
jac: JacobianCallable | None = None,
|
||||
):
|
||||
"""Integrate an ODE, optionally restarting at equation discontinuities.
|
||||
|
||||
@@ -1104,10 +1220,26 @@ def integrate_ode(
|
||||
normalized_breakpoints,
|
||||
state_transition_handler,
|
||||
jac_sparsity,
|
||||
jac,
|
||||
)
|
||||
|
||||
implicit_jac = jac if config.method in {"BDF", "Radau"} else None
|
||||
solve_rhs = rhs
|
||||
if implicit_jac is not None:
|
||||
observer = getattr(implicit_jac, "observe", None)
|
||||
if observer is not None:
|
||||
def observed_rhs(time, state):
|
||||
derivative = rhs(time, state)
|
||||
observer(float(time), state, derivative)
|
||||
return derivative
|
||||
|
||||
solve_rhs = observed_rhs
|
||||
start_segment = getattr(implicit_jac, "start_segment", None)
|
||||
if start_segment is not None:
|
||||
start_segment()
|
||||
|
||||
solve_options = {
|
||||
"fun": rhs,
|
||||
"fun": solve_rhs,
|
||||
"t_span": (config.t_start, config.t_stop),
|
||||
"y0": initial_state,
|
||||
"method": config.method,
|
||||
@@ -1118,6 +1250,8 @@ def integrate_ode(
|
||||
}
|
||||
if config.first_step is not None:
|
||||
solve_options["first_step"] = config.first_step
|
||||
if jac_sparsity is not None and config.method in {"BDF", "Radau"}:
|
||||
if implicit_jac is not None:
|
||||
solve_options["jac"] = implicit_jac
|
||||
elif jac_sparsity is not None and config.method in {"BDF", "Radau"}:
|
||||
solve_options["jac_sparsity"] = jac_sparsity
|
||||
return solve_ivp(**solve_options)
|
||||
Reference in new issue
Block a user