优化求解器重试并校正AMESim机械端口

This commit is contained in:
huojiarong committed 2026-08-03 09:54:46 +00:00
1 parent 971e8f2336
commit 18d9802f03
15 files changed
+383 -166

No files matched your search

+65 -9
View File
@@ -1,5 +1,7 @@
from __future__ import annotations
from app.simulation.core.errors import RecoverableTrialStateError
import math
from dataclasses import dataclass
from typing import Callable, Literal, Sequence
@@ -535,11 +537,10 @@ def _integrate_scipy_stepwise(
) -> ODESolution:
"""Initial stepwise integration path for breakpoints and state resets.
Known V1 limitation: an adaptive solver can evaluate a trial state outside
the algebraic or thermodynamic model domain. Such an RHS exception still
aborts the run here; recoverable trial failures are not yet restored to the
last accepted state and retried with a smaller step. This is not specific
to BDF, although implicit Newton/Jacobian probes make it especially visible.
Recoverable physical-domain failures from rejected integrator trial states
restore the last accepted state and rebuild the same solver with a smaller
maximum/first step. Structural, algebraic, and ordinary model errors still
fail immediately.
"""
import numpy as np
from scipy.integrate import BDF, DOP853, LSODA, RK23, RK45, Radau
@@ -609,6 +610,9 @@ def _integrate_scipy_stepwise(
math.nextafter(segment_end, -math.inf) if is_breakpoint else segment_end
)
has_integration_interval = integration_end > last_accepted_time
segment_max_step = float(config.max_step)
recoverable_retry_count = 0
last_recoverable_error: RecoverableTrialStateError | None = None
while has_integration_interval and last_accepted_time < integration_end:
if cancel_check():
@@ -619,11 +623,16 @@ def _integrate_scipy_stepwise(
solver_options = {
"rtol": config.rtol,
"atol": config.atol,
"max_step": config.max_step,
"max_step": segment_max_step,
}
if config.first_step is not None:
requested_first_step = (
0.1 * segment_max_step
if last_recoverable_error is not None
else config.first_step
)
if requested_first_step is not None:
solver_options["first_step"] = min(
config.first_step,
requested_first_step,
integration_end - last_accepted_time,
)
@@ -639,6 +648,18 @@ def _integrate_scipy_stepwise(
status = "cancelled"
message = cancellation_message()
break
except RecoverableTrialStateError as exc:
recoverable_retry_count += 1
last_recoverable_error = exc
next_step = 0.5 * segment_max_step
minimum_step = 64.0 * math.ulp(max(abs(last_accepted_time), 1.0))
if recoverable_retry_count > 16 or next_step <= minimum_step:
status = "failed"
message = str(exc)
error = exc
break
segment_max_step = next_step
continue
except Exception as exc:
status = "failed"
message = str(exc)
@@ -646,6 +667,7 @@ def _integrate_scipy_stepwise(
break
restart_at_transition = False
restart_after_recoverable = False
while solver.status == "running":
if cancel_check():
status = "cancelled"
@@ -664,6 +686,22 @@ def _integrate_scipy_stepwise(
"Simulation was stopped before reaching the requested end time."
)
break
except RecoverableTrialStateError as exc:
recoverable_retry_count += 1
last_recoverable_error = exc
attempted_step = segment_max_step
next_step = 0.5 * attempted_step
minimum_step = 64.0 * math.ulp(
max(abs(last_accepted_time), 1.0)
)
if recoverable_retry_count > 16 or next_step <= minimum_step:
status = "failed"
message = str(exc)
error = exc
break
segment_max_step = next_step
restart_after_recoverable = True
break
except Exception as exc:
status = "failed"
message = str(exc)
@@ -672,6 +710,19 @@ def _integrate_scipy_stepwise(
integration_progressed = True
if solver.status == "failed":
if last_recoverable_error is not None:
recoverable_retry_count += 1
next_step = 0.5 * segment_max_step
minimum_step = 64.0 * math.ulp(
max(abs(last_accepted_time), 1.0)
)
if (
recoverable_retry_count <= 16
and next_step > minimum_step
):
segment_max_step = next_step
restart_after_recoverable = True
break
status = "failed"
message = str(step_message or "Integration step failed.")
break
@@ -775,6 +826,7 @@ def _integrate_scipy_stepwise(
last_accepted_time = step_end_time
last_accepted_state = step_end_state
recoverable_retry_count = 0
reported_time = (
float(segment_end)
if is_breakpoint and solver.status == "finished"
@@ -806,7 +858,11 @@ def _integrate_scipy_stepwise(
)
report_step(reported_time)
if status != "completed" or not restart_at_transition:
if status != "completed":
break
if restart_after_recoverable:
continue
if not restart_at_transition:
break
if status != "completed":