-
Notifications
You must be signed in to change notification settings - Fork 25
Open
Description
Environment
opstool version: 1.0.26
Python version: 3.12
OS: Windows 10
Description
When using SmartAnalyze for transient analysis, if the step size converges to a value smaller than minStep, the _try_relax_step strategy enters a state where it repeatedly prints the failure message without properly exiting or falling back to other strategies. This causes the outer loop to call TransientAnalyze indefinitely, generating massive redundant logs.
Reproduction Steps
- Create an OpenSees model with convergence difficulties.
- Run transient analysis using
SmartAnalyze. - Observe the output once the solver struggles to converge.
Actual Behavior (Logs)
🚀 OPSTOOL::SmartAnalyze: 14%|██████▍ | 1390/10000 [05:03<5:11:49, 2.17s/ step]
>>> ✳️ OPSTOOL::SmartAnalyze:: Current step 3.432e-04 is below the min step 4.304e-04.
🚀 OPSTOOL::SmartAnalyze: 100%|█████████████████████████████████████████████████| 1390/1390 [05:06<00:00, 4.53 step/s]
>>> ❌ OPSTOOL::SmartAnalyze:: Analyze failed. Time consumption: 306.680 s.
>>> ✳️ OPSTOOL::SmartAnalyze:: Current step 3.432e-04 is below the min step 4.304e-04.
>>> ❌ OPSTOOL::SmartAnalyze:: Analyze failed. Time consumption: 310.019 s.
... (Infinite repetition)
Root Cause
In _smart_analyze.py (approx. lines 788-797), the _try_relax_step method returns -1 immediately when step_try < min_step without attempting a final try at the min_step limit. This causes the strategy to fail early and "trap" the outer loop in a repetitive failure path.
Expected Behavior
- If
step_try<minStep, it should be clamped tominStepand attempted one last time. - If the analysis still fails at
minStep, the strategy should be abandoned to allow_analyze()to try fallback methods (e.g.,_try_loose_test_tol). - The final sub-step (
step_remaining<minStep) should be allowed to run without theminSteprestriction.
Suggested Fix
Modify the logic in _try_relax_step as follows:
ok = -1
while step_remaining > self.eps:
# Clamp step_try to min_step, but allow final sub-step (step_remaining < min_step) to be smaller
clamped_to_min = False
if step_try < min_step and step_remaining >= min_step:
if verbose:
print(f">>> ✳️ {self.logo} Step {step_try:.3e} below min step, clamping to {min_step:.3e}.")
step_try = min_step
clamped_to_min = True
if step_try > step_remaining:
step_try = step_remaining # avoid overshooting
# Try to run one substep
ok = self._analyze_one_step(step_try, verbose=verbose)
if ok == 0:
step_remaining -= step_try
step_try = step_remaining
# ... verbose output ...
else:
# If we already clamped to min_step and still failed, give up this strategy
if clamped_to_min:
if verbose:
print(f">>> ✳️ {self.logo} Failed at min step {min_step:.3e}, giving up relax_step strategy.")
return -1
# Shrink step_try and continue
step_try *= alpha
# ... verbose output ...
return okReactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels