class PlateComponentLHS(om.ExplicitComponent): """Robust Bump Flow Problem, with LHS Monte Carlo Samples""" def initialize(self): # Need to modify this dictionary when we change the SA constants #import pdb; pdb.set_trace() #sys.stdout = open(os.devnull, "w") self.aoptions = aeroOptions self.woptions = warpOptions self.ooptions = optOptions self.uoptions = uqOptions self.Pr = 0. self.P = self.uoptions['P'] self.NS0 = self.uoptions['NS0'] # Generate FFD and DVs if rank == 0: rank0dvg = pf.createFFD() else: rank0dvg = None self.DVGeo = comm.bcast(rank0dvg, root=0) # starting flat mesh meshname = self.aoptions['gridFile'] gridFile = meshname # flow characteristics alpha = 0.0 mach = self.ooptions['mach'] #0.95 Re = self.ooptions['Re'] #50000 Re_L = 1.0 temp = 540 arearef = 2.0 chordref = 1.0 # Spalart Allmaras model constants, to be changed in UQ (4 for now) saconstsm = [0.41, 0.1355, 0.622, 0.66666666667] self.saconstsb = [7.1, 0.3, 2.0, 1.0, 2.0, 1.2, 0.5, 2.0] self.saconsts = saconstsm + self.saconstsb self.aoptions['SAConsts'] = self.saconsts #self.gridSol = f'{meshname}_{saconstsm}_sol' solname = self.ooptions['prob_name'] self.gridSol = f'{solname}_sol' # Get a set of UQ sample points (LHS) #if self.ooptions['run_once']: # self.sample = self.uoptions['dist'] #else # Scatter samples, multi-point parallelism if self.uoptions['MCTimeBudget']: self.aps = [] self.solvers = [] self.meshes = [] self.current_samples = self.NS0 if rank == 0: rank0sam = plate_sa_lhs.genLHS(s=self.current_samples) else: rank0sam = None self.sample = comm.bcast(rank0sam, root=0) self.cases = divide_cases(self.NS0, size) # Scatter samples on each level, multi-point parallelism self.samplep = self.sample[self.cases[rank]] self.nsp = len(self.cases[rank]) # Create solvers for the preliminary data for i in range(self.nsp): namestr = self.gridSol + "_" + str(self.cases[rank][i]) # create meshes self.meshes.append( USMesh(options=self.woptions, comm=MPI.COMM_SELF)) # create aeroproblems self.aps.append( AeroProblem(name=namestr, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=temp, areaRef=arearef, chordRef=chordref, evalFuncs=['cd'])) time.sleep(0.1) # this solves a few problems for some reason # create solvers self.solvers.append( ADFLOW(options=self.aoptions, comm=MPI.COMM_SELF)) saconstsm = self.samplep[i].tolist() self.saconsts = saconstsm + self.saconstsb self.solvers[i].setOption('SAConsts', self.saconsts) self.solvers[i].setDVGeo(self.DVGeo) self.solvers[i].setMesh(self.meshes[i]) print("what up %i", str(rank)) coords = self.solvers[i].getSurfaceCoordinates( groupName=self.solvers[i].allWallsGroup) self.solvers[i].DVGeo.addPointSet(coords, 'coords') # start looping over mesh levels sumt = 0. sumtp = 0. Et = 0. funcs = {} a_init = self.DVGeo.getValues() a_init['pnts'][:] = self.ooptions['DVInit'] dvdict = {'pnts': a_init['pnts']} for i in range(self.nsp): saconstsm = self.samplep[i].tolist() self.saconsts = saconstsm + self.saconstsb self.solvers[i].setOption('SAConsts', self.saconsts) self.solvers[i].DVGeo.setDesignVars(dvdict) self.aps[i].setDesignVars(dvdict) pc0 = time.process_time() self.solvers[i](self.aps[i]) self.solvers[i].evalFunctions(self.aps[i], funcs) pc1 = time.process_time() astr = self.gridSol + "_" + str(self.cases[rank][i]) + "_cd" sumtp += (pc1 - pc0) sumt = comm.allreduce(sumtp) Et = sumt / self.NS0 self.NS = math.ceil(self.P / Et) self.Pr = self.NS * Et else: self.NS = self.uoptions['NS'] #import pdb; pdb.set_trace() if rank == 0: rank0sam = plate_sa_lhs.genLHS(s=self.NS) else: rank0sam = None self.sample = comm.bcast(rank0sam, root=0) self.cases = divide_cases(self.NS, size) self.nsp = len(self.cases[rank]) #int(ns/size) # samples per processor #import pdb; pdb.set_trace() self.samplep = self.sample[self.cases[ rank]] #self.sample[(rank*self.nsp):(rank*self.nsp+(self.nsp))] #shouldn't really need to "scatter" per se #import pdb; pdb.set_trace() #assert len(self.samplep) == self.nsp # Actually create solvers (and aeroproblems?) (and mesh?) now self.aps = [] self.solvers = [] self.meshes = [] #self.mesh = USMesh(options=self.woptions, comm=MPI.COMM_SELF) for i in range(self.nsp): namestr = self.gridSol + "_" + str(self.cases[rank][i]) # create meshes self.meshes.append( USMesh(options=self.woptions, comm=MPI.COMM_SELF)) # create aeroproblems self.aps.append( AeroProblem(name=namestr, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=temp, areaRef=arearef, chordRef=chordref, evalFuncs=['cd'])) time.sleep(0.1) # this solves a few problems for some reason # create solvers self.solvers.append( ADFLOW(options=self.aoptions, comm=MPI.COMM_SELF)) # if not self.ooptions['run_once']: # saconstsm = self.samplep[i].tolist() # else: saconstsm = self.samplep[i].tolist() self.saconsts = saconstsm + self.saconstsb self.solvers[i].setOption('SAConsts', self.saconsts) self.solvers[i].setDVGeo(self.DVGeo) self.solvers[i].setMesh(self.meshes[i]) print("what up %i", str(rank)) coords = self.solvers[i].getSurfaceCoordinates( groupName=self.solvers[i].allWallsGroup) self.solvers[i].DVGeo.addPointSet(coords, 'coords') # Set constraints, should only need one of those solvers, the meshes are all the same self.DVCon = DVConstraints() self.DVCon2 = DVConstraints() self.DVCon.setDVGeo(self.solvers[0].DVGeo.getFlattenedChildren()[1]) self.DVCon2.setDVGeo(self.solvers[0].DVGeo) self.DVCon.setSurface(self.solvers[0].getTriangulatedMeshSurface( groupName='allSurfaces')) # set extra group for surface area condition self.DVCon2.setSurface(self.solvers[0].getTriangulatedMeshSurface(), name='wall') # DV should be same into page (not doing anything right now) #import pdb; pdb.set_trace() lIndex = self.solvers[0].DVGeo.getFlattenedChildren()[1].getLocalIndex( 0) indSetA = [] indSetB = [] nXc = optOptions['NX'] self.NC = math.trunc( ((1.0 - self.ooptions['DVFraction']) * self.ooptions['NX'])) ind = [ int(nXc / 2) - int(self.NC / 2), int(nXc / 2) + int(self.NC / 2) ] for i in range(ind[0], ind[1]): indSetA.append(lIndex[i, 0, 1]) indSetB.append(lIndex[i, 1, 1]) # for i in range(lIndex.shape[0]): # indSetA.append(lIndex[i, 0, 1]) # indSetB.append(lIndex[i, 1, 1]) self.DVCon.addLinearConstraintsShape(indSetA, indSetB, factorA=1.0, factorB=-1.0, lower=0, upper=0, name='eqs') # Thickness constraints (one for each active DV) #import pdb; pdb.set_trace() # Maximum thickness of the domain, translates to minimum thickness of bump ub = 1.0 - self.ooptions['DCMinThick'] tcf = self.ooptions['DCThickFrac'] ra = self.ooptions['bumpBounds'] lim = self.ooptions['DCMinArea'] span = numpy.linspace(0, 1, nXc) xc = span * (ra[1] - ra[0]) + ra[0] #ind = range(int(nXc/2) - int(self.NC/2), int(nXc/2) + int(self.NC/2))) ind = [ int(nXc / 2) - int(tcf * self.NC / 2), int(nXc / 2) + int(tcf * self.NC / 2) ] ptList = numpy.zeros([2, 3]) ptList[:, 0] = xc[ind] ptList[:, 1] = 0.5 ptList[:, 2] = 0.5 if self.ooptions['use_area_con']: self.DVCon2.addSurfaceAreaConstraint(lower=lim, upper=10., name='sas', surfaceName='wall') else: self.DVCon2.addThicknessConstraints1D(ptList, self.NC, [0, 0, 1], lower=0.5, upper=ub, name='tcs') print("excuse me") dummy = rank dsum = comm.allgather(dummy) sys.stdout = sys.__stdout__ def setup(self): #initialize shape and set deformation points as inputs a_init = self.solvers[0].DVGeo.getValues() a_init['pnts'][:] = self.ooptions['DVInit'] # mult = numpy.linspace(1.0,1.5,num=int(0.5*len(a_init['pnts']))) # mult = numpy.concatenate((mult, mult)) #if self.ooptions['run_once']: # a_init['pnts'] = self.ooptions['ro_shape'] #a_init['pnts'] = numpy.multiply(mult, a_init['pnts']) self.add_input('a', a_init['pnts'], desc="Bump Shape Control Points") #self.add_input('a', 0.2, desc="Bump Shape Control Points") if self.ooptions['use_area_con']: self.add_output('SA', 1.0, desc='Surface Area Constraint') else: self.add_output('TC', numpy.zeros(self.NC), desc='Thickness Constraints') self.add_output('Cd_m', 0.0, desc="Mean Drag Coefficient") self.add_output('Cd_v', 0.0, desc="Variance Drag Coefficient") self.add_output('Cd_r', 0.0, desc="Robust Drag Objective") self.add_output('EQ', numpy.zeros(int(len(a_init['pnts']) / 2)), desc="Control Point Symmetry") self.add_output('N1', self.NS, desc="Number of samples used") self.add_output('Pr', self.Pr, desc="MFMC Samples at each level") def setup_partials(self): self.declare_partials('Cd_m', 'a', method='exact') self.declare_partials('Cd_v', 'a', method='exact') self.declare_partials('Cd_r', 'a', method='exact') if self.ooptions['use_area_con']: self.declare_partials('SA', 'a', method='exact') else: self.declare_partials('TC', 'a', method='exact') self.declare_partials('EQ', 'a', method='exact') def compute(self, inputs, outputs): # run the bump shape model #import pdb; pdb.set_trace() # evaluate each sample point #print("hello") dvdict = {'pnts': inputs['a']} funcs = {} ns = self.NS sump = 0. musp = numpy.zeros(self.nsp) #self.aps[0].setDesignVars(dvdict) for i in range(self.nsp): self.solvers[i].DVGeo.setDesignVars(dvdict) self.aps[i].setDesignVars(dvdict) self.solvers[i](self.aps[i]) self.solvers[i].evalFunctions(self.aps[i], funcs) astr = self.gridSol + "_" + str(self.cases[rank][i]) + "_cd" #import pdb; pdb.set_trace() musp[i] = funcs[astr] sump += funcs[astr] # compute mean and variance sum = comm.allreduce(sump) mus = comm.allgather(musp) #import pdb; pdb.set_trace() E = sum / ns sum2 = 0. for i in range(len(mus)): #range(size): for j in range(len(mus[i])): #range(self.nsp): sum2 += (mus[i][j] - E)**2 V = sum2 / ns self.DVCon.evalFunctions(funcs, includeLinear=True) self.DVCon2.evalFunctions(funcs, includeLinear=True) outputs['Cd_m'] = E outputs['Cd_v'] = math.sqrt(V) rho = self.uoptions['rho'] outputs['Cd_r'] = E + rho * math.sqrt(V) if self.ooptions['use_area_con']: outputs['SA'] = funcs['sas'] else: outputs['TC'] = funcs['tcs'] outputs['EQ'] = funcs['eqs'] outputs['N1'] = self.NS outputs['Pr'] = self.Pr #outputs['Cd'] = inputs['a']*inputs['a'] def compute_partials(self, inputs, J): dvdict = {'pnts': inputs['a']} funcs = {} funcSens = {} ns = self.NS sump = 0. musp = numpy.zeros(self.nsp) pmup = [] psump = numpy.zeros(len(inputs['a'])) self.aps[0].setDesignVars(dvdict) #import pdb; pdb.set_trace() for i in range(self.nsp): self.solvers[i].DVGeo.setDesignVars(dvdict) self.aps[i].setDesignVars(dvdict) self.solvers[i].evalFunctions(self.aps[i], funcs) self.solvers[i].evalFunctionsSens(self.aps[i], funcSens, ['cd']) astr = self.gridSol + "_" + str(self.cases[rank][i]) + "_cd" arr = [x * (1. / ns) for x in funcSens[astr]['pnts']] sump += funcs[astr] musp[i] = funcs[astr] pmup.append(arr[0]) psump += arr[0] sum = comm.allreduce(sump) mus = comm.allgather(musp) pmu = comm.allgather(pmup) psum = comm.allreduce(psump) #import pdb; pdb.set_trace() #import pdb; pdb.set_trace() # compute variance sensitivity E = sum / ns sum2 = 0. psum2 = numpy.zeros(len(inputs['a'])) for i in range(len(mus)): #range(size): for j in range(len(mus[i])): #range(self.nsp): sum2 += (mus[i][j] - E)**2 temp = pmu[i][j] * ns - psum arr2 = [x * 2 * (mus[i][j] - E) / ns for x in temp] psum2 += arr2 #import pdb; pdb.set_trace() V = sum2 / ns #import pdb; pdb.set_trace() self.DVCon.evalFunctionsSens(funcSens, includeLinear=True) self.DVCon2.evalFunctionsSens(funcSens, includeLinear=True) J['Cd_m', 'a'] = psum J['Cd_v', 'a'] = (1. / (2 * math.sqrt(V))) * psum2 rho = self.uoptions['rho'] J['Cd_r', 'a'] = psum + rho * (1. / (2 * math.sqrt(V))) * psum2 if self.ooptions['use_area_con']: J['SA', 'a'] = funcSens['sas']['pnts'] else: J['TC', 'a'] = funcSens['tcs']['pnts'] J['EQ', 'a'] = funcSens['eqs']['pnts']
class PlateComponentMLMC(om.ExplicitComponent): """Robust Bump Flow Problem, with LHS Multi Level Monte Carlo Samples""" def initialize(self): # Need to modify this dictionary when we change the SA constants #import pdb; pdb.set_trace() sys.stdout = open(os.devnull, "w") self.aoptions = aeroOptions self.woptions = warpOptions self.ooptions = optOptions self.uoptions = uqOptions # Generate FFD and DVs if rank == 0: rank0dvg = pf.createFFD() else: rank0dvg = None self.DVGeo = comm.bcast(rank0dvg, root=0) # Get a full list of every mesh name we have, assume they are ordered properly by level self.meshnames = self.uoptions['gridFileLevels'] self.Lmax = len(self.meshnames) #as many levels as we have meshes if self.Lmax < 3: raise ValueError('Not enough meshes available, ' + self.Lmax + ' < 3') # Spalart Allmaras model constants, to be changed in UQ (4 for now) saconstsm = [0.41, 0.1355, 0.622, 0.66666666667] self.saconstsb = [7.1, 0.3, 2.0, 1.0, 2.0, 1.2, 0.5, 2.0] self.saconsts = saconstsm + self.saconstsb self.aoptions['SAConsts'] = self.saconsts #self.gridSol = f'{meshname}_{saconstsm}_sol' solname = self.ooptions['prob_name'] self.gridSol = f'{solname}_sol' self.cases = [] self.nsp = [] #keep track per level self.samplep = [] self.naddedtot = [] for i in range(self.Lmax): self.naddedtot.append(0) self.aps = [] self.solvers = [] self.meshes = [] self.NS0 = self.uoptions['NS0'] self.current_samples = self.NS0 * self.Lmax self.N1 = None ########## # call distribute samples here? if not self.uoptions['use-predetermined-samples']: self.MLMC() else: self.N1 = self.uoptions['predet-N1'] self.dist_samples() ########## # Set constraints, should only need one of those solvers, the meshes are all the same if rank == 0: self.DVCon = DVConstraints() self.DVCon2 = DVConstraints() self.DVCon.setDVGeo( self.solvers[self.Lmax - 1][0].DVGeo.getFlattenedChildren()[1]) self.DVCon2.setDVGeo(self.solvers[self.Lmax - 1][0].DVGeo) self.DVCon.setSurface( self.solvers[self.Lmax - 1][0].getTriangulatedMeshSurface( groupName='allSurfaces')) # set extra group for surface area condition self.DVCon2.setSurface( self.solvers[self.Lmax - 1][0].getTriangulatedMeshSurface(), name='wall') # DV should be same into page (not doing anything right now) #import pdb; pdb.set_trace() lIndex = self.solvers[ self.Lmax - 1][0].DVGeo.getFlattenedChildren()[1].getLocalIndex(0) indSetA = [] indSetB = [] nXc = optOptions['NX'] self.NC = math.trunc( ((1.0 - self.ooptions['DVFraction']) * self.ooptions['NX'])) ind = [ int(nXc / 2) - int(self.NC / 2), int(nXc / 2) + int(self.NC / 2) ] for i in range(ind[0], ind[1]): indSetA.append(lIndex[i, 0, 1]) indSetB.append(lIndex[i, 1, 1]) # for i in range(lIndex.shape[0]): # indSetA.append(lIndex[i, 0, 1]) # indSetB.append(lIndex[i, 1, 1]) self.DVCon.addLinearConstraintsShape(indSetA, indSetB, factorA=1.0, factorB=-1.0, lower=0, upper=0, name='eqs') # Thickness constraints (one for each active DV) #import pdb; pdb.set_trace() # Maximum thickness of the domain, translates to minimum thickness of bump ub = 1.0 - self.ooptions['DCMinThick'] tcf = self.ooptions['DCThickFrac'] ra = self.ooptions['bumpBounds'] lim = self.ooptions['DCMinArea'] span = numpy.linspace(0, 1, nXc) xc = span * (ra[1] - ra[0]) + ra[0] #ind = range(int(nXc/2) - int(self.NC/2), int(nXc/2) + int(self.NC/2))) ind = [ int(nXc / 2) - int(tcf * self.NC / 2), int(nXc / 2) + int(tcf * self.NC / 2) ] ptList = numpy.zeros([2, 3]) ptList[:, 0] = xc[ind] ptList[:, 1] = 0.5 ptList[:, 2] = 0.5 if self.ooptions['use_area_con']: self.DVCon2.addSurfaceAreaConstraint(lower=lim, upper=10., name='sas', surfaceName='wall') else: self.DVCon2.addThicknessConstraints1D(ptList, self.NC, [0, 0, 1], lower=0.5, upper=ub, name='tcs') dummy = rank dsum = comm.allgather(dummy) sys.stdout = sys.__stdout__ def setup(self): #initialize shape and set deformation points as inputs a_init = self.DVGeo.getValues() a_init['pnts'][:] = self.ooptions['DVInit'] # mult = numpy.linspace(1.0,1.5,num=int(0.5*len(a_init['pnts']))) # mult = numpy.concatenate((mult, mult)) #if self.ooptions['run_once']: # a_init['pnts'] = self.ooptions['ro_shape'] #a_init['pnts'] = numpy.multiply(mult, a_init['pnts']) self.add_input('a', a_init['pnts'], desc="Bump Shape Control Points") #self.add_input('a', 0.2, desc="Bump Shape Control Points") if self.ooptions['use_area_con']: self.add_output('SA', 1.0, desc='Surface Area Constraint') else: self.add_output('TC', numpy.zeros(self.NC), desc='Thickness Constraints') self.add_output('Cd_m', 0.0, desc="Mean Drag Coefficient") self.add_output('Cd_v', 0.0, desc="Variance Drag Coefficient") self.add_output('Cd_r', 0.0, desc="Robust Drag Objective") self.add_output('EQ', numpy.zeros(int(len(a_init['pnts']) / 2)), desc="Control Point Symmetry") self.add_output('N1', self.N1, desc="MLMC Samples at each level") def setup_partials(self): self.declare_partials('Cd_m', 'a', method='exact') self.declare_partials('Cd_v', 'a', method='exact') self.declare_partials('Cd_r', 'a', method='exact') if self.ooptions['use_area_con']: self.declare_partials('SA', 'a', method='exact') else: self.declare_partials('TC', 'a', method='exact') self.declare_partials('EQ', 'a', method='exact') def compute(self, inputs, outputs): # run the bump shape model #import pdb; pdb.set_trace() dvdict = {'pnts': inputs['a']} ntot = self.current_samples nslp = [] nslt = [] for k in range(self.Lmax): nslp.append(len(self.cases[k][rank])) nslt.append(sum([len(self.cases[k][x]) for x in range(size)])) funcs = {} sump = [] musp = [] sum1 = [] mus = [] sumpm = [] muspm = [] summ = [] musm = [] E = numpy.zeros(self.Lmax) V = numpy.zeros(self.Lmax) for k in range(self.Lmax): sump.append(0.0) musp.append(numpy.zeros(nslp[k])) sumpm.append(0.) muspm.append(numpy.zeros(nslp[k])) for i in range(nslp[k]): saconstsm = self.samplep[k][i].tolist() self.saconsts = saconstsm + self.saconstsb self.solvers[k][i].setOption('SAConsts', self.saconsts) self.solvers[k][i].DVGeo.setDesignVars(dvdict) self.aps[k][i].setDesignVars(dvdict) self.solvers[k][i](self.aps[k][i]) self.solvers[k][i].evalFunctions(self.aps[k][i], funcs) astr = self.gridSol + "_" + str(self.cases[k][rank][i]) + "_cd" musp[k][i] = funcs[astr] sump[k] += funcs[astr] if k > 0: self.solvers[k][i + nslp[k]].setOption( 'SAConsts', self.saconsts) self.solvers[k][i + nslp[k]].DVGeo.setDesignVars(dvdict) self.aps[k][i + nslp[k]].setDesignVars(dvdict) self.solvers[k][i + nslp[k]](self.aps[k][i + nslp[k]]) self.solvers[k][i + nslp[k]].evalFunctions( self.aps[k][i + nslp[k]], funcs) astr = self.gridSol + "_" + str( self.cases[k][rank][i]) + "_m_cd" muspm[k][i] = -funcs[astr] sumpm[k] += -funcs[astr] # compute mean and variance for k in range(self.Lmax): sum1.append(comm.allreduce(sump[k])) mus.append(comm.allgather(musp[k])) summ.append(comm.allreduce(sumpm[k])) musm.append(comm.allgather(muspm[k])) #import pdb; pdb.set_trace() E[k] = (sum1[k] + summ[k]) / nslt[k] sum2 = 0. for i in range(len(mus[k])): #loop over processors for j in range(len( mus[k][i])): #loop over samples on processors if k > 0: sum2 += ((mus[k][i][j] + musm[k][i][j]) - E[k])**2 else: sum2 += (mus[k][i][j] - E[k])**2 V[k] = sum2 / nslt[k] import pdb pdb.set_trace() if rank == 0: self.DVCon.evalFunctions(funcs, includeLinear=True) self.DVCon2.evalFunctions(funcs, includeLinear=True) eq0 = funcs['eqs'] sa0 = funcs['sas'] else: eq0 = None sa0 = None eq = comm.bcast(eq0, root=0) sa = comm.bcast(sa0, root=0) outputs['Cd_m'] = sum(E) outputs['Cd_v'] = V[0] #by assumption rho = self.uoptions['rho'] outputs['Cd_r'] = sum(E) + rho * math.sqrt(V[0]) if self.ooptions['use_area_con']: outputs['SA'] = sa else: outputs['TC'] = funcs['tcs'] outputs['EQ'] = eq outputs['N1'] = self.N1 #outputs['Cd'] = inputs['a']*inputs['a'] def compute_partials(self, inputs, J): dvdict = {'pnts': inputs['a']} funcs = {} funcSens = {} nslp = [] nslt = [] for k in range(self.Lmax): nslp.append(len(self.cases[k][rank])) nslt.append(sum([len(self.cases[k][x]) for x in range(size)])) sump = [] musp = [] sum1 = [] sum2 = [] mus = [] sumpm = [] muspm = [] summ = [] musm = [] pmup = [] psump = [] #numpy.zeros(len(inputs['a'])) pmu = [] psum1 = [] pmupm = [] psumpm = [] #numpy.zeros(len(inputs['a'])) pmum = [] psumm = [] E = numpy.zeros(self.Lmax) V = numpy.zeros(self.Lmax) #import pdb; pdb.set_trace() for k in range(self.Lmax): sump.append(0.0) musp.append(numpy.zeros(nslp[k])) sumpm.append(0.) muspm.append(numpy.zeros(nslp[k])) pmup.append([]) psump.append(numpy.zeros(len(inputs['a']))) pmupm.append([]) psumpm.append(numpy.zeros(len(inputs['a']))) for i in range(nslp[k]): saconstsm = self.samplep[k][i].tolist() self.saconsts = saconstsm + self.saconstsb self.solvers[k][i].setOption('SAConsts', self.saconsts) self.solvers[k][i].DVGeo.setDesignVars(dvdict) self.aps[k][i].setDesignVars(dvdict) self.solvers[k][i](self.aps[k][i]) self.solvers[k][i].evalFunctions(self.aps[k][i], funcs) self.solvers[k][i].evalFunctionsSens(self.aps[k][i], funcSens, ['cd']) astr = self.gridSol + "_" + str(self.cases[k][rank][i]) + "_cd" arr = [x * (1. / nslt[k]) for x in funcSens[astr]['pnts']] musp[k][i] = funcs[astr] sump[k] += funcs[astr] pmup[k].append(arr[0]) psump[k] += arr[0] if k > 0: self.solvers[k][i + nslp[k]].setOption( 'SAConsts', self.saconsts) self.solvers[k][i + nslp[k]].DVGeo.setDesignVars(dvdict) #import pdb; pdb.set_trace() self.aps[k][i + nslp[k]].setDesignVars(dvdict) self.solvers[k][i + nslp[k]](self.aps[k][i + nslp[k]]) self.solvers[k][i + nslp[k]].evalFunctions( self.aps[k][i + nslp[k]], funcs) self.solvers[k][i + nslp[k]].evalFunctionsSens( self.aps[k][i + nslp[k]], funcSens, ['cd']) astr = self.gridSol + "_" + str( self.cases[k][rank][i]) + "_m_cd" arr = [x * (1. / nslt[k]) for x in funcSens[astr]['pnts']] muspm[k][i] = -funcs[astr] sumpm[k] += -funcs[astr] pmupm[k].append(-arr[0]) psumpm[k] -= arr[0] # compute mean and variance psum2 = numpy.zeros(len(inputs['a'])) for k in range(self.Lmax): sum1.append(comm.allreduce(sump[k])) mus.append(comm.allgather(musp[k])) summ.append(comm.allreduce(sumpm[k])) musm.append(comm.allgather(muspm[k])) psum1.append(comm.allreduce(psump[k])) pmu.append(comm.allgather(pmup[k])) psumm.append(comm.allreduce(psumpm[k])) pmum.append(comm.allgather(pmupm[k])) E[k] = (sum1[k] + summ[k]) / nslt[k] sum2 = 0. for i in range(len(mus[0])): #loop over processors for j in range(len(mus[0][i])): #loop over samples on processors #import pdb; pdb.set_trace() sum2 += (mus[0][i][j] - E[0])**2 temp = pmu[0][i][j] * nslt[0] - psum1[0] arr2 = [x * 2 * (mus[0][i][j] - E[0]) / nslt[0] for x in temp] psum2 += arr2 V = sum2 / nslt[0] # compute variance sensitivity #import pdb; pdb.set_trace() if rank == 0: self.DVCon.evalFunctionsSens(funcSens, includeLinear=True) self.DVCon2.evalFunctionsSens(funcSens, includeLinear=True) eq0p = funcSens['eqs']['pnts'] sa0p = funcSens['sas']['pnts'] else: eq0p = None sa0p = None eqp = comm.bcast(eq0p, root=0) sap = comm.bcast(sa0p, root=0) J['Cd_m', 'a'] = sum(psum1) + sum(psumm) J['Cd_v', 'a'] = psum2 rho = self.uoptions['rho'] J['Cd_r', 'a'] = sum(psum1) + sum(psumm) + rho * (1. / (2 * math.sqrt(V))) * psum2 #import pdb; pdb.set_trace() if self.ooptions['use_area_con']: J['SA', 'a'] = sap else: J['TC', 'a'] = funcSens['tcs']['pnts'] J['EQ', 'a'] = eqp #J['Cd','a'][0] = 2*inputs['a'] def MLMC(self): # Use an MLMC algorithm to determine an optimal sample distribution between existing mesh levels # We do this once before optimization, then compute statistics with the same set of samples at every iteration # start with initial samples # Get a set of UQ sample points (LHS), enough for each level at the start #sys.stdout = open(os.devnull, "w") # flow characteristics alpha = 0.0 mach = self.ooptions['mach'] #0.95 Re = self.ooptions['Re'] #50000 Re_L = 1.0 tempR = 540 arearef = 2.0 chordref = 1.0 a_init = self.DVGeo.getValues() a_init['pnts'][:] = self.ooptions['DVInit'] self.current_samples = self.NS0 * self.Lmax if rank == 0: rank0sam = plate_sa_lhs.genLHS(s=self.current_samples) else: rank0sam = None self.sample = comm.bcast(rank0sam, root=0) # Scatter samples on each level, multi-point parallelism for i in range(self.Lmax): self.cases.append(divide_cases(self.NS0, size)) for j in range(len(self.cases[i])): for k in range(len(self.cases[i][j])): self.cases[i][j][k] += i * self.NS0 #self.nsp.append(len(self.cases[i][rank]))#int(ns/size) # samples per processor self.samplep.append(self.sample[self.cases[i][rank]]) #import pdb; pdb.set_trace() #self.samplep = self.sample[self.cases[rank]]#self.sample[(rank*self.nsp):(rank*self.nsp+(self.nsp))] #shouldn't really need to "scatter" per se #import pdb; pdb.set_trace() # for i in range(self.Lmax): # assert len(self.samplep[i]) == self.nsp[i] # Actually create solvers (and aeroproblems?) (and mesh?) now nslp = [] nslt = [] for k in range(self.Lmax): alist = [] slist = [] mlist = [] alist2 = [] slist2 = [] mlist2 = [] nslp.append(len(self.cases[k][rank])) nslt.append(sum([len(self.cases[k][x]) for x in range(size)])) for i in range(nslp[k]): namestr = self.gridSol + "_" + str(self.cases[k][rank][i]) # create meshes leveloptions = self.woptions leveloptions['gridFile'] = self.meshnames[k] mlist.append(USMesh(options=leveloptions, comm=MPI.COMM_SELF)) # create aeroproblems aloptions = self.aoptions aloptions['gridFile'] = self.meshnames[k] alist.append( AeroProblem(name=namestr, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=tempR, areaRef=arearef, chordRef=chordref, evalFuncs=['cd'])) time.sleep(0.1) # this solves a few problems for some reason # create solvers slist.append(ADFLOW(options=aloptions, comm=MPI.COMM_SELF)) # if not self.ooptions['run_once']: # saconstsm = self.samplep[i].tolist() # else: saconstsm = self.samplep[k][i].tolist() self.saconsts = saconstsm + self.saconstsb slist[i].setOption('SAConsts', self.saconsts) slist[i].setDVGeo(self.DVGeo) slist[i].setMesh(mlist[i]) coords = slist[i].getSurfaceCoordinates( groupName=slist[i].allWallsGroup) slist[i].DVGeo.addPointSet(coords, 'coords') if k > 0: #create additional solvers at higher levels for the estimators # create meshes namestr = self.gridSol + "_" + str( self.cases[k][rank][i]) + "_m" leveloptions = self.woptions leveloptions['gridFile'] = self.meshnames[k - 1] mlist2.append( USMesh(options=leveloptions, comm=MPI.COMM_SELF)) # create aeroproblems aloptions = self.aoptions aloptions['gridFile'] = self.meshnames[k - 1] alist2.append( AeroProblem(name=namestr, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=tempR, areaRef=arearef, chordRef=chordref, evalFuncs=['cd'])) time.sleep( 0.1) # this solves a few problems for some reason # create solvers slist2.append(ADFLOW(options=aloptions, comm=MPI.COMM_SELF)) slist2[i].setOption('SAConsts', self.saconsts) slist2[i].setDVGeo(self.DVGeo) slist2[i].setMesh(mlist2[i]) coords = slist[i].getSurfaceCoordinates( groupName=slist2[i].allWallsGroup) slist2[i].DVGeo.addPointSet(coords, 'coords') self.aps.append(alist) self.solvers.append(slist) self.meshes.append(mlist) if k > 0: self.aps[k] += alist2 self.solvers[k] += slist2 self.meshes[k] += mlist2 #import pdb; pdb.set_trace() # start looping over mesh levels L = 0 M = 4.0 #0.5 #refinement factor? converged = 0 eps = self.uoptions['vartol'] sum1 = [] mus = [] sump = [] musp = [] sumpm = [] muspm = [] summ = [] musm = [] E = [] V = [] N1 = [] while ~converged & L < self.Lmax: # compute start up samples to estimate variance dvdict = {'pnts': a_init['pnts']} funcs = {} nslp = [] nslt = [] for k in range(self.Lmax): nslp.append(len(self.cases[k][rank])) nslt.append(sum([len(self.cases[k][x]) for x in range(size)])) sump.append(0.) musp.append(numpy.zeros(nslp[L])) sumpm.append(0.) muspm.append(numpy.zeros(nslp[L])) for i in range(nslp[L]): # just do this again in case saconstsm = self.samplep[L][i].tolist() self.saconsts = saconstsm + self.saconstsb self.solvers[L][i].setOption('SAConsts', self.saconsts) self.solvers[L][i].DVGeo.setDesignVars(dvdict) self.aps[L][i].setDesignVars(dvdict) self.solvers[L][i](self.aps[L][i]) self.solvers[L][i].evalFunctions(self.aps[L][i], funcs) astr = self.gridSol + "_" + str(self.cases[L][rank][i]) + "_cd" musp[L][i] = funcs[astr] sump[L] += funcs[astr] #import pdb; pdb.set_trace() if L > 0: self.solvers[L][i + nslp[L]].setOption( 'SAConsts', self.saconsts) self.solvers[L][i + nslp[L]].DVGeo.setDesignVars(dvdict) self.aps[L][i + nslp[L]].setDesignVars(dvdict) self.solvers[L][i + nslp[L]](self.aps[L][i + nslp[L]]) self.solvers[L][i + nslp[L]].evalFunctions( self.aps[L][i + nslp[L]], funcs) astr = self.gridSol + "_" + str( self.cases[L][rank][i]) + "_m_cd" muspm[L][i] = -funcs[astr] sumpm[L] += -funcs[astr] # compute mean and variance estimate from start up samples sum1.append(comm.allreduce(sump[L])) mus.append(comm.allgather(musp[L])) summ.append(comm.allreduce(sumpm[L])) musm.append(comm.allgather(muspm[L])) #import pdb; pdb.set_trace() # mean at each level E = numpy.zeros(L + 1) for l in range(L + 1): E[l] = (sum1[l] + summ[l]) / nslt[l] # variance at each level V = numpy.zeros(L + 1) for l in range(L + 1): sum2 = 0. for i in range(len(mus[l])): #range(size): for j in range(len(mus[l][i])): #range(self.nsp): if l > 0: sum2 += ((mus[l][i][j] + musm[l][i][j]) - E[l])**2 else: sum2 += (mus[l][i][j] - E[l])**2 V[l] = sum2 / nslt[l] #import pdb; pdb.set_trace() # now determine the optimal number of samples at each level N1.append(0.) worksum = 0 for l in range(L + 1): worksum += numpy.sqrt(V[l] * (M**l)) for l in range(L + 1): nlf = 2 * numpy.sqrt(V[l] / (M**l)) * worksum / (eps * eps) nlfm = max(nslt[l], math.ceil(nlf)) N1[l] = nlfm # now compute and generate additional samples at each level # first partition samples NEVERMIND (just do it once at each level, no need to repeat) # create the extra number of solvers at each (the current) level # need to loop everything from here on for l in range(L + 1): alist = self.aps[l][0:nslp[l]] slist = self.solvers[l][0:nslp[l]] mlist = self.meshes[l][0:nslp[l]] if l > 0: alist2 = self.aps[l][nslp[l]:] slist2 = self.solvers[l][nslp[l]:] mlist2 = self.meshes[l][nslp[l]:] self.naddedtot[l] = N1[l] - nslt[l] self.current_samples += self.naddedtot[l] #import pdb; pdb.set_trace() if rank == 0: rank0sam = plate_sa_lhs.genLHS(s=self.current_samples) else: rank0sam = None self.sample = comm.bcast(rank0sam, root=0) if self.naddedtot[l] > 0: temp = divide_cases(self.naddedtot[l], size) for i in range(len(temp)): for j in range(len(temp[i])): temp[i][j] += self.current_samples - self.naddedtot[ l] #self.Lmax*self.NS0 + sum(self.naddedtot[0:L]) else: temp = [] if len(temp): for ns in range(size): self.cases[l][ns] += temp[ns] #append nslpnew = len(self.cases[l][rank]) nsltnew = sum([len(self.cases[l][x]) for x in range(size)]) #self.nsp[L] = len(self.cases[L][rank]) #int(ns/size) # samples per processor self.samplep[l] = self.sample[self.cases[l][rank]] for i in range(nslp[l], nslpnew): #need it to be just the extra cases #import pdb; pdb.set_trace() namestr = self.gridSol + "_" + str(self.cases[l][rank][i]) # create meshes leveloptions = self.woptions leveloptions['gridFile'] = self.meshnames[l] mlist.append( USMesh(options=leveloptions, comm=MPI.COMM_SELF)) # create aeroproblems aloptions = self.aoptions aloptions['gridFile'] = self.meshnames[l] alist.append( AeroProblem(name=namestr, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=tempR, areaRef=arearef, chordRef=chordref, evalFuncs=['cd'])) time.sleep( 0.1) # this solves a few problems for some reason # create solvers slist.append(ADFLOW(options=aloptions, comm=MPI.COMM_SELF)) saconstsm = self.samplep[l][i].tolist() self.saconsts = saconstsm + self.saconstsb slist[i].setOption('SAConsts', self.saconsts) slist[i].setDVGeo(self.DVGeo) slist[i].setMesh(mlist[i]) coords = slist[i].getSurfaceCoordinates( groupName=slist[i].allWallsGroup) slist[i].DVGeo.addPointSet(coords, 'coords') time.sleep(0.1) if l > 0: #create additional solvers at higher levels for the estimators # create meshes #import pdb; pdb.set_trace() namestr = self.gridSol + "_" + str( self.cases[l][rank][i]) + "_m" leveloptions = self.woptions leveloptions['gridFile'] = self.meshnames[l - 1] mlist2.append( USMesh(options=leveloptions, comm=MPI.COMM_SELF)) # create aeroproblems aloptions = self.aoptions aloptions['gridFile'] = self.meshnames[l - 1] alist2.append( AeroProblem(name=namestr, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=tempR, areaRef=arearef, chordRef=chordref, evalFuncs=['cd'])) time.sleep( 0.1) # this solves a few problems for some reason # create solvers slist2.append( ADFLOW(options=aloptions, comm=MPI.COMM_SELF)) slist2[i].setOption('SAConsts', self.saconsts) slist2[i].setDVGeo(self.DVGeo) slist2[i].setMesh(mlist2[i]) coords = slist[i].getSurfaceCoordinates( groupName=slist2[i].allWallsGroup) slist2[i].DVGeo.addPointSet(coords, 'coords') nslp[l] = nslpnew nslt[l] = nsltnew self.aps[l] = alist self.solvers[l] = slist self.meshes[l] = mlist if l > 0: self.aps[l] += alist2 self.solvers[l] += slist2 self.meshes[l] += mlist2 # compute remaining samples sump[l] = 0 sumpm[l] = 0 musp[l] = numpy.zeros(nslp[l]) muspm[l] = numpy.zeros(nslp[l]) for i in range(nslp[l]): # just do this again in case saconstsm = self.samplep[l][i].tolist() self.saconsts = saconstsm + self.saconstsb self.solvers[l][i].setOption('SAConsts', self.saconsts) self.solvers[l][i].DVGeo.setDesignVars(dvdict) self.aps[l][i].setDesignVars(dvdict) self.solvers[l][i](self.aps[l][i]) self.solvers[l][i].evalFunctions(self.aps[l][i], funcs) astr = self.gridSol + "_" + str( self.cases[l][rank][i]) + "_cd" musp[l][i] = funcs[astr] sump[l] += funcs[astr] #import pdb; pdb.set_trace() if l > 0: self.solvers[l][i + nslp[l]].setOption( 'SAConsts', self.saconsts) self.solvers[l][i + nslp[l]].DVGeo.setDesignVars(dvdict) self.aps[l][i + nslp[l]].setDesignVars(dvdict) self.solvers[l][i + nslp[l]](self.aps[l][i + nslp[l]]) self.solvers[l][i + nslp[l]].evalFunctions( self.aps[l][i + nslp[l]], funcs) astr = self.gridSol + "_" + str( self.cases[l][rank][i]) + "_m_cd" muspm[l][i] = -funcs[astr] sumpm[l] += -funcs[astr] # compute mean and variance estimate from all samples sum1[l] = comm.allreduce(sump[l]) mus[l] = comm.allgather(musp[l]) summ[l] = comm.allreduce(sumpm[l]) musm[l] = comm.allgather(muspm[l]) # mean at each level E[l] = (sum1[l] + summ[l]) / nslt[l] # variance at each level sum2 = 0. for i in range(len(mus[l])): #range(size): for j in range(len(mus[l][i])): #range(self.nsp): if l > 0: sum2 += ((mus[l][i][j] + musm[l][i][j]) - E[l])**2 else: sum2 += (mus[l][i][j] - E[l])**2 V[l] = sum2 / nslt[l] # if L == 1: # import pdb; pdb.set_trace() L += 1 #import pdb; pdb.set_trace() #sys.stdout = sys.__stdout__ if rank == 0: print("MLMC Completed, Samples per level: ", N1) self.N1 = N1 #import pdb; pdb.set_trace() # test for convergence # don't actually need this, won't ever end early # range = -1:0 # if L > 1 & M**L >= 4: # con = M**(range.*suml(2,L+1+range)./suml(1,L+1+range)) # converged = (max(abs(con)) < (M-1)*eps/sqrt(2)) # once done, we have aps, solvers, meshes, which is all we need def dist_samples(self): # If we already have the number of samples, just create as many solvers as needed at each level # Just do this after running MLMC() anyway # flow characteristics alpha = 0.0 mach = self.ooptions['mach'] #0.95 Re = self.ooptions['Re'] #50000 Re_L = 1.0 tempR = 540 arearef = 2.0 chordref = 1.0 a_init = self.DVGeo.getValues() a_init['pnts'][:] = self.ooptions['DVInit'] self.current_samples = sum(self.N1) if rank == 0: rank0sam = plate_sa_lhs.genLHS(s=self.current_samples) else: rank0sam = None self.sample = comm.bcast(rank0sam, root=0) #import pdb; pdb.set_trace() # Scatter samples on each level, multi-point parallelism self.cases = [] self.samplep = [] for i in range(self.Lmax): self.cases.append(divide_cases(self.N1[i], size)) for j in range(len(self.cases[i])): for k in range(len(self.cases[i][j])): self.cases[i][j][k] += sum(self.N1[0:i]) #self.nsp.append(len(self.cases[i][rank]))#int(ns/size) # samples per processor self.samplep.append(self.sample[self.cases[i][rank]]) # Actually create solvers (and aeroproblems?) (and mesh?) now self.aps = [] self.solvers = [] self.meshes = [] nslp = [] nslt = [] for k in range(self.Lmax): alist = [] slist = [] mlist = [] alist2 = [] slist2 = [] mlist2 = [] nslp.append(len(self.cases[k][rank])) nslt.append(sum([len(self.cases[k][x]) for x in range(size)])) for i in range(nslp[k]): namestr = self.gridSol + "_" + str(self.cases[k][rank][i]) # create meshes leveloptions = self.woptions leveloptions['gridFile'] = self.meshnames[k] mlist.append(USMesh(options=leveloptions, comm=MPI.COMM_SELF)) # create aeroproblems aloptions = self.aoptions aloptions['gridFile'] = self.meshnames[k] alist.append( AeroProblem(name=namestr, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=tempR, areaRef=arearef, chordRef=chordref, evalFuncs=['cd'])) time.sleep(0.1) # this solves a few problems for some reason # create solvers slist.append(ADFLOW(options=aloptions, comm=MPI.COMM_SELF)) # if not self.ooptions['run_once']: # saconstsm = self.samplep[i].tolist() # else: saconstsm = self.samplep[k][i].tolist() self.saconsts = saconstsm + self.saconstsb slist[i].setOption('SAConsts', self.saconsts) slist[i].setDVGeo(self.DVGeo) slist[i].setMesh(mlist[i]) coords = slist[i].getSurfaceCoordinates( groupName=slist[i].allWallsGroup) slist[i].DVGeo.addPointSet(coords, 'coords') if k > 0: #create additional solvers at higher levels for the estimators # create meshes namestr = self.gridSol + "_" + str( self.cases[k][rank][i]) + "_m" leveloptions = self.woptions leveloptions['gridFile'] = self.meshnames[k - 1] mlist2.append( USMesh(options=leveloptions, comm=MPI.COMM_SELF)) # create aeroproblems aloptions = self.aoptions aloptions['gridFile'] = self.meshnames[k - 1] alist2.append( AeroProblem(name=namestr, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=tempR, areaRef=arearef, chordRef=chordref, evalFuncs=['cd'])) time.sleep( 0.1) # this solves a few problems for some reason # create solvers slist2.append(ADFLOW(options=aloptions, comm=MPI.COMM_SELF)) slist2[i].setOption('SAConsts', self.saconsts) slist2[i].setDVGeo(self.DVGeo) slist2[i].setMesh(mlist2[i]) coords = slist[i].getSurfaceCoordinates( groupName=slist2[i].allWallsGroup) slist2[i].DVGeo.addPointSet(coords, 'coords') self.aps.append(alist) self.solvers.append(slist) self.meshes.append(mlist) if k > 0: self.aps[k] += alist2 self.solvers[k] += slist2 self.meshes[k] += mlist2
class PlateComponentMFMC(om.ExplicitComponent): """Robust Bump Flow Problem, with LHS Multi Level Monte Carlo Samples""" def initialize(self): # Need to modify this dictionary when we change the SA constants #import pdb; pdb.set_trace() #sys.stdout = open(os.devnull, "w") self.aoptions = aeroOptions self.woptions = warpOptions self.ooptions = optOptions self.uoptions = uqOptions self.Pr = 0. # Generate FFD and DVs if rank == 0: rank0dvg = pf.createFFD() else: rank0dvg = None self.DVGeo = comm.bcast(rank0dvg, root=0) # Get a full list of every mesh name we have, assume they are ordered properly by level self.meshnames = self.uoptions['gridFileLevels'] self.Lmax = len(self.meshnames) #as many levels as we have meshes self.mord = [*range(self.Lmax)] self.mord.reverse() if self.Lmax < 3: raise ValueError('Not enough meshes available, ' + self.Lmax + ' < 3') # Spalart Allmaras model constants, to be changed in UQ (4 for now) saconstsm = [0.41, 0.1355, 0.622, 0.66666666667] self.saconstsb = [7.1, 0.3, 2.0, 1.0, 2.0, 1.2, 0.5, 2.0] self.saconsts = saconstsm + self.saconstsb self.aoptions['SAConsts'] = self.saconsts #self.gridSol = f'{meshname}_{saconstsm}_sol' solname = self.ooptions['prob_name'] self.gridSol = f'{solname}_sol' self.cases = [] #self.nsp = [] #keep track per level self.samplep = [] self.naddedtot = [] for i in range(self.Lmax): self.naddedtot.append(0) self.aps = [] self.solvers = [] self.meshes = [] self.NS0 = self.uoptions['NS0'] self.current_samples = self.NS0 * self.Lmax self.N1 = None self.a1 = None self.P = self.uoptions['P'] ########## # call distribute samples here? if not self.uoptions['use-predetermined-samples']: self.MFMC() else: self.N1 = self.uoptions['predet-N1'] self.a1 = self.uoptions['predet-a1'] self.dist_samples() ########## # Set constraints, should only need one of those solvers, the meshes are all the same if rank == 0: self.DVCon = DVConstraints() self.DVCon2 = DVConstraints() self.DVCon.setDVGeo( self.solvers[0][0].DVGeo.getFlattenedChildren()[1]) self.DVCon2.setDVGeo(self.solvers[0][0].DVGeo) self.DVCon.setSurface( self.solvers[0][0].getTriangulatedMeshSurface( groupName='allSurfaces')) # set extra group for surface area condition self.DVCon2.setSurface( self.solvers[0][0].getTriangulatedMeshSurface(), name='wall') # DV should be same into page (not doing anything right now) #import pdb; pdb.set_trace() lIndex = self.solvers[0][0].DVGeo.getFlattenedChildren( )[1].getLocalIndex(0) indSetA = [] indSetB = [] nXc = optOptions['NX'] self.NC = math.trunc( ((1.0 - self.ooptions['DVFraction']) * self.ooptions['NX'])) ind = [ int(nXc / 2) - int(self.NC / 2), int(nXc / 2) + int(self.NC / 2) ] for i in range(ind[0], ind[1]): indSetA.append(lIndex[i, 0, 1]) indSetB.append(lIndex[i, 1, 1]) # for i in range(lIndex.shape[0]): # indSetA.append(lIndex[i, 0, 1]) # indSetB.append(lIndex[i, 1, 1]) self.DVCon.addLinearConstraintsShape(indSetA, indSetB, factorA=1.0, factorB=-1.0, lower=0, upper=0, name='eqs') # Thickness constraints (one for each active DV) #import pdb; pdb.set_trace() # Maximum thickness of the domain, translates to minimum thickness of bump ub = 1.0 - self.ooptions['DCMinThick'] tcf = self.ooptions['DCThickFrac'] ra = self.ooptions['bumpBounds'] lim = self.ooptions['DCMinArea'] span = numpy.linspace(0, 1, nXc) xc = span * (ra[1] - ra[0]) + ra[0] #ind = range(int(nXc/2) - int(self.NC/2), int(nXc/2) + int(self.NC/2))) ind = [ int(nXc / 2) - int(tcf * self.NC / 2), int(nXc / 2) + int(tcf * self.NC / 2) ] ptList = numpy.zeros([2, 3]) ptList[:, 0] = xc[ind] ptList[:, 1] = 0.5 ptList[:, 2] = 0.5 if self.ooptions['use_area_con']: self.DVCon2.addSurfaceAreaConstraint(lower=lim, upper=10., name='sas', surfaceName='wall') else: self.DVCon2.addThicknessConstraints1D(ptList, self.NC, [0, 0, 1], lower=0.5, upper=ub, name='tcs') dummy = rank dsum = comm.allgather(dummy) sys.stdout = sys.__stdout__ def setup(self): #initialize shape and set deformation points as inputs a_init = self.DVGeo.getValues() a_init['pnts'][:] = self.ooptions['DVInit'] # mult = numpy.linspace(1.0,1.5,num=int(0.5*len(a_init['pnts']))) # mult = numpy.concatenate((mult, mult)) #if self.ooptions['run_once']: # a_init['pnts'] = self.ooptions['ro_shape'] #a_init['pnts'] = numpy.multiply(mult, a_init['pnts']) self.add_input('a', a_init['pnts'], desc="Bump Shape Control Points") #self.add_input('a', 0.2, desc="Bump Shape Control Points") if self.ooptions['use_area_con']: self.add_output('SA', 1.0, desc='Surface Area Constraint') else: self.add_output('TC', numpy.zeros(self.NC), desc='Thickness Constraints') self.add_output('Cd_m', 0.0, desc="Mean Drag Coefficient") self.add_output('Cd_v', 0.0, desc="Variance Drag Coefficient") self.add_output('Cd_r', 0.0, desc="Robust Drag Objective") self.add_output('EQ', numpy.zeros(int(len(a_init['pnts']) / 2)), desc="Control Point Symmetry") self.add_output('N1', self.N1, desc="MFMC Samples at each level") self.add_output('a1', self.a1, desc="MFMC Coeffs at each level") self.add_output('Pr', 0., desc="MFMC Samples at each level") def setup_partials(self): self.declare_partials('Cd_m', 'a', method='exact') self.declare_partials('Cd_v', 'a', method='exact') self.declare_partials('Cd_r', 'a', method='exact') if self.ooptions['use_area_con']: self.declare_partials('SA', 'a', method='exact') else: self.declare_partials('TC', 'a', method='exact') self.declare_partials('EQ', 'a', method='exact') def compute(self, inputs, outputs): # run the bump shape model #import pdb; pdb.set_trace() dvdict = {'pnts': inputs['a']} ntot = self.current_samples nslp = [] nslt = [] for k in range(self.Lmax): nslp.append(len(self.cases[k][rank])) nslt.append(sum([len(self.cases[k][x]) for x in range(size)])) funcs = {} sump = [] musp = [] sum1 = [] mus = [] sumpm = [] muspm = [] summ = [] musm = [] E = numpy.zeros(self.Lmax) V = numpy.zeros(self.Lmax) for k in range(self.Lmax): sump.append(0.0) musp.append(numpy.zeros(nslp[k])) sumpm.append(0.) if k > 0: muspm.append(numpy.zeros(nslp[k - 1])) else: muspm.append(numpy.zeros(nslp[k])) #not used for i in range(nslp[k]): saconstsm = self.samplep[self.Lmax - 1][i].tolist() self.saconsts = saconstsm + self.saconstsb self.solvers[k][i].setOption('SAConsts', self.saconsts) self.solvers[k][i].DVGeo.setDesignVars(dvdict) self.aps[k][i].setDesignVars(dvdict) self.solvers[k][i](self.aps[k][i]) self.solvers[k][i].evalFunctions(self.aps[k][i], funcs) astr = self.gridSol + "_" + str(self.cases[k][rank][i]) + "_cd" musp[k][i] = funcs[astr] sump[k] += funcs[astr] if k > 0 and i < nslp[k - 1]: muspm[k][i] = -funcs[astr] sumpm[k] += -funcs[astr] # compute mean and variance for k in range(self.Lmax): sum1.append(comm.allreduce(sump[k])) mus.append(comm.allgather(musp[k])) summ.append(comm.allreduce(sumpm[k])) musm.append(comm.allgather(muspm[k])) #import pdb; pdb.set_trace() if k > 0: E[k] = (sum1[k] / nslt[k] + summ[k] / nslt[k - 1]) else: E[k] = (sum1[k] / nslt[k]) sum2 = 0. for i in range(len(mus[k])): #loop over processors for j in range(len( mus[k][i])): #loop over samples on processors if k > 0: #sum2 = 0 sum2 += ( (mus[k][i][j] - sum1[k] / nslt[k])**2) / nslt[k] if j < len(mus[k - 1][i]): sum2 -= ((musm[k][i][j] - summ[k] / nslt[k - 1])** 2) / nslt[k - 1] else: sum2 += ((mus[k][i][j] - E[k])**2) / nslt[k] V[k] = sum2 #import pdb; pdb.set_trace() if rank == 0: self.DVCon.evalFunctions(funcs, includeLinear=True) self.DVCon2.evalFunctions(funcs, includeLinear=True) eq0 = funcs['eqs'] sa0 = funcs['sas'] else: eq0 = None sa0 = None eq = comm.bcast(eq0, root=0) sa = comm.bcast(sa0, root=0) outputs['Cd_m'] = numpy.dot(self.a1, E) outputs['Cd_v'] = numpy.dot(self.a1, V) #by assumption rho = self.uoptions['rho'] outputs['Cd_r'] = numpy.dot(self.a1, E) + rho * math.sqrt(numpy.dot(self.a1, V)) #import pdb; pdb.set_trace() if self.ooptions['use_area_con']: outputs['SA'] = sa else: outputs['TC'] = funcs['tcs'] outputs['EQ'] = eq outputs['N1'] = self.N1 outputs['a1'] = self.a1 outputs['Pr'] = self.Pr #outputs['Cd'] = inputs['a']*inputs['a'] def compute_partials(self, inputs, J): dvdict = {'pnts': inputs['a']} funcs = {} funcSens = {} nslp = [] nslt = [] for k in range(self.Lmax): nslp.append(len(self.cases[k][rank])) nslt.append(sum([len(self.cases[k][x]) for x in range(size)])) sump = [] musp = [] sum1 = [] sum2 = [] mus = [] sumpm = [] muspm = [] summ = [] musm = [] pmup = [] psump = [] #numpy.zeros(len(inputs['a'])) pmu = [] psum1 = [] pmupm = [] psumpm = [] #numpy.zeros(len(inputs['a'])) pmum = [] psumm = [] E = numpy.zeros(self.Lmax) V = numpy.zeros(self.Lmax) #import pdb; pdb.set_trace() for k in range(self.Lmax): sump.append(0.0) musp.append(numpy.zeros(nslp[k])) sumpm.append(0.) if k > 0: muspm.append(numpy.zeros(nslp[k - 1])) else: muspm.append(numpy.zeros(nslp[k])) #not used pmup.append([]) psump.append(numpy.zeros(len(inputs['a']))) pmupm.append([]) psumpm.append(numpy.zeros(len(inputs['a']))) for i in range(nslp[k]): saconstsm = self.samplep[k][i].tolist() self.saconsts = saconstsm + self.saconstsb self.solvers[k][i].setOption('SAConsts', self.saconsts) self.solvers[k][i].DVGeo.setDesignVars(dvdict) self.aps[k][i].setDesignVars(dvdict) self.solvers[k][i](self.aps[k][i]) self.solvers[k][i].evalFunctions(self.aps[k][i], funcs) self.solvers[k][i].evalFunctionsSens(self.aps[k][i], funcSens, ['cd']) astr = self.gridSol + "_" + str(self.cases[k][rank][i]) + "_cd" arr = [ x * (self.a1[k] / nslt[k]) for x in funcSens[astr]['pnts'] ] musp[k][i] = funcs[astr] sump[k] += funcs[astr] pmup[k].append(arr[0]) psump[k] += arr[0] if k > 0 and i < nslp[k - 1]: arrm = [ x * (self.a1[k] / nslt[k - 1]) for x in funcSens[astr]['pnts'] ] muspm[k][i] = -funcs[astr] sumpm[k] += -funcs[astr] pmupm[k].append(-arrm[0]) psumpm[k] -= arrm[0] # compute mean and variance psum2 = numpy.zeros(len(inputs['a'])) for k in range(self.Lmax): sum1.append(comm.allreduce(sump[k])) mus.append(comm.allgather(musp[k])) summ.append(comm.allreduce(sumpm[k])) musm.append(comm.allgather(muspm[k])) psum1.append(comm.allreduce(psump[k])) pmu.append(comm.allgather(pmup[k])) psumm.append(comm.allreduce(psumpm[k])) pmum.append(comm.allgather(pmupm[k])) if k > 0: E[k] = (sum1[k] / nslt[k] + summ[k] / nslt[k - 1]) else: E[k] = (sum1[k] / nslt[k]) sum2 = 0. for i in range(len(mus[k])): #loop over processors for j in range(len( mus[k][i])): #loop over samples on processors if k > 0: #sum2 = 0 sum2 += ( (mus[k][i][j] - sum1[k] / nslt[k])**2) / nslt[k] if j < len(mus[k - 1][i]): sum2 -= ((musm[k][i][j] - summ[k] / nslt[k - 1])** 2) / nslt[k - 1] else: sum2 += ((mus[k][i][j] - E[k])**2) / nslt[k] V[k] = sum2 # compute variance sensitivity psum2 = [] for k in range(self.Lmax): psum2.append(numpy.zeros(len(inputs['a']))) for i in range(len(mus[0])): #loop over processors for j in range(len( mus[0][i])): #loop over samples on processors if k > 0: temp = pmu[k][i][j] * nslt[k] - psum1[k] arr2 = [ x * 2 * (mus[k][i][j] - sum1[k]) / nslt[k] for x in temp ] psum2[k] += arr2 if j < len(mus[k - 1][i]): temp = pmu[k][i][j] * nslt[k - 1] - psum1[k] arr2 = [ x * 2 * (musm[k][i][j] - summ[k] / nslt[k - 1]) / nslt[k - 1] for x in temp ] psum2[k] -= arr2 else: temp = pmu[k][i][j] * nslt[k] - psum1[k] arr2 = [ x * 2 * (mus[k][i][j] - E[k]) / nslt[k] for x in temp ] psum2[k] += arr2 #import pdb; pdb.set_trace() if rank == 0: self.DVCon.evalFunctionsSens(funcSens, includeLinear=True) self.DVCon2.evalFunctionsSens(funcSens, includeLinear=True) eq0p = funcSens['eqs']['pnts'] sa0p = funcSens['sas']['pnts'] else: eq0p = None sa0p = None eqp = comm.bcast(eq0p, root=0) sap = comm.bcast(sa0p, root=0) J['Cd_m', 'a'] = sum(psum1) + sum(psumm) J['Cd_v', 'a'] = sum(psum2) rho = self.uoptions['rho'] J['Cd_r', 'a'] = sum(psum1) + sum(psumm) + rho * ( 1. / (2 * math.sqrt(numpy.dot(self.a1, V)))) * sum(psum2) if self.ooptions['use_area_con']: J['SA', 'a'] = sap else: J['TC', 'a'] = funcSens['tcs']['pnts'] J['EQ', 'a'] = eqp #J['Cd','a'][0] = 2*inputs['a'] def MFMC(self): # Use an MFMC algorithm to determine optimal sample distribution and coefficients among mesh levels # We do this once before optimization, then compute statistics with the same set of samples and coeffs at every iteration # start with initial samples # Get a set of UQ sample points (LHS), enough for each level at the start #sys.stdout = open(os.devnull, "w") # flow characteristics alpha = 0.0 mach = self.ooptions['mach'] #0.95 Re = self.ooptions['Re'] #50000 Re_L = 1.0 tempR = 540 arearef = 2.0 chordref = 1.0 a_init = self.DVGeo.getValues() a_init['pnts'][:] = self.ooptions['DVInit'] self.current_samples = self.NS0 * self.Lmax if rank == 0: rank0sam = plate_sa_lhs.genLHS(s=self.current_samples) else: rank0sam = None self.sample = comm.bcast(rank0sam, root=0) N1 = [] a1 = numpy.zeros(self.Lmax) r1 = numpy.zeros(self.Lmax) # Scatter samples on each level, multi-point parallelism for i in range(self.Lmax): self.cases.append(divide_cases(self.NS0, size)) for j in range(len(self.cases[i])): for k in range(len(self.cases[i][j])): self.cases[i][j][k] += i * self.NS0 #self.nsp.append(len(self.cases[i][rank]))#int(ns/size) # samples per processor self.samplep.append(self.sample[self.cases[i][rank]]) #import pdb; pdb.set_trace() #self.samplep = self.sample[self.cases[rank]]#self.sample[(rank*self.nsp):(rank*self.nsp+(self.nsp))] #shouldn't really need to "scatter" per se #import pdb; pdb.set_trace() # for i in range(self.Lmax): # assert len(self.samplep[i]) == self.nsp[i] # Create solvers for the preliminary data nslp = [] nslt = [] for k in range(self.Lmax): alist = [] slist = [] mlist = [] nslp.append(len(self.cases[k][rank])) nslt.append(sum([len(self.cases[k][x]) for x in range(size)])) for i in range(nslp[k]): namestr = self.gridSol + "_" + str(self.cases[k][rank][i]) # create meshes leveloptions = self.woptions leveloptions['gridFile'] = self.meshnames[self.mord[k]] #import pdb; pdb.set_trace() mlist.append(USMesh(options=leveloptions, comm=MPI.COMM_SELF)) # create aeroproblems aloptions = self.aoptions aloptions['gridFile'] = self.meshnames[self.mord[k]] alist.append( AeroProblem(name=namestr, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=tempR, areaRef=arearef, chordRef=chordref, evalFuncs=['cd'])) time.sleep(0.1) # this solves a few problems for some reason # create solvers slist.append(ADFLOW(options=aloptions, comm=MPI.COMM_SELF)) # if not self.ooptions['run_once']: # saconstsm = self.samplep[i].tolist() # else: saconstsm = self.samplep[0][i].tolist() self.saconsts = saconstsm + self.saconstsb slist[i].setOption('SAConsts', self.saconsts) slist[i].setDVGeo(self.DVGeo) slist[i].setMesh(mlist[i]) coords = slist[i].getSurfaceCoordinates( groupName=slist[i].allWallsGroup) slist[i].DVGeo.addPointSet(coords, 'coords') self.aps.append(alist) self.solvers.append(slist) self.meshes.append(mlist) # Solve the preliminary samples # start looping over mesh levels sumt = [] sumtp = [] nslp = [] nslt = [] sum1 = [] mus = [] sump = [] musp = [] sumpm = [] muspm = [] summ = [] musm = [] Et = numpy.zeros(self.Lmax) E = numpy.zeros(self.Lmax) V = numpy.zeros(self.Lmax) S = numpy.zeros(self.Lmax) N1 = [] for k in range(self.Lmax): nslp.append(len(self.cases[k][rank])) nslt.append(sum([len(self.cases[k][x]) for x in range(size)])) dvdict = {'pnts': a_init['pnts']} funcs = {} sumtp.append(0.0) sump.append(0.) musp.append(numpy.zeros(nslp[k])) sumpm.append(0.) muspm.append(numpy.zeros(nslp[k])) for i in range(nslp[k]): # just do this again in case saconstsm = self.samplep[0][i].tolist() self.saconsts = saconstsm + self.saconstsb self.solvers[k][i].setOption('SAConsts', self.saconsts) self.solvers[k][i].DVGeo.setDesignVars(dvdict) self.aps[k][i].setDesignVars(dvdict) pc0 = time.process_time() self.solvers[k][i](self.aps[k][i]) self.solvers[k][i].evalFunctions(self.aps[k][i], funcs) pc1 = time.process_time() astr = self.gridSol + "_" + str(self.cases[k][rank][i]) + "_cd" musp[k][i] = funcs[astr] sump[k] += funcs[astr] sumtp[k] += (pc1 - pc0) # compute mean and variance estimate from start up samples for k in range(self.Lmax): sumt.append(comm.allreduce(sumtp[k])) sum1.append(comm.allreduce(sump[k])) mus.append(comm.allgather(musp[k])) summ.append(comm.allreduce(sumpm[k])) musm.append(comm.allgather(muspm[k])) mus[k] = numpy.concatenate(mus[k][:]) musm[k] = numpy.concatenate(musm[k][:]) #import pdb; pdb.set_trace() # mean at each level Et[k] = sumt[k] / nslt[k] E[k] = (sum1[k]) / nslt[k] #+summ[k] sum2 = 0. for i in range(len(mus[k])): #loop over processors sum2 += (mus[k][i] - E[k])**2 V[k] = sum2 / nslt[k] S[k] = math.sqrt(V[k]) # compute correlation matrix and rearrange models if necessary ordered = False while not ordered: rho = numpy.corrcoef(mus) ordered = True # check if contradicted #tarr = rho[0,1:] for k in range(self.Lmax - 2): test = rho[0, 1 + k]**2 - rho[0, 2 + k]**2 if test < 0: ordered = False tarr = -rho[0, :]**2 if not ordered: sind = numpy.argsort(tarr) #import pdb; pdb.set_trace() self.mord[:] = [self.mord[i] for i in sind] E[:] = [E[i] for i in sind] Et[:] = [Et[i] for i in sind] V[:] = [V[i] for i in sind] S[:] = [S[i] for i in sind] mus[:] = [mus[i] for i in sind] # now compute N1 and a1 using sigma, rho, w, and p for k in range(self.Lmax): a1[k] = S[0] * rho[0, k] / S[k] if k == 0: r1[k] = 1 elif k == self.Lmax - 1: work = Et[0] * (rho[0, k]**2) work /= Et[k] * (1 - rho[0, 1]**2) r1[k] = math.sqrt(work) else: work = Et[0] * (rho[0, k - 1]**2 - rho[0, k]**2) work /= Et[k] * (1 - rho[0, 1]**2) r1[k] = math.sqrt(work) for k in range(self.Lmax): N1.append(0) nsf = self.P / numpy.dot(Et, r1) N1[0] = math.ceil(nsf) for k in range(self.Lmax): nsf = N1[0] * r1[k] N1[k] = math.ceil(nsf) # limit the number of samples on the last one to pass the sanity check, for debug sanity = numpy.dot(N1, Et) if sanity > 1.2 * self.P: N1n = (self.P - numpy.dot(N1[0:self.Lmax - 2], Et[0:self.Lmax - 2])) / Et[self.Lmax - 1] N1[self.Lmax - 1] = math.ceil(N1n) self.Pr = numpy.dot(N1, Et) self.N1 = N1 self.a1 = a1 #import pdb; pdb.set_trace() if rank == 0: print("MFMC Completed, Samples per level: ", N1) # call dist_samples after this def dist_samples(self): # If we already have the number of samples, just create as many solvers as needed at each level # Just do this after running MLMC() anyway # flow characteristics alpha = 0.0 mach = self.ooptions['mach'] #0.95 Re = self.ooptions['Re'] #50000 Re_L = 1.0 tempR = 540 arearef = 2.0 chordref = 1.0 a_init = self.DVGeo.getValues() a_init['pnts'][:] = self.ooptions['DVInit'] self.current_samples = sum(self.N1) if rank == 0: rank0sam = plate_sa_lhs.genLHS(s=self.current_samples) else: rank0sam = None self.sample = comm.bcast(rank0sam, root=0) #import pdb; pdb.set_trace() # Scatter samples on each level, multi-point parallelism self.cases = [] self.samplep = [] for i in range(self.Lmax): self.cases.append(divide_cases(self.N1[i], size)) for j in range(len(self.cases[i])): for k in range(len(self.cases[i][j])): self.cases[i][j][k] += sum(self.N1[0:i]) #self.nsp.append(len(self.cases[i][rank]))#int(ns/size) # samples per processor self.samplep.append(self.sample[self.cases[i][rank]]) # Actually create solvers (and aeroproblems?) (and mesh?) now self.aps = [] self.solvers = [] self.meshes = [] nslp = [] nslt = [] for k in range(self.Lmax): alist = [] slist = [] mlist = [] nslp.append(len(self.cases[k][rank])) nslt.append(sum([len(self.cases[k][x]) for x in range(size)])) for i in range(nslp[k]): namestr = self.gridSol + "_" + str(self.cases[k][rank][i]) # create meshes leveloptions = self.woptions leveloptions['gridFile'] = self.meshnames[self.mord[k]] mlist.append(USMesh(options=leveloptions, comm=MPI.COMM_SELF)) # create aeroproblems aloptions = self.aoptions aloptions['gridFile'] = self.meshnames[self.mord[k]] alist.append( AeroProblem(name=namestr, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=tempR, areaRef=arearef, chordRef=chordref, evalFuncs=['cd'])) time.sleep(0.1) # this solves a few problems for some reason # create solvers slist.append(ADFLOW(options=aloptions, comm=MPI.COMM_SELF)) saconstsm = self.samplep[self.Lmax - 1][i].tolist() self.saconsts = saconstsm + self.saconstsb slist[i].setOption('SAConsts', self.saconsts) slist[i].setDVGeo(self.DVGeo) slist[i].setMesh(mlist[i]) coords = slist[i].getSurfaceCoordinates( groupName=slist[i].allWallsGroup) slist[i].DVGeo.addPointSet(coords, 'coords') self.aps.append(alist) self.solvers.append(slist) self.meshes.append(mlist)
class PlateComponent(om.ExplicitComponent): """Deterministic Bump Flow Problem""" def initialize(self): # Need to modify this dictionary when we change the SA constants sys.stdout = open(os.devnull, "w") self.aoptions = aeroOptions self.woptions = warpOptions self.ooptions = optOptions # Generate FFD and DVs self.DVGeo = pf.createFFD() # starting flat mesh meshname = self.aoptions['gridFile'] gridFile = meshname # flow characteristics alpha = 0.0 mach = self.ooptions['mach']#0.95 Re = self.ooptions['Re']#50000 Re_L = 1.0 temp = 540 arearef = 2.0 chordref = 1.0 # Spalart Allmaras model constants, to be changed in UQ saconstsm = [0.41, 0.1355, 0.622, 0.66666666667, 7.1, 0.3, 2.0] self.saconsts = saconstsm + [1.0, 2.0, 1.2, 0.5, 2.0] self.aoptions['SAConsts'] = self.saconsts #self.gridSol = f'{meshname}_{saconstsm}_sol' solname = self.ooptions['prob_name'] self.gridSol = f'{solname}_sol' # Aerodynamic problem description self.ap = AeroProblem(name=self.gridSol, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=temp, areaRef=arearef, chordRef=chordref, evalFuncs=['cd']) # Create solver self.CFDSolver = ADFLOW(options=self.aoptions, comm=MPI.COMM_WORLD) self.CFDSolver.setDVGeo(self.DVGeo) # Set up mesh warping self.mesh = USMesh(options=self.woptions, comm=MPI.COMM_WORLD) self.CFDSolver.setMesh(self.mesh) # Try setting the DVGeo coordinates here coords = self.CFDSolver.getSurfaceCoordinates(groupName=self.CFDSolver.allWallsGroup) self.CFDSolver.DVGeo.addPointSet(coords, 'coords') self.CFDSolver.DVGeo.getFlattenedChildren()[1].writePlot3d("ffdp_opt_def.xyz") # Set constraints self.DVCon = DVConstraints() self.DVCon2 = DVConstraints() self.DVCon.setDVGeo(self.CFDSolver.DVGeo.getFlattenedChildren()[1]) self.DVCon2.setDVGeo(self.CFDSolver.DVGeo) self.DVCon.setSurface(self.CFDSolver.getTriangulatedMeshSurface(groupName='allSurfaces')) # set extra group for surface area condition self.DVCon2.setSurface(self.CFDSolver.getTriangulatedMeshSurface(), name='wall') # DV should be same into page (not doing anything right now) #import pdb; pdb.set_trace() lIndex = self.CFDSolver.DVGeo.getFlattenedChildren()[1].getLocalIndex(0) indSetA = [] indSetB = [] nXc = optOptions['NX'] self.NC = math.trunc(((1.0 - self.ooptions['DVFraction'])*self.ooptions['NX'])) ind = [int(nXc/2) - int(self.NC/2), int(nXc/2) + int(self.NC/2)] for i in range(ind[0], ind[1]): indSetA.append(lIndex[i, 0, 1]) indSetB.append(lIndex[i, 1, 1]) # for i in range(lIndex.shape[0]): # indSetA.append(lIndex[i, 0, 1]) # indSetB.append(lIndex[i, 1, 1]) self.DVCon.addLinearConstraintsShape(indSetA, indSetB, factorA=1.0, factorB=-1.0, lower=0, upper=0, name='eqs') # Thickness constraints (one for each active DV) #import pdb; pdb.set_trace() # Maximum thickness of the domain, translates to minimum thickness of bump ub = 1.0 - self.ooptions['DCMinThick'] tcf = self.ooptions['DCThickFrac'] ra = self.ooptions['bumpBounds'] lim = self.ooptions['DCMinArea'] span = numpy.linspace(0, 1, nXc) xc = span * (ra[1] - ra[0]) + ra[0] #ind = range(int(nXc/2) - int(self.NC/2), int(nXc/2) + int(self.NC/2))) ind = [int(nXc/2) - int(tcf*self.NC/2), int(nXc/2) + int(tcf*self.NC/2)] ptList = numpy.zeros([2, 3]) ptList[:,0] = xc[ind] ptList[:,1] = 0.5 ptList[:,2] = 0.5 if self.ooptions['use_area_con']: self.DVCon2.addSurfaceAreaConstraint(lower=lim, upper=10., name='sas', surfaceName='wall') else: self.DVCon2.addThicknessConstraints1D(ptList, self.NC, [0,0,1], lower=0.5, upper=ub, name='tcs') sys.stdout = sys.__stdout__ def setup(self): #initialize shape and set deformation points as inputs a_init = self.CFDSolver.DVGeo.getValues() a_init['pnts'][:] = self.ooptions['DVInit'] # mult = numpy.linspace(1.0,1.5,num=int(0.5*len(a_init['pnts']))) # mult = numpy.concatenate((mult, mult)) # a_init['pnts'] = numpy.multiply(mult, a_init['pnts']) #if self.ooptions['run_once']: # a_init['pnts'] = self.ooptions['ro_shape'] self.add_input('a', a_init['pnts'], desc="Bump Shape Control Points") #self.add_input('a', 0.2, desc="Bump Shape Control Points") if self.ooptions['use_area_con']: self.add_output('SA', 1.0, desc='Surface Area Constraint') else: self.add_output('TC', numpy.zeros(self.NC), desc='Thickness Constraints') self.add_output('Cd', 0.0, desc="Drag Coefficient") self.add_output('EQ', numpy.zeros(int(len(a_init['pnts'])/2)), desc="Control Point Symmetry") def setup_partials(self): self.declare_partials('Cd','a', method='exact') if self.ooptions['use_area_con']: self.declare_partials('SA','a', method='exact') else: self.declare_partials('TC','a', method='exact') self.declare_partials('EQ','a', method='exact') def compute(self, inputs, outputs): # run the bump shape model # move the mesh #import pdb; pdb.set_trace() dvdict = {'pnts':inputs['a']} self.CFDSolver.DVGeo.setDesignVars(dvdict) self.ap.setDesignVars(dvdict) #self.CFDSolver.DVGeo.update("coords") # Solve and evaluate functions funcs = {} self.CFDSolver(self.ap) self.DVCon.evalFunctions(funcs, includeLinear=True) self.DVCon2.evalFunctions(funcs, includeLinear=True) self.CFDSolver.evalFunctions(self.ap, funcs) str = self.gridSol + '_cd' outputs['Cd'] = funcs[str] if self.ooptions['use_area_con']: outputs['SA'] = funcs['sas'] else: outputs['TC'] = funcs['tcs'] outputs['EQ'] = funcs['eqs'] #outputs['Cd'] = inputs['a']*inputs['a'] def compute_partials(self, inputs, J): # move the mesh #import pdb; pdb.set_trace() dvdict = {'pnts':inputs['a']} self.CFDSolver.DVGeo.setDesignVars(dvdict) self.ap.setDesignVars(dvdict) #self.CFDSolver.DVGeo.update("coords") funcSens = {} #self.CFDSolver(self.ap) #ASSUME WE ALREADY COMPUTED THE SOLUTION self.DVCon.evalFunctionsSens(funcSens, includeLinear=True) self.DVCon2.evalFunctionsSens(funcSens, includeLinear=True) self.CFDSolver.evalFunctionsSens(self.ap, funcSens, ['cd']) str = self.gridSol + '_cd' J['Cd','a'] = funcSens[str]['pnts'] if self.ooptions['use_area_con']: J['SA','a'] = funcSens['sas']['pnts'] else: J['TC','a'] = funcSens['tcs']['pnts'] J['EQ','a'] = funcSens['eqs']['pnts']