Jacob Schwartz
Jacob Schwartz

Reputation: 83

In OpenMDAO, why might the optimizer try values for design variables far outside the specified range?

I'm using the pyOptSparseDriver and my optimizer is SLSQP. I have a design variable A defined with

ivc = om.IndepVarComp()
ivc.add_output("A", 2.00)
...
prob.model.add_design_var("A", lower=1.6, upper=5.00, ref=1.6)

A represents the aspect ratio of a torus, so it always needs to be larger than 1 to make physical sense; here I've given it a slightly higher 'reasonable' lower bound.

In a component -- actually the first component in the first group in the model -- I see that A is being given negative values in its input, and even nan (which results in errors and eventually halting the code). The component is an ExplicitComponent and the group that it's in does not have a specific solver attached; the n2 shows that it's LN:RUNONCE.

Is this expected behavior? Is there a way to prevent this from happening?

Things I've tried

Changing from pyOptSparseDriver to ScipyOptimizerDriver results in not raising this issue, but I might like to use the former for other reasons.

I have other variables named A elsewhere in the model (but encapsulated within groups) so I suspected this might be a bug related to naming; I tried renaming A to Asp (which is unique in my model) but the issue still occurred.

Why I don't have a MWE

I tried removing parts of the model after this initial group, but in doing so I had to change the objective function. Then, the issue no longer occurred.

Possible hints?

Later in the model I have a group with a NewtonSolver, which I'll call secondsolver. It uses a Armijo linesearch with the default parameters for rho and c.

newton.linesearch = om.ArmijoGoldsteinLS(retry_on_analysis_error=True,
            rho=0.5, c=0.1, method="Armijo", bound_enforcement="vector")

I added a print statement the component's compute function; when I run the code it outputs

...

===========
thirdsolver
===========
NL: Newton 0 ; 6.54500652 1
|  LS: BCHK 0 ; 0.000394994169 6.03504623e-05
NL: Newton 1 ; 4.4408921e-17 6.7851607e-18
NL: Newton Converged
A in compute is [-37490.25190183]
A in compute is [-18743.90453135]
A in compute is [-9370.73084611]
A in compute is [-4684.1440035]
A in compute is [-2340.85058219]
A in compute is [-1169.20387153]
A in compute is [-583.3805162]
A in compute is [-290.46883854]
A in compute is [-144.01299971]
A in compute is [-70.78508029]
A in compute is [-34.17112058]
<test.py>:104: RuntimeWarning: invalid value encountered in power
<problematic line here; it's from the
 analytic derivative of this first component, where A is being raised to a small, constant, nonzero power>
A in compute is [nan]

Here thirdsolver is a NewtonSolver later in the model. Maybe the printing is occurring out-of-order? Anyway, the values for A each differ by a factor of 2 (at least at the higher values), so perhaps that's related to rho=0.5. If I change the parameters rho or c on that linesearch the error no longer occurs.

I can slightly change one of those parameters and move on, but if there's a better explanation for what's going on, I'd like to be able to avoid it in the future.

Upvotes: 1

Views: 186

Answers (1)

Justin Gray
Justin Gray

Reputation: 5710

In older versions of SLSQP, there were bugs in the design variable bounds enforcement. This was fixed in the scipy SLSQP code base, but never in the pyoptsparse one. In other words the SLSQP code in the two code bases is not the same, and has diverged a bit. That explains why ScipyOptimizerDriver is respecting your bounds and pyOptSparseDriver is not (when using SLSQP). If you switch to IPOPT in pyOptSparse, then it would respect your bounds.

Upvotes: 1

Related Questions