Skip to content

Meaningless results when implementing second order derivatives using Tuple notation in pyomo.DAE #2278

Open
@samphillips38

Description

@samphillips38

#When implementing second order derivatives using the (model.t, model.t) notation, I do not get reasonable results. Here's an example with the cart-pole swing-up problem. Implementing the second order derivatives as first order with respect to the first order derivative produces a reasonable result:

# Define constants
m1 = 1
m2 = 0.3
g = 9.81

# Problem global parameters
d = 1.0
d_max = 1.0
u_max = 20.0

# Construct model
model = pyo.ConcreteModel("Cart-Pole Swing-up")

# Parameters
model.T = pyo.Param(default=2)
model.l = pyo.Param(default=0.5)

# Create time
model.t = pyoDAE.ContinuousSet(bounds=(0, model.T))

# Create State variables
model.q1 = pyo.Var(model.t, bounds=(-d_max, d_max))
model.q2 = pyo.Var(model.t)

# Create control variables
model.u = pyo.Var(model.t, bounds=(-u_max, u_max))

# Create derivatives
model.q1_dot = pyoDAE.DerivativeVar(model.q1, wrt=model.t)
model.q2_dot = pyoDAE.DerivativeVar(model.q2, wrt=model.t)

model.q1_ddot = pyoDAE.DerivativeVar(model.q1, wrt=(model.t, model.t)) # This doesn't work
model.q2_ddot = pyoDAE.DerivativeVar(model.q2, wrt=(model.t, model.t)) # This doesn't work
# model.q1_ddot = pyoDAE.DerivativeVar(model.q1_dot, wrt=model.t) # This works
# model.q2_ddot = pyoDAE.DerivativeVar(model.q2_dot, wrt=model.t) # This works

# Initial and final constraints
def _init(model):
    yield model.q1[0] == 0
    yield model.q2[0] == 0
    yield model.q1_dot[0] == 0
    yield model.q2_dot[0] == 0

def _final(model):
    yield model.q1[model.T] == d
    yield model.q2[model.T] == np.pi
    yield model.q1_dot[model.T] == 0
    yield model.q2_dot[model.T] == 0

model.initial_constraints = pyo.ConstraintList(rule=_init)
model.final_constraints = pyo.ConstraintList(rule=_final)

def dynamic_constraint_1(model, t):
    q1_ddot = (model.l*m2*pyo.sin(model.q2[t])*model.q2_dot[t]**2 + model.u[t] + m2*g*pyo.cos(model.q2[t])*pyo.sin(model.q2[t])) / (m1 + m2*(1 - pyo.cos(model.q2[t])**2))
    return q1_ddot == model.q1_ddot[t]

def dynamic_constraint_2(model, t):
    q2_ddot = - (model.l*m2*pyo.cos(model.q2[t])*pyo.sin(model.q2[t])*model.q2_dot[t]**2 + model.u[t]*pyo.cos(model.q2[t]) + (m1 + m2)*g*pyo.sin(model.q2[t])) / (model.l*m1 + model.l*m2*(1 - pyo.cos(model.q2[t])**2))
    return q2_ddot == model.q2_ddot[t]

model.dynamic_constraint_1 = pyo.Constraint(model.t, rule=dynamic_constraint_1)
model.dynamic_constraint_2 = pyo.Constraint(model.t, rule=dynamic_constraint_2)

# New Objective function method - Differential equation in J
model.J = pyo.Var(model.t)
model.dJdt = pyoDAE.DerivativeVar(model.J, wrt=model.t)
model.dJdt_constraint = pyo.Constraint(model.t, rule=lambda model, t: model.dJdt[t] == model.u[t]**2)

model.objective = pyo.Objective(expr=model.J[model.T] - model.J[0])

discretizer = pyo.TransformationFactory('dae.collocation')
discretizer.apply_to(model, wrt=model.t, nfe=30, ncp=4, scheme='LAGRANGE-RADAU')

opt = pyo.SolverFactory("ipopt")
opt.solve(model, tee=True)
model.display()

Here's some plots to show a comparison of the outputs:

Screenshot 2022-02-03 at 11 45 33

Screenshot 2022-02-03 at 11 46 31

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions