Example #1
0
	def __init__(self, romDict):

		
		self.numericalJacob = catchInput(romDict, "numericalJacob", False)
		if self.numericalJacob: self.fdStep = catchInput(romDict, "fdStep", fdStepDefault)

		self.encoder = catchInput(romDict, "encoderROM", False)

		# load models

		# check model dimensions against solDomain

		# do a test run just to make sure everything works okay

		pass
    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])  #
Example #3
0
	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"
Example #4
0
    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)
Example #5
0
    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"
                )
Example #6
0
    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: timeScheme should be specific to the romDomain, not the solver
        if self.hasTimeIntegrator:
            self.timeIntegrator = getTimeIntegrator(solver.timeScheme,
                                                    solver.paramDict)

            # 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
Example #7
0
    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"
Example #8
0
    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))