def main(tot_iter): objectives = { 0: "compliance", 1: "stress", 2: "conduction", 3: "coupled_heat" } loadFolder = loadFolder0 + "" restart_iter = 66 import os try: os.mkdir(loadFolder + 'restart_' + str(restart_iter)) except: pass try: os.mkdir(loadFolder + 'restart_' + str(restart_iter) + '/figs') except: pass inspctFlag = False if tot_iter < 0: inspctFlag = True tot_iter = restart_iter + 1 # select which problem to solve obj_flag = 3 print(locals()) print("solving %s problem" % objectives[obj_flag]) print("restarting from %d ..." % restart_iter) fname0 = loadFolder + 'phi%03i.pkl' % restart_iter with open(fname0, 'rb') as f: raw = pickle.load(f) phi0 = raw['phi'] fname0 = loadFolder0 + 'const.pkl' with open(fname0, 'rb') as f: raw = pickle.load(f) # nodes = raw['mesh'] nodes = raw['nodes'] elem = raw['elem'] GF_e = raw['GF_e'] GF_t = raw['GF_t'] BCid_e = raw['BCid_e'] BCid_t = raw['BCid_t'] E = raw['E'] nu = raw['nu'] f = raw['f'] K_cond = raw['K_cond'] alpha = raw['alpha'] nelx = raw['nelx'] nely = raw['nely'] length_x = raw['length_x'] length_y = raw['length_y'] coord_e = raw['coord_e'] tol_e = raw['tol_e'] ######################################################## ################# FEA #################### ######################################################## # NB: only Q4 elements + integer-spaced mesh are assumed ls2fe_x = length_x / float(nelx) ls2fe_y = length_y / float(nely) num_nodes_x = nelx + 1 num_nodes_y = nely + 1 nELEM = nelx * nely nNODE = num_nodes_x * num_nodes_y # Declare FEA object (OpenLSTO_FEA) ====================== fea_solver = py_FEA(lx=length_x, ly=length_y, nelx=nelx, nely=nely, element_order=2) [node, elem, elem_dof] = fea_solver.get_mesh() # validate the mesh if nELEM != elem.shape[0]: error("error found in the element") if nNODE != node.shape[0]: error("error found in the node") nDOF_t = nNODE * 1 # each node has one temperature DOF nDOF_e = nNODE * 2 # each node has two displacement DOFs # constitutive properties ================================= fea_solver.set_material(E=E, nu=nu, rho=1.0) # Boundary Conditions ===================================== fea_solver.set_boundary(coord=coord_e, tol=tol_e) BCid_e = fea_solver.get_boundary() nDOF_e_wLag = nDOF_e + len(BCid_e) # elasticity DOF nDOF_t_wLag = nDOF_t + len(BCid_t) # temperature DOF ######################################################## ################# LSM #################### ######################################################## movelimit = 0.5 # Declare Level-set object lsm_solver = py_LSM(nelx=nelx, nely=nely, moveLimit=movelimit) lsm_solver.add_holes([], [], []) lsm_solver.set_levelset() lsm_solver.set_phi_re(phi0) lsm_solver.reinitialise() for i_HJ in range(restart_iter, tot_iter): (bpts_xy, areafraction, seglength) = lsm_solver.discretise() ######################################################## ############### OpenMDAO ################ ######################################################## # Declare Group if (objectives[obj_flag] == "compliance"): model = ComplianceGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, BCid=BCid_e) elif (objectives[obj_flag] == "stress"): # TODO: sensitivity has not been verified yet model = StressGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, pval=5.0, E=E, nu=nu) elif (objectives[obj_flag] == "conduction"): model = ConductionGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_t, movelimit=movelimit, K_cond=K_cond, BCid=BCid_t) elif (objectives[obj_flag] == "coupled_heat"): model = HeatCouplingGroup( fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force_e=GF_e, force_t=GF_t, movelimit=movelimit, K_cond=K_cond, BCid_e=BCid_e, BCid_t=BCid_t, E=E, nu=nu, alpha=alpha, w=0.0 ) # if w = 0.0, thermoelastic + conduction, if w = 1.0, conduction only # One Problem per one OpenMDAO object prob = Problem(model) # optimize ... prob.driver = pyOptSparseDriver() prob.driver.options['optimizer'] = 'IPOPT' prob.driver.opt_settings['linear_solver'] = 'ma27' prob.setup(check=False) prob.run_model() # Total derivative using MAUD ===================== total = prob.compute_totals() if (objectives[obj_flag] == "compliance"): ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "stress"): ff = total['pnorm_comp.pnorm', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "conduction"): ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "coupled_heat"): ff = total['objective_comp.y', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] nBpts = int(bpts_xy.shape[0]) # # WIP checking sensitivity 10/23 Sf = -ff[:nBpts] # equal to M2DO-perturbation Cf = np.multiply(Sf, seglength) Sg = -gg[:nBpts] Cg = np.multiply(Sf, seglength) # ## WIP # previous ver. # Cf = -ff[:nBpts] # Cg = -gg[:nBpts] # Sf = np.divide(Cf, seglength) # Sg = np.divide(Cg, seglength) # bracketing Sf and Sg Sg[Sg < -1.5] = -1.5 Sg[Sg > 0.5] = 0.5 # Sg[:] = -1.0 Cg = np.multiply(Sg, seglength) ######################################################## ############## suboptimize ################ ######################################################## if 1: suboptim = Solvers(bpts_xy=bpts_xy, Sf=Sf, Sg=Sg, Cf=Cf, Cg=Cg, length_x=length_x, length_y=length_y, areafraction=areafraction, movelimit=movelimit) # suboptimization if 1: # simplex Bpt_Vel = suboptim.simplex(isprint=False) else: # bisection.. Bpt_Vel = suboptim.bisection(isprint=False) timestep = 1.0 elif 1: # works okay now. bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() model = LSM2D_slpGroup(lsm_solver=lsm_solver, num_bpts=nBpts, ub=ub2, lb=lb2, Sf=bpts_sens[:, 0], Sg=bpts_sens[:, 1], constraintDistance=constraint_distance, movelimit=movelimit) subprob = Problem(model) subprob.setup() subprob.driver = ScipyOptimizeDriver() subprob.driver.options['optimizer'] = 'SLSQP' subprob.driver.options['disp'] = True subprob.driver.options['tol'] = 1e-10 subprob.run_driver() lambdas = subprob['inputs_comp.lambdas'] displacements_ = subprob['displacement_comp.displacements'] displacements_[displacements_ > movelimit] = movelimit displacements_[displacements_ < -movelimit] = -movelimit timestep = 1.0 #abs(lambdas[0]*scales[0]) Bpt_Vel = displacements_ / timestep # print(timestep) del subprob else: # branch: perturb-suboptim bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() constraintDistance = np.array([constraint_distance]) scaled_constraintDist = lsm_solver.compute_scaledConstraintDistance( constraintDistance) def objF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delF(displacement_np) def conF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delG(displacement_np, scaled_constraintDist, 1) cons = ({'type': 'eq', 'fun': lambda x: conF_nocallback(x)}) res = sp_optim.minimize(objF_nocallback, np.zeros(2), method='SLSQP', options={'disp': True}, bounds=((lb2[0], ub2[0]), (lb2[1], ub2[1])), constraints=cons) lambdas = res.x displacements_ = lsm_solver.compute_unscaledDisplacement(lambdas) displacements_[displacements_ > movelimit] = movelimit displacements_[displacements_ < -movelimit] = -movelimit timestep = 1.0 #abs(lambdas[0]*scales[0]) Bpt_Vel = displacements_ / timestep # scaling # Bpt_Vel = Bpt_Vel#/np.max(np.abs(Bpt_Vel)) lsm_solver.advect(Bpt_Vel, timestep) lsm_solver.reinitialise() if not inspctFlag: # quickplot plt.figure(1) plt.clf() plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10) plt.axis("equal") plt.savefig(loadFolder + 'restart_' + str(restart_iter) + "/" + "figs/bpts_%d.png" % i_HJ) print('loop %d is finished' % i_HJ) area = areafraction.sum() / (nelx * nely) try: u = prob['temp_comp.disp'] compliance = np.dot(u, GF_t[:nNODE]) except: u = prob['disp_comp.disp'] # compliance = np.dot(u, GF_e[:nDOF_e]) pass if 1: # quickplot plt.figure(1) plt.clf() plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10) plt.axis("equal") plt.savefig(loadFolder + 'restart_' + str(restart_iter) + "/" + "figs/bpts_%d.png" % i_HJ) if obj_flag == 3 or obj_flag == 2: plt.figure(2) plt.clf() [xx, yy] = np.meshgrid(range(0, 161), range(0, 81)) plt.contourf(xx, yy, np.reshape(u, [81, 161])) plt.colorbar() plt.axis("equal") plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 5) plt.savefig(loadFolder + 'restart_' + str(restart_iter) + "/" + "figs/temp_%d.png" % i_HJ) if (objectives[obj_flag] == "compliance" and not inspctFlag): compliance = prob['compliance_comp.compliance'] print(compliance, area) fid = open( loadFolder + 'restart_' + str(restart_iter) + "/" + "log.txt", "a+") fid.write(str(compliance) + ", " + str(area) + "\n") fid.close() elif (objectives[obj_flag] == "stress" and not inspctFlag): print(prob['pnorm_comp.pnorm'][0], area) fid = open( loadFolder + 'restart_' + str(restart_iter) + "/" + "log.txt", "a+") fid.write( str(prob['pnorm_comp.pnorm'][0]) + ", " + str(area) + "\n") fid.close() elif (objectives[obj_flag] == "coupled_heat" and not inspctFlag): obj1 = prob['objective_comp.x1'][0] obj2 = prob['objective_comp.x2'][0] obj = prob['objective_comp.y'][0] print([obj1, obj2, obj, area]) fid = open( loadFolder + 'restart_' + str(restart_iter) + "/" + "log.txt", "a+") fid.write( str(obj1) + ", " + str(obj2) + ", " + str(obj) + ", " + str(area) + "\n") fid.close() # Saving Phi phi = lsm_solver.get_phi() if not inspctFlag: raw = {} raw['phi'] = phi filename = loadFolder + 'restart_' + str( restart_iter) + '/' + 'phi%03i.pkl' % i_HJ with open(filename, 'wb') as f: pickle.dump(raw, f) del model del prob mem = virtual_memory() print(str(mem.available / 1024. / 1024. / 1024.) + "GB") if mem.available / 1024. / 1024. / 1024. < 3.0: print("memory explodes at iteration %3i " % i_HJ) exit()
def main(maxiter): print(locals()) print("solving single physics stress problem") ############################################################################ ########################### FEA ########################### ############################################################################ # NB: only Q4 elements + integer-spaced mesh are assumed nelx = 10 nely = 10 length_x = float(nelx) length_y = float(nely) ls2fe_x = length_x / float(nelx) ls2fe_y = length_y / float(nely) num_nodes_x = nelx + 1 num_nodes_y = nely + 1 nELEM = nelx * nely nNODE = num_nodes_x * num_nodes_y # NB: nodes for plotting (quickfix...) nodes = get_mesh(num_nodes_x, num_nodes_y, nelx, nely) # Declare FEA object (OpenLSTO_FEA) ============================== fea_solver = py_FEA(lx=length_x, ly=length_y, nelx=nelx, nely=nely, element_order=2) [node, elem, elem_dof] = fea_solver.get_mesh() ## validate the mesh if nELEM != elem.shape[0]: error("error found in the element") if nNODE != node.shape[0]: error("error found in the node") nDOF_e = nNODE * 2 # each node has two displacement DOFs # constitutive properties ======================================== E = 1. nu = 0.3 fea_solver.set_material(E=E, nu=nu, rho=1.0) # sets elastic material only # Boundary Conditions ============================================ ## Set elastic boundary conditions coord_e = np.array([[0., length_y]]) tol_e = np.array([[2. * length_x / 5. + 0.1 * ls2fe_x, 1e-3]]) fea_solver.set_boundary(coord=coord_e, tol=tol_e) BCid_e = fea_solver.get_boundary() nDOF_e_wLag = nDOF_e + len(BCid_e) # elasticity DOF # Loading Conditions ============================================= ## Set the elastic loading conditions coord = np.array([length_x * 0.5, 0.0]) # length_y]) tol = np.array([1.1, 1e-3]) load_val = -0.5 # dead load GF_e_ = fea_solver.set_force(coord=coord, tol=tol, direction=1, f=load_val) GF_e = np.zeros(nDOF_e_wLag) GF_e[:nDOF_e] = GF_e_ ############################################################################ ########################### LSM ########################### ############################################################################ movelimit = 0.5 # Declare Level-set object lsm_solver = py_LSM(nelx=nelx, nely=nely, moveLimit=movelimit, isLbeam=True) # Assign holes =================================================== lsm_solver.add_holes([], [], []) lsm_solver.set_levelset() ############################################################################ ######################## T.O. LOOP ######################## ############################################################################ # Set maximum area constraint (percentage of the initial area) area_constraint = 0.6 for i_HJ in range(maxiter): (bpts_xy, areafraction, seglength) = lsm_solver.discretise() # OpenMDAO =================================================== ## Define Group model = StressGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, BCid=BCid_e, pval=6.0, E=E, nu=nu) ## Define problem for OpenMDAO object prob = Problem(model) ## Setup the problem prob.driver = pyOptSparseDriver() prob.driver.options['optimizer'] = 'IPOPT' prob.driver.opt_settings['linear_solver'] = 'ma27' prob.setup(check=False) prob.run_model() ## Total derivative using MAUD total = prob.compute_totals() ff = total['pnorm_comp.pnorm', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] ## Assign object function sensitivities nBpts = int(bpts_xy.shape[0]) Sf = -ff[:nBpts] # equal to M2DO-perturbation Cf = np.multiply( Sf, seglength) # Shape sensitivity (integral coefficients) ## Assign constraint sensitivities Sg = -gg[:nBpts] Sg[Sg < -1.5] = -1.5 # apply caps (bracketing) to constraint sensitivities Sg[Sg > 0.5] = 0.5 # apply caps (bracketing) to constraint sensitivities Cg = np.multiply( Sg, seglength) # Shape sensitivity (integral coefficients) # Suboptimize ================================================ if 1: suboptim = Solvers(bpts_xy=bpts_xy, Sf=Sf, Sg=Sg, Cf=Cf, Cg=Cg, length_x=length_x, length_y=length_y, areafraction=areafraction, movelimit=movelimit) # suboptimization if 1: # simplex Bpt_Vel = suboptim.simplex(isprint=False) else: # bisection. Bpt_Vel = suboptim.bisection(isprint=False) timestep = 1.0 np.savetxt('a.txt', Bpt_Vel) elif 1: # works when Sf <- Sf / length is used (which means Cf <- actual Sf) bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() max_area = area_constraint * (1 - pow(3. / 5., 2)) * nelx * nely constraint_distance = max_area - areafraction.sum() model = LSM2D_slpGroup(lsm_solver=lsm_solver, num_bpts=nBpts, ub=ub2, lb=lb2, Sf=bpts_sens[:, 0], Sg=bpts_sens[:, 1], constraintDistance=constraint_distance, movelimit=movelimit) subprob = Problem(model) subprob.setup() subprob.driver = ScipyOptimizeDriver() subprob.driver.options['optimizer'] = 'SLSQP' subprob.driver.options['disp'] = True subprob.driver.options['tol'] = 1e-10 subprob.run_driver() lambdas = subprob['inputs_comp.lambdas'] displacements_ = subprob['displacement_comp.displacements'] # displacements_[displacements_ > movelimit] = movelimit # displacements_[displacements_ < -movelimit] = -movelimit timestep = abs(lambdas[0] * scales[0]) Bpt_Vel = displacements_ / timestep np.savetxt('a.txt', Bpt_Vel) # print(timestep) del subprob else: # branch: perturb-suboptim bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() max_area = area_constraint * (1 - pow(3. / 5., 2)) * nelx * nely constraint_distance = max_area - areafraction.sum() constraintDistance = np.array([constraint_distance]) scaled_constraintDist = lsm_solver.compute_scaledConstraintDistance( constraintDistance) def objF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delF(displacement_np) def conF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delG(displacement_np, scaled_constraintDist, 1) cons = ({'type': 'eq', 'fun': lambda x: conF_nocallback(x)}) res = sp_optim.minimize(objF_nocallback, np.zeros(2), method='SLSQP', options={'disp': True}, bounds=((lb2[0], ub2[0]), (lb2[1], ub2[1])), constraints=cons) lambdas = res.x displacements_ = lsm_solver.compute_unscaledDisplacement(lambdas) displacements_[displacements_ > movelimit] = movelimit displacements_[displacements_ < -movelimit] = -movelimit timestep = 1.0 #abs(lambdas[0]*scales[0]) Bpt_Vel = displacements_ / timestep # scaling # Bpt_Vel = Bpt_Vel#/np.max(np.abs(Bpt_Vel)) lsm_solver.advect(Bpt_Vel, timestep) lsm_solver.reinitialise() print('loop %d is finished' % i_HJ) area = areafraction.sum() / (nelx * nely) u = prob['disp_comp.disp'] compliance = np.dot(u, GF_e[:nDOF_e]) # Printing/Plotting ========================================== if 1: # quickplot plt.figure(1) plt.clf() plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10) plt.axis("equal") plt.savefig(saveFolder + "figs/bpts_%d.png" % i_HJ) # print([compliance[0], area]) print(prob['pnorm_comp.pnorm'][0], area) fid = open(saveFolder + "log.txt", "a+") fid.write(str(prob['pnorm_comp.pnorm'][0]) + ", " + str(area) + "\n") fid.close() ## Saving phi phi = lsm_solver.get_phi() if i_HJ == 0: raw = {} raw['mesh'] = nodes raw['nodes'] = nodes raw['elem'] = elem raw['GF_e'] = GF_e raw['BCid_e'] = BCid_e raw['E'] = E raw['nu'] = nu raw['f'] = load_val raw['nelx'] = nelx raw['nely'] = nely raw['length_x'] = length_x raw['length_y'] = length_y raw['coord_e'] = coord_e raw['tol_e'] = tol_e filename = saveFolder + 'const.pkl' with open(filename, 'wb') as f: pickle.dump(raw, f) raw = {} raw['phi'] = phi filename = saveFolder + 'phi%03i.pkl' % i_HJ with open(filename, 'wb') as f: pickle.dump(raw, f) del model del prob mem = virtual_memory() print(str(mem.available / 1024. / 1024. / 1024.) + "GB") if mem.available / 1024. / 1024. / 1024. < 3.0: print("memory explodes at iteration %3i " % i_HJ) return ()
num_elems = (num_nodes_x - 1) * (num_nodes_y - 1) # LSM Mesh num_dofs = num_nodes_x * num_nodes_y * 2 num_dofs_w_lambda = num_dofs + num_nodes_y * 2 nodes = get_mesh(num_nodes_x, num_nodes_y, nelx, nely) # for plotting # FEA properties E = 1. nu = 0.3 f = -1. fem_solver = py_FEA(lx=length_x, ly=length_y, nelx=nelx, nely=nely, element_order=2) [node, elem, elem_dof] = fem_solver.get_mesh() ## BCs =================================== fem_solver.set_material(E, nu, 1.0) coord = np.array([0, 0]) tol = np.array([1e-3, 1e10]) fem_solver.set_boundary(coord=coord, tol=tol) BCid = fem_solver.get_boundary() coord = np.array([length_x, length_y / 2]) tol = np.array([1, 1]) GF_ = fem_solver.set_force(coord=coord, tol=tol, direction=1, f=-1.0)
from pyBind import py_FEA, py_Sensitivity import matplotlib.pyplot as plt import numpy as np import scipy.sparse.linalg from matching_dofIds import matching_dof, matching_el nelx = 10 nely = 5 a = py_FEA(nelx=nelx, nely=nely, element_order=2) [node, elem, elem_dof] = a.get_mesh() a.set_material(1.0, 0.3, 1) # plt.figure(1) # plt.axis([0,max(node[:,0]),0,max(node[:,1])]) # elem_ext = np.zeros([elem.shape[0],elem.shape[1]+1],dtype = int) # elem_ext[:,0:4] = elem # elem_ext[:,4] = elem[:,0] coord = np.array([0, 0]) tol = np.array([1e-3, 1e10]) a.set_boundary(coord=coord, tol=tol) BCid = a.get_boundary() coord = np.array([nelx, nely / 2]) tol = np.array([1, 1]) la = a.set_force(coord=coord, tol=tol, direction=1, f=-1) la = np.array(la) (rows, cols, vals) = a.compute_K()
def main(maxiter): # select which problem to solve obj_flag = 1 print(locals()) print("solving %s problem" % objectives[obj_flag]) ######################################################## ################# FEA #################### ######################################################## # NB: only Q4 elements + integer-spaced mesh are assumed nelx = 160 nely = 80 length_x = 160. length_y = 80. ls2fe_x = length_x / float(nelx) ls2fe_y = length_y / float(nely) num_nodes_x = nelx + 1 num_nodes_y = nely + 1 nELEM = nelx * nely nNODE = num_nodes_x * num_nodes_y # NB: nodes for plotting (quickfix...) nodes = get_mesh(num_nodes_x, num_nodes_y, nelx, nely) # Declare FEA object (OpenLSTO_FEA) ====================== fea_solver = py_FEA(lx=length_x, ly=length_y, nelx=nelx, nely=nely, element_order=2) [node, elem, elem_dof] = fea_solver.get_mesh() # validate the mesh if nELEM != elem.shape[0]: error("error found in the element") if nNODE != node.shape[0]: error("error found in the node") nDOF_t = nNODE * 1 # each node has one temperature DOF nDOF_e = nNODE * 2 # each node has two displacement DOFs # constitutive properties ================================= E = 1. nu = 0.3 f = -1 # dead load K_cond = 0.1 # thermal conductivity alpha = 1e-5 # thermal expansion coefficient fea_solver.set_material(E=E, nu=nu, rho=1.0) # Boundary Conditions ===================================== if 1: coord_e = np.array([[0., 0.], [length_x, 0.]]) tol_e = np.array([[1e-3, 1e3], [1e-3, 1e+3]]) fea_solver.set_boundary(coord=coord_e, tol=tol_e) BCid_e = fea_solver.get_boundary() nDOF_e_wLag = nDOF_e + len(BCid_e) # elasticity DOF coord = np.array([length_x * 0.5, 0.0]) # length_y]) tol = np.array([0.1, 1e-3]) GF_e_ = fea_solver.set_force(coord=coord, tol=tol, direction=1, f=-f) GF_e = np.zeros(nDOF_e_wLag) GF_e[:nDOF_e] = GF_e_ else: # cantilever bending coord_e = np.array([[0, 0]]) tol_e = np.array([[1e-3, 1e10]]) fea_solver.set_boundary(coord=coord_e, tol=tol_e) BCid_e = fea_solver.get_boundary() nDOF_e_wLag = nDOF_e + len(BCid_e) # elasticity DOF coord = np.array([length_x, length_y / 2]) tol = np.array([0.1, 0.1]) GF_e_ = fea_solver.set_force(coord=coord, tol=tol, direction=1, f=-1.0) GF_e = np.zeros(nDOF_e_wLag) GF_e[:nDOF_e] = GF_e_ xlo = np.array(range(0, nNODE, num_nodes_x)) xhi = np.array(range(nelx, nNODE, num_nodes_x)) # xfix = np.array([num_nodes_x*(nely/2-1), num_nodes_x*nely/2, # num_nodes_x*(nely/2-1) + nelx, num_nodes_x*nely/2 + nelx]) xfix = np.append(xlo, xhi) yfix = np.array(range(num_nodes_x * nely + 70, nNODE - 70)) # yloid = np.array(range(70, 91)) # fixID_d = np.append(xfix, yfix) #fixID_d = np.unique(fixID_d) #fixID = np.append(fixID_d, arange(70, 91)) # BCid_t = np.array(np.append(xfix, arange(70,91)), dtype=int) BCid_t = np.array(np.append(yfix, arange(70, 91)), dtype=int) nDOF_t_wLag = nDOF_t + len(BCid_t) # temperature DOF (zero temp) GF_t = np.zeros(nDOF_t_wLag) # FORCE_HEAT (NB: Q matrix) for ee in range(nELEM): # between element 70 to 91 GF_t[elem[ee]] += 10. # heat generation GF_t[BCid_t] = 0.0 GF_t /= np.sum(GF_t) #GF_t[nDOF_t:nDOF_t+len(fixID_d)+1] = 100. # GF_t[:] = 0.0 ######################################################## ################# LSM #################### ######################################################## movelimit = 0.5 # Declare Level-set object lsm_solver = py_LSM(nelx=nelx, nely=nely, moveLimit=movelimit) if ((nelx == 160) and (nely == 80)): # 160 x 80 case hole = array( [[16, 14, 5], [48, 14, 5], [80, 14, 5], [112, 14, 5], [144, 14, 5], [32, 27, 5], [64, 27, 5], [96, 27, 5], [128, 27, 5], [16, 40, 5], [48, 40, 5], [80, 40, 5], [112, 40, 5], [144, 40, 5], [32, 53, 5], [64, 53, 5], [96, 53, 5], [128, 53, 5], [16, 66, 5], [48, 66, 5], [80, 66, 5], [112, 66, 5], [144, 66, 5]], dtype=float) # NB: level set value at the corners should not be 0.0 hole = append( hole, [[0., 0., 0.1], [0., 80., 0.1], [160., 0., 0.1], [160., 80., 0.1]], axis=0) lsm_solver.add_holes(locx=list(hole[:, 0]), locy=list(hole[:, 1]), radius=list(hole[:, 2])) elif ((nelx == 80) and (nely == 40)): hole = np.array( [[8, 7, 2.5], [24, 7, 2.5], [40, 7, 2.5], [56, 7, 2.5], [72, 7, 2.5], [16, 13.5, 2.5], [32, 13.5, 2.5], [48, 13.5, 2.5], [64, 13.5, 2.5], [8, 20, 2.5], [24, 20, 2.5], [40, 20, 2.5], [56, 20, 2.5], [72, 20, 2.5], [16, 26.5, 2.5], [32, 26.5, 2.5], [48, 26.5, 2.5], [64, 26.5, 2.5], [8, 33, 2.5], [24, 33, 2.5], [40, 33, 2.5], [56, 33, 2.5], [72, 33, 2.5]], dtype=np.float) # NB: level set value at the corners should not be 0.0 hole = append( hole, [[0., 0., 0.1], [0., 40., 0.1], [80., 0., 0.1], [80., 40., 0.1]], axis=0) lsm_solver.add_holes(locx=list(hole[:, 0]), locy=list(hole[:, 1]), radius=list(hole[:, 2])) else: lsm_solver.add_holes([], [], []) lsm_solver.set_levelset() for i_HJ in range(maxiter): (bpts_xy, areafraction, seglength) = lsm_solver.discretise() ######################################################## ############### OpenMDAO ################ ######################################################## # Declare Group if (objectives[obj_flag] == "compliance"): model = ComplianceGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, BCid=BCid_e) elif (objectives[obj_flag] == "stress"): # TODO: sensitivity has not been verified yet model = StressGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, pval=5.0, E=E, nu=nu) elif (objectives[obj_flag] == "conduction"): model = ConductionGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_t, movelimit=movelimit, K_cond=K_cond, BCid=BCid_t) elif (objectives[obj_flag] == "coupled_heat"): model = HeatCouplingGroup( fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force_e=GF_e, force_t=GF_t, movelimit=movelimit, K_cond=K_cond, BCid_e=BCid_e, BCid_t=BCid_t, E=E, nu=nu, alpha=alpha, w=0.9 ) # if w = 0.0, thermoelastic + conduction, if w = 1.0, conduction only # One Problem per one OpenMDAO object prob = Problem(model) # optimize ... prob.driver = pyOptSparseDriver() prob.driver.options['optimizer'] = 'IPOPT' prob.driver.opt_settings['linear_solver'] = 'ma27' prob.setup(check=False) if i_HJ == 0: view_model(prob) prob.run_model() # Total derivative using MAUD ===================== total = prob.compute_totals() if (objectives[obj_flag] == "compliance"): ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "stress"): ff = total['pnorm_comp.pnorm', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "conduction"): ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "coupled_heat"): ff = total['objective_comp.y', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] nBpts = int(bpts_xy.shape[0]) # # WIP checking sensitivity 10/23 Sf = -ff[:nBpts] # equal to M2DO-perturbation Cf = np.multiply(Sf, seglength) #np.savetxt('/home/hayoung/Desktop/a',Sf) #exit() Sg = -gg[:nBpts] Cg = np.multiply(Sf, seglength) # ## WIP # previous ver. # Cf = -ff[:nBpts] # Cg = -gg[:nBpts] # Sf = np.divide(Cf, seglength) # Sg = np.divide(Cg, seglength) # bracketing Sf and Sg Sg[Sg < -1.5] = -1.5 Sg[Sg > 0.5] = 0.5 # Sg[:] = -1.0 Cg = np.multiply(Sg, seglength) ######################################################## ############## suboptimize ################ ######################################################## if 1: suboptim = Solvers(bpts_xy=bpts_xy, Sf=Sf, Sg=Sg, Cf=Cf, Cg=Cg, length_x=length_x, length_y=length_y, areafraction=areafraction, movelimit=movelimit) # suboptimization if 1: # simplex Bpt_Vel = suboptim.simplex(isprint=False) else: # bisection.. Bpt_Vel = suboptim.bisection(isprint=False) timestep = 1.0 np.savetxt('a.txt', Bpt_Vel) elif 1: # works when Sf <- Sf / length is used (which means Cf <- actual Sf) bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() model = LSM2D_slpGroup(lsm_solver=lsm_solver, num_bpts=nBpts, ub=ub2, lb=lb2, Sf=bpts_sens[:, 0], Sg=bpts_sens[:, 1], constraintDistance=constraint_distance, movelimit=movelimit) subprob = Problem(model) subprob.setup() subprob.driver = ScipyOptimizeDriver() subprob.driver.options['optimizer'] = 'SLSQP' subprob.driver.options['disp'] = True subprob.driver.options['tol'] = 1e-10 subprob.run_driver() lambdas = subprob['inputs_comp.lambdas'] displacements_ = subprob['displacement_comp.displacements'] # displacements_[displacements_ > movelimit] = movelimit # displacements_[displacements_ < -movelimit] = -movelimit timestep = abs(lambdas[0] * scales[0]) Bpt_Vel = displacements_ / timestep np.savetxt('a.txt', Bpt_Vel) # print(timestep) del subprob else: # branch: perturb-suboptim bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() constraintDistance = np.array([constraint_distance]) scaled_constraintDist = lsm_solver.compute_scaledConstraintDistance( constraintDistance) def objF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delF(displacement_np) def conF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delG(displacement_np, scaled_constraintDist, 1) cons = ({'type': 'eq', 'fun': lambda x: conF_nocallback(x)}) res = sp_optim.minimize(objF_nocallback, np.zeros(2), method='SLSQP', options={'disp': True}, bounds=((lb2[0], ub2[0]), (lb2[1], ub2[1])), constraints=cons) lambdas = res.x displacements_ = lsm_solver.compute_unscaledDisplacement(lambdas) displacements_[displacements_ > movelimit] = movelimit displacements_[displacements_ < -movelimit] = -movelimit timestep = 1.0 #abs(lambdas[0]*scales[0]) Bpt_Vel = displacements_ / timestep # scaling # Bpt_Vel = Bpt_Vel#/np.max(np.abs(Bpt_Vel)) lsm_solver.advect(Bpt_Vel, timestep) lsm_solver.reinitialise() print('loop %d is finished' % i_HJ) area = areafraction.sum() / (nelx * nely) try: u = prob['temp_comp.disp'] compliance = np.dot(u, GF_t[:nNODE]) except: u = prob['disp_comp.disp'] # compliance = np.dot(u, GF_e[:nDOF_e]) pass if 1: # quickplot plt.figure(1) plt.clf() plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10) plt.axis("equal") plt.savefig(saveFolder + "figs/bpts_%d.png" % i_HJ) if obj_flag == 3 or obj_flag == 2: plt.figure(2) plt.clf() [xx, yy] = np.meshgrid(range(0, 161), range(0, 81)) plt.contourf(xx, yy, np.reshape(u, [81, 161])) plt.colorbar() plt.axis("equal") plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 5) plt.savefig(saveFolder + "figs/temp_%d.png" % i_HJ) # print([compliance[0], area]) if (objectives[obj_flag] == "compliance"): compliance = prob['compliance_comp.compliance'] print(compliance, area) fid = open(saveFolder + "log.txt", "a+") fid.write(str(compliance) + ", " + str(area) + "\n") fid.close() elif (objectives[obj_flag] == "stress"): print(prob['pnorm_comp.pnorm'][0], area) fid = open(saveFolder + "log.txt", "a+") fid.write( str(prob['pnorm_comp.pnorm'][0]) + ", " + str(area) + "\n") fid.close() elif (objectives[obj_flag] == "coupled_heat"): obj1 = prob['objective_comp.x1'][0] obj2 = prob['objective_comp.x2'][0] obj = prob['objective_comp.y'][0] print([obj1, obj2, obj, area]) fid = open(saveFolder + "log.txt", "a+") fid.write( str(obj1) + ", " + str(obj2) + ", " + str(obj) + ", " + str(area) + "\n") fid.close() # Saving Phi phi = lsm_solver.get_phi() if i_HJ == 0: raw = {} raw['mesh'] = nodes raw['nodes'] = nodes raw['elem'] = elem raw['GF_e'] = GF_e raw['GF_t'] = GF_t raw['BCid_e'] = BCid_e raw['BCid_t'] = BCid_t raw['E'] = E raw['nu'] = nu raw['f'] = f raw['K_cond'] = K_cond raw['alpha'] = alpha raw['nelx'] = nelx raw['nely'] = nely raw['length_x'] = length_x raw['length_y'] = length_y raw['coord_e'] = coord_e raw['tol_e'] = tol_e filename = saveFolder + 'const.pkl' with open(filename, 'wb') as f: pickle.dump(raw, f) raw = {} raw['phi'] = phi if obj_flag == 3: raw['T'] = prob['temp_comp.disp'] filename = saveFolder + 'phi%03i.pkl' % i_HJ with open(filename, 'wb') as f: pickle.dump(raw, f) del model del prob mem = virtual_memory() print(str(mem.available / 1024. / 1024. / 1024.) + "GB") if mem.available / 1024. / 1024. / 1024. < 3.0: print("memory explodes at iteration %3i " % i_HJ) return ()
def main(tot_iter): objectives = {0: "compliance", 1: "stress"} # TODO: folder path and restart # must be manually input each time loadFolder = loadFolder0 + "" restart_iter = 26 import os try: os.mkdir(loadFolder + 'restart_' + str(restart_iter)) except: pass try: os.mkdir(loadFolder + 'restart_' + str(restart_iter) + '/figs') except: pass inspctFlag = False if tot_iter < 0: inspctFlag = True tot_iter = restart_iter + 1 # Select which problem to solve obj_flag = 1 print(locals()) print("solving single physics %s problem" % objectives[obj_flag]) print("restarting from %d ..." % restart_iter) fname0 = loadFolder + 'phi%03i.pkl' % restart_iter with open(fname0, 'rb') as f: raw = pickle.load(f) phi0 = raw['phi'] fname0 = loadFolder0 + 'const.pkl' with open(fname0, 'rb') as f: raw = pickle.load(f) # nodes = raw['mesh'] nodes = raw['nodes'] elem = raw['elem'] GF_e = raw['GF_e'] BCid_e = raw['BCid_e'] E = raw['E'] nu = raw['nu'] f = raw['f'] nelx = raw['nelx'] nely = raw['nely'] length_x = raw['length_x'] length_y = raw['length_y'] coord_e = raw['coord_e'] tol_e = raw['tol_e'] ############################################################################ ########################### FEA ########################### ############################################################################ # NB: only Q4 elements + integer-spaced mesh are assumed ls2fe_x = length_x / float(nelx) ls2fe_y = length_y / float(nely) num_nodes_x = nelx + 1 num_nodes_y = nely + 1 nELEM = nelx * nely nNODE = num_nodes_x * num_nodes_y # Declare FEA object (OpenLSTO_FEA) ============================== fea_solver = py_FEA(lx=length_x, ly=length_y, nelx=nelx, nely=nely, element_order=2) [node, elem, elem_dof] = fea_solver.get_mesh() ## validate the mesh if nELEM != elem.shape[0]: error("error found in the element") if nNODE != node.shape[0]: error("error found in the node") nDOF_e = nNODE * 2 # each node has two displacement DOFs # constitutive properties ======================================== fea_solver.set_material(E=E, nu=nu, rho=1.0) # Boundary Conditions ============================================ fea_solver.set_boundary(coord=coord_e, tol=tol_e) BCid_e = fea_solver.get_boundary() nDOF_e_wLag = nDOF_e + len(BCid_e) # elasticity DOF ############################################################################ ########################### LSM ########################### ############################################################################ movelimit = 0.5 # Declare Level-set object lsm_solver = py_LSM(nelx=nelx, nely=nely, moveLimit=movelimit) lsm_solver.add_holes([], [], []) lsm_solver.set_levelset() lsm_solver.set_phi_re(phi0) lsm_solver.reinitialise() ############################################################################ ######################## T.O. LOOP ######################## ############################################################################ for i_HJ in range(restart_iter, tot_iter): (bpts_xy, areafraction, seglength) = lsm_solver.discretise() # OpenMDAO =================================================== ## Define Group if (objectives[obj_flag] == "compliance"): model = ComplianceGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, BCid=BCid_e) elif (objectives[obj_flag] == "stress"): model = StressGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, pval=6.0, BCid=BCid_e) ## Define problem for OpenMDAO object prob = Problem(model) ## Setup the problem prob.driver = pyOptSparseDriver() prob.driver.options['optimizer'] = 'IPOPT' prob.driver.opt_settings['linear_solver'] = 'ma27' prob.setup(check=False) prob.run_model() ## Total derivative using MAUD if (objectives[obj_flag] == "compliance"): ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "stress"): ff = total['pnorm_comp.pnorm', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] ## Assign object function sensitivities nBpts = int(bpts_xy.shape[0]) Sf = -ff[:nBpts] # equal to M2DO-perturbation Cf = np.multiply( Sf, seglength) # Shape sensitivity (integral coefficients) ## Assign constraint sensitivities Sg = -gg[:nBpts] Sg[Sg < -1.5] = -1.5 # apply caps (bracketing) to constraint sensitivities Sg[Sg > 0.5] = 0.5 # apply caps (bracketing) to constraint sensitivities Cg = np.multiply( Sg, seglength) # Shape sensitivity (integral coefficients) # Suboptimize ================================================ if 1: suboptim = Solvers(bpts_xy=bpts_xy, Sf=Sf, Sg=Sg, Cf=Cf, Cg=Cg, length_x=length_x, length_y=length_y, areafraction=areafraction, movelimit=movelimit) # suboptimization if 1: # simplex Bpt_Vel = suboptim.simplex(isprint=False) else: # bisection.. Bpt_Vel = suboptim.bisection(isprint=False) timestep = 1.0 elif 1: # works okay now. bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() model = LSM2D_slpGroup(lsm_solver=lsm_solver, num_bpts=nBpts, b=ub2, lb=lb2, Sf=bpts_sens[:, 0], Sg=bpts_sens[:, 1], constraintDistance=constraint_distance, movelimit=movelimit) subprob = Problem(model) subprob.setup() subprob.driver = ScipyOptimizeDriver() subprob.driver.options['optimizer'] = 'SLSQP' subprob.driver.options['disp'] = True subprob.driver.options['tol'] = 1e-10 subprob.run_driver() lambdas = subprob['inputs_comp.lambdas'] displacements_ = subprob['displacement_comp.displacements'] displacements_[displacements_ > movelimit] = movelimit displacements_[displacements_ < -movelimit] = -movelimit timestep = 1.0 #abs(lambdas[0]*scales[0]) Bpt_Vel = displacements_ / timestep # print(timestep) del subprob else: # branch: perturb-suboptim bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (0.4 * nelx * nely) - areafraction.sum() constraintDistance = np.array([constraint_distance]) scaled_constraintDist = lsm_solver.compute_scaledConstraintDistance( constraintDistance) def objF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delF(displacement_np) def conF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delG(displacement_np, scaled_constraintDist, 1) cons = ({'type': 'eq', 'fun': lambda x: conF_nocallback(x)}) res = sp_optim.minimize(objF_nocallback, np.zeros(2), method='SLSQP', options={'disp': True}, bounds=((lb2[0], ub2[0]), (lb2[1], ub2[1])), constraints=cons) lambdas = res.x displacements_ = lsm_solver.compute_unscaledDisplacement(lambdas) displacements_[displacements_ > movelimit] = movelimit displacements_[displacements_ < -movelimit] = -movelimit timestep = 1.0 #abs(lambdas[0]*scales[0]) Bpt_Vel = displacements_ / timestep # scaling # Bpt_Vel = Bpt_Vel#/np.max(np.abs(Bpt_Vel)) lsm_solver.advect(Bpt_Vel, timestep) lsm_solver.reinitialise() if not inspctFlag: # quickplot plt.figure(1) plt.clf() plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10) plt.axis("equal") plt.savefig(loadFolder + 'restart_' + str(restart_iter) + "/" + "figs/bpts_%d.png" % i_HJ) print('loop %d is finished' % i_HJ) area = areafraction.sum() / (nelx * nely) u = prob['disp_comp.disp'] compliance = np.dot(u, GF_e[:nDOF_e]) # Printing/Plotting ========================================== if 1: # quickplot plt.figure(1) plt.clf() plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10) plt.axis("equal") plt.savefig(loadFolder + 'restart_' + str(restart_iter) + "/" + "figs/bpts_%d.png" % i_HJ) if (objectives[obj_flag] == "compliance" and not inspctFlag): compliance = prob['compliance_comp.compliance'] print(compliance, area) fid = open( loadFolder + 'restart_' + str(restart_iter) + "/" + "log.txt", "a+") fid.write(str(compliance) + ", " + str(area) + "\n") fid.close() elif (objectives[obj_flag] == "stress" and not inspctFlag): print(prob['pnorm_comp.pnorm'][0], area) fid = open( loadFolder + 'restart_' + str(restart_iter) + "/" + "log.txt", "a+") fid.write( str(prob['pnorm_comp.pnorm'][0]) + ", " + str(area) + "\n") fid.close() ## Saving Phi phi = lsm_solver.get_phi() if not inspctFlag: raw = {} raw['phi'] = phi filename = loadFolder + 'restart_' + str( restart_iter) + '/' + 'phi%03i.pkl' % i_HJ with open(filename, 'wb') as f: pickle.dump(raw, f) del model del prob mem = virtual_memory() print(str(mem.available / 1024. / 1024. / 1024.) + "GB") if mem.available / 1024. / 1024. / 1024. < 3.0: print("memory explodes at iteration %3i " % i_HJ) exit()
def main(maxiter): # Select which problem to solve obj_flag = 0 print(locals()) print("solving single physics %s problem" % objectives[obj_flag]) ############################################################################## ############################ FEA ############################ ############################################################################## # NB: only Q4 elements + integer-spaced mesh are assumed nelx = 10 nely = 5 length_x = float(nelx) length_y = float(nely) ls2fe_x = length_x / float(nelx) ls2fe_y = length_y / float(nely) num_nodes_x = nelx + 1 num_nodes_y = nely + 1 nELEM = nelx * nely nNODE = num_nodes_x * num_nodes_y # NB: nodes for plotting (quickfix...) nodes = get_mesh(num_nodes_x, num_nodes_y, nelx, nely) # Declare FEA object (OpenLSTO_FEA) ============================== fea_solver = py_FEA(lx=length_x, ly=length_y, nelx=nelx, nely=nely, element_order=2) [node, elem, elem_dof] = fea_solver.get_mesh() ## validate the mesh if nELEM != elem.shape[0]: error("error found in the element") if nNODE != node.shape[0]: error("error found in the node") nDOF_e = nNODE * 2 # each node has two displacement DOFs # constitutive properties ========================================== E = 1. nu = 0.3 fea_solver.set_material(E=E, nu=nu, rho=1.0) # sets elastic material only # ================================================================== # Boundary Conditions ============================================== ## Set elastic boundary conditions coord_e = np.array([[0., 0.], [length_x, 0.]]) tol_e = np.array([[1e-3, 1e3], [1e-3, 1e+3]]) fea_solver.set_boundary(coord=coord_e, tol=tol_e) BCid_e = fea_solver.get_boundary() nDOF_e_wLag = nDOF_e + len(BCid_e) # elasticity DOF # ================================================================== # Loading Conditions =============================================== ## Set the elastic loading conditions coord = np.array([length_x * 0.5, 0.0]) # length_y]) tol = np.array([ls2fe_x * 0.1, ls2fe_y * 0.1]) load_val = -1 # dead load GF_e_ = fea_solver.set_force(coord=coord, tol=tol, direction=1, f=load_val) GF_e = np.zeros(nDOF_e_wLag) GF_e[:nDOF_e] = GF_e_ # ================================================================== ############################################################################## ############################ LSM ############################ ############################################################################## movelimit = 0.5 # Declare Level-set object lsm_solver = py_LSM(nelx=nelx, nely=nely, moveLimit=movelimit) # Assign holes =================================================== if (int(nelx) / int(nely) == 2) and (nelx >= 80): rad = float(nelx) / 32.0 # radius of the hole x1 = nelx / 10. # x-coord of the center of the 1st hole 1st row y1 = 14. * nely / 80. # y-coord of the center of the 1st row of holes y2 = 27. * nely / 80. # y-coord of the center of the 2nd row of holes y3 = nely / 2. # y-coord of the center of the 3rd row of holes y4 = 53. * nely / 80. # y-coord of the center of the 4th row of holes y5 = 66. * nely / 80. # y-coord of the center of the 5th row of holes hole = array([[x1, y1, rad], [3 * x1, y1, rad], [5 * x1, y1, rad], [7 * x1, y1, rad], [9 * x1, y1, rad], [2 * x1, y2, rad], [4 * x1, y2, rad], [6 * x1, y2, rad], [8 * x1, y2, rad], [x1, y3, rad], [3 * x1, y3, rad], [5 * x1, y3, rad], [7 * x1, y3, rad], [9 * x1, y3, rad], [2 * x1, y4, rad], [4 * x1, y4, rad], [6 * x1, y4, rad], [8 * x1, y4, rad], [x1, y5, rad], [3 * x1, y5, rad], [5 * x1, y5, rad], [7 * x1, y5, rad], [9 * x1, y5, rad]]) # NB: level set value at the corners should not be 0.0 hole = append( hole, [[0., 0., 0.1], [0., float(nely), 0.1], [float(nelx), 0., 0.1], [float(nelx), float(nely), 0.1]], axis=0) lsm_solver.add_holes(locx=list(hole[:, 0]), locy=list(hole[:, 1]), radius=list(hole[:, 2])) else: lsm_solver.add_holes([], [], []) lsm_solver.set_levelset() ############################################################################## ################## OPTIMIZATION PARAMETERS ################## ############################################################################## area_constraint = 0.6 # Area constraint (max percentage of the initial area) opt_move_limit = 0.2 # Move limit for simplex and bisection optimizers ############################################################################## ######################### T.O. LOOP ######################### ############################################################################## for i_HJ in range(maxiter): (bpts_xy, areafraction, seglength) = lsm_solver.discretise() # OpenMDAO =================================================== ## Define Group if (objectives[obj_flag] == "compliance"): model = ComplianceGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, BCid=BCid_e) elif (objectives[obj_flag] == "stress"): model = StressGroup(fea_solver=fea_solver, lsm_solver=lsm_solver, nelx=nelx, nely=nely, force=GF_e, movelimit=movelimit, BCid=BCid_e, pval=6.0, E=E, nu=nu) ## Define problem for OpenMDAO object prob = Problem(model) ## Setup the problem prob.driver = pyOptSparseDriver() prob.driver.options['optimizer'] = 'IPOPT' prob.driver.opt_settings['linear_solver'] = 'ma27' prob.setup(check=False) prob.run_model() ## Total derivative using MAUD total = prob.compute_totals() if (objectives[obj_flag] == "compliance"): ff = total['compliance_comp.compliance', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] elif (objectives[obj_flag] == "stress"): ff = total['pnorm_comp.pnorm', 'inputs_comp.Vn'][0] gg = total['weight_comp.weight', 'inputs_comp.Vn'][0] ## Assign object function sensitivities nBpts = int(bpts_xy.shape[0]) Sf = -ff[:nBpts] # equal to M2DO-perturbation Cf = np.multiply( Sf, seglength) # Shape sensitivity (integral coefficients) # TODO: delete after debugging np.savetxt(saveFolder + "sens/sf_%d.txt" % i_HJ, Sf) # save to text file np.savetxt(saveFolder + "sens/cf_%d.txt" % i_HJ, Cf) # save to text file ## Assign constraint sensitivities Sg = -gg[:nBpts] Sg[Sg < -1.5] = -1.5 # apply caps (bracketing) to constraint sensitivities Sg[Sg > 0.5] = 0.5 # apply caps (bracketing) to constraint sensitivities Cg = np.multiply( Sg, seglength) # Shape sensitivity (integral coefficients) # TODO: delete after debugging np.savetxt(saveFolder + "sens/sg_%d.txt" % i_HJ, Sg) # save to text file np.savetxt(saveFolder + "sens/cg_%d.txt" % i_HJ, Cg) # save to text file # Suboptimize ================================================ if 1: # TODO: delete after debugging # print("\nEntered first suboptimize if statement. Perturbation method?") suboptim = Solvers(bpts_xy=bpts_xy, Sf=Sf, Sg=Sg, Cf=Cf, Cg=Cg, length_x=length_x, length_y=length_y, areafraction=areafraction, movelimit=opt_move_limit) # suboptimization if 1: # simplex # TODO: delete after debugging # print(" Entered simplex if statement\n") Bpt_Vel = suboptim.simplex(isprint=False) else: # bisection. # TODO: delete after debugging print(" Entered bisection if statement\n") Bpt_Vel = suboptim.bisection(isprint=False) timestep = 1.0 elif 1: # works when Sf <- Sf / length is used (which means Cf <- actual Sf) # TODO: delete after debugging print("\nEntered suboptimize else if statement. Least squares?") bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (area_constraint * nelx * nely) - areafraction.sum() model = LSM2D_slpGroup(lsm_solver=lsm_solver, num_bpts=nBpts, ub=ub2, lb=lb2, Sf=bpts_sens[:, 0], Sg=bpts_sens[:, 1], constraintDistance=constraint_distance, movelimit=movelimit) subprob = Problem(model) subprob.setup() subprob.driver = ScipyOptimizeDriver() subprob.driver.options['optimizer'] = 'SLSQP' subprob.driver.options['disp'] = True subprob.driver.options['tol'] = 1e-10 subprob.run_driver() lambdas = subprob['inputs_comp.lambdas'] displacements_ = subprob['displacement_comp.displacements'] # displacements_[displacements_ > movelimit] = movelimit # displacements_[displacements_ < -movelimit] = -movelimit timestep = abs(lambdas[0] * scales[0]) Bpt_Vel = displacements_ / timestep np.savetxt('a.txt', Bpt_Vel) # print(timestep) del subprob else: # branch: perturb-suboptim # TODO: delete after debugging print( "\nEntered suboptimize else if statement. Perturb with least squares?" ) bpts_sens = np.zeros((nBpts, 2)) # issue: scaling problem # bpts_sens[:, 0] = Sf bpts_sens[:, 1] = Sg lsm_solver.set_BptsSens(bpts_sens) scales = lsm_solver.get_scale_factors() (lb2, ub2) = lsm_solver.get_Lambda_Limits() constraint_distance = (area_constraint * nelx * nely) - areafraction.sum() constraintDistance = np.array([constraint_distance]) scaled_constraintDist = lsm_solver.compute_scaledConstraintDistance( constraintDistance) def objF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delF(displacement_np) def conF_nocallback(x): displacement = lsm_solver.compute_displacement(x) displacement_np = np.asarray(displacement) return lsm_solver.compute_delG(displacement_np, scaled_constraintDist, 1) cons = ({'type': 'eq', 'fun': lambda x: conF_nocallback(x)}) res = sp_optim.minimize(objF_nocallback, np.zeros(2), method='SLSQP', options={'disp': True}, bounds=((lb2[0], ub2[0]), (lb2[1], ub2[1])), constraints=cons) lambdas = res.x displacements_ = lsm_solver.compute_unscaledDisplacement(lambdas) displacements_[displacements_ > movelimit] = movelimit displacements_[displacements_ < -movelimit] = -movelimit timestep = 1.0 #abs(lambdas[0]*scales[0]) Bpt_Vel = displacements_ / timestep # scaling # Bpt_Vel = Bpt_Vel#/np.max(np.abs(Bpt_Vel)) # TODO: delete after debugging bpt_mat = np.append(bpts_xy, Bpt_Vel.reshape((Bpt_Vel.size, 1)), axis=1) np.savetxt(fname=(saveFolder + "sens/bpt_vel_%d.txt" % i_HJ), X=bpt_mat, fmt=('%20.5f', '%20.5f', '%20.10e'), header='Columns: X coord, Y coord, Bpt velocity') lsm_solver.advect(Bpt_Vel, timestep) lsm_solver.reinitialise() print('loop %d is finished' % i_HJ) area = areafraction.sum() / (nelx * nely) u = prob['disp_comp.disp'] compliance = np.dot(u, GF_e[:nDOF_e]) # Printing/Plotting ========================================== if 1: # quickplot plt.figure(1) plt.clf() plt.scatter(bpts_xy[:, 0], bpts_xy[:, 1], 10) plt.axis("equal") plt.xlim(-2, nelx + 2) plt.ylim(-2, nely + 2) plt.savefig(saveFolder + "figs/bpts_%d.png" % i_HJ) # print([compliance[0], area]) if (objectives[obj_flag] == "compliance"): compliance = prob['compliance_comp.compliance'] print(compliance, area) fid = open(saveFolder + "log.txt", "a+") fid.write(str(compliance) + ", " + str(area) + "\n") fid.close() elif (objectives[obj_flag] == "stress"): print(prob['pnorm_comp.pnorm'][0], area) fid = open(saveFolder + "log.txt", "a+") fid.write( str(prob['pnorm_comp.pnorm'][0]) + ", " + str(area) + "\n") fid.close() ## Saving phi phi = lsm_solver.get_phi() if i_HJ == 0: raw = {} raw['mesh'] = nodes raw['nodes'] = nodes raw['elem'] = elem raw['GF_e'] = GF_e raw['BCid_e'] = BCid_e raw['E'] = E raw['nu'] = nu raw['f'] = load_val raw['nelx'] = nelx raw['nely'] = nely raw['length_x'] = length_x raw['length_y'] = length_y raw['coord_e'] = coord_e raw['tol_e'] = tol_e filename = saveFolder + 'const.pkl' with open(filename, 'wb') as f: pickle.dump(raw, f) raw = {} raw['phi'] = phi filename = saveFolder + 'phi%03i.pkl' % i_HJ with open(filename, 'wb') as f: pickle.dump(raw, f) del model del prob mem = virtual_memory() print(str(mem.available / 1024. / 1024. / 1024.) + "GB") if mem.available / 1024. / 1024. / 1024. < 3.0: print("memory explodes at iteration %3i " % i_HJ) return ()