#!/usr/bin/env python ''' pyOpt_gradient Holds the Python Design Optimization Gradient Calculation Class. Copyright (c) 2008-2014 by pyOpt Developers All rights reserved. Revision: 1.0 $Date: 20/06/2010 21:00$ Developers: ----------- - Dr. Ruben E. Perez (RP) - Mr. Peter W. Jansen (PJ) History ------- v. 1.0 - Initial Class Creation (PJ,RP 2010) ''' __version__ = '$Revision: $' ''' To Do: - add calc fail flag ''' # ============================================================================= # Standard Python modules # ============================================================================= import os, sys import copy import pdb # ============================================================================= # External Python modules # ============================================================================= import numpy # ============================================================================= # Extension modules # ============================================================================= #import extension # ============================================================================= # Misc Definitions # ============================================================================= eps = 1.0 # define a value for machine precision while ((eps/2.0 + 1.0) > 1.0): eps = eps/2.0 #end eps = 2.0*eps #eps = math.ldexp(1,-52) # ============================================================================= # Gradient Class # ============================================================================= class Gradient(object): ''' Abstract Class for Optimizer Gradient Calculation Object ''' def __init__(self, opt_problem, sens_type, sens_mode='', sens_step={}, *args, **kwargs): ''' Optimizer Gradient Calculation Class Initialization **Arguments:** - opt_problem -> INST: Optimization instance - sens_type -> STR/FUNC: Sensitivity type ('FD', 'CS', or function) **Keyword arguments:** - sens_mode -> STR: Parallel flag [''-serial,'pgc'-parallel], *Default* = '' - sens_step -> INT: Step size, *Default* = {} [=1e-6(FD), 1e-20(CS)] Documentation last updated: Feb. 03, 2011 - Peter W. Jansen ''' # self.opt_problem = opt_problem if isinstance(sens_type,str): self.sens_type = sens_type.lower() else: self.sens_type = sens_type #end if (sens_step == {}): if (self.sens_type == 'fd'): self.sens_step = 1.0e-6 elif (self.sens_type == 'cs'): self.sens_step = 1.0e-20 else: self.sens_step = sens_step #end else: self.sens_step = sens_step #end self.sens_mode = sens_mode.lower() # MPI Setup if (self.sens_mode.lower() == 'pgc'): try: import mpi4py from mpi4py import MPI except ImportError: print 'Error: mpi4py library failed to import' #end comm = MPI.COMM_WORLD self.nproc = comm.Get_size() self.myrank = comm.Get_rank() if (mpi4py.__version__[0] == '0'): self.Send = comm.Send self.Recv = comm.Recv self.Bcast = comm.Bcast elif (mpi4py.__version__[0] == '1'): self.Send = comm.send self.Recv = comm.recv self.Bcast = comm.bcast #end self.mydvs = xrange(self.myrank,len(opt_problem._variables.keys()),self.nproc) else: self.myrank = 0 self.mydvs = xrange(len(opt_problem._variables.keys())) #end def getGrad(self, x, group_ids, f, g, *args, **kwargs): ''' Get Gradient **Arguments:** - x -> ARRAY: Design variables - group_ids -> DICT: Group identifications - f -> ARRAY: Objective values - g -> ARRAY: Constraint values Documentation last updated: Feb. 07, 2011 - Peter W. Jansen ''' # opt_problem = self.opt_problem sens_type = self.sens_type sens_mode = self.sens_mode sens_step = self.sens_step mydvs = self.mydvs myrank = self.myrank # dfi = numpy.zeros([len(opt_problem._objectives.keys()),len(mydvs)],'d') dgi = numpy.zeros([len(opt_problem._constraints.keys()),len(mydvs)],'d') if (sens_type == 'fd'): # Finite Differences dh = sens_step xs = x k = 0 for i in mydvs: xh = copy.copy(xs) xh[i] += dh # Variables Groups Handling if opt_problem.use_groups: xhg = {} for group in group_ids.keys(): if (group_ids[group][1]-group_ids[group][0] == 1): xhg[group] = xh[group_ids[group][0]] else: xhg[group] = xh[group_ids[group][0]:group_ids[group][1]] #end #end xh = xhg #end [fph,gph,fail] = opt_problem.obj_fun(xh, *args, **kwargs) if isinstance(fph,float): fph = [fph] #end for j in xrange(len(opt_problem._objectives.keys())): dfi[j,k] = (fph[j] - f[j])/dh #end for j in xrange(len(opt_problem._constraints.keys())): dgi[j,k] = (gph[j] - g[j])/dh #end k += 1 #end elif (sens_type == 'cs'): # Complex Step cdh = sens_step cxs = copy.copy(x) k = 0 for i in mydvs: cxh = cxs + numpy.zeros(len(cxs),complex) cxh[i] = complex(cxh[i],cdh) # Variables Groups Handling if opt_problem.use_groups: cxhg = {} for group in group_ids.keys(): if (group_ids[group][1]-group_ids[group][0] == 1): cxhg[group] = cxh[group_ids[group][0]] else: cxhg[group] = cxh[group_ids[group][0]:group_ids[group][1]] #end #end cxh = cxhg #end [cfph,cgph,fail] = opt_problem.obj_fun(cxh, *args, **kwargs) if isinstance(cfph,complex): cfph = [cfph] #end for j in xrange(len(opt_problem._objectives.keys())): dfi[j,k] = cfph[j].imag/cdh #end for j in xrange(len(opt_problem._constraints.keys())): dgi[j,k] = cgph[j].imag/cdh #end k += 1 #end dfi = dfi.astype(float) dgi = dgi.astype(float) else: # Variables Groups Handling if opt_problem.use_groups: xg = {} for group in group_ids.keys(): if (group_ids[group][1]-group_ids[group][0] == 1): xg[group] = x[group_ids[group][0]] else: xg[group] = x[group_ids[group][0]:group_ids[group][1]] #end #end xn = xg else: xn = x #end # User Provided Sensitivities [df_user,dg_user,fail] = sens_type(xn, f, g, *args, **kwargs) if isinstance(df_user,list): if len(opt_problem._objectives.keys()) == 1: df_user = [df_user] #end df_user = numpy.array(df_user) #end if isinstance(dg_user,list): dg_user = numpy.array(dg_user) #end # for i in xrange(len(opt_problem._variables.keys())): for j in xrange(len(opt_problem._objectives.keys())): dfi[j,i] = df_user[j,i] #end for j in xrange(len(opt_problem._constraints.keys())): dgi[j,i] = dg_user[j,i] #end #end #end # MPI Gradient Assembly df = numpy.zeros([len(opt_problem._objectives.keys()),len(opt_problem._variables.keys())],'d') dg = numpy.zeros([len(opt_problem._constraints.keys()),len(opt_problem._variables.keys())],'d') if (sens_mode == 'pgc'): if (sens_type == 'fd') or (sens_type == 'cs'): if myrank != 0: self.Send([myrank, dfi, dgi],dest=0) else: p_results = [[myrank, dfi, dgi]] for proc in xrange(1,self.nproc): p_results.append(self.Recv(source=proc)) #end #end if myrank == 0: for proc in xrange(self.nproc): k = 0 for i in xrange(p_results[proc][0],len(opt_problem._variables.keys()),self.nproc): df[:,i] = p_results[proc][1][:,k] dg[:,i] = p_results[proc][2][:,k] k += 1 #end #end #end [df,dg] = self.Bcast([df,dg],root=0) #end else: df = dfi dg = dgi #end return df,dg def getHess(self, *args, **kwargs): ''' Get Hessian Documentation last updated: June. 20, 2010 - Ruben E. Perez ''' # # return #============================================================================== # Optimizer Gradient Calculation Test #============================================================================== if __name__ == '__main__': # Test Optimizer Gradient Calculation print 'Testing Optimizer Gradient Calculation...' grd = Gradient()