def __init__(self, visID, solDomain, solver): self.visType = "probe" self.visID = visID self.xLabel = "t (s)" self.probeNum = catchInput(solver.paramDict, "probeNum" + str(self.visID), -2) - 1 assert ( self.probeNum >= 0), "Must provide positive integer probe number for probe" + str( self.visID) assert (self.probeNum < solver.numProbes), "probeNum" + str( self.visID) + " must correspond to a valid probe" super().__init__(solDomain, solver) # image file on disk visName = "" for visVar in self.visVar: visName += "_" + visVar figName = "probe" + visName + "_" + str( self.probeNum) + "_" + solver.simType + ".png" self.figFile = os.path.join(const.imageOutputDir, figName) # check that requested variables are being probed for visVar in self.visVar: assert ( visVar in solver.probeVars), "Must probe " + visVar + " to plot it"
def __init__(self, paramDict): super().__init__(paramDict) self.timeType = "implicit" self.subiterMax = catchInput(paramDict, "subiterMax", const.subiterMaxImpDefault) self.resTol = catchInput(paramDict, "resTol", const.l2ResTolDefault) # dual time-stepping, robustness controls self.dualTime = catchInput(paramDict, "dualTime", True) self.dtau = catchInput(paramDict, "dtau", const.dtauDefault) if (self.dualTime): self.adaptDTau = catchInput(paramDict, "adaptDTau", False) else: self.adaptDTau = False self.CFL = catchInput( paramDict, "CFL", const.CFLDefault) # reference CFL for advective control of dtau self.VNN = catchInput( paramDict, "VNN", const.VNNDefault ) # von Neumann number for diffusion control of dtau self.refConst = catchInput(paramDict, "refConst", [None]) # constants for limiting dtau self.relaxConst = catchInput(paramDict, "relaxConst", [None]) #
def __init__(self, gasDict): # gas composition self.numSpeciesFull = int(gasDict["numSpecies"]) # total number of species in case self.molWeights = gasDict["molWeights"].astype(realType) # molecular weights, g/mol self.enthRef = gasDict["enthRef"].astype(realType) # reference enthalpy, J/kg self.Cp = gasDict["Cp"].astype(realType) # heat capacity at constant pressure, J/(kg-K) self.Pr = gasDict["Pr"].astype(realType) # Prandtl number self.Sc = gasDict["Sc"].astype(realType) # Schmidt number self.muRef = gasDict["muRef"].astype(realType) # reference dynamic viscosity for Sutherland model self.tempRef = gasDict["tempRef"].astype(realType) # reference temperature for Sutherland model, K # Arrhenius factors # TODO: modify these to allow for multiple global reactions self.nu = gasDict["nu"].astype(realType) # global reaction stoichiometric "forward" coefficients self.nuArr = gasDict["nuArr"].astype(realType) # global reaction concentration exponents self.actEnergy = float(gasDict["actEnergy"]) # global reaction Arrhenius activation energy, divided by RUniv, ????? self.preExpFact = float(gasDict["preExpFact"]) # global reaction Arrhenius pre-exponential factor # misc calculations self.RGas = RUniv / self.molWeights # specific gas constant of each species, J/(K*kg) self.molWeightNu = self.molWeights * self.nu self.suthLaw = catchInput(gasDict, "suthLaw", False) # dealing with single-species option if (self.numSpeciesFull == 1): self.numSpecies = self.numSpeciesFull else: self.numSpecies = self.numSpeciesFull - 1 # last species is not directly solved for self.massFracSlice = np.arange(self.numSpecies) self.mwInv = 1.0 / self.molWeights self.mwInvDiffs = self.mwInv[self.massFracSlice] - self.mwInv[-1] self.CpDiffs = self.Cp[self.massFracSlice] - self.Cp[-1] self.enthRefDiffs = self.enthRef[self.massFracSlice] - self.enthRef[-1] self.numEqs = self.numSpecies + 3 # pressure, velocity, temperature, and species transport # mass matrices for calculating viscosity and thermal conductivity mixing laws self.mixMassMatrix = np.zeros((self.numSpeciesFull, self.numSpeciesFull), dtype=realType) self.mixInvMassMatrix = np.zeros((self.numSpeciesFull, self.numSpeciesFull), dtype=realType) self.precompMixMassMatrices()
def __init__(self, solDomain, solver): romDict = readInputFile(solver.romInputs) self.romDict = romDict # load model parameters self.romMethod = str(romDict["romMethod"]) self.numModels = int(romDict["numModels"]) self.latentDims = catchList(romDict, "latentDims", [0], lenHighest=self.numModels) modelVarIdxs = catchList(romDict, "modelVarIdxs", [[-1]], lenHighest=self.numModels) # check model parameters for i in self.latentDims: assert (i > 0), "latentDims must contain positive integers" if (self.numModels == 1): assert (len(self.latentDims) == 1), "Must provide only one value of latentDims when numModels = 1" assert (self.latentDims[0] > 0), "latentDims must contain positive integers" else: if (len(self.latentDims) == self.numModels): pass elif (len(self.latentDims) == 1): print("Only one value provided in latentDims, applying to all models") sleep(1.0) self.latentDims = [self.latentDims[0]] * self.numModels else: raise ValueError("Must provide either numModels or 1 entry in latentDims") # load and check modelVarIdxs for modelIdx in range(self.numModels): assert (modelVarIdxs[modelIdx][0] != -1), "modelVarIdxs input incorrectly, probably too few lists" assert (len(modelVarIdxs) == self.numModels), "Must specify modelVarIdxs for every model" modelVarSum = 0 for modelIdx in range(self.numModels): modelVarSum += len(modelVarIdxs[modelIdx]) for modelVarIdx in modelVarIdxs[modelIdx]: assert (modelVarIdx >= 0), "modelVarIdxs must be non-negative integers" assert (modelVarIdx < solDomain.gasModel.numEqs), "modelVarIdxs must less than the number of governing equations" assert (modelVarSum == solDomain.gasModel.numEqs), ("Must specify as many modelVarIdxs entries as governing equations (" + str(modelVarSum) + " != " + str(solDomain.gasModel.numEqs) + ")") modelVarIdxsOneList = sum(modelVarIdxs, []) assert (len(modelVarIdxsOneList) == len(set(modelVarIdxsOneList))), "All entries in modelVarIdxs must be unique" self.modelVarIdxs = modelVarIdxs # load and check model input locations self.modelDir = str(romDict["modelDir"]) modelFiles = romDict["modelFiles"] self.modelFiles = [None] * self.numModels assert (len(modelFiles) == self.numModels), "Must provide modelFiles for each model" for modelIdx in range(self.numModels): inFile = os.path.join(self.modelDir, modelFiles[modelIdx]) assert (os.path.isfile(inFile)), "Could not find model file at " + inFile self.modelFiles[modelIdx] = inFile # load standardization profiles, if they are required self.normSubConsIn = catchList(romDict, "normSubConsIn", [""]) self.normFacConsIn = catchList(romDict, "normFacConsIn", [""]) self.centConsIn = catchList(romDict, "centConsIn", [""]) self.normSubPrimIn = catchList(romDict, "normSubPrimIn", [""]) self.normFacPrimIn = catchList(romDict, "normFacPrimIn", [""]) self.centPrimIn = catchList(romDict, "centPrimIn", [""]) # load low-dimensional initial condition state, if desired self.loadInitCode(romDict) self.setModelFlags() self.adaptiveROM = catchInput(romDict, "adaptiveROM", False) # set up hyper-reduction, if necessary self.hyperReduc = catchInput(romDict, "hyperReduc", False) if (self.isIntrusive and self.hyperReduc): self.loadHyperReduc(solDomain, solver) # initialize models for domain self.modelList = [None] * self.numModels for modelIdx in range(self.numModels): if (self.romMethod == "linearGalerkinProj"): self.modelList[modelIdx] = linearGalerkinProj(modelIdx, self, solver, solDomain) elif (self.romMethod == "linearLSPGProj"): raise ValueError("linearLSPGProj ROM not implemented yet") elif (self.romMethod == "linearSPLSVTProj"): raise ValueError("linearSPLSVTProj ROM not implemented yet") elif (self.romMethod == "autoencoderGalerkinProjTF"): raise ValueError("autoencoderGalerkinProjTF ROM not implemented yet") elif (self.romMethod == "autoencoderLSPGProjTF"): raise ValueError("autoencoderLSPGProjTF ROM not implemented yet") elif (self.romMethod == "autoencoderSPLSVTProjTF"): raise ValueError("autoencoderSPLSVTProjTF ROM not implemented yet") elif (self.romMethod == "liftAndLearn"): raise ValueError("liftAndLearn ROM not implemented yet") elif (self.romMethod == "tcnNonintrusive"): raise ValueError("tcnNonintrusive ROM not implemented yet") else: raise ValueError("Invalid ROM method name: "+self.romMethod) # initialize state if self.initROMFromFile[modelIdx]: self.modelList[modelIdx].initFromCode(self.code0[modelIdx], solDomain, solver) else: self.modelList[modelIdx].initFromSol(solDomain, solver) solDomain.solInt.updateState(fromCons=self.targetCons) # get time integrator, if necessary # TODO: move this selection to an external function? This is repeated in solutionDomain # TODO: timeScheme should be specific to the romDomain, not the solver if self.hasTimeIntegrator: if (solver.timeScheme == "bdf"): self.timeIntegrator = bdf(solver.paramDict) elif (solver.timeScheme == "rkExp"): self.timeIntegrator = rkExplicit(solver.paramDict) else: raise ValueError("Invalid choice of timeScheme: "+solver.timeScheme) # initialize code history # TODO: this is necessary for non-time-integrated methods, e.g. TCN for model in self.modelList: model.codeHist = [model.code.copy()] * (self.timeIntegrator.timeOrder+1) else: self.timeIntegrator = None # TODO: this might be pointless
def loadHyperReduc(self, solDomain, solver): """ Loads direct sampling indices and determines cell indices for calculating fluxes and gradients """ raise ValueError("Hyper-reduction temporarily out of commission for development") # TODO: add some explanations for what each index array accomplishes # load and check sample points sampFile = catchInput(self.romDict, "sampFile", "") assert (sampFile != ""), "Must supply sampFile if performing hyper-reduction" sampFile = os.path.join(self.modelDir, sampFile) assert (os.path.isfile(sampFile)), ("Could not find sampFile at " + sampFile) # NOTE: assumed that sample indices are zero-indexed solDomain.directSampIdxs = np.load(sampFile).flatten() solDomain.directSampIdxs = (np.sort(solDomain.directSampIdxs)).astype(np.int32) solDomain.numSampCells = len(solDomain.directSampIdxs) assert (solDomain.numSampCells <= solver.mesh.numCells), "Cannot supply more sampling points than cells in domain." assert (np.amin(solDomain.directSampIdxs) >= 0), "Sampling indices must be non-negative integers" assert (np.amax(solDomain.directSampIdxs) < solver.mesh.numCells), "Sampling indices must be less than the number of cells in the domain" assert (len(np.unique(solDomain.directSampIdxs)) == solDomain.numSampCells), "Sampling indices must be unique" # TODO: should probably shunt these over to a function for when indices get updated in adaptive method # compute indices for inviscid flux calculations # NOTE: have to account for fact that boundary cells are prepended/appended solDomain.fluxSampLIdxs = np.zeros(2 * solDomain.numSampCells, dtype=np.int32) solDomain.fluxSampLIdxs[0::2] = solDomain.directSampIdxs solDomain.fluxSampLIdxs[1::2] = solDomain.directSampIdxs + 1 solDomain.fluxSampRIdxs = np.zeros(2 * solDomain.numSampCells, dtype=np.int32) solDomain.fluxSampRIdxs[0::2] = solDomain.directSampIdxs + 1 solDomain.fluxSampRIdxs[1::2] = solDomain.directSampIdxs + 2 # eliminate repeated indices solDomain.fluxSampLIdxs = np.unique(solDomain.fluxSampLIdxs) solDomain.fluxSampRIdxs = np.unique(solDomain.fluxSampRIdxs) solDomain.numFluxFaces = len(solDomain.fluxSampLIdxs) # Roe average if (solver.spaceScheme == "roe"): zerosProf = np.zeros((solDomain.gasModel.numEqs, solDomain.numFluxFaces), dtype=const.realType) solDomain.solAve = solutionPhys(solDomain, zerosProf, zerosProf, solDomain.numFluxFaces, solver) # to slice flux when calculating RHS solDomain.fluxRHSIdxs = np.zeros(solDomain.numSampCells, np.int32) for i in range(1,solDomain.numSampCells): if (solDomain.directSampIdxs[i] == (solDomain.directSampIdxs[i-1]+1)): solDomain.fluxRHSIdxs[i] = solDomain.fluxRHSIdxs[i-1] + 1 else: solDomain.fluxRHSIdxs[i] = solDomain.fluxRHSIdxs[i-1] + 2 # compute indices for gradient calculations # NOTE: also need to account for prepended/appended boundary cells # TODO: generalize for higher-order schemes if (solver.spaceOrder > 1): if (solver.spaceOrder == 2): solDomain.gradIdxs = np.concatenate((solDomain.directSampIdxs+1, solDomain.directSampIdxs, solDomain.directSampIdxs+2)) solDomain.gradIdxs = np.unique(solDomain.gradIdxs) # exclude left neighbor of inlet, right neighbor of outlet if (solDomain.gradIdxs[0] == 0): solDomain.gradIdxs = solDomain.gradIdxs[1:] if (solDomain.gradIdxs[-1] == (solver.mesh.numCells+1)): solDomain.gradIdxs = solDomain.gradIdxs[:-1] solDomain.numGradCells = len(solDomain.gradIdxs) # neighbors of gradient cells solDomain.gradNeighIdxs = np.concatenate((solDomain.gradIdxs-1, solDomain.gradIdxs+1)) solDomain.gradNeighIdxs = np.unique(solDomain.gradNeighIdxs) # exclude left neighbor of inlet, right neighbor of outlet if (solDomain.gradNeighIdxs[0] == -1): solDomain.gradNeighIdxs = solDomain.gradNeighIdxs[1:] if (solDomain.gradNeighIdxs[-1] == (solver.mesh.numCells+2)): solDomain.gradNeighIdxs = solDomain.gradNeighIdxs[:-1] # indices of gradIdxs in gradNeighIdxs _, _, solDomain.gradNeighExtract = np.intersect1d(solDomain.gradIdxs, solDomain.gradNeighIdxs, return_indices=True) # indices of gradIdxs in fluxSampLIdxs and fluxSampRIdxs, and vice versa _, solDomain.gradLExtract, solDomain.fluxLExtract = np.intersect1d(solDomain.gradIdxs, solDomain.fluxSampLIdxs, return_indices=True) _, solDomain.gradRExtract, solDomain.fluxRExtract = np.intersect1d(solDomain.gradIdxs, solDomain.fluxSampRIdxs, return_indices=True) else: raise ValueError("Sampling for higher-order schemes not implemented yet") # copy indices for ease of use self.numSampCells = solDomain.numSampCells self.directSampIdxs = solDomain.directSampIdxs # paths to hyper-reduction files (unpacked later) hyperReducFiles = self.romDict["hyperReducFiles"] self.hyperReducFiles = [None] * self.numModels assert (len(hyperReducFiles) == self.numModels), "Must provide hyperReducFiles for each model" for modelIdx in range(self.numModels): inFile = os.path.join(self.modelDir, hyperReducFiles[modelIdx]) assert (os.path.isfile(inFile)), "Could not find hyper-reduction file at " + inFile self.hyperReducFiles[modelIdx] = inFile # load hyper reduction dimensions and check validity self.hyperReducDims = catchList(self.romDict, "hyperReducDims", [0], lenHighest=self.numModels) for i in self.hyperReducDims: assert (i > 0), "hyperReducDims must contain positive integers" if (self.numModels == 1): assert (len(self.hyperReducDims) == 1), "Must provide only one value of hyperReducDims when numModels = 1" assert (self.hyperReducDims[0] > 0), "hyperReducDims must contain positive integers" else: if (len(self.hyperReducDims) == self.numModels): pass elif (len(self.hyperReducDims) == 1): print("Only one value provided in hyperReducDims, applying to all models") sleep(1.0) self.hyperReducDims = [self.hyperReducDims[0]] * self.numModels else: raise ValueError("Must provide either numModels or 1 entry in hyperReducDims")
def setModelFlags(self): """ Set universal ROM method flags that dictate various execution behaviors """ self.hasTimeIntegrator = False # whether the model uses numerical time integration to advance the solution self.isIntrusive = False # whether the model requires access to the ODE RHS calculation self.targetCons = False # whether the ROM models the conservative variables self.targetPrim = False # whether the ROM models the primitive variables self.hasConsNorm = False # whether the model must load conservative variable normalization profiles self.hasConsCent = False # whether the model must load conservative variable centering profile self.hasPrimNorm = False # whether the model must load primitive variable normalization profiles self.hasPrimCent = False # whether the model must load primitive variable centering profile if (self.romMethod == "linearGalerkinProj"): self.hasTimeIntegrator = True self.isIntrusive = True self.targetCons = True self.hasConsNorm = True self.hasConsCent = True elif (self.romMethod == "linearLSPGProj"): self.hasTimeIntegrator = True self.isIntrusive = True self.targetCons = True self.hasConsNorm = True self.hasConsCent = True elif (self.romMethod == "linearSPLSVTProj"): self.hasTimeIntegrator = True self.isIntrusive = True self.targetPrim = True self.hasConsNorm = True self.hasPrimNorm = True self.hasPrimCent = True elif (self.romMethod == "autoencoderGalerkinProjTF"): self.hasTimeIntegrator = True self.isIntrusive = True self.targetCons = True self.hasConsNorm = True self.hasConsCent = True elif (self.romMethod == "autoencoderLSPGProjTF"): self.hasTimeIntegrator = True self.isIntrusive = True self.targetCons = True self.hasConsNorm = True self.hasConsCent = True elif (self.romMethod == "autoencoderSPLSVTProjTF"): self.hasTimeIntegrator = True self.isIntrusive = True self.targetPrim = True self.hasConsNorm = True self.hasPrimNorm = True self.hasPrimCent = True elif (self.romMethod == "liftAndLearn"): # TODO: the cons/prim dichotomy doesn't work for lifted variables self.hasTimeIntegrator = True raise ValueError("Finalize settings of method parameters for lift and learn") elif (self.romMethod == "tcnNonintrusive"): # TODO: TCN does not **need** to target one or the other self.targetCons = catchInput(self.romDict, "targetCons", False) self.targetPrim = catchInput(self.romDict, "targetPrim", False) else: raise ValueError("Invalid ROM method name: "+self.romMethod) # TODO: not strictly true for the non-intrusive models assert (self.targetCons != self.targetPrim), "Model must target either the primitive or conservative variables"
def __init__(self, solDomain, solver): paramDict = solver.paramDict self.visShow = catchInput(paramDict, "visShow", True) self.visSave = catchInput(paramDict, "visSave", False) self.visInterval = catchInput(paramDict, "visInterval", 1) self.niceVis = catchInput(paramDict, "niceVis", False) # if not saving or showing, don't even draw the plots self.visDraw = True if ((not self.visShow) and (not self.visSave)): self.visDraw = False return # count number of visualizations requested self.numVisPlots = 0 plotCount = True while plotCount: try: keyName = "visType" + str(self.numVisPlots + 1) plotType = str(paramDict[keyName]) # TODO: should honestly just fail for incorrect input assert (plotType in [ "field", "probe", "residual" ]), (keyName + " must be either \"field\", \"probe\", or \"residual\"") self.numVisPlots += 1 except: plotCount = False if (self.numVisPlots == 0): print("WARNING: No visualization plots selected...") sleep(1.0) self.visList = [None] * self.numVisPlots # initialize each figure object for visIdx in range(1, self.numVisPlots + 1): visType = str(paramDict["visType" + str(visIdx)]) if (visType == "field"): self.visList[visIdx - 1] = fieldPlot(visIdx, self.visInterval, solDomain, solver) elif (visType == "probe"): self.visList[visIdx - 1] = probePlot(visIdx, solDomain, solver) elif (visType == "residual"): raise ValueError("Residual plot not implemented yet") else: raise ValueError("Invalid visualization selection: " + visType) # set plot positions/dimensions if (self.niceVis and self.visShow): try: self.movePlots() except: for vis in self.visList: vis.fig, vis.ax = plt.subplots(nrows=vis.numRows, ncols=vis.numCols, num=vis.visID, figsize=(figWidthDefault, figHeightDefault)) else: for vis in self.visList: vis.fig, vis.ax = plt.subplots(nrows=vis.numRows, ncols=vis.numCols, num=vis.visID, figsize=(figWidthDefault, figHeightDefault))
def __init__(self, solver): paramDict = solver.paramDict # time integrator if (solver.timeScheme == "bdf"): self.timeIntegrator = bdf(paramDict) elif (solver.timeScheme == "rkExp"): self.timeIntegrator = rkExplicit(paramDict) else: raise ValueError("Invalid choice of timeScheme: " + solver.timeScheme) # gas model gasFile = str(paramDict["gasFile"]) # gas properties file (string) gasDict = readInputFile(gasFile) gasType = catchInput(gasDict, "gasType", "cpg") if (gasType == "cpg"): self.gasModel = caloricallyPerfectGas(gasDict) else: raise ValueError("Ivalid choice of gasType: " + gasType) gas = self.gasModel # solution solPrim0 = getInitialConditions(self, solver) self.solInt = solutionInterior(gas, solPrim0, solver, self.timeIntegrator) self.solIn = solutionInlet(gas, solver) self.solOut = solutionOutlet(gas, solver) # average solution for Roe scheme if (solver.spaceScheme == "roe"): onesProf = np.ones( (self.gasModel.numEqs, self.solInt.numCells + 1), dtype=const.realType) self.solAve = solutionPhys(gas, onesProf, self.solInt.numCells + 1) # for flux calculations onesProf = np.ones((self.gasModel.numEqs, self.solInt.numCells + 1), dtype=const.realType) self.solL = solutionPhys(gas, onesProf, self.solInt.numCells + 1) self.solR = solutionPhys(gas, onesProf, self.solInt.numCells + 1) # to avoid repeated concatenation of ghost cell states self.solPrimFull = np.zeros( (self.gasModel.numEqs, self.solIn.numCells + self.solInt.numCells + self.solOut.numCells), dtype=const.realType) self.solConsFull = np.zeros(self.solPrimFull.shape, dtype=const.realType) # probe storage (as this can include boundaries as well) self.probeLocs = catchList(paramDict, "probeLocs", [None]) self.probeVars = catchList(paramDict, "probeVars", [None]) if ((self.probeLocs[0] is not None) and (self.probeVars[0] is not None)): self.numProbes = len(self.probeLocs) self.numProbeVars = len(self.probeVars) self.probeVals = np.zeros( (self.numProbes, self.numProbeVars, solver.numSteps), dtype=const.realType) # get probe locations self.probeIdxs = [None] * self.numProbes self.probeSecs = [None] * self.numProbes for idx, probeLoc in enumerate(self.probeLocs): if (probeLoc > solver.mesh.xR): self.probeSecs[idx] = "outlet" elif (probeLoc < solver.mesh.xL): self.probeSecs[idx] = "inlet" else: self.probeSecs[idx] = "interior" self.probeIdxs[idx] = np.absolute(solver.mesh.xCell - probeLoc).argmin() assert (not ((("outlet" in self.probeSecs) or ("inlet" in self.probeSecs)) and (("source" in self.probeVars) or ("rhs" in self.probeVars))) ), \ "Cannot probe source or RHS in inlet/outlet" else: self.numProbes = 0 # copy this for use with plotting functions solver.numProbes = self.numProbes solver.probeVars = self.probeVars # TODO: include initial conditions in probeVals, timeVals self.timeVals = np.linspace(solver.dt * (solver.timeIter), solver.dt * (solver.timeIter + solver.numSteps), solver.numSteps, dtype=const.realType) # for compatability with hyper-reduction # are overwritten if actually using hyper-reduction self.numSampCells = solver.mesh.numCells self.numFluxFaces = solver.mesh.numCells + 1 self.numGradCells = solver.mesh.numCells self.directSampIdxs = np.arange(0, solver.mesh.numCells) self.fluxSampLIdxs = np.arange(0, solver.mesh.numCells + 1) self.fluxSampRIdxs = np.arange(1, solver.mesh.numCells + 2) self.gradIdxs = np.arange(1, solver.mesh.numCells + 1) self.gradNeighIdxs = np.arange(0, solver.mesh.numCells + 2) self.gradNeighExtract = np.arange(1, solver.mesh.numCells + 1) self.fluxLExtract = np.arange(1, solver.mesh.numCells + 1) self.fluxRExtract = np.arange(0, solver.mesh.numCells) self.gradLExtract = np.arange(0, solver.mesh.numCells) self.gradRExtract = np.arange(0, solver.mesh.numCells) self.fluxRHSIdxs = np.arange(0, solver.mesh.numCells)
def __init__(self): # input parameters from solverParams.inp paramFile = os.path.join(const.workingDir, const.paramInputs) paramDict = readInputFile(paramFile) self.paramDict = paramDict # spatial domain meshFile = str(paramDict["meshFile"]) # mesh properties file (string) meshDict = readInputFile(meshFile) self.mesh = mesh.mesh(meshDict) # TODO: selection for different meshes, when implemented # meshType = str(meshDict["meshType"]) # if (meshType == "uniform"): # self.mesh = mesh.uniformMesh(meshDict) # else: # raise ValueError("Invalid choice of meshType: " + meshType) # initial condition file try: self.initFile = str(paramDict["initFile"]) except: self.initFile = None # temporal discretization self.dt = float(paramDict["dt"]) # physical time step self.timeScheme = str(paramDict["timeScheme"]) self.runSteady = catchInput(paramDict, "runSteady", False) # run "steady" simulation self.numSteps = int( paramDict["numSteps"]) # total number of physical time iterations self.iter = 1 # iteration number for current run self.solTime = 0.0 # physical time self.timeIter = 1 # physical time iteration number if self.runSteady: self.steadyTol = catchInput( paramDict, "steadyTol", const.l2SteadyTolDefault) # threshold on convergence # spatial discretization parameters self.spaceScheme = catchInput( paramDict, "spaceScheme", "roe") # spatial discretization scheme (string) self.spaceOrder = catchInput( paramDict, "spaceOrder", 1) # spatial discretization order of accuracy (int) self.gradLimiter = catchInput( paramDict, "gradLimiter", "") # gradient limiter for higher-order face reconstructions self.viscScheme = catchInput(paramDict, "viscScheme", 0) # 0 for inviscid, 1 for viscous # restart files # TODO: could move this to solutionDomain, not terribly necessary self.saveRestarts = catchInput(paramDict, "saveRestarts", False) # whether to save restart files if self.saveRestarts: self.restartInterval = catchInput( paramDict, "restartInterval", 100) # number of steps between restart file saves self.numRestarts = catchInput( paramDict, "numRestarts", 20) # number of restart files to keep saved self.restartIter = 1 # file number counter self.initFromRestart = catchInput(paramDict, "initFromRestart", False) if ((self.initFile == None) and (not self.initFromRestart)): try: self.icParamsFile = str(paramDict["icParamsFile"]) except: raise KeyError( "If not providing IC profile or restarting from restart file, must provide icParamsFile" ) # unsteady output self.outInterval = catchInput( paramDict, "outInterval", 1) # iteration interval to save data (int) self.primOut = catchInput( paramDict, "primOut", True) # whether to save the primitive variables self.consOut = catchInput( paramDict, "consOut", False) # whether to save the conservative variables self.sourceOut = catchInput( paramDict, "sourceOut", False) # whether to save the species source term self.RHSOut = catchInput(paramDict, "RHSOut", False) # whether to save the RHS vector self.numSnaps = int(self.numSteps / self.outInterval) # misc self.velAdd = catchInput(paramDict, "velAdd", 0.0) self.resNormPrim = catchInput(paramDict, "steadyNorm", [None]) self.sourceOn = catchInput(paramDict, "sourceOn", True) self.solveFailed = False # visualization self.numProbes = 0 self.probeVars = [] # ROM flag self.calcROM = catchInput(paramDict, "calcROM", False) if not self.calcROM: self.simType = "FOM" else: self.simType = "ROM" self.romInputs = os.path.join(const.workingDir, const.romInputs)