优化求解器重试并校正AMESim机械端口
This commit is contained in:
1 parent
971e8f2336
commit
18d9802f03
15 files changed
+383
-166
No files matched your search
@@ -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":
|
||||
|
||||
Reference in new issue
Block a user