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 computeFaceFluxTF(self, u, f=None): assert (f is None) world = self.world NWorldCoarse = world.NWorldCoarse d = np.size(NWorldCoarse) NtCoarse = np.prod(NWorldCoarse) NpCoarse = np.prod(NWorldCoarse + 1) fluxTF = np.zeros([NtCoarse, 2 * d]) elementpIndexMap = util.elementpIndexMap(NWorldCoarse) elementpStartIndices = util.lowerLeftpIndexMap(NWorldCoarse - 1, NWorldCoarse) for TInd in np.arange(NtCoarse): ecT = self.ecList[TInd] assert (hasattr(ecT, 'csi')) patchtStartIndex = util.convertpCoordinateToIndex( NWorldCoarse - 1, ecT.iPatchWorldCoarse) patchtIndexMap = util.lowerLeftpIndexMap(ecT.NPatchCoarse - 1, NWorldCoarse - 1) elementpIndex = elementpStartIndices[TInd] + elementpIndexMap patchtIndices = patchtStartIndex + patchtIndexMap fluxTF[TInd, :] += np.einsum('iF, i -> F', ecT.csi.basisFluxTF, u[elementpIndex]) fluxTF[patchtIndices, :] -= np.einsum('iTF, i -> TF', ecT.csi.correctorFluxTF, u[elementpIndex]) return fluxTF
def harmonicMeanOverFaces(NPatchCoarse, NCoarseElement, k, boundary, aPatch): NPatchFine = NPatchCoarse*NCoarseElement TPatchBasis = util.linearpIndexBasis(NPatchCoarse-1) NPatchBottom = np.array(NPatchCoarse) NPatchBottom[k] = 1 NtBottom = np.prod(NPatchBottom) NPatchBase = np.array(NPatchCoarse) NPatchBase[k] -= 1 TIndBase = util.lowerLeftpIndexMap(NPatchBase-1, NPatchCoarse-1) TIndBottom = util.lowerLeftpIndexMap(NPatchBottom-1, NPatchCoarse-1) t0Faces = faceElementIndices(NPatchCoarse, NCoarseElement, k, 0) t1Faces = faceElementIndices(NPatchCoarse, NCoarseElement, k, 1) aH0Faces = aPatch[t0Faces[TPatchBasis[k] + TIndBase]] aH1Faces = aPatch[t1Faces[TIndBase]] if boundary==0: abFaces = aPatch[t0Faces] abFaces[TPatchBasis[k] + TIndBase] = 2*aH0Faces*aH1Faces/(aH0Faces + aH1Faces) elif boundary==1: abFaces = aPatch[t1Faces] abFaces[TIndBase] = 2*aH0Faces*aH1Faces/(aH0Faces + aH1Faces) return abFaces
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 computeUpwindSaturation(NWorldCoarse, boundarys, sT, fluxTF): d = np.size(NWorldCoarse) sTF = np.tile(sT[...,None], [1, 2*d]) basis = util.linearpIndexBasis(NWorldCoarse-1) for k in range(d): b = basis[k] N = np.array(NWorldCoarse-1) N[k] -= 1 TIndBase = util.lowerLeftpIndexMap(N, NWorldCoarse-1) N[k] = 0 TIndBottom = util.lowerLeftpIndexMap(N, NWorldCoarse-1) for face in [0,1]: faceInd = 2*k+face stepToFace = b*(face*(NWorldCoarse[k]-1)) TIndInterior = (1-face)*b + TIndBase TIndBoundary = stepToFace + TIndBottom # Interior TIndDst = TIndInterior[fluxTF[TIndInterior, faceInd] < 0] TIndSrc = TIndDst + (2*face - 1)*b sTF[TIndDst, faceInd] = sT[TIndSrc] # Boundary TIndDst = TIndBoundary[fluxTF[TIndBoundary, faceInd] < 0] sTF[TIndDst, faceInd] = boundarys[k, face] return sTF
def localize(self, iSubPatchCoarse, NSubPatchCoarse): # Either ._aBase or ._aFine exists, not both if not hasattr(self, '_aFine'): a = self._aBase else: a = self._aFine NPatchCoarse = self.NPatchCoarse NCoarseElement = self.NCoarseElement NPatchFine = NPatchCoarse*NCoarseElement NSubPatchFine = NSubPatchCoarse*NCoarseElement iSubPatchFine = iSubPatchCoarse*NCoarseElement # rCoarse coarseTIndexMap = util.lowerLeftpIndexMap(NSubPatchCoarse-1, NPatchCoarse-1) coarseTStartIndex = util.convertpCoordinateToIndex(NPatchCoarse-1, iSubPatchCoarse) rCoarseLocalized = self._rCoarse[coarseTStartIndex + coarseTIndexMap] # a coarsetIndexMap = util.lowerLeftpIndexMap(NSubPatchFine-1, NPatchFine-1) coarsetStartIndex = util.convertpCoordinateToIndex(NPatchFine-1, iSubPatchFine) aLocalized = a[coarsetStartIndex + coarsetIndexMap] localizedCoefficient = coefficientCoarseFactor(NSubPatchCoarse, NCoarseElement, None, rCoarseLocalized) if not hasattr(self, '_aFine'): localizedCoefficient._aBase = aLocalized else: localizedCoefficient._aFine = aLocalized del localizedCoefficient._aBase return localizedCoefficient
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 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 assembleBasisCorrectors(self): if self.basisCorrectors is not None: return self.basisCorrectors assert (self.ecList is not None) world = self.world NWorldCoarse = world.NWorldCoarse NCoarseElement = world.NCoarseElement NWorldFine = NWorldCoarse * NCoarseElement NtCoarse = np.prod(NWorldCoarse) NpCoarse = np.prod(NWorldCoarse + 1) NpFine = np.prod(NWorldFine + 1) TpIndexMap = util.lowerLeftpIndexMap(np.ones_like(NWorldCoarse), NWorldCoarse) TpStartIndices = util.lowerLeftpIndexMap(NWorldCoarse - 1, NWorldCoarse) cols = [] rows = [] data = [] ecList = self.ecList for TInd in range(NtCoarse): ecT = ecList[TInd] assert (ecT is not None) assert (hasattr(ecT, 'fsi')) NPatchFine = ecT.NPatchCoarse * NCoarseElement iPatchWorldFine = ecT.iPatchWorldCoarse * NCoarseElement patchpIndexMap = util.lowerLeftpIndexMap(NPatchFine, NWorldFine) patchpStartIndex = util.convertpCoordinateToIndex( NWorldFine, iPatchWorldFine) colsT = TpStartIndices[TInd] + TpIndexMap rowsT = patchpStartIndex + patchpIndexMap dataT = np.hstack(ecT.fsi.correctorsList) cols.extend(np.repeat(colsT, np.size(rowsT))) rows.extend(np.tile(rowsT, np.size(colsT))) data.extend(dataT) basisCorrectors = sparse.csc_matrix((data, (rows, cols)), shape=(NpFine, NpCoarse)) self.basisCorrectors = basisCorrectors return basisCorrectors
def assembleMsStiffnessMatrix(self): if self.Kms is not None: return self.Kms assert (self.ecList is not None) world = self.world NWorldCoarse = world.NWorldCoarse NtCoarse = np.prod(world.NWorldCoarse) NpCoarse = np.prod(world.NWorldCoarse + 1) TpIndexMap = util.lowerLeftpIndexMap(np.ones_like(NWorldCoarse), NWorldCoarse) TpStartIndices = util.lowerLeftpIndexMap(NWorldCoarse - 1, NWorldCoarse) cols = [] rows = [] data = [] ecList = self.ecList for TInd in range(NtCoarse): ecT = ecList[TInd] assert (ecT is not None) NPatchCoarse = ecT.NPatchCoarse patchpIndexMap = util.lowerLeftpIndexMap(NPatchCoarse, NWorldCoarse) patchpStartIndex = util.convertpCoordinateToIndex( NWorldCoarse, ecT.iPatchWorldCoarse) colsT = TpStartIndices[TInd] + TpIndexMap rowsT = patchpStartIndex + patchpIndexMap dataT = ecT.csi.Kmsij.flatten() cols.extend(np.tile(colsT, np.size(rowsT))) rows.extend(np.repeat(rowsT, np.size(colsT))) data.extend(dataT) Kms = sparse.csc_matrix((data, (rows, cols)), shape=(NpCoarse, NpCoarse)) self.Kms = Kms return Kms
def localToPatchSparsityPattern(NPatch, NSubPatch=None): if NSubPatch is None: NSubPatch = NPatch d = np.size(NPatch) loc2Patch = util.lowerLeftpIndexMap(np.ones(d, 'int64'), NPatch) pInd = util.lowerLeftpIndexMap(NSubPatch - 1, NPatch) loc2PatchRep = np.repeat(loc2Patch, 2**d) loc2PatchTile = np.tile(loc2Patch, 2**d) indexMatrixRows = np.add.outer(pInd, loc2PatchRep) indexMatrixCols = np.add.outer(pInd, loc2PatchTile) rows = indexMatrixRows.flatten() cols = indexMatrixCols.flatten() return rows, cols
def computeErrorIndicatorFine(self, coefficientNew): assert (hasattr(self, 'fsi')) NPatchCoarse = self.NPatchCoarse world = self.world NCoarseElement = world.NCoarseElement NPatchFine = NPatchCoarse * NCoarseElement ALocFine = world.ALocFine P = world.localBasis a = coefficientNew.aFine aTilde = self.fsi.coefficient.aFine TFinetIndexMap = util.lowerLeftpIndexMap(NCoarseElement - 1, NPatchFine - 1) iElementPatchFine = self.iElementPatchCoarse * NCoarseElement TFinetStartIndex = util.convertpCoordinateToIndex( NPatchFine - 1, iElementPatchFine) b = ((aTilde - a)**2) / a bT = b[TFinetStartIndex + TFinetIndexMap] PatchNorm = fem.assemblePatchMatrix(NPatchFine, ALocFine, b) TNorm = fem.assemblePatchMatrix(NCoarseElement, ALocFine, bT) BNorm = fem.assemblePatchMatrix(NCoarseElement, ALocFine, a[TFinetStartIndex + TFinetIndexMap]) TFinepIndexMap = util.lowerLeftpIndexMap(NCoarseElement, NPatchFine) TFinepStartIndex = util.convertpCoordinateToIndex( NPatchFine, iElementPatchFine) Q = np.column_stack(self.fsi.correctorsList) QT = Q[TFinepStartIndex + TFinepIndexMap, :] A = np.dot((P - QT).T, TNorm * (P - QT)) + np.dot(Q.T, PatchNorm * Q) B = np.dot(P.T, BNorm * P) eigenvalues = scipy.linalg.eigvals(A[:-1, :-1], B[:-1, :-1]) epsilonTSquare = np.max(np.real(eigenvalues)) return np.sqrt(epsilonTSquare)
def assemblePatchBoundaryMatrix(NPatch, CLocGetter, aPatch=None, boundaryMap=None): # Integral over part of boundary can be implemented by adding an # input "chi" as an indicator function to be callable with edge # midpoints as inputs. d = np.size(NPatch) Np = np.prod(NPatch + 1) Nt = np.prod(NPatch) if aPatch is None: aPatch = np.ones(Nt) if boundaryMap is None: boundaryMap = np.ones([d, 2], dtype='bool') rows = [] cols = [] values = [] # Loop through each dimension for k in range(d): NEdge = NPatch.copy() NEdge[k] = 1 edgeElementInd0 = util.lowerLeftpIndexMap(NEdge - 1, NPatch - 1) rows0, cols0 = localToPatchSparsityPattern(NPatch, NSubPatch=NEdge) for neg in [False, True]: if boundaryMap[k][int(neg)]: CLoc = CLocGetter(k, neg) if not neg: edgeElementIndneg = edgeElementInd0 rowsneg = rows0 colsneg = cols0 else: pointIndexDisplacement = int( np.prod(NPatch[:k] + 1) * (NPatch[k] - 1)) elementIndexDisplacement = int( np.prod(NPatch[:k]) * (NPatch[k] - 1)) edgeElementIndneg = edgeElementInd0 + elementIndexDisplacement rowsneg = rows0 + pointIndexDisplacement colsneg = cols0 + pointIndexDisplacement valuesneg = np.kron(aPatch[edgeElementIndneg], CLoc.flatten()) rows = np.hstack([rows, rowsneg]) cols = np.hstack([cols, colsneg]) values = np.hstack([values, valuesneg]) APatch = sparse.csc_matrix((values, (rows, cols)), shape=(Np, Np)) APatch.eliminate_zeros() return APatch
def localize(self, iSubPatchCoarse, NSubPatchCoarse): NPatchCoarse = self.NPatchCoarse NCoarseElement = self.NCoarseElement NPatchFine = NPatchCoarse*NCoarseElement NSubPatchFine = NSubPatchCoarse*NCoarseElement iSubPatchFine = iSubPatchCoarse*NCoarseElement # a coarsetIndexMap = util.lowerLeftpIndexMap(NSubPatchFine-1, NPatchFine-1) coarsetStartIndex = util.convertpCoordinateToIndex(NPatchFine-1, iSubPatchFine) aFineLocalized = self._aFine[coarsetStartIndex + coarsetIndexMap] localizedCoefficient = coefficientFine(NSubPatchCoarse, NCoarseElement, aFineLocalized) return localizedCoefficient
def faceElementPointIndices(NPatchCoarse, NCoarseElement, k, boundary): '''Return indices of points in fine elements adjacent to face (k, boundary) for all coarse triangles Return type shape: (NtCoarse, Number of elements of face, 2**d) ''' NPatchFine = NPatchCoarse*NCoarseElement tIndices = faceElementIndices(NPatchCoarse, NCoarseElement, k, boundary) tpIndexMap = util.lowerLeftpIndexMap(NPatchFine-1, NPatchFine) elementpIndices = util.elementpIndexMap(NPatchFine) pIndices = np.add.outer(tpIndexMap[tIndices], elementpIndices) return pIndices
def computeJumps(NWorldCoarse, quantityT): d = np.size(NWorldCoarse) b = util.linearpIndexBasis(NWorldCoarse-1) jumpTF = np.tile(quantityT[...,None], [1, 2*d]) for k in range(d): NWorldBase = np.array(NWorldCoarse) NWorldBase[k] -= 1 TIndBase = util.lowerLeftpIndexMap(NWorldBase-1, NWorldCoarse-1) jump = quantityT[TIndBase] - quantityT[TIndBase + b[k]] jumpTF[TIndBase, 2*k + 1] = jump jumpTF[TIndBase + b[k], 2*k] = -jump return jumpTF
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 computeAverageFaceFlux(NWorldCoarse, fluxTF): # Note I: these velocities are not conservative and do not fulfill # strongly with Neumann boundary conditions # # Note II: the velocities are integrated and hence already scaled with face # area d = np.size(NWorldCoarse) b = util.linearpIndexBasis(NWorldCoarse-1) avgFluxTF = np.array(fluxTF) for k in range(d): NWorldBase = np.array(NWorldCoarse-1) NWorldBase[k] -= 1 TIndBase = util.lowerLeftpIndexMap(NWorldBase, NWorldCoarse-1) avg = 0.5*(fluxTF[TIndBase, 2*k + 1] - fluxTF[TIndBase + b[k], 2*k]) avgFluxTF[TIndBase, 2*k + 1] = avg avgFluxTF[TIndBase + b[k], 2*k] = -avg return avgFluxTF
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 computeElementFaceFluxFromSigma(NWorldCoarse, sigmaFluxT): d = np.size(NWorldCoarse) NtCoarse = np.prod(NWorldCoarse) fluxTF = np.zeros([NtCoarse, 2*d]) pBasis = util.linearpIndexBasis(np.ones_like(NWorldCoarse)) for k in range(d): N = np.ones_like(NWorldCoarse) N[k] = 0 bottomp = util.lowerLeftpIndexMap(N, np.ones_like(N)) topp = bottomp + pBasis[k] NFace = np.array(NWorldCoarse) NFace[k] = 1 faceArea = np.prod(1./NFace) fluxTF[:,2*k] = faceArea*np.mean(-sigmaFluxT[:,bottomp], axis=1) fluxTF[:,2*k + 1] = faceArea*np.mean(-sigmaFluxT[:,topp], axis=1) return fluxTF
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)
def assembleFaceConnectivityMatrix(NPatch, FLoc, boundaryMap=None): Nt = np.prod(NPatch) d = np.size(NPatch) if boundaryMap is None: boundaryMap = np.zeros([d, 2], dtype='bool') rowsList = [] colsList = [] valuesList = [] tBasis = util.linearpIndexBasis(NPatch - 1) for k in range(d): for boundary in [0, 1]: NPatchBase = np.array(NPatch) NPatchBase[k] -= 1 TIndInterior = (1 - boundary) * tBasis[k] + util.lowerLeftpIndexMap( NPatchBase - 1, NPatch - 1) nT = np.size(TIndInterior) FLocRepeated = np.repeat(FLoc[2 * k + boundary], nT) # Add diagonal elements rowsList.append(TIndInterior) colsList.append(TIndInterior) valuesList.append(FLocRepeated) # Add off-diagonal elements rowsList.append(TIndInterior + (2 * boundary - 1) * tBasis[k]) colsList.append(TIndInterior) valuesList.append(-FLocRepeated / 2.) rowsList.append(TIndInterior) colsList.append(TIndInterior + (2 * boundary - 1) * tBasis[k]) valuesList.append(-FLocRepeated / 2.) # Add boundary diagonal elements, if applies if boundaryMap[k, boundary]: NPatchBottom = np.array(NPatch) NPatchBottom[k] = 1 TIndBoundary = (boundary)*tBasis[k]*(NPatch[k]-1) + \ util.lowerLeftpIndexMap(NPatchBottom-1, NPatch-1) nT = np.size(TIndBoundary) FLocRepeatedBoundary = np.repeat(FLoc[2 * k + boundary], nT) rowsList.append(TIndBoundary) colsList.append(TIndBoundary) valuesList.append(FLocRepeatedBoundary) # Concatenate lists rows = np.hstack(rowsList) cols = np.hstack(colsList) values = np.hstack(valuesList) # Create sparse matrix FC = sparse.csc_matrix((values, (rows, cols)), shape=(Nt, Nt)) return FC
def applyNeumannBoundaryConditionsOneSide(fluxTF, k, boundary): stepToFace = (boundary)*tBasis[k]*(NWorldCoarse[k]-1) NWorldBottom = np.array(NWorldCoarse) NWorldBottom[k] = 1 TIndBoundary = stepToFace + util.lowerLeftpIndexMap(NWorldBottom-1, NWorldCoarse-1) fluxTF[TIndBoundary, 2*k+boundary] = 0