# Source code for openmdao.lib.optproblems.sellar

"""
Two discipline components.
From Sellar's analytic problem.

Sellar, R. S., Batill, S. M., and Renaud, J. E., "Response Surface Based, Concurrent Subspace
Optimization for Multidisciplinary System Design," Proceedings References 79 of the 34th AIAA
Aerospace Sciences Meeting and Exhibit, Reno, NV, January 1996.
"""

from openmdao.main.api import Component, ComponentWithDerivatives
from openmdao.main.problem_formulation import OptProblem
from openmdao.lib.datatypes.api import Float

[docs]class Discipline1(Component):
"""Component containing Discipline 1."""

# pylint: disable-msg=E1101
z1 = Float(0.0, iotype='in', desc='Global Design Variable.')
z2 = Float(0.0, iotype='in', desc='Global Design Variable.')
x1 = Float(1.0, iotype='in', desc='Local Design Variable.')
y2 = Float(1.0, iotype='in', desc='Disciplinary Coupling.')

y1 = Float(iotype='out', desc='Output of this Discipline.')

[docs]    def execute(self):
"""Evaluates the equation
y1 = z1**2 + z2 + x1 - 0.2*y2"""

z1 = self.z1
z2 = self.z2
x1 = self.x1
y2 = self.y2

self.y1 = z1**2 + z2 + x1 - 0.2*y2
#print "(%f, %f, %f)" % (z1, z2, x1)

[docs]class Discipline1_WithDerivatives(ComponentWithDerivatives):
"""Component containing Discipline 1."""

# pylint: disable-msg=E1101
z1 = Float(0.0, iotype='in', desc='Global Design Variable.')
z2 = Float(0.0, iotype='in', desc='Global Design Variable.')
x1 = Float(0.0, iotype='in', desc='Local Design Variable.')
y2 = Float(1.0, iotype='in', desc='Disciplinary Coupling.')

y1 = Float(iotype='out', desc='Output of this Discipline.')

def __init__(self):
super(Discipline1_WithDerivatives,self).__init__()

self.derivatives.declare_first_derivative('y1', 'z1')
self.derivatives.declare_first_derivative('y1', 'z2')
self.derivatives.declare_first_derivative('y1', 'x1')
self.derivatives.declare_first_derivative('y1', 'y2')

[docs]    def calculate_first_derivatives(self):
"""Analytical first derivatives"""

self.derivatives.set_first_derivative('y1', 'z1', 2.0*self.z1)
self.derivatives.set_first_derivative('y1', 'z2', 1.0)
self.derivatives.set_first_derivative('y1', 'x1', 1.0)
self.derivatives.set_first_derivative('y1', 'y2', -0.2)

[docs]    def execute(self):
"""Evaluates the equation
y1 = z1**2 + z2 + x1 - 0.2*y2."""

z1 = self.z1
z2 = self.z2
x1 = self.x1
y2 = self.y2

self.y1 = z1**2 + z2 + x1 - 0.2*y2
#print "(%f, %f, %f)" % (z1, z2, x1)

[docs]class Discipline2(Component):
"""Component containing Discipline 2."""

# pylint: disable-msg=E1101
z1 = Float(0.0, iotype='in', desc='Global Design Variable.')
z2 = Float(0.0, iotype='in', desc='Global Design Variable.')
y1 = Float(1.0, iotype='in', desc='Disciplinary Coupling.')

y2 = Float(iotype='out', desc='Output of this Discipline.')

[docs]    def execute(self):
"""Evaluates the equation
y2 = y1**(.5) + z1 + z2"""

z1 = self.z1
z2 = self.z2

# Note: this may cause some issues. However, y1 is constrained to be
# above 3.16, so lets just let it converge, and the optimizer will
# throw it out
y1 = abs(self.y1)

self.y2 = y1**(.5) + z1 + z2

[docs]class Discipline2_WithDerivatives(ComponentWithDerivatives):
"""Component containing Discipline 2."""

# pylint: disable-msg=E1101
z1 = Float(0.0, iotype='in', desc='Global Design Variable.')
z2 = Float(0.0, iotype='in', desc='Global Design Variable.')
y1 = Float(1.0, iotype='in', desc='Disciplinary Coupling.')

y2 = Float(iotype='out', desc='Output of this Discipline.')

def __init__(self):
super(Discipline2_WithDerivatives,self).__init__()

self.derivatives.declare_first_derivative('y2', 'z1')
self.derivatives.declare_first_derivative('y2', 'z2')
self.derivatives.declare_first_derivative('y2', 'y1')

[docs]    def calculate_first_derivatives(self):
"""Analytical first derivatives"""

self.derivatives.set_first_derivative('y2', 'z1', 1.0)
self.derivatives.set_first_derivative('y2', 'z2', 1.0)
# Derivative blows up around y1=0, and is imaginary for y1<0
# y1 should be kept above 0.
self.derivatives.set_first_derivative('y2', 'y1', .5*(abs(self.y1))**-0.5)

[docs]    def execute(self):
"""Evaluates the equation
y2 = y1**(.5) + z1 + z2."""

z1 = self.z1
z2 = self.z2

# Note: this may cause some issues. However, y1 is constrained to be
# above 3.16, so lets just let it converge, and the optimizer will
# throw it out
y1 = abs(self.y1)

self.y2 = y1**(.5) + z1 + z2

[docs]class SellarProblem(OptProblem):
""" Sellar test problem definition."""

[docs]    def configure(self):
"""
Optimal Design at (1.9776, 0, 0)

Optimal Objective = 3.18339"""

#add the discipline components to the assembly

#START OF MDAO Problem Definition
#Global Des Vars

#Local Des Vars

#Coupling Vars

self.add_objective('(dis1.x1)**2 + dis1.z2 + dis1.y1 + math.exp(-dis2.y2)',name="obj1")

#solution to the opt problem
self.solution = {
"z1":1.9776,
"z2":0.0,
"dis1.x1":0.0,
"y1":3.16,
"y2": 3.756,
'obj1':3.1834
}

#END OF MDAO Problem Definition

[docs]class SellarProblemWithDeriv(OptProblem):
""" Sellar test problem definition using components analytical derivatives."""

[docs]    def configure(self):
""" Creates a new Assembly with this problem.

Optimal Design at (1.9776, 0, 0)

Optimal Objective = 3.18339"""

#add the discipline components to the assembly

#START OF MDAO Problem Definition
#Global Des Vars

#Local Des Vars

#Coupling Vars

self.add_objective('(dis1.x1)**2 + dis1.z2 + dis1.y1 + math.exp(-dis2.y2)',name="obj1")

#solution to the opt problem
self.solution = {
"z1":1.9776,
"z2":0.0,
"dis1.x1":0.0,
"y1":3.16,
"y2": 3.756,
'obj1':3.1834
}

#END OF MDAO Problem Definition