def computeElementFaceFlux(NWorldCoarse, NPatchCoarse, NCoarseElement, aPatch, uPatch): '''Per element, compute face normal flux integrals.''' NPatchFine = NPatchCoarse*NCoarseElement NWorldFine = NWorldCoarse*NCoarseElement NtCoarse = np.prod(NPatchCoarse) d = np.size(NPatchCoarse) fluxTF = np.zeros([NtCoarse, 2*d]) TFinepIndexMap = util.lowerLeftpIndexMap(NCoarseElement, NPatchFine) TFinepStartIndices = util.pIndexMap(NPatchCoarse-1, NPatchFine, NCoarseElement) TFinetIndexMap = util.lowerLeftpIndexMap(NCoarseElement-1, NPatchFine-1) TFinetStartIndices = util.pIndexMap(NPatchCoarse-1, NPatchFine-1, NCoarseElement) faces = np.arange(2*d) CLocGetter = fem.localBoundaryNormalDerivativeMatrixGetter(NWorldFine) boundaryMap = np.zeros([d, 2], dtype='bool') for TInd in np.arange(NtCoarse): aElement = aPatch[TFinetStartIndices[TInd] + TFinetIndexMap] uElement = uPatch[TFinepStartIndices[TInd] + TFinepIndexMap] for F in faces: boundaryMap[:] = False boundaryMap.flat[F] = True AFace = fem.assemblePatchBoundaryMatrix(NCoarseElement, CLocGetter, aElement, boundaryMap) fluxFace = -np.sum(AFace*uElement) fluxTF[TInd,F] = fluxFace return fluxTF
def assembleProlongationMatrix(NPatchCoarse, NCoarseElement): #, localBasis): d = np.size(NPatchCoarse) Phi = localBasis(NCoarseElement) assert np.size(Phi, 1) == 2**d NPatchFine = NPatchCoarse * NCoarseElement NtCoarse = np.prod(NPatchCoarse) NpCoarse = np.prod(NPatchCoarse + 1) NpFine = np.prod(NPatchFine + 1) rowsBasis = util.lowerLeftpIndexMap(NCoarseElement, NPatchFine) colsBasis = np.zeros_like(rowsBasis) rowsElement = np.tile(rowsBasis, 2**d) colsElement = np.add.outer( util.lowerLeftpIndexMap(np.ones(d, dtype='int64'), NPatchCoarse), colsBasis).flatten() rowsOffset = util.pIndexMap(NPatchCoarse - 1, NPatchFine, NCoarseElement) colsOffset = util.lowerLeftpIndexMap(NPatchCoarse - 1, NPatchCoarse) rows = np.add.outer(rowsOffset, rowsElement).flatten() cols = np.add.outer(colsOffset, colsElement).flatten() values = np.tile(Phi.flatten('F'), NtCoarse) rows, cols, values = util.ignoreDuplicates(rows, cols, values) PPatch = sparse.csc_matrix((values, (rows, cols)), shape=(NpFine, NpCoarse)) PPatch.eliminate_zeros() return PPatch
def assemblePatchInterpolationMatrix(IElement, NPatchFine, NCoarseElement): assert np.all(np.mod(NPatchFine, NCoarseElement) == 0) d = np.size(NPatchFine) NPatchCoarse = NPatchFine / NCoarseElement NpFine = np.prod(NPatchFine + 1) NpCoarse = np.prod(NPatchCoarse + 1) fineToPatchMap = util.lowerLeftpIndexMap(NCoarseElement, NPatchFine) coarseToPatchMap = util.lowerLeftpIndexMap(np.ones(d, dtype='int64'), NPatchCoarse) IElementCoo = IElement.tocoo() raisedRows = coarseToPatchMap[IElementCoo.row] raisedCols = fineToPatchMap[IElementCoo.col] pCoarseInd = util.lowerLeftpIndexMap(NPatchCoarse - 1, NPatchCoarse) pFineInd = util.pIndexMap(NPatchCoarse - 1, NPatchFine, NCoarseElement) fullRows = np.add.outer(pCoarseInd, raisedRows).flatten() fullCols = np.add.outer(pFineInd, raisedCols).flatten() fullData = np.tile(IElementCoo.data, np.size(pFineInd)) I = sparse.csr_matrix((fullData, (fullRows, fullCols)), shape=(NpCoarse, NpFine)) return I
def computeCorrection(self, ARhsFull=None, MRhsFull=None): assert (self.ecList is not None) assert (self.coefficient is not None) world = self.world NCoarseElement = world.NCoarseElement NWorldCoarse = world.NWorldCoarse NWorldFine = NWorldCoarse * NCoarseElement NpFine = np.prod(NWorldFine + 1) coefficient = self.coefficient IPatchGenerator = self.IPatchGenerator localBasis = world.localBasis TpIndexMap = util.lowerLeftpIndexMap(NCoarseElement, NWorldFine) TpStartIndices = util.pIndexMap(NWorldCoarse - 1, NWorldFine, NCoarseElement) uFine = np.zeros(NpFine) NtCoarse = np.prod(world.NWorldCoarse) for TInd in range(NtCoarse): if self.printLevel > 0: print str(TInd) + ' / ' + str(NtCoarse) ecT = self.ecList[TInd] coefficientPatch = coefficient.localize(ecT.iPatchWorldCoarse, ecT.NPatchCoarse) IPatch = IPatchGenerator(ecT.iPatchWorldCoarse, ecT.NPatchCoarse) if ARhsFull is not None: ARhsList = [ARhsFull[TpStartIndices[TInd] + TpIndexMap]] else: ARhsList = None if MRhsFull is not None: MRhsList = [MRhsFull[TpStartIndices[TInd] + TpIndexMap]] else: MRhsList = None correctorT = ecT.computeElementCorrector(coefficientPatch, IPatch, ARhsList, MRhsList)[0] NPatchFine = ecT.NPatchCoarse * NCoarseElement iPatchWorldFine = ecT.iPatchWorldCoarse * NCoarseElement patchpIndexMap = util.lowerLeftpIndexMap(NPatchFine, NWorldFine) patchpStartIndex = util.convertpCoordinateToIndex( NWorldFine, iPatchWorldFine) uFine[patchpStartIndex + patchpIndexMap] += correctorT return uFine
def precompute(self): if hasattr(self, '_aFine'): return NPatchCoarse = self.NPatchCoarse NCoarseElement = self.NCoarseElement NPatchFine = NPatchCoarse*NCoarseElement coarsetStartIndices = util.pIndexMap(NPatchCoarse-1, NPatchFine-1, NCoarseElement) coarsetIndexMap = util.lowerLeftpIndexMap(NCoarseElement-1, NPatchFine-1) coarsetIndexTensor = np.add.outer(coarsetIndexMap, coarsetStartIndices) self._aFine = np.array(self._aBase) self._aFine[coarsetIndexTensor] *= self._rCoarse del self._aBase
def faceElementIndices(NPatchCoarse, NCoarseElement, k, boundary): '''Return indices of fine elements adjacent to face (k, boundary) for all coarse triangles Return type shape: (NtCoarse, Number of elements of face) ''' NPatchFine = NPatchCoarse*NCoarseElement NFace = np.array(NCoarseElement) NFace[k] = 1 tPatchBasis = util.linearpIndexBasis(NPatchFine-1) tStepToFace = boundary*tPatchBasis[k]*(NCoarseElement[k]-1) tIndexMap = tStepToFace + util.lowerLeftpIndexMap(NFace-1, NPatchFine-1) tStartIndices = util.pIndexMap(NPatchCoarse-1, NPatchFine-1, NCoarseElement) tIndices = np.add.outer(tStartIndices, tIndexMap) return tIndices
def assembleHierarchicalBasisMatrix(NPatchCoarse, NCoarseElement): NPatchFine = NPatchCoarse * NCoarseElement NpFine = np.prod(NPatchFine + 1) # Use simplest possible hierarchy, divide by two in all dimensions NLevelElement = NCoarseElement.copy() while np.all(np.mod(NLevelElement, 2) == 0): NLevelElement /= 2 assert np.all(NLevelElement == 1) rowsList = [] colsList = [] valuesList = [] # Loop over levels while np.all(NLevelElement <= NCoarseElement): # Compute level basis functions on fine mesh NCoarseLevel = NCoarseElement / NLevelElement NPatchLevel = NPatchCoarse * NCoarseLevel PLevel = assembleProlongationMatrix(NPatchLevel, NLevelElement) PLevel = PLevel.tocoo() # Rows are ok. Columns must be sparsened to fine mesh. colsMap = util.pIndexMap(NPatchLevel, NPatchFine, NLevelElement) rowsList.append(PLevel.row) colsList.append(colsMap[PLevel.col]) valuesList.append(PLevel.data) NLevelElement = 2 * NLevelElement # Concatenate lists (backwards so that we can ignore duplicates) rows = np.hstack(rowsList[::-1]) cols = np.hstack(colsList[::-1]) values = np.hstack(valuesList[::-1]) # Ignore duplicates rows, cols, values = util.ignoreDuplicates(rows, cols, values) # Create sparse matrix PHier = sparse.csc_matrix((values, (rows, cols)), shape=(NpFine, NpFine)) PHier.eliminate_zeros() return PHier
def uncoupledL2ProjectionCoarseElementMatrix(NCoarseElement): d = np.size(NCoarseElement) NpFine = np.prod(NCoarseElement + 1) # First compute full element P'*M MLoc = fem.localMassMatrix(NCoarseElement) MElement = fem.assemblePatchMatrix(NCoarseElement, MLoc) Phi = fem.localBasis(NCoarseElement) PhiTM = Phi.T * MElement # Prepare indices to go from local to element and find all corner # element indices dOnes = np.ones_like(NCoarseElement, dtype='int64') loc2ElementIndexMap = util.lowerLeftpIndexMap(dOnes, NCoarseElement) cornerElementIndices = util.pIndexMap(dOnes, NCoarseElement, NCoarseElement - 1) # Compute P'*MCorner for all corners PhiTMCornersList = [] for i in range(2**d): cornerInd = cornerElementIndices[i] + loc2ElementIndexMap PhiTMCorner = 0 * PhiTM PhiTMCorner[:, cornerInd] = np.dot(Phi.T[:, cornerInd], MLoc) PhiTMCornersList.append(PhiTMCorner) PhiTMAllCorners = reduce(np.add, PhiTMCornersList) # For each corner, compute # P'*M - P'*MAllCorners + P'*MCorner IDense = np.zeros((2**d, NpFine)) for i in range(2**d): PhiTMCorner = PhiTMCornersList[i] PhiTMi = PhiTM - PhiTMAllCorners + PhiTMCorner PhiTMiPhi = np.dot(PhiTMi, Phi) IiDense = np.dot(np.linalg.inv(PhiTMiPhi), PhiTMi) IDense[i, :] = IiDense[i, :] I = sparse.coo_matrix(IDense) return I
def computeErrorIndicatorFineWithLagging(self, a, aTilde): assert (hasattr(self, 'csi')) world = self.world NPatchCoarse = self.NPatchCoarse NCoarseElement = world.NCoarseElement NPatchFine = NPatchCoarse * NCoarseElement iElementPatchCoarse = self.iElementPatchCoarse elementCoarseIndex = util.convertpCoordinateToIndex( NPatchCoarse - 1, iElementPatchCoarse) TPrimeFinetStartIndices = util.pIndexMap(NPatchCoarse - 1, NPatchFine - 1, NCoarseElement) TPrimeFinetIndexMap = util.lowerLeftpIndexMap(NCoarseElement - 1, NPatchFine - 1) muTPrime = self.csi.muTPrime TPrimeIndices = np.add.outer(TPrimeFinetStartIndices, TPrimeFinetIndexMap) aTPrime = a[TPrimeIndices] aTildeTPrime = aTilde[TPrimeIndices] deltaMaxNormTPrime = np.max(np.abs( (aTPrime - aTildeTPrime) / np.sqrt(aTPrime * aTildeTPrime)), axis=1) theOtherUnnamedFactorTPrime = np.max( np.abs(aTPrime[elementCoarseIndex] / aTildeTPrime[elementCoarseIndex])) epsilonTSquare = theOtherUnnamedFactorTPrime * \ np.sum((deltaMaxNormTPrime**2)*muTPrime) return np.sqrt(epsilonTSquare)
def computeCoarseQuantities(self): '''Compute the coarse quantities K and L for this element corrector Compute the tensors (T is given by the class instance): KTij = (A \nabla lambda_j, \nabla lambda_i)_{T} KmsTij = (A \nabla (lambda_j - Q_T lambda_j), \nabla lambda_i)_{U_k(T)} muTT' = max_{w_H} || A \nabla (\chi_T - Q_T) w_H ||^2_T' / || A \nabla w_H ||^2_T and store them in the self.csi object. See notes/coarse_quantities*.pdf for a description. Auxiliary quantities are computed, but not saved, e.g. LTT'ij = (A \nabla (chi_T - Q_T)lambda_j, \nabla (chi_T - Q_T) lambda_j)_{T'} ''' assert (hasattr(self, 'fsi')) world = self.world NCoarseElement = world.NCoarseElement NPatchCoarse = self.NPatchCoarse NPatchFine = NPatchCoarse * NCoarseElement NTPrime = np.prod(NPatchCoarse) NpPatchCoarse = np.prod(NPatchCoarse + 1) d = np.size(NPatchCoarse) correctorsList = self.fsi.correctorsList aPatch = self.fsi.coefficient.aFine ALocFine = world.ALocFine localBasis = world.localBasis TPrimeCoarsepStartIndices = util.lowerLeftpIndexMap( NPatchCoarse - 1, NPatchCoarse) TPrimeCoarsepIndexMap = util.lowerLeftpIndexMap( np.ones_like(NPatchCoarse), NPatchCoarse) TPrimeFinetStartIndices = util.pIndexMap(NPatchCoarse - 1, NPatchFine - 1, NCoarseElement) TPrimeFinetIndexMap = util.lowerLeftpIndexMap(NCoarseElement - 1, NPatchFine - 1) TPrimeFinepStartIndices = util.pIndexMap(NPatchCoarse - 1, NPatchFine, NCoarseElement) TPrimeFinepIndexMap = util.lowerLeftpIndexMap(NCoarseElement, NPatchFine) TInd = util.convertpCoordinateToIndex(NPatchCoarse - 1, self.iElementPatchCoarse) QPatch = np.column_stack(correctorsList) # This loop can probably be done faster than this. If a bottle-neck, fix! Kmsij = np.zeros((NpPatchCoarse, 2**d)) LTPrimeij = np.zeros((NTPrime, 2**d, 2**d)) for (TPrimeInd, TPrimeCoarsepStartIndex, TPrimeFinetStartIndex, TPrimeFinepStartIndex) \ in zip(np.arange(NTPrime), TPrimeCoarsepStartIndices, TPrimeFinetStartIndices, TPrimeFinepStartIndices): aTPrime = aPatch[TPrimeFinetStartIndex + TPrimeFinetIndexMap] KTPrime = fem.assemblePatchMatrix(NCoarseElement, ALocFine, aTPrime) P = localBasis Q = QPatch[TPrimeFinepStartIndex + TPrimeFinepIndexMap, :] BTPrimeij = np.dot(P.T, KTPrime * Q) CTPrimeij = np.dot(Q.T, KTPrime * Q) sigma = TPrimeCoarsepStartIndex + TPrimeCoarsepIndexMap if TPrimeInd == TInd: Kij = np.dot(P.T, KTPrime * P) LTPrimeij[TPrimeInd] = CTPrimeij \ - BTPrimeij \ - BTPrimeij.T \ + Kij Kmsij[sigma, :] += Kij - BTPrimeij else: LTPrimeij[TPrimeInd] = CTPrimeij Kmsij[sigma, :] += -BTPrimeij muTPrime = np.zeros(NTPrime) for TPrimeInd in np.arange(NTPrime): # Solve eigenvalue problem LTPrimeij x = mu_TPrime Mij x eigenvalues = scipy.linalg.eigvals(LTPrimeij[TPrimeInd][:-1, :-1], Kij[:-1, :-1]) muTPrime[TPrimeInd] = np.max(np.real(eigenvalues)) # Compute coarse element face flux for basis and Q (not yet implemented for R) correctorFluxTF = transport.computeHarmonicMeanFaceFlux( world.NWorldCoarse, NPatchCoarse, NCoarseElement, aPatch, QPatch) # Need to compute over at least one fine element over the # boundary of the main element to make the harmonic average # right. Note: We don't do this for correctorFluxTF, beause # we do not have access to a outside the patch... localBasisExtended = np.zeros_like(QPatch) localBasisExtended[TPrimeFinepStartIndices[TInd] + TPrimeFinepIndexMap, :] = localBasis basisFluxTF = transport.computeHarmonicMeanFaceFlux( world.NWorldCoarse, NPatchCoarse, NCoarseElement, aPatch, localBasisExtended)[:, TInd, :] if isinstance(self.fsi.coefficient, coef.coefficientCoarseFactorAbstract): rCoarse = self.fsi.coefficient.rCoarse else: rCoarse = None self.csi = CoarseScaleInformation(Kij, Kmsij, muTPrime, correctorFluxTF, basisFluxTF, rCoarse)