.. _MecaSequentialNoZsetLocalBasis: MecaSequentialNoZsetLocalBasis ============================== This use case aims to validate the methodology POD + ECM for uniform isotropic elactic material computations with Z-set, see Section :ref:`Publications`, article 1. In this linear case, the ECM should find a trivial quadrature formula, since the operators can be completely precomputed in the *offline* stage. This tutorial illustrates in particular how to include data from more than one HFM computation, and how to construct local reduced-order bases (ROB). No optional prerequisite. The data needed to execute the tutorials below can be loaded here: :download:`exampleMecaSequentialNoZsetLocalBasis.zip ` Features: construct 2 local-ROBs from 2 HFM simulations with linear materials ----------------------------------------------------------------------------- The physical setting is the same as in the tutorial :ref:`MecaSequential`, except that there is no thermal loading in this case. Moreover, the workflow illutrate the capacity of the library to deal with data from various HFM, and to deal with multiple local ROB. *Offline* stage ~~~~~~~~~~~~~~~ First, we define a list that will contain two objects ``collectionProblemData``, one for each of the two local ROB to be constructed: .. code-block:: python collectionProblemDatas = [] for i in range(2): The rest if the commented code for the *offline* stage is in this loop on ``i``. For each local ROB, we start by initiating a ``collectionProblemData``: .. code-block:: python collectionProblemData = CPD.CollectionProblemData() collectionProblemData.AddVariabilityAxis('config', str, description="dummy variability") collectionProblemData.DefineQuantity("U", "displacement", "m") collectionProblemData.DefineQuantity("sigma", "stress", "Pa") collectionProblemDatas.append(collectionProblemData) Then, set up two ``problemData`` which we populate with data from two HFM computations, either from the early time steps (``i=0`` for the first local ROB), or from the late time steps (``i=1`` for the second local ROB). .. code-block:: python folders = [folder0+"Computation1"+os.sep, folder0+"Computation2"+os.sep] for j, folder in enumerate(folders): solutionReader = ZSR.ZsetSolutionReader(folder+solutionFileName) solutionU = S.Solution("U", nbeOfComponentsPrimal, numberOfNodes, primality = True) solutionSigma = S.Solution("sigma", nbeOfComponentsDual, numberOfIntegrationPoints, primality = False) outputTimeSequence = solutionReader.ReadTimeSequenceFromSolutionFile() if i==0: outputTimeSequence = outputTimeSequence[:len(outputTimeSequence)//2+2] elif i==1: outputTimeSequence = outputTimeSequence[len(outputTimeSequence)//2-2:] problemData = PD.ProblemData("case-"+str(i)+"_"+str(j)) problemData.AddSolution(solutionU) problemData.AddSolution(solutionSigma) collectionProblemData.AddProblemData(problemData, config="case-"+str(i)+"_"+str(j)) for time in outputTimeSequence: U = solutionReader.ReadSnapshot("U", time, nbeOfComponentsPrimal, primality=True) solutionU.AddSnapshot(U, time) sigma = solutionReader.ReadSnapshot("sig", time, nbeOfComponentsDual, primality=False) solutionSigma.AddSnapshot(sigma, time) Then, set up two ``problemData`` which we populate with data from two HFM computations, either from the early time steps (``i=0`` for the first local ROB), or from the late time steps (``i=1`` for the second local ROB). .. code-block:: python SP.CompressData(collectionProblemData, "U", 1.e-4, snapshotCorrelationOperator["U"] ) Mechanical.CompressOperator(collectionProblemData, operatorPreCompressionData, mesh, 1.e-3) print("check compression...") reducedOrderBasis = collectionProblemData.GetReducedOrderBasis("U") collectionProblemData.CompressSolutions("U", snapshotCorrelationOperator["U"]) Compression errors are computed and printed. These lines illustrate how to declare a new ``Solution`` object, populate it with reduced coordinates, and uncompress them to express the reduced solution in the high-dimensional space. .. code-block:: python compressionErrors = [] for j, folder in enumerate(folders): problemData = collectionProblemData.GetProblemData(config="case-"+str(i)+"_"+str(j)) solutionU = problemData.GetSolution("U") outputTimeSequence = solutionU.GetTimeSequenceFromSnapshots() reducedCoordinatesU = solutionU.GetReducedCoordinates() solutionUApprox = S.Solution("U", nbeOfComponentsPrimal, numberOfNodes, primality = True) solutionUApprox.SetReducedCoordinates(reducedCoordinatesU) solutionUApprox.UncompressSnapshots(reducedOrderBasis) for t in outputTimeSequence: approxSolution = solutionUApprox.GetSnapshotAtTime(t) exactSolution = solutionU.GetSnapshotAtTime(t) norml2ExactSolution = np.linalg.norm(exactSolution) if norml2ExactSolution != 0: relError = np.linalg.norm(approxSolution-exactSolution)/norml2ExactSolution else: relError = np.linalg.norm(approxSolution-exactSolution) compressionErrors.append(relError) print("compressionErrors =", compressionErrors) Finally, change-of-basis matrices for converting reduced coordinates from one local ROB to the other are computed, and data is stored on disk for re-use in the *online* stage. .. code-block:: python for i in range(2): dataCompressionData = {} for j in [j for j in range(2) if j != i]: reducedOrderBasisJ = collectionProblemDatas[j].GetReducedOrderBasis("U") dataCompressionData["projectedReducedOrderBasis_"+str(j)] = \ collectionProblemDatas[i].ComputeReducedOrderBasisProjection("U", \ reducedOrderBasisJ, snapshotCorrelationOperator["U"]) collectionProblemDatas[i].AddDataCompressionData("U", dataCompressionData) SIO.SaveState("mordicusState_Basis_"+str(i), collectionProblemDatas[i]) *Online* stage ~~~~~~~~~~~~~~ We illustrate below how the *online* problem is solved, with a switch between two local ROBs, all in complexity independent of the high-fidelity dimension. .. code-block:: python onlineReducedCoordinates = [] for i in range(2): for loading in onlineProblemData.GetLoadingsForSolution("U"): loading.ReduceLoading(mesh, onlineProblemData, reducedOrderBases[i], operatorCompressionDatas[i]) onlineCompressedSolution = Mechanical.ComputeOnline(onlineProblemData, timeSequences[i], operatorCompressionDatas[i], 1.e-4) onlineReducedCoordinates.append(onlineCompressedSolution) for t, reducedCoordinates in onlineReducedCoordinates[i].items(): onlinesolution.AddReducedCoordinates(reducedCoordinates, t) if i==0: previousTime = timeSequences[i][-1] projectedReducedOrderBasis = collectionProblemDatas[0].GetDataCompressionData("U")["projectedReducedOrderBasis_1"] onlinesolution.ConvertReducedCoordinatesReducedOrderBasisAtTime(projectedReducedOrderBasis, previousTime) onlineProblemData.GetInitialCondition().SetReducedInitialSnapshot("U", onlinesolution.GetReducedCoordinatesAtTime(previousTime)) In the last 3 lines, the reduced coordinated of the online solution are converted from the first ROB to the second, and these converted reduced coordinates are set as an initial condition for the second local ROB *online* resolution. Results ------- The ECM selects 2 reduced integration points in each of the 2 constructed local ROB. (this can slightly vary due the probabilistic nature of our implementation for ECM) In :numref:`cube-local-lin-res`, the quality of the reduced model is illustrated by comparing it to the high-fidelity reference. The comparison is done on the displacement, since no internal variable is available with the simple considered material. .. figure:: res.jpg :name: cube-local-lin-res :align: center :width: 75% Illustration of the ROM accuracy on the displacement ``U`` (left) HFM, (right) pointwise difference between the ROM and the HFM.