def createTACS(self, options, model, ndof=8): """ Set up TACS and TACSIntegator. """ # grab the tacs instance from the builder self.tacs = self.builder.getTACS(options['ordering'], TACS.PY_DIRECT_SCHUR, ndof=ndof) # Things for configuring time marching self.integrator = {} for scenario in model.scenarios: self.integrator[scenario.id] = self.createIntegrator( self.tacs, options) # Control F5 output if self.builder.rigid_viz == 1: flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.EXTRAS) rigidf5 = TACS.ToFH5(self.tacs, TACS.PY_RIGID, flag) self.integrator[scenario.id].setRigidOutput(rigidf5) if self.builder.shell_viz == 1: flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS | TACS.ToFH5.STRESSES | TACS.ToFH5.EXTRAS) shellf5 = TACS.ToFH5(self.tacs, TACS.PY_SHELL, flag) self.integrator[scenario.id].setShellOutput(shellf5) if self.builder.beam_viz == 1: flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS | TACS.ToFH5.STRESSES | TACS.ToFH5.EXTRAS) beamf5 = TACS.ToFH5(self.tacs, TACS.PY_BEAM, flag) self.integrator[scenario.id].setBeamOutput(beamf5) if self.builder.solid_viz == 1: flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS | TACS.ToFH5.STRESSES | TACS.ToFH5.EXTRAS) solidf5 = TACS.ToFH5(self.tacs, TACS.PY_SOLID, flag) self.integrator[scenario.id].setSolidOutput(solidf5) # store the reference to body list after initializations are complete self.tacs_body_list = self.builder.body_list return
def post_export_f5(self): flag = (TACS.OUTPUT_CONNECTIVITY | TACS.OUTPUT_NODES | TACS.OUTPUT_DISPLACEMENTS | TACS.OUTPUT_STRAINS) f5 = TACS.ToFH5(self.assembler, TACS.SOLID_ELEMENT, flag) filename_struct_out = "tets" + ".f5" f5.writeToFile(filename_struct_out)
def post_export_f5(self): flag = (TACS.OUTPUT_CONNECTIVITY | TACS.OUTPUT_NODES | TACS.OUTPUT_DISPLACEMENTS | TACS.OUTPUT_EXTRAS) f5 = TACS.ToFH5(self.assembler, TACS.BEAM_OR_SHELL_ELEMENT, flag) file_out = "onera_struct_out.f5" f5.writeToFile(file_out) return
def setAssembler(self, assembler, ksfunc): # Create tacs assembler object from mesh loader self.assembler = assembler # Create the list of functions self.funcs = [functions.StructuralMass(self.assembler), ksfunc] # Set up the solver self.ans = self.assembler.createVec() self.res = self.assembler.createVec() self.adjoint = self.assembler.createVec() self.dfdu = self.assembler.createVec() self.mat = self.assembler.createFEMat() self.pc = TACS.Pc(self.mat) self.gmres = TACS.KSM(self.mat, self.pc, 10) # For visualization flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS | TACS.ToFH5.EXTRAS) self.f5 = TACS.ToFH5(self.assembler, TACS.PY_PLANE_STRESS, flag) return
print('avg temp to set into SU2 = ', np.mean(np.array(ans_holder))) # transfer surface temps to theta (size of nodes on aero side) meld.transferTemp(ans_holder, theta) # set theta temps into SU2 for next run # don't do this on iter=0 because it'll set all zeros in if Iter > 0: for iVertex in range(nVertex_CHTMarker): setTemp = temp_check[iVertex] + 0.5 * (theta[iVertex] - temp_check[iVertex]) SU2Driver.SetVertexTemperature(CHTMarkerID, iVertex, setTemp) # Run an iteration of the CFD SU2Driver.Run() SU2Driver.Monitor(Iter) SU2Driver.Output(Iter) Iter += 1 delta_avg_temp = abs( np.mean(np.array(ans_holder)) - np.mean(np.array(temp_check))) # Set the element flag flag = (TACS.OUTPUT_CONNECTIVITY | TACS.OUTPUT_NODES | TACS.OUTPUT_DISPLACEMENTS | TACS.OUTPUT_STRAINS) f5 = TACS.ToFH5(assembler, TACS.SCALAR_2D_ELEMENT, flag) f5.writeToFile('tacs_4deg_inv.f5') SU2Driver.Postprocessing()
use_project = args.use_project props = TMR.StiffnessProperties(rho, E, nu, k0=1e-3, use_project=use_project) for ite in range(max_iterations): # Create the TACSAssembler and TMRTopoProblem instance nlevs = mg_levels[ite] assembler, problem, filtr, varmap = createTopoProblem( props, forest, nlevels=nlevs, Xscale=Xscale, ordering=TACS.PY_MULTICOLOR_ORDER) # Write out just the mesh - for visualization flag = TACS.ToFH5.NODES f5 = TACS.ToFH5(assembler, TACS.PY_SOLID, flag) f5.writeToFile(os.path.join(args.prefix, 'beam_mesh%d.f5' % (ite))) # Set the constraint type funcs = [functions.StructuralMass(assembler)] # Add the point loads to the vertices T = 1e3 force1 = addVertexLoad(comm, forest, 'pt1', assembler, [0.0, -T, 0.0]) force2 = addVertexLoad(comm, forest, 'pt2', assembler, [0.0, 0.0, -T]) force1.axpy(1.0, force2) force1.scale(-1.0) # Reorder the load vector assembler.reorderVec(force1) # Set the load cases
def integrate(assembler, forest, tfinal=30.0, nsteps=30, output=False): # Create the BDF integrator tinit = 0.0 order = 2 bdf = TACS.BDFIntegrator(assembler, tinit, tfinal, nsteps, order) bdf.setPrintLevel(0) bdf.setAbsTol(1e-6) bdf.setRelTol(1e-15) if output: # Set the output file name flag = (TACS.OUTPUT_CONNECTIVITY | TACS.OUTPUT_NODES | TACS.OUTPUT_DISPLACEMENTS | TACS.OUTPUT_EXTRAS) f5 = TACS.ToFH5(assembler, TACS.PLANE_STRESS_ELEMENT, flag) bdf.setFH5(f5) bdf.setOutputFrequency(1) bdf.setOutputPrefix('time_history/') # Define the functions of interest temp0 = functions.KSTemperature(assembler, 50.0) temp0.setKSTemperatureType('discrete') elems, _ = get_elems_and_surfs(['battery_0']) temp0.setDomain(elems) temp1 = functions.KSTemperature(assembler, 50.0) temp1.setKSTemperatureType('discrete') elems, _ = get_elems_and_surfs(['battery_1']) temp1.setDomain(elems) temp2 = functions.KSTemperature(assembler, 50.0) temp2.setKSTemperatureType('discrete') elems, _ = get_elems_and_surfs(['battery_2']) temp2.setDomain(elems) # Set the functions into the integrator class bdf.setFunctions([temp0, temp1, temp2]) # Create a vector that will store the instantaneous traction # load at any point in time forces = assembler.createVec() # Compute the tractions due to a unit input heat flux unit_forces = update_force(forest, assembler, qdot_in=1.0) # Iterate in time to march the equations of motion forward # in time t_array = np.linspace(tinit, tfinal, nsteps + 1) for i, t in enumerate(t_array): # Compute the magnitude of the input heat flux q_in = qdot_in_func(t) # Copy the unit force values and scale by the heat flux forces.copyValues(unit_forces) forces.scale(q_in) # Iterate forward in time for one time step bdf.iterate(i, forces=forces) # Compute the nodal sensitivities fvals = bdf.evalFunctions([temp0, temp1, temp2]) bdf.integrateAdjoint() df0dXpt = bdf.getXptGradient(0) df1dXpt = bdf.getXptGradient(1) df2dXpt = bdf.getXptGradient(2) dfdXpt = [df0dXpt, df1dXpt, df2dXpt] # Extract the time history qvals = np.zeros(nsteps + 1) tvals = np.zeros(nsteps + 1) for time_step in range(nsteps + 1): # Extract vectors time, q, _, _ = bdf.getStates(time_step) # Extract Arrays qarray = q.getArray() qvals[time_step] = np.amax(qarray) tvals[time_step] = time # Evaluate the functions at every time step temp0_vals = np.zeros(nsteps + 1) temp1_vals = np.zeros(nsteps + 1) temp2_vals = np.zeros(nsteps + 1) for time_step in range(nsteps + 1): # Extract vectors _, q, qdot, qddot = bdf.getStates(time_step) # Compute the function values assembler.setVariables(q) fvals = assembler.evalFunctions([temp0, temp1, temp2]) temp0_vals[time_step] = fvals[0] temp1_vals[time_step] = fvals[1] temp2_vals[time_step] = fvals[2] fvals = [temp0_vals, temp1_vals, temp2_vals] return tvals, qvals, fvals, dfdXpt
struct_disps[2::3] = ans_array[2::6] # We can use TACS built-in visualization capability to look at the loads that # came out of the load transfer. We do so by overwriting the rotations in ans # with those loads ans_array[3::6] = struct_loads[0::3] ans_array[4::6] = struct_loads[1::3] ans_array[5::6] = struct_loads[2::3] tacs.applyBCs(ans) tacs.setVariables(ans) """ # Output information from TACS for visualization in Tecplot flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS | TACS.ToFH5.STRESSES | TACS.ToFH5.EXTRAS) f5 = TACS.ToFH5(tacs, TACS.PY_SHELL, flag) f5.writeToFile('crm_meld.f5') """ -------------------------------------------------------------------------------- Compute displacements due to the RBF scheme's loads using TACS -------------------------------------------------------------------------------- """ # Set structural loads into residual array res. Since we're using shell # elements, res specifies three force components and three moment components per # node res.zeroEntries() res_array = res.getArray() res_array[0::6] = struct_loads_rbf[0::3] res_array[1::6] = struct_loads_rbf[1::3] res_array[2::6] = struct_loads_rbf[2::3] tacs.applyBCs(res)
def __init__(self, comm, props, tacs, const, num_materials, xpts=None, conn=None, m_fixed=1.0, min_mat_fraction=-1.0): ''' Analysis problem ''' # Keep the communicator self.comm = comm # Set the TACS object and the constitutive list self.props = props self.tacs = tacs self.const = const # Set the material information self.num_materials = num_materials self.num_elements = self.tacs.getNumElements() # Keep the pointer to the connectivity/positions self.xpts = xpts self.conn = conn # Set the target fixed mass self.m_fixed = m_fixed # Set a fixed material fraction self.min_mat_fraction = min_mat_fraction # Set the number of constraints self.ncon = 1 if self.min_mat_fraction > 0.0: self.ncon += self.num_materials # Set the number of design variables nwblock = 1 self.num_design_vars = (self.num_materials + 1) * self.num_elements # Initialize the super class super(TACSAnalysis, self).__init__(comm, self.num_design_vars, self.ncon, self.num_elements, nwblock) # Set the size of the design variable 'blocks' self.nblock = self.num_materials + 1 # Create the state variable vectors self.res = tacs.createVec() self.u = tacs.createVec() self.psi = tacs.createVec() self.mat = tacs.createFEMat() # Create the preconditioner for the corresponding matrix self.pc = TACS.Pc(self.mat) # Create the KSM object subspace_size = 20 nrestart = 0 self.ksm = TACS.KSM(self.mat, self.pc, subspace_size, nrestart) self.ksm.setTolerances(1e-12, 1e-30) # Set the block size self.nwblock = self.num_materials + 1 # Allocate a vector that stores the gradient of the mass self.gmass = np.zeros(self.num_design_vars) # Create the mass function and evaluate the gradient of the # mass. This is assumed to remain constatnt throughout the # optimization. self.mass_func = functions.StructuralMass(self.tacs) self.tacs.evalDVSens(self.mass_func, self.gmass) # Set the initial variable values self.xinit = np.ones(self.num_design_vars) # Set the initial design variable values xi = self.m_fixed / np.dot(self.gmass, self.xinit) self.xinit[:] = xi # Set the penalization tval = xi * self.num_materials self.xinit[::self.nblock] = tval # Create a temporary vector for the hessian-vector products self.hvec_tmp = np.zeros(self.xinit.shape) # Set the initial linearization/point self.RAMP_penalty = 0.0 self.setNewInitPointPenalty(self.xinit) # Set the number of function/gradient/hessian-vector # evaluations to zero self.fevals = 0 self.gevals = 0 self.hevals = 0 # Evaluate the objective at the initial point self.obj_scale = 1.0 fail, obj, con = self.evalObjCon(self.xinit) self.obj_scale = obj_scale_factor * obj print('objective scaling = ', self.obj_scale) # Create the FH5 file object flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS) self.f5 = TACS.ToFH5(self.tacs, TACS.PY_PLANE_STRESS, flag) return
mg.factor() pc = mg mat = mg.getMat() # Create the GMRES object gmres = TACS.KSM(mat, pc, 100, isFlexible=1) gmres.setMonitor(comm, freq=10) gmres.setTolerances(1e-14, 1e-30) gmres.solve(res, ans) ans.scale(-1.0) # Set the variables assembler.setVariables(ans) flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS) f5 = TACS.ToFH5(assembler, TACS.PY_POISSON_2D_ELEMENT, flag) f5.writeToFile('results/%s_solution%02d.f5' % (descript, k)) # Create and compute the function fval = 0.0 if functional == 'ks': direction = [1.0 / R**2, 0.0, 0.0] func = functions.KSDisplacement(assembler, ksweight, direction) func.setKSDispType('continuous') elif functional == 'pnorm': direction = [1.0 / R**2, 0.0, 0.0] func = functions.KSDisplacement(assembler, ksweight, direction) func.setKSDispType('pnorm-continuous') elif functional == 'ks_grad': direction = [1.0 / R, 0.0] func = poisson_function.KSPoissonGrad(assembler, ksweight, direction)
def post_export_f5(self): flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.EXTRAS ) f5 = TACS.ToFH5(self.tacs, TACS.PY_SHELL, flag) filename_struct_out = "crm" + ".f5" f5.writeToFile(filename_struct_out)
# Evaluate the function and the df/du termp assembler.evalFunctions([avg_temp_func]) assembler.addSVSens([avg_temp_func], [dfdu]) # Solve for the adjoint equations assembler.assembleJacobian(alpha, beta, gamma, res, mat, matOr=TACS.TRANSPOSE) pc.factor() gmres.solve(dfdu, adjoint) # Compute the total derivative assembler.addDVSens([avg_temp_func], [g]) assembler.addAdjointResProducts([adjoint], [g], alpha=-1.0) # Compute the gradient grad = np.dot(A.T, g.getArray()) if comm.rank == 0: print(grad) # Write out the solution flag = (TACS.OUTPUT_CONNECTIVITY | TACS.OUTPUT_NODES | TACS.OUTPUT_DISPLACEMENTS) f5 = TACS.ToFH5(assembler, TACS.SOLID_ELEMENT, flag) filename_struct_out = "test.f5" f5.writeToFile(filename_struct_out)
aero_disps = np.zeros(len(aero_X), dtype=TransferScheme.dtype) meld.transferDisps(struct_disps, aero_disps) # Transfer loads from fluid and get loads on structure struct_loads = np.zeros(len(struct_X), dtype=TransferScheme.dtype) meld.transferLoads(aero_loads, struct_loads) # Set loads on structure struct_loads_moments = np.zeros(2 * len(struct_loads)) struct_loads_moments[::6] = struct_loads[::3] struct_loads_moments[1::6] = struct_loads[1::3] struct_loads_moments[2::6] = struct_loads[2::3] write_flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS | TACS.ToFH5.STRESSES | TACS.ToFH5.EXTRAS) f5 = TACS.ToFH5(tacs, TACS.PY_SHELL, write_flag) ################################################################################ # ParOpt # ################################################################################ # Create sizing as a ParOpt problem class CRMSizing(ParOpt.pyParOptProblem): def __init__(self, tacs, f5): # Set the communicator pointer self.comm = MPI.COMM_WORLD self.rank = self.comm.Get_rank() self.size = self.comm.Get_size() self.nvars = num_components / self.size
# The volumes of the elements in the filter mesh filtr_volumes = None # Set the values of the objective array obj_array = [1.0e2] for ite in range(max_iterations): # Create the TACSAssembler and TMRTopoProblem instance nlevs = mg_levels[ite] assembler, problem, filtr, varmap = createTopoProblem(forest, nlevels=nlevs) # Write out just the mesh - for visualization flag = (TACS.ToFH5.NODES) f5 = TACS.ToFH5(assembler, TACS.PY_PLANE_STRESS, flag) f5.writeToFile(os.path.join(args.prefix, 'plate_mesh%d.f5' % (ite))) # Set the constraint type funcs = [functions.StructuralMass(assembler)] # Add the point loads to the vertices force1 = addVertexLoad(comm, order, forest, 'pt1', assembler, [0.0, -1000.]) force1.scale(-1.0) # Set the load cases forces = [force1] problem.setLoadCases(forces) # Set the mass constraint problem.addConstraints(0, funcs, [-m_fixed], [-1.0 / m_fixed])
restarts = 2 gmres = TACS.KSM(K, pc, subspace, restarts) # Guess for the lowest natural frequency sigma_hz = 1.0 sigma = 2.0 * np.pi * sigma_hz # Create the frequency analysis object num_eigs = 5 freq = TACS.FrequencyAnalysis(assembler, sigma, M, K, gmres, num_eigs=num_eigs, eig_tol=1e-12) # Solve the frequency analysis problem freq.solve() # Output for visualization flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS | TACS.ToFH5.EXTRAS) f5 = TACS.ToFH5(assembler, TACS.PY_SHELL, flag) vec = assembler.createVec() for i in range(num_eigs): freq.extractEigenvector(i, vec) assembler.setVariables(vec) f5.writeToFile('ucrm_mode%d.f5' % (i))
def __init__(self, comm, bdf_name): self.comm = comm struct_mesh = TACS.MeshLoader(self.comm) struct_mesh.scanBDFFile(bdf_name) # Set constitutive properties rho = 2500.0 # density, kg/m^3 E = 70e9 # elastic modulus, Pa nu = 0.3 # poisson's ratio kcorr = 5.0 / 6.0 # shear correction factor ys = 350e6 # yield stress, Pa min_thickness = 0.002 max_thickness = 0.20 thickness = 0.02 # Loop over components, creating stiffness and element object for each num_components = struct_mesh.getNumComponents() for i in range(num_components): descriptor = struct_mesh.getElementDescript(i) # Set the design variable index design_variable_index = i stiff = constitutive.isoFSDT(rho, E, nu, kcorr, ys, thickness, design_variable_index, min_thickness, max_thickness) element = None # Create the element object if descriptor in ["CQUAD", "CQUADR", "CQUAD4"]: element = elements.MITCShell(2, stiff, component_num=i) struct_mesh.setElement(i, element) # Create tacs assembler object from mesh loader self.assembler = struct_mesh.createTACS(6) # Create the KS Function ksWeight = 50.0 self.funcs = [ functions.StructuralMass(self.assembler), functions.KSFailure(self.assembler, ksWeight) ] # Create the forces self.forces = self.assembler.createVec() force_array = self.forces.getArray() force_array[2::6] += 100.0 # uniform load in z direction self.assembler.applyBCs(self.forces) # Set up the solver self.ans = self.assembler.createVec() self.res = self.assembler.createVec() self.adjoint = self.assembler.createVec() self.dfdu = self.assembler.createVec() self.mat = self.assembler.createFEMat() self.pc = TACS.Pc(self.mat) subspace = 100 restarts = 2 self.gmres = TACS.KSM(self.mat, self.pc, subspace, restarts) # Scale the mass objective so that it is O(10) self.mass_scale = 1e-3 # Scale the thickness variables so that they are measured in # mm rather than meters self.thickness_scale = 1000.0 # The number of thickness variables in the problem self.nvars = num_components # The number of constraints (1 global stress constraint that # will use the KS function) self.ncon = 1 # Initialize the base class - this will run the same problem # on all processors super(uCRM_VonMisesMassMin, self).__init__(MPI.COMM_SELF, self.nvars, self.ncon) # Set the inequality options for this problem in ParOpt: # The dense constraints are inequalities c(x) >= 0 and # use both the upper/lower bounds self.setInequalityOptions(dense_ineq=True, use_lower=True, use_upper=True) # For visualization flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS | TACS.ToFH5.EXTRAS) self.f5 = TACS.ToFH5(self.assembler, TACS.PY_SHELL, flag) self.iter_count = 0 return
# Assemble the Jacobian alpha = 1.0 beta = 0.0 gamma = 0.0 tacs.assembleJacobian(alpha, beta, gamma, res, mat) pc.factor() res.setRand(1.0, 1.0) tacs.applyBCs(res) pc.applyFactor(res, ans) ans.scale(-1.0) tacs.setVariables(ans) tacs.setSimulationTime(0.15) # Create the function list funcs = [] # Create the KS function ksweight = 100.0 for i in range(1): funcs.append(functions.KSFailure(tacs, ksweight)) func_vals = tacs.evalFunctions(funcs) # Set the element flag flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS) f5 = TACS.ToFH5(tacs, TACS.PY_PLANE_STRESS, flag) f5.writeToFile('triangle_test.f5')
gamma = 0.0 mg.assembleJacobian(alpha, beta, gamma, res) # Factor the preconditioner mg.factor() subspace = 100 gmres = TACS.KSM(mg.getMat(), mg, subspace, isFlexible=1) gmres.setMonitor(comm, 'GMRES', 1) gmres.solve(res, ans) ans.scale(-1.0) assembler.setVariables(ans) # Output for visualization flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS) f5 = TACS.ToFH5(assembler, TACS.PY_SHELL, flag) f5.writeToFile('visualization.f5') # Duplicate the forest and refine it uniformly forest_refined = forest.duplicate() forest_refined.setMeshOrder(4) forest_refined.balance(1) assembler_refined = creator.createTACS(forest_refined) ans_refined = assembler_refined.createVec() TMR.computeReconSolution(forest, assembler, forest_refined, assembler_refined, ans, ans_refined) assembler_refined.setVariables(ans_refined) # Output for visualization flag = (TACS.ToFH5.NODES | TACS.ToFH5.DISPLACEMENTS | TACS.ToFH5.STRAINS) f5 = TACS.ToFH5(assembler_refined, TACS.PY_SHELL, flag)
assembler.setDesignVars(dv_vec) # Perform the numerical integration tfinal = 5.0 nsteps = 50 t, u, fvals, dfdXpt = integrate(assembler, forest, nsteps=nsteps, tfinal=tfinal, output=True) flag = (TACS.OUTPUT_CONNECTIVITY | TACS.OUTPUT_NODES | TACS.OUTPUT_DISPLACEMENTS | TACS.OUTPUT_EXTRAS) assembler.setVariables(dfdXpt[0]) f5 = TACS.ToFH5(assembler, TACS.PLANE_STRESS_ELEMENT, flag) f5.writeToFile('Xpt0.f5') assembler.setVariables(dfdXpt[1]) f5 = TACS.ToFH5(assembler, TACS.PLANE_STRESS_ELEMENT, flag) f5.writeToFile('Xpt1.f5') assembler.setVariables(dfdXpt[2]) f5 = TACS.ToFH5(assembler, TACS.PLANE_STRESS_ELEMENT, flag) f5.writeToFile('Xpt2.f5') # Plot the maximum temperature over time i0 = np.argmax(fvals[0]) i1 = np.argmax(fvals[1]) i2 = np.argmax(fvals[2])