# Source code for openmdao.lib.optproblems.scalable

"""Scalable Test Optimization test problem proposed by Martins and Marriage.

J. R. R. A. Martins and C. Marriage, "An Object-Oriented Framework for
Multidisciplinary Design Optimization," 3rd AIAA Multidisciplinary
Design Optimization Specialist Conference, 2007. """

from openmdao.main.api import Component
from openmdao.main.problem_formulation import OptProblem

from openmdao.lib.datatypes.api import Float, Array

from numpy import array, matrix, identity, zeros, ones

[docs]class Discipline(Component):

c_y_out = Float(1.0,iotype="in",
desc="coefficient for the output variables")

def __init__(self,prob_size=1):
super(Discipline,self).__init__()

desc="global varaibles",
shape=(prob_size,1)))

desc="global variable constants",
shape=(prob_size,prob_size)))

desc="local variables",
shape=(prob_size,1)))

desc="local variable constants",
shape=(prob_size,prob_size)))

#have to have the same number of coupling inputs as discipline outputs
desc="discipline output varaibles",
shape=(prob_size,1)))

desc="input coupling variables",
shape=(prob_size,1)))

desc="local variable constants",
shape=(prob_size,prob_size)))

[docs]    def execute(self):
Cz = matrix(self.C_z)
z = matrix(self.z)
Cx = matrix(self.C_x)
x = matrix(self.x)
Cy = matrix(self.C_y)
y = matrix(self.y_in)

self.y_out = array(-1/self.c_y_out*(Cz*z+Cx*x-Cy*y))

[docs]class UnitScalableProblem(OptProblem):
def __init__(self,n_disciplines=3,prob_size=3):
self.solution = {}

self.disciplines = []

self.n_disciplines = n_disciplines
self.prob_size = prob_size

super(UnitScalableProblem,self).__init__()

[docs]    def configure(self):
n_disciplines = self.n_disciplines
prob_size = self.prob_size

for i in range(0,n_disciplines):
name = 'd%d'%i
#each discipline as n_discipline-1 coupling vars
self.disciplines.append(name)
d.c_y_out = float(n_disciplines) #scale to the number of disciplines to keep values of y at 1

#adding all local variables to the problem formulation
for j in range(0,prob_size):
self.solution['%s.x[%d][0]'%(name,j)] = (1/float(n_disciplines))-1

for j in range(0,prob_size):

#global variables
for i in range(0,prob_size):
params = tuple(["%s.z[%d][0]"%(name,i) for name in self.disciplines])
self.solution["z%d"%i] = 0

#coupling vars
for i,j in zip(range(0,n_disciplines-1),range(1,n_disciplines)):
for k in range(0,prob_size):
self.solution[("%s.y_in[%d][0]"%(self.disciplines[j],k),"%s.y_out[%d][0]"%(self.disciplines[i],k))] = 1.0
#self.connect("%s.y_out"%(self.disciplines[i],),"%s.y_in"%(self.disciplines[j],))
for k in range(0,prob_size):
self.solution[("%s.y_in[%d][0]"%(self.disciplines[0],k),"%s.y_out[%d][0]"%(self.disciplines[-1],k))] = 1.0

#objective
parts = []
for i in range(0,prob_size):
parts.append('d0.z[%d][0]**2'%i) #only need one target for each global
for d in self.disciplines:
for j in range(0,prob_size):
parts.append("%s.y_out[%d][0]**2"%(d,j))

self.solution['obj1'] = float(n_disciplines)*prob_size

if __name__ == '__main__':
from openmdao.lib.architectures.api import MDF, CO, BLISS

sp = UnitScalableProblem(3)

sp.architecture = MDF()

sp.run()

error = sp.check_solution()

for k,v in sp.solution.iteritems():
print k,v
print
#print sp.d0.x0
for k,v in error.iteritems():
print k,v

#print sum([v**2 for k,v in error.iteritems()])**.5