0

I am trying to build a script to size a tank. At some point I have to minimize the weight of the tank depending on three parameters (A_frames, A_stringers and t_skin) and I am using the minimize function of scipy with the SLSQP method to do it.

I begun with a very simple case without any constraints at first. I have to minize the weight for different combination of N_frames/N_stringers but for 3/4 of the combination scipy stops the optimisation at the initial guess, thinking it is the minimum value when it is obviously not (the weight function is linear and very simple!)

I don't understand this at all, especially as it doesn't appear with other methods like ‘L-BFGS-B’ but I can't use the others as they don't take into account bounds and/or constraints.

If someone has the explanation for this it would help me a lot

Here is the section of my code where the problem appears :

import numpy as np
import pandas as pd

from scipy.optimize import minimize


L_tank = 11
rho_s = 2850
rho_f= 2850
rho_skin = 2850
r_tank = 1.9

def Weight(X):
    A_frames = X[0]
    A_stringers = X[1]
    t_skin = X[2]
    return L_tank*A_stringers*rho_s*N_stringers + N_frames *A_frames*rho_f*2*np.pi*r_tank + 2*np.pi*r_tank*L_tank*t_skin*rho_skin

def grad_weight(X):
    A_frames = X[0]
    A_stringers = X[1]
    t_skin = X[2]
    grad = np.array([rho_f*2*np.pi*r_tank,  L_tank*rho_s*N_stringers ,  2*np.pi*r_tank*L_tank*rho_skin])
    return grad

for N_frames in range (4,40):
    for N_stringers in range (8,130,2):

        bnd = ((0.0, None), (0.0, None),(tshear, None))
        X0 = [0.001,0.000001,0.005]
        sol = minimize(Weight, x0 = X0,   bounds=bnd, method='SLSQP', jac = grad_weight)
           if sol.success:
                A_frames = sol.x[0]
                A_stringers = sol.x[1]
                t_skin = sol.x[2]
                weight = Weight(sol.x)
  • 2
    Your function monotonically increases. That means the minimum value is at (0,0,0), so the only way to do better is to get closer to 0. But your increment values are huge (like 30000), so there are no possible values between your initial estimate and 0. Your initial estimate is the best value. BTW, what is `tshear`? – Tim Roberts Aug 17 '23 at 17:53
  • The values of your jacobians are huge - on the order of 1e5 or so. That can interfere with the SLSQP solver. See https://stackoverflow.com/questions/76122980/fitting-data-with-scipy-optimize-minimize-with-both-constraints-and-bounds/76124870#76124870 (ctrl-f "jacobian magnitude") If I divide both your gradient and objective function by 1e5, the solver is much more likely to make progress. – Nick ODell Aug 17 '23 at 18:54
  • I found out that the design variable are too small because they are expressed in meter and meter square when I am expecting results in the ordre of milimeter or milimeter². By working with design variable closer to 1 the solver works much better – Romain Parello Aug 22 '23 at 17:31

1 Answers1

0

The following is contrived, but serves to illustrate the problem.

Your optimization objective is linear, so don't use a generic minimize; use LP, pre-calculating a coefficient matrix:

import numpy as np
from scipy.optimize import milp, Bounds

L_tank = 11
rho_s = rho_f = rho_skin = 2850
r_tank = 1.9
n_frames = np.arange(4, 40)
n_stringers = np.arange(8, 130, 2)
t_shear = 1  # entirely bogus

# All stringer terms, then all frame terms, then all skin terms
coeffs = np.stack(
    np.meshgrid(
        L_tank * rho_s * n_stringers,
         n_frames * rho_f * 2*np.pi * r_tank,
        (2*np.pi * r_tank * L_tank * rho_skin,),
    )
).reshape((3, -1)).ravel()

n_cases = coeffs.size // 3

res = milp(
    c=coeffs,
    integrality=0,
    bounds=Bounds(
        lb=np.concatenate((
            np.zeros(n_cases),
            np.zeros(n_cases),
            np.full(n_cases, fill_value=t_shear),
        ))
    ),
)
assert res.success, res.message
A_stringers, A_frames, t_skin = res.x.reshape((3, -1))

Since there are no other constraints and the objective coefficients are all positive, it's a throw-away LP construction and A_frames and A_stringers will always be 0; t_skin will be whatever you set t_shear to.

Reinderien
  • 11,755
  • 5
  • 49
  • 77
  • Thanks for your help but as I said in my description, I will add constraints later that are non-linear so I don't think your solution can be used in my more general problem. I merely would like to know why the SLSQP method is having trouble ... – Romain Parello Aug 18 '23 at 08:00
  • You didn't say that, but cool. If you show what your intended constraints _actually_ are then we can help further. – Reinderien Aug 18 '23 at 11:08