def invert_cq1_mapping(N, mapping): """Invert a y = psi(x) CQ1 mapping using the iterative method "A simple fixed-point approach to invert a deformation field", Chen et al 2008. """ coords = util.pCoordinates(N) displace = mapping - coords inv_displace = np.zeros_like(displace) max_iter = 100 iter = 0 tolerance = 1e-7 error = 1 while iter < max_iter and error > tolerance: inv_displace_previous = inv_displace points = np.maximum(0, np.minimum(1.0, coords + inv_displace)) inv_displace = -func.evaluateCQ1(N, displace, points) iter += 1 error = np.max(np.abs(inv_displace - inv_displace_previous)) return inv_displace + coords
def evaluateSolution(self, u): NFine = self.world.NWorldFine xpFine = util.pCoordinates(NFine) xpFine_ref = self.psi.inverse_evaluate(xpFine) return func.evaluateCQ1(NFine, u, xpFine_ref)
def test_evaluateCQ1_1d(self): N = np.array([3]) cq1 = np.array([10, 20, 25, 0]) x = np.array([[0], [1./6], [0.5], [2./3], [1.0]]) cq1OfX = func.evaluateCQ1(N, cq1, x) cq1ShouldBe = np.array([10, 15, 22.5, 25, 0]) self.assertTrue(np.allclose(cq1OfX, cq1ShouldBe))
def test_evaluateCQ1_2d(self): N = np.array([3, 2]) cq1 = np.array([10, 10, 30, 30, 60, 60, 80, 80, 60, 60, 90, 100]) x = np.array([[0.1, 0.1], [0.9, 0.1], [0.5, 0.5], [0.0, 0.0], [1.0, 1.0], [5./6, 1.0], [5./6, .75]]) cq1OfX = func.evaluateCQ1(N, cq1, x) cq1ShouldBe = np.array([20, 40, 70, 10, 100, 95, 87.5]) self.assertTrue(np.allclose(cq1OfX, cq1ShouldBe))
def computeTransformation(self, aFine, f_ref): assert (len(aFine) == np.prod(self.world.NWorldFine)) assert (len(f_ref) == np.prod(self.world.NWorldFine + 1)) assert (self.psi) psi = self.psi NFine = self.world.NWorldFine xtFine = util.tCoordinates(NFine) a_trans = np.einsum('tij, t, tkj, t -> tik', psi.Jinv(xtFine), aFine, psi.Jinv(xtFine), psi.detJ(xtFine)) xpFine = util.pCoordinates(NFine) xpFine_pert = self.psi.evaluate(xpFine) f_trans = func.evaluateCQ1(NFine, f_ref, xpFine_pert) f_trans = np.einsum('t, t -> t', f_trans, psi.detJ(xpFine_pert)) return a_trans, f_trans
def create_psi_function(): cq1 = np.zeros((int(fine) + 1, int(fine) + 1)) for c in range(number_of_channels): count = 0 for i in range(np.size(ref_array)): if ref_array[i] == 1: count += 1 if count == (c + 1) * thick: begin = i + 1 - space // 2 end = i + 1 + thick + space // 2 break increasing_length = (end - begin) // 2 - thick - 1 constant_length = (end - begin) - increasing_length * 2 epsilon = np.random.binomial(increasing_length - 2, 0.2) minus = random.sample([-1, 1], 1)[0] epsilon *= minus #epsilon = random.sample(list(np.arange(-increasing_length+3,increasing_length-2,1)), 1)[0] #print(epsilon) maximal_walk = increasing_length * walk_with_perturbation walk = epsilon * walk_with_perturbation for i in range(increasing_length): cq1[:, begin + 1 + i] = (i + 1) / increasing_length * walk cq1[:, begin + increasing_length + i + constant_length] = walk - (i + 1) / increasing_length * walk for i in range(constant_length): cq1[:, begin + increasing_length + i] = walk cq1 = cq1.flatten() alpha = 1. for_mapping = np.stack( (xpFine[:, 0] + alpha * func.evaluateCQ1(Nmapping, cq1, xpFine), xpFine[:, 1]), axis=1) psi = discrete_mapping.MappingCQ1(NFine, for_mapping) return psi, cq1
def Monte_Carlo_simulation(): print('Computing Monte Carlo step') global aFine_ref global aFine_trans global aFine_pert global k global KmsijT global correctorsListT aFine_ref = aFine_ref_shaped.flatten() psi, cq1 = create_psi_function() # plt.figure('domain mapping') # plt.plot(np.arange(0, fine + 1), cq1[0, :], label='$id(x) - \psi(x)$') # plt.plot(np.arange(0, fine), ref_array * 0.01) # plt.title('Domain mapping') # plt.legend() xpFine_pert = psi.evaluate(xpFine) xpFine_ref = psi.inverse_evaluate(xpFine) xtFine_pert = psi.evaluate(xtFine) xtFine_ref = psi.inverse_evaluate(xtFine) aFine_pert = func.evaluateDQ0(NFine, aFine_ref, xtFine_ref) aBack_ref = func.evaluateDQ0(NFine, aFine_pert, xtFine_pert) print('Psi is invertible if this is zero: {}'.format( np.linalg.norm(aBack_ref - aFine_ref))) every_psi_was_valid.append(np.linalg.norm(aBack_ref - aFine_ref)) #aFine_trans is the transformed perturbed reference coefficient aFine_trans = np.einsum('tji, t, tkj, t -> tik', psi.Jinv(xtFine), aFine_ref, psi.Jinv(xtFine), psi.detJ(xtFine)) f_pert = np.ones(np.prod(NFine + 1)) f_ref = func.evaluateCQ1(NFine, f_pert, xpFine_pert) f_trans = np.einsum('t, t -> t', f_ref, psi.detJ(xpFine)) uFineFull_pert, AFine_pert, MFine = femsolver.solveFine( world, aFine_pert, f_pert, None, boundaryConditions) uFineFull_trans, AFine_trans, _ = femsolver.solveFine( world, aFine_trans, f_trans, None, boundaryConditions) uFineFull_trans_pert = func.evaluateCQ1(NFine, uFineFull_trans, xpFine_ref) energy_norm = np.sqrt(np.dot(uFineFull_pert, AFine_pert * uFineFull_pert)) energy_error = np.sqrt( np.dot((uFineFull_trans_pert - uFineFull_pert), AFine_pert * (uFineFull_trans_pert - uFineFull_pert))) print("Energy norm {}, error {}, rel. error {}".format( energy_norm, energy_error, energy_error / energy_norm)) Aeye = np.tile(np.eye(2), [np.prod(NFine), 1, 1]) aFine_ref = np.einsum('tji, t-> tji', Aeye, aFine_ref) print('compute domain mapping error indicators') epsFine, epsCoarse = zip(*map(computeIndicators, range(world.NtCoarse))) print('apply tolerance') Elements_to_be_updated = [] TOL = 0.1 for i in range(world.NtCoarse): if epsFine[i] >= TOL: Elements_to_be_updated.append(i) print('.... to be updated for domain mapping: {}%'.format( np.size(Elements_to_be_updated) / np.size(epsFine) * 100)) print('update correctors') if np.size(Elements_to_be_updated) == 0: correctorsListTNew, KmsijTNew = correctorsListT, KmsijT else: patchT_irrelevant, correctorsListTNew, KmsijTNew, csiTNew = zip( *map(UpdateCorrectors, Elements_to_be_updated)) KmsijT_list = list(KmsijT) correctorsListT_list = list(correctorsListT) i = 0 for T in Elements_to_be_updated: KmsijT_list[T] = KmsijTNew[i] correctorsListT_list[T] = correctorsListTNew[i] i += 1 KmsijT = tuple(KmsijT_list) correctorsListT = tuple(correctorsListT_list) print('solve the system') KFull = pglod.assembleMsStiffnessMatrix(world, patchT, KmsijT) MFull = fem.assemblePatchMatrix(NFine, world.MLocFine) basis = fem.assembleProlongationMatrix(NWorldCoarse, NCoarseElement) basisCorrectors = pglod.assembleBasisCorrectors(world, patchT, correctorsListT) modifiedBasis = basis - basisCorrectors bFull = MFull * f_trans bFull = basis.T * bFull uFull, _ = pglod.solve(world, KFull, bFull, boundaryConditions) uLodFine = modifiedBasis * uFull uLodFine_METHOD = uLodFine newErrorFine = np.sqrt( np.dot(uLodFine - uFineFull_trans, AFine_trans * (uLodFine - uFineFull_trans))) print('Method error: {}'.format(newErrorFine)) print('update all correctors') patchT_irrelevant, correctorsListT, KmsijT, csiTNew = zip( *map(UpdateCorrectors, range(world.NtCoarse))) print('solve the system') KFull = pglod.assembleMsStiffnessMatrix(world, patchT, KmsijT) MFull = fem.assemblePatchMatrix(NFine, world.MLocFine) basis = fem.assembleProlongationMatrix(NWorldCoarse, NCoarseElement) basisCorrectors = pglod.assembleBasisCorrectors(world, patchT, correctorsListT) modifiedBasis = basis - basisCorrectors bFull = MFull * f_trans bFull = basis.T * bFull uFull, _ = pglod.solve(world, KFull, bFull, boundaryConditions) uLodFine = modifiedBasis * uFull newErrorFine = np.sqrt( np.dot(uLodFine - uFineFull_trans, AFine_trans * (uLodFine - uFineFull_trans))) print('Exact LOD error: {}'.format(newErrorFine)) return uLodFine_METHOD, uLodFine, uFineFull_pert, MFine
def inverse_evaluate(self, x): return func.evaluateCQ1(self.N, self.inv_mapping, x)
def evaluate(self, x): return func.evaluateCQ1(self.N, self.mapping, x)
def create(self): NFine = self.world.NWorldFine fine = NFine[0] xpFine = util.pCoordinates(NFine) number_of_perturbed_channels = 4 now = 0 count = 0 for i in range(np.size(self.ref_array)): if self.ref_array[i] == 1: count += 1 if count == 8 * self.thick: # at the 8ths shape (which is the last dot in one line, the cq starts) begin = i + 1 break count = 0 for i in range(np.size(self.ref_array)): if self.ref_array[i] == 1: count += 1 if count == 13 * self.thick - 3: # it ends after the last channel end = i break # Discrete mapping Nmapping = np.array([int(fine), int(fine)]) cq1 = np.zeros((int(fine) + 1, int(fine) + 1)) # I only want to perturb on the fine mesh. size_of_an_element = 1. / fine walk_with_perturbation = size_of_an_element channels_position_from_zero = self.space channels_end_from_zero = channels_position_from_zero + self.thick # The next only have the purpose to make the psi invertible. increasing_length = (end - begin) // (number_of_perturbed_channels + 1) - self.thick - 2 constant_length = (end - begin) - increasing_length * 2 maximum_walk = (increasing_length - 6) * walk_with_perturbation walk_with_perturbation = maximum_walk for i in range(increasing_length): cq1[:, begin + 1 + i] = (i + 1) / increasing_length * walk_with_perturbation cq1[:, begin + increasing_length + i + constant_length] = walk_with_perturbation - ( i + 1) / increasing_length * walk_with_perturbation for i in range(constant_length): cq1[:, begin + increasing_length + i] = walk_with_perturbation # Check what purtubation I have if self.plot_mapping: plt.figure('DomainMapping') plt.plot(np.arange(0, fine + 1), cq1[self.space, :], label='$id(x) - \psi(x)$') plt.title('Domain mapping') plt.legend() cq1 = cq1.flatten() xpFine = util.pCoordinates(NFine) alpha = 1. for_mapping = np.stack( (xpFine[:, 0] + alpha * func.evaluateCQ1(Nmapping, cq1, xpFine), xpFine[:, 1]), axis=1) self.psi = discrete_mapping.MappingCQ1(NFine, for_mapping)
def create(self): NFine = self.world.NWorldFine fine = NFine[0] xpFine = util.pCoordinates(NFine) Nmapping = np.array([int(fine), int(fine)]) size_of_an_element = 1. / fine print('the size of a fine element is {}'.format(size_of_an_element)) walk_with_perturbation = size_of_an_element epsilonT = [] cq1 = np.zeros((int(fine) + 1, int(fine) + 1)) random.seed(20) cs = np.random.randint(0, 2, self.number_of_channels) cs = [c * random.sample([-1, 1], 1)[0] for c in cs] ## or manually cs[2] = 0 cs[3] = -1 cs[4] = 0 cs[5] = 0 print(cs) last_value = 0 for i, c in enumerate(cs): platform = self.space // 2 + 2 * self.thick begin = platform // 2 + i * (self.space + self.thick) end = begin + self.space - platform + self.thick epsilon = c * walk_with_perturbation epsilonT.append(epsilon) walk = epsilon - last_value constant_length = platform + self.thick increasing_length = end - begin for i in range(increasing_length): cq1[:, begin + i] = last_value + (i + 1) / increasing_length * walk for i in range(constant_length): cq1[:, begin + increasing_length + i] = epsilon last_value = epsilon # ending begin += self.space + self.thick end = begin + self.space - platform + self.thick epsilon = 0 walk = epsilon - last_value increasing_length = end - begin for i in range(increasing_length): cq1[:, begin + i] = last_value + (i + 1) / increasing_length * walk if self.plot_mapping: plt.plot(np.arange(0, fine + 1), cq1[self.space, :], label='$id(x) - \psi(x)$') plt.title('Domain mapping') plt.legend() plt.show() print('These are the results of the shift epsilon', epsilonT) cq1 = cq1.flatten() alpha = 1. for_mapping = np.stack( (xpFine[:, 0] + alpha * func.evaluateCQ1(Nmapping, cq1, xpFine), xpFine[:, 1]), axis=1) self.psi = discrete_mapping.MappingCQ1(NFine, for_mapping)
def helmholtz_nonlinear_adaptive(mapper, fineLvl, coarseLvl, maxit): fineExp = fineLvl NFine = np.array([2**fineLvl, 2**fineLvl]) NpFine = np.prod(NFine + 1) N = 2**coarseLvl tolList = [2.0, 1.0, 0.5, 0.25, 0.125, 0.0625, 0.] ell = 2 # localization parameter k = 15. # wavenumber maxit_Fine = 200 xt = util.tCoordinates(NFine) xp = util.pCoordinates(NFine) # multiscale coefficients on the scale NFine-2 np.random.seed(444) sizeK = np.size(xt[:, 0]) nFine = NFine[0] # determine domain D_eps = supp(1-n) = supp(1-A) (all equal for the moment) indicesIn = (xt[:, 0] > 0.15) & (xt[:, 0] < 0.85) & (xt[:, 1] > 0.15) & ( xt[:, 1] < 0.85) indicesInEps = (xt[:, 0] > 0.15) & (xt[:, 0] < 0.85) & ( xt[:, 1] > 0.15) & (xt[:, 1] < 0.85) # coefficients aFine = np.ones(xt.shape[0]) cn = .05 # lower bound on n Cn = 1. # upper bound on n nEpsPro = coeffi(xt[:, 0], xt[:, 1], fineLvl) k2Fine = k**2 * np.ones(xt.shape[0]) k2Fine[indicesIn] = k**2 * ((Cn - cn) * nEpsPro[indicesIn] + cn) kFine = k * np.ones(xt.shape[0]) Ceps = 0.3 # upper bound on eps (lower bound is 0) epsEpsPro = np.ones(sizeK) epsFine = np.zeros(xt.shape[0]) epsFine[indicesInEps] = Ceps * epsEpsPro[indicesInEps] # 0 OR Ceps plotC = np.ones(sizeK) plotC[indicesIn] = nEpsPro[indicesIn] drawCoefficient(NFine, plotC) xC = xp[:, 0] yC = xp[:, 1] # define right-hand side and boundary condition def funcF(x, y): res = 100 * np.ones(x.shape, dtype='complex128') return res f = funcF(xC, yC) # reference solution uSol = np.zeros(NpFine, dtype='complex128') # boundary conditions boundaryConditions = np.array([[1, 1], [1, 1]]) worldFine = World(NFine, np.array([1, 1]), boundaryConditions) # fine matrices BdFineFEM = fem.assemblePatchBoundaryMatrix( NFine, fem.localBoundaryMassMatrixGetter(NFine)) MFineFEM = fem.assemblePatchMatrix(NFine, fem.localMassMatrix(NFine)) KFineFEM = fem.assemblePatchMatrix( NFine, fem.localStiffnessMatrix(NFine)) # , aFine) kBdFine = fem.assemblePatchBoundaryMatrix( NFine, fem.localBoundaryMassMatrixGetter(NFine), kFine) KFine = fem.assemblePatchMatrix(NFine, fem.localStiffnessMatrix(NFine), aFine) print('***computing reference solution***') uOldFine = np.zeros(NpFine, dtype='complex128') for it in np.arange(maxit_Fine): print('-- itFine = %d' % it) knonlinUpreFine = np.abs(uOldFine) knonlinUFine = func.evaluateCQ1(NFine, knonlinUpreFine, xt) k2FineUfine = np.copy(k2Fine) k2FineUfine[indicesInEps] *= ( 1. + epsFine[indicesInEps] * knonlinUFine[indicesInEps]**2 ) # full coefficient, including nonlinearity k2MFine = fem.assemblePatchMatrix( NFine, fem.localMassMatrix(NFine), k2FineUfine) # weighted mass matrix, updated in every iteration nodesFine = np.arange(worldFine.NpFine) fixFine = util.boundarypIndexMap(NFine, boundaryConditions == 0) freeFine = np.setdiff1d(nodesFine, fixFine) # right-hand side fhQuad = MFineFEM * f # fine system lhsh = KFine[freeFine][:, freeFine] - k2MFine[ freeFine][:, freeFine] + 1j * kBdFine[freeFine][:, freeFine] rhsh = fhQuad[freeFine] xFreeFine = sparse.linalg.spsolve(lhsh, rhsh) xFullFine = np.zeros(worldFine.NpFine, dtype='complex128') xFullFine[freeFine] = xFreeFine uOldFine = np.copy(xFullFine) # residual - used as stopping criterion knonlinU = np.abs(uOldFine) knonlinUFineIt = func.evaluateCQ1(NFine, knonlinU, xt) k2FineUfineIt = np.copy(k2Fine) k2FineUfineIt[indicesInEps] *= ( 1. + epsFine[indicesInEps] * knonlinUFineIt[indicesInEps]**2 ) # update full coefficient, including nonlinearity k2MFineIt = fem.assemblePatchMatrix(NFine, fem.localMassMatrix(NFine), k2FineUfineIt) Ares = KFine - k2MFineIt + 1j * kBdFine residual = np.linalg.norm(Ares * xFullFine - fhQuad) / np.linalg.norm( Ares * xFullFine) print('---- residual = %.4e' % residual) if residual < 1e-12: break # stopping criterion uSol = xFullFine # final fine reference solution print('***reference solution computed***\n') counter = 0 # for figures print('***computing multiscale approximations***') relErrEnergy = np.zeros([len(tolList), maxit]) for tol in tolList: counter += 1 print('H = %.4e, tol = %.4e' % (1. / N, tol)) NWorldCoarse = np.array([N, N]) NCoarseElement = NFine // NWorldCoarse world = World(NWorldCoarse, NCoarseElement, boundaryConditions) NpCoarse = np.prod(NWorldCoarse + 1) uOldUps = np.zeros(NpFine, dtype='complex128') for it in np.arange(maxit): print('-- it = %d:' % it) knonlinUpre = np.abs(uOldUps) knonlinU = func.evaluateCQ1(NFine, knonlinUpre, xt) k2FineU = np.copy(k2Fine) k2FineU[indicesInEps] *= ( 1. + epsFine[indicesInEps] * knonlinU[indicesInEps]**2) print('---- starting computation of correctors') def computeLocalContribution(TInd): patch = Patch(world, ell, TInd) IPatch = lambda: interp.L2ProjectionPatchMatrix( patch, boundaryConditions) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) correctorsList = lod.computeBasisCorrectors_helmholtz( patch, IPatch, aPatch, kPatch, k2Patch) # adapted for Helmholtz setting csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctorsList, aPatch, kPatch, k2Patch) # adapted for Helmholtz setting return patch, correctorsList, csi.Kmsij, csi.Mmsij, csi.Bdmsij, csi.muTPrime def computeIndicators(TInd): k2FineUPatch = lambda: coef.localizeCoefficient( patchT[TInd], k2FineU) k2FineUOldPatch = lambda: coef.localizeCoefficient( patchT[TInd], k2FineUOld) E_vh = lod.computeErrorIndicatorCoarse_helmholtz( patchT[TInd], muTPrime[TInd], k2FineUOldPatch, k2FineUPatch) return E_vh def UpdateCorrectors(TInd): patch = Patch(world, ell, TInd) IPatch = lambda: interp.L2ProjectionPatchMatrix( patch, boundaryConditions) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) correctorsList = lod.computeBasisCorrectors_helmholtz( patch, IPatch, aPatch, kPatch, k2Patch) csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctorsList, aPatch, kPatch, k2Patch) # adapted for Helmholtz setting return patch, correctorsList, csi.Kmsij, csi.Mmsij, csi.Bdmsij, csi.muTPrime def UpdateElements(tol, E, Kmsij_old, Mmsij_old, Bdmsij_old, correctors_old, mu_old): print('---- apply tolerance') Elements_to_be_updated = [] for (i, eps) in E.items(): if eps > tol * k**2: Elements_to_be_updated.append(i) if len(E) > 0: print( '---- percentage of non-zero element correctors to be updated: %.4f' % (100 * np.size(Elements_to_be_updated) / len(E)), flush=True) print( '---- total percentage of element correctors to be updated: %.4f' % (100 * np.size(Elements_to_be_updated) / len(mu_old)), flush=True) print('---- update local contributions') KmsijT_list = list(np.copy(Kmsij_old)) MmsijT_list = list(np.copy(Mmsij_old)) BdmsijT_list = list(np.copy(Bdmsij_old)) muT_list = np.copy(mu_old) for T in np.setdiff1d(range(world.NtCoarse), Elements_to_be_updated): patch = Patch(world, ell, T) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctors_old[T], aPatch, kPatch, k2Patch) KmsijT_list[T] = csi.Kmsij MmsijT_list[T] = csi.Mmsij BdmsijT_list[T] = csi.Bdmsij muT_list[T] = csi.muTPrime if np.size(Elements_to_be_updated) != 0: #print('---- update correctors') patchT_irrelevant, correctorsListTNew, KmsijTNew, MmsijTNew, BdmsijTNew, muTPrimeNew = zip( *mapper(UpdateCorrectors, Elements_to_be_updated)) #print('---- update correctorsList') correctorsListT_list = list(np.copy(correctors_old)) i = 0 for T in Elements_to_be_updated: KmsijT_list[T] = KmsijTNew[i] correctorsListT_list[T] = correctorsListTNew[i] MmsijT_list[T] = MmsijTNew[i] BdmsijT_list[T] = BdmsijTNew[i] muT_list[T] = muTPrimeNew[i] i += 1 KmsijT = tuple(KmsijT_list) correctorsListT = tuple(correctorsListT_list) MmsijT = tuple(MmsijT_list) BdmsijT = tuple(BdmsijT_list) muTPrime = tuple(muT_list) return correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime else: KmsijT = tuple(KmsijT_list) MmsijT = tuple(MmsijT_list) BdmsijT = tuple(BdmsijT_list) muTPrime = tuple(muT_list) return correctors_old, KmsijT, MmsijT, BdmsijT, muTPrime if it == 0: patchT, correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime = zip( *mapper(computeLocalContribution, range(world.NtCoarse))) else: E_vh = list(mapper(computeIndicators, range(world.NtCoarse))) print( '---- maximal value error estimator for basis correctors {}' .format(np.max(E_vh))) E = {i: E_vh[i] for i in range(np.size(E_vh)) if E_vh[i] > 0} # loop over elements with possible recomputation of correctors correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime = UpdateElements( tol, E, KmsijT, MmsijT, BdmsijT, correctorsListT, muTPrime) # tol scaled by maximal error indicator print('---- finished computation of correctors') KLOD = pglod.assembleMsStiffnessMatrix( world, patchT, KmsijT) # ms stiffness matrix k2MLOD = pglod.assembleMsStiffnessMatrix(world, patchT, MmsijT) # ms mass matrix kBdLOD = pglod.assembleMsStiffnessMatrix( world, patchT, BdmsijT) # ms boundary matrix MFEM = fem.assemblePatchMatrix(NWorldCoarse, world.MLocCoarse) BdFEM = fem.assemblePatchBoundaryMatrix( NWorldCoarse, fem.localBoundaryMassMatrixGetter(NWorldCoarse)) print('---- coarse matrices assembled') nodes = np.arange(world.NpCoarse) fix = util.boundarypIndexMap(NWorldCoarse, boundaryConditions == 0) free = np.setdiff1d(nodes, fix) assert (nodes.all() == free.all()) # compute global interpolation matrix patchGlobal = Patch(world, NFine[0] + 2, 0) IH = interp.L2ProjectionPatchMatrix(patchGlobal, boundaryConditions) assert (IH.shape[0] == NpCoarse) basis = fem.assembleProlongationMatrix(NWorldCoarse, NCoarseElement) fHQuad = basis.T * MFineFEM * f print('---- solving coarse system') # coarse system lhsH = KLOD[free][:, free] - k2MLOD[ free][:, free] + 1j * kBdLOD[free][:, free] rhsH = fHQuad[free] xFree = sparse.linalg.spsolve(lhsH, rhsH) basisCorrectors = pglod.assembleBasisCorrectors( world, patchT, correctorsListT) modifiedBasis = basis - basisCorrectors xFull = np.zeros(world.NpCoarse, dtype='complex128') xFull[free] = xFree uLodCoarse = basis * xFull uLodFine = modifiedBasis * xFull uOldUps = np.copy(uLodFine) k2FineUOld = np.copy(k2FineU) Err = np.sqrt( np.dot((uSol - uLodFine).conj(), KFineFEM * (uSol - uLodFine)) + k**2 * np.dot((uSol - uLodFine).conj(), MFineFEM * (uSol - uLodFine))) ErrEnergy = Err / np.sqrt( np.dot((uSol).conj(), KFineFEM * (uSol)) + k**2 * np.dot((uSol).conj(), MFineFEM * (uSol))) print('---- ', np.abs(ErrEnergy), '\n***********************************************') # save errors in arrays relErrEnergy[counter - 1, it] = ErrEnergy print('\n') its = np.arange(1, maxit + 1) plt.figure(1) plt.title( 'Relative energy errors w.r.t iterations for different tolerances - Ex 3' ) plt.plot(its, relErrEnergy[0, :], 'x--', color='black', label='tol = 2') plt.plot(its, relErrEnergy[1, :], 'x-', color='blue', label='tol = 1') plt.plot(its, relErrEnergy[2, :], 'x-', color='green', label='tol = 0.5') plt.plot(its, relErrEnergy[3, :], 'x-', color='orange', label='tol = 0.25') plt.plot(its, relErrEnergy[4, :], 'x-', color='red', label='tol = 0.125') plt.plot(its, relErrEnergy[5, :], 'x-', color='magenta', label='tol = 0.0625') plt.plot(its, relErrEnergy[6, :], 'x--', color='black', label='tol = 0') plt.yscale('log') plt.legend() plt.show()
def helmholtz_nonlinear_adaptive(mapper, fineLvl, maxCoarseLvl, maxit): NFine = np.array([2**fineLvl, 2**fineLvl]) NpFine = np.prod(NFine + 1) NList = 2**np.arange(1, maxCoarseLvl + 1) ell = 2 # localization parameter k = 30. # wavenumber maxit_Fine = 250 tol = 0.5 # coupled to maximal error indicator xt = util.tCoordinates(NFine) xp = util.pCoordinates(NFine) # multiscale coefficients on the scale NFine-2 np.random.seed(123) sizeK = np.size(xt[:, 0]) nFine = NFine[0] # determine domain D_eps = supp(1-n) = supp(1-A) (all equal for this experiment) indicesIn = (xt[:, 0] > 0.25) & (xt[:, 0] < 0.75) & (xt[:, 1] > 0.25) & ( xt[:, 1] < 0.75) indicesInEps = (xt[:, 0] > 0.25) & (xt[:, 0] < 0.75) & ( xt[:, 1] > 0.25) & (xt[:, 1] < 0.75) # coefficients cA = .2 # lower bound on A CA = 1. # upper bound on A aEps = np.random.uniform(0, 1, sizeK // 16) aEpsPro = np.zeros(sizeK) for i in range((nFine) // 4): aEpsPro[4 * i * (nFine):4 * (i + 1) * (nFine)] = np.tile( np.repeat(aEps[i * (nFine) // 4:(i + 1) * (nFine) // 4], 4), 4) aFine = np.ones(xt.shape[0]) aFine[indicesIn] = (CA - cA) * aEpsPro[indicesIn] + cA cn = 1. # lower bound on n Cn = 1. # upper bound on n nEps = np.random.uniform(0, 1, sizeK // 16) nEpsPro = np.zeros(sizeK) for i in range((nFine) // 4): nEpsPro[4 * i * (nFine):4 * (i + 1) * (nFine)] = np.tile( np.repeat(nEps[i * (nFine) // 4:(i + 1) * (nFine) // 4], 4), 4) k2Fine = k**2 * np.ones(xt.shape[0]) k2Fine[indicesIn] = k**2 * ((Cn - cn) * nEpsPro[indicesIn] + cn) kFine = k * np.ones(xt.shape[0]) Ceps = .85 # upper bound on eps (lower bound is 0) lvl = 4 epsEps = np.random.randint(2, size=(sizeK // lvl**2)) epsEpsPro = np.zeros(sizeK) for i in range((nFine) // lvl): epsEpsPro[lvl * i * (nFine):lvl * (i + 1) * (nFine)] = np.tile( np.repeat(epsEps[i * (nFine) // lvl:(i + 1) * (nFine) // lvl], lvl), lvl) epsFine = np.zeros(xt.shape[0]) epsFine[indicesInEps] = Ceps * epsEpsPro[indicesInEps] # 0 OR Ceps drawCoefficient(NFine, epsFine) xC = xp[:, 0] yC = xp[:, 1] fact = 100. mult = .8 a = .5 b = .25 k2 = 30. # define right-hand side and boundary condition def funcF(x, y): res = mult * (-np.exp(-1.j * k2 * (a * x - b)) * (2 * a**2 * fact**2 * np.sinh(fact * (a * x - b))**2 / (np.cosh(fact * (a * x - b)) + 1)**3 - a**2 * fact**2 * np.cosh(fact * (a * x - b)) / (np.cosh(fact * (a * x - b)) + 1)**2) + a**2 * k2**2 * np.exp(-1.j * k2 * (a * x - b)) / (np.cosh(fact * (a * x - b)) + 1) - 2.j * a**2 * fact * k2 * np.exp(-1.j * k2 * (a * x - b)) * np.sinh(fact * (a * x - b)) / (np.cosh(fact * (a * x - b)) + 1)**2 - k**2 * np.exp(-1.j * k2 * (a * x - b)) / (np.cosh(fact * (a * x - b)) + 1)) return res f = funcF(xC, yC) g = np.zeros(NpFine, dtype='complex128') # bottom boundary g[0:(NFine[0] + 1)] = mult * 1.j * k * 1. / (np.cosh(fact * (a * xC[0:(NFine[0] + 1)] - b)) + 1) * np.exp( -1.j * k2 * (a * xC[0:(NFine[0] + 1)] - b)) # top boundary g[(NpFine - NFine[0] - 1):] = mult * 1.j * k * 1. / (np.cosh(fact * (a * xC[ (NpFine - NFine[0] - 1):NpFine] - b)) + 1) * np.exp( -1.j * k2 * (a * xC[(NpFine - NFine[0] - 1):NpFine] - b)) # left boundary g[0:(NpFine - NFine[0]):( NFine[0] + 1)] = mult * 1.j * k * np.ones_like(yC[0:(NpFine - NFine[0]):( NFine[0] + 1)]) / (np.cosh(fact * (a * 0 - b)) + 1) * np.exp( -1.j * k2 * (a * 0 - b)) + mult * np.ones_like( yC[0:(NpFine - NFine[0]):(NFine[0] + 1)]) * ( a * 1.j * k2 * np.exp(-1.j * k2 * (a * 0 - b)) / (np.cosh((a * 0 - b) * fact) + 1) + a * fact * np.sinh( (a * 0 - b) * fact) * np.exp(-1.j * k2 * (a * 0 - b)) / (np.cosh((a * 0 - b) * fact) + 1)**2) # right boundary g[NFine[0]:NpFine:( NFine[0] + 1)] = mult * 1.j * k * np.ones_like(yC[NFine[0]:NpFine:( NFine[0] + 1)]) / (np.cosh(fact * (a * 1. - b)) + 1) * np.exp( -1.j * k2 * (a * 1. - b)) - mult * np.ones_like( yC[NFine[0]:NpFine:(NFine[0] + 1)]) * ( a * 1.j * k2 * np.exp(-1.j * k2 * (a * 1. - b)) / (np.cosh( (a * 1. - b) * fact) + 1) + a * fact * np.sinh( (a * 1. - b) * fact) * np.exp(-1.j * k2 * (a * 1. - b)) / (np.cosh((a * 1. - b) * fact) + 1)**2) # reference solution uSol = np.zeros(NpFine, dtype='complex128') # boundary conditions boundaryConditions = np.array([[1, 1], [1, 1]]) # Robin boundary worldFine = World(NFine, np.array([1, 1]), boundaryConditions) # fine matrices BdFineFEM = fem.assemblePatchBoundaryMatrix( NFine, fem.localBoundaryMassMatrixGetter(NFine)) MFineFEM = fem.assemblePatchMatrix(NFine, fem.localMassMatrix(NFine)) KFineFEM = fem.assemblePatchMatrix(NFine, fem.localStiffnessMatrix(NFine)) kBdFine = fem.assemblePatchBoundaryMatrix( NFine, fem.localBoundaryMassMatrixGetter(NFine), kFine) KFine = fem.assemblePatchMatrix(NFine, fem.localStiffnessMatrix(NFine), aFine) # incident beam uInc = mult / (np.cosh(fact * (a * xC - b)) + 1) * np.exp(-1.j * k2 * (a * xC - b)) print('***computing reference solution***') uOldFine = np.zeros(NpFine, dtype='complex128') for it in np.arange(maxit_Fine): print('-- itFine = %d' % it) knonlinUpreFine = np.abs(uOldFine) knonlinUFine = func.evaluateCQ1(NFine, knonlinUpreFine, xt) k2FineUfine = np.copy(k2Fine) k2FineUfine[indicesInEps] *= ( 1. + epsFine[indicesInEps] * knonlinUFine[indicesInEps]**2 ) # full coefficient, including nonlinearity k2MFine = fem.assemblePatchMatrix( NFine, fem.localMassMatrix(NFine), k2FineUfine) # weighted mass matrix, updated in every iteration nodesFine = np.arange(worldFine.NpFine) fixFine = util.boundarypIndexMap(NFine, boundaryConditions == 0) freeFine = np.setdiff1d(nodesFine, fixFine) # right-hand side (including boundary condition) fhQuad = MFineFEM * f + BdFineFEM * g # fine system lhsh = KFine[freeFine][:, freeFine] - k2MFine[ freeFine][:, freeFine] + 1j * kBdFine[freeFine][:, freeFine] rhsh = fhQuad[freeFine] xFreeFine = sparse.linalg.spsolve(lhsh, rhsh) xFullFine = np.zeros(worldFine.NpFine, dtype='complex128') xFullFine[freeFine] = xFreeFine uOldFine = np.copy(xFullFine) # residual - used as stopping criterion knonlinU = np.abs(uOldFine) knonlinUFineIt = func.evaluateCQ1(NFine, knonlinU, xt) k2FineUfineIt = np.copy(k2Fine) k2FineUfineIt[indicesInEps] *= ( 1. + epsFine[indicesInEps] * knonlinUFineIt[indicesInEps]**2 ) # update full coefficient, including nonlinearity k2MFineIt = fem.assemblePatchMatrix(NFine, fem.localMassMatrix(NFine), k2FineUfineIt) Ares = KFine - k2MFineIt + 1j * kBdFine residual = np.linalg.norm(Ares * xFullFine - fhQuad) / np.linalg.norm( Ares * xFullFine) print('---- residual = %.4e' % residual) if residual < 1e-12: break # stopping criterion uSol = xFullFine # final fine reference solution print('***reference solution computed***\n') ###################################################################################### print('***computing multiscale approximations***') relErrEnergy = np.zeros([len(NList), maxit]) counter = 0 for N in NList: counter += 1 print('H = %.4e' % (1. / N)) NWorldCoarse = np.array([N, N]) NCoarseElement = NFine // NWorldCoarse world = World(NWorldCoarse, NCoarseElement, boundaryConditions) NpCoarse = np.prod(NWorldCoarse + 1) uOldUps = np.zeros(NpFine, dtype='complex128') for it in np.arange(maxit): print('-- it = %d:' % it) knonlinUpre = np.abs(uOldUps) knonlinU = func.evaluateCQ1(NFine, knonlinUpre, xt) k2FineU = np.copy(k2Fine) k2FineU[indicesInEps] *= ( 1. + epsFine[indicesInEps] * knonlinU[indicesInEps]**2) print('---- starting computation of correctors') def computeLocalContribution(TInd): patch = Patch(world, ell, TInd) IPatch = lambda: interp.L2ProjectionPatchMatrix( patch, boundaryConditions) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) correctorsList = lod.computeBasisCorrectors_helmholtz( patch, IPatch, aPatch, kPatch, k2Patch) csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctorsList, aPatch, kPatch, k2Patch) return patch, correctorsList, csi.Kmsij, csi.Mmsij, csi.Bdmsij, csi.muTPrime def computeIndicators(TInd): k2FineUPatch = lambda: coef.localizeCoefficient( patchT[TInd], k2FineU) k2FineUOldPatch = lambda: coef.localizeCoefficient( patchT[TInd], k2FineUOld) E_vh = lod.computeErrorIndicatorCoarse_helmholtz( patchT[TInd], muTPrime[TInd], k2FineUOldPatch, k2FineUPatch) return E_vh def UpdateCorrectors(TInd): patch = Patch(world, ell, TInd) IPatch = lambda: interp.L2ProjectionPatchMatrix( patch, boundaryConditions) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) correctorsList = lod.computeBasisCorrectors_helmholtz( patch, IPatch, aPatch, kPatch, k2Patch) csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctorsList, aPatch, kPatch, k2Patch) return patch, correctorsList, csi.Kmsij, csi.Mmsij, csi.Bdmsij, csi.muTPrime def UpdateElements(tol, E, Kmsij_old, Mmsij_old, Bdmsij_old, correctors_old, mu_old): print('---- apply tolerance') Elements_to_be_updated = [] for (i, eps) in E.items(): if eps > tol: Elements_to_be_updated.append(i) if len(E) > 0: print( '---- total percentage of element correctors to be updated: %.4f' % (100 * np.size(Elements_to_be_updated) / len(mu_old)), flush=True) print('---- update local contributions') KmsijT_list = list(np.copy(Kmsij_old)) MmsijT_list = list(np.copy(Mmsij_old)) BdmsijT_list = list(np.copy(Bdmsij_old)) muT_list = np.copy(mu_old) for T in np.setdiff1d(range(world.NtCoarse), Elements_to_be_updated): patch = Patch(world, ell, T) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctors_old[T], aPatch, kPatch, k2Patch) KmsijT_list[T] = csi.Kmsij MmsijT_list[T] = csi.Mmsij BdmsijT_list[T] = csi.Bdmsij muT_list[T] = csi.muTPrime if np.size(Elements_to_be_updated) != 0: #print('---- update correctors') patchT_irrelevant, correctorsListTNew, KmsijTNew, MmsijTNew, BdmsijTNew, muTPrimeNew = zip( *mapper(UpdateCorrectors, Elements_to_be_updated)) #print('---- update correctorsList') correctorsListT_list = list(np.copy(correctors_old)) i = 0 for T in Elements_to_be_updated: KmsijT_list[T] = KmsijTNew[i] correctorsListT_list[T] = correctorsListTNew[i] MmsijT_list[T] = MmsijTNew[i] BdmsijT_list[T] = BdmsijTNew[i] muT_list[T] = muTPrimeNew[i] i += 1 KmsijT = tuple(KmsijT_list) correctorsListT = tuple(correctorsListT_list) MmsijT = tuple(MmsijT_list) BdmsijT = tuple(BdmsijT_list) muTPrime = tuple(muT_list) return correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime else: KmsijT = tuple(KmsijT_list) MmsijT = tuple(MmsijT_list) BdmsijT = tuple(BdmsijT_list) muTPrime = tuple(muT_list) return correctors_old, KmsijT, MmsijT, BdmsijT, muTPrime if it == 0: patchT, correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime = zip( *mapper(computeLocalContribution, range(world.NtCoarse))) else: E_vh = list(mapper(computeIndicators, range(world.NtCoarse))) print( '---- maximal value error estimator for basis correctors {}' .format(np.max(E_vh))) E = {i: E_vh[i] for i in range(np.size(E_vh)) if E_vh[i] > 0} # loop over elements with possible recomputation of correctors correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime = UpdateElements( tol * np.max(E_vh), E, KmsijT, MmsijT, BdmsijT, correctorsListT, muTPrime) # tol scaled by maximal error indicator print('---- finished computation of correctors') KLOD = pglod.assembleMsStiffnessMatrix( world, patchT, KmsijT) # ms stiffness matrix k2MLOD = pglod.assembleMsStiffnessMatrix(world, patchT, MmsijT) # ms mass matrix kBdLOD = pglod.assembleMsStiffnessMatrix( world, patchT, BdmsijT) # ms boundary matrix MFEM = fem.assemblePatchMatrix(NWorldCoarse, world.MLocCoarse) BdFEM = fem.assemblePatchBoundaryMatrix( NWorldCoarse, fem.localBoundaryMassMatrixGetter(NWorldCoarse)) print('---- coarse matrices assembled') nodes = np.arange(world.NpCoarse) fix = util.boundarypIndexMap(NWorldCoarse, boundaryConditions == 0) free = np.setdiff1d(nodes, fix) assert (nodes.all() == free.all()) # compute global interpolation matrix patchGlobal = Patch(world, NFine[0] + 2, 0) IH = interp.L2ProjectionPatchMatrix(patchGlobal, boundaryConditions) assert (IH.shape[0] == NpCoarse) basis = fem.assembleProlongationMatrix(NWorldCoarse, NCoarseElement) fHQuad = basis.T * MFineFEM * f + basis.T * BdFineFEM * g print('---- solving coarse system') # coarse system lhsH = KLOD[free][:, free] - k2MLOD[ free][:, free] + 1j * kBdLOD[free][:, free] rhsH = fHQuad[free] xFree = sparse.linalg.spsolve(lhsH, rhsH) basisCorrectors = pglod.assembleBasisCorrectors( world, patchT, correctorsListT) modifiedBasis = basis - basisCorrectors xFull = np.zeros(world.NpCoarse, dtype='complex128') xFull[free] = xFree uLodCoarse = basis * xFull uLodFine = modifiedBasis * xFull uOldUps = np.copy(uLodFine) k2FineUOld = np.copy(k2FineU) # visualization if it == maxit - 1 and N == 2**4: grid = uLodFine.reshape(NFine + 1, order='C') plt.figure(2) plt.title('LOD_ad, Hlvl=4 - Ex 2') plt.imshow(grid.real, extent=(xC.min(), xC.max(), yC.min(), yC.max()), cmap=plt.cm.hot, origin='lower', vmin=-.6, vmax=.6) plt.colorbar() grid2 = uSol.reshape(NFine + 1, order='C') plt.figure(1) plt.title('reference solution - Ex 2') plt.imshow(grid2.real, extent=(xC.min(), xC.max(), yC.min(), yC.max()), cmap=plt.cm.hot, origin='lower', vmin=-.6, vmax=.6) plt.colorbar() grid3 = uInc.reshape(NFine + 1, order='C') plt.figure(6) plt.title('incident beam - Ex 2') plt.imshow(grid3.real, extent=(xC.min(), xC.max(), yC.min(), yC.max()), cmap=plt.cm.hot, origin='lower', vmin=-.6, vmax=.6) plt.colorbar() Err = np.sqrt( np.dot((uSol - uLodFine).conj(), KFineFEM * (uSol - uLodFine)) + k**2 * np.dot((uSol - uLodFine).conj(), MFineFEM * (uSol - uLodFine))) ErrEnergy = Err / np.sqrt( np.dot((uSol).conj(), KFineFEM * (uSol)) + k**2 * np.dot((uSol).conj(), MFineFEM * (uSol))) print('---- ', np.abs(ErrEnergy), '\n***********************************************') # save errors in arrays relErrEnergy[counter - 1, it] = ErrEnergy print('\n') ###################################################################################### print( '***computing multiscale approximations without updates of correctors***' ) relErrEnergyNoUpdate = np.zeros([len(NList), maxit]) counter = 0 for N in NList: counter += 1 print('H = %.4e' % (1. / N)) NWorldCoarse = np.array([N, N]) NCoarseElement = NFine // NWorldCoarse world = World(NWorldCoarse, NCoarseElement, boundaryConditions) NpCoarse = np.prod(NWorldCoarse + 1) uOldUps = np.zeros(NpFine, dtype='complex128') for it in np.arange(maxit): print('-- it = %d:' % it) knonlinUpre = np.abs(uOldUps) knonlinU = func.evaluateCQ1(NFine, knonlinUpre, xt) k2FineU = np.copy(k2Fine) k2FineU[indicesInEps] *= ( 1. + epsFine[indicesInEps] * knonlinU[indicesInEps]**2) print('---- starting computation of correctors') def computeLocalContribution(TInd): patch = Patch(world, ell, TInd) IPatch = lambda: interp.L2ProjectionPatchMatrix( patch, boundaryConditions) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) correctorsList = lod.computeBasisCorrectors_helmholtz( patch, IPatch, aPatch, kPatch, k2Patch) # adapted for Helmholtz setting csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctorsList, aPatch, kPatch, k2Patch) # adapted for Helmholtz setting return patch, correctorsList, csi.Kmsij, csi.Mmsij, csi.Bdmsij, csi.muTPrime def computeIndicators(TInd): k2FineUPatch = lambda: coef.localizeCoefficient( patchT[TInd], k2FineU) k2FineUOldPatch = lambda: coef.localizeCoefficient( patchT[TInd], k2FineUOld) E_vh = lod.computeErrorIndicatorCoarse_helmholtz( patchT[TInd], muTPrime[TInd], k2FineUOldPatch, k2FineUPatch) return E_vh def UpdateCorrectors(TInd): patch = Patch(world, ell, TInd) IPatch = lambda: interp.L2ProjectionPatchMatrix( patch, boundaryConditions) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) correctorsList = lod.computeBasisCorrectors_helmholtz( patch, IPatch, aPatch, kPatch, k2Patch) csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctorsList, aPatch, kPatch, k2Patch) # adapted for Helmholtz setting return patch, correctorsList, csi.Kmsij, csi.Mmsij, csi.Bdmsij, csi.muTPrime def UpdateElements(tol, E, Kmsij_old, Mmsij_old, Bdmsij_old, correctors_old, mu_old): print('---- apply tolerance') Elements_to_be_updated = [] for (i, eps) in E.items(): if eps > tol: Elements_to_be_updated.append(i) if len(E) > 0: print( '---- total percentage of element correctors to be updated: %.4f' % (100 * np.size(Elements_to_be_updated) / len(mu_old)), flush=True) print('---- update local contributions') KmsijT_list = list(np.copy(Kmsij_old)) MmsijT_list = list(np.copy(Mmsij_old)) BdmsijT_list = list(np.copy(Bdmsij_old)) muT_list = np.copy(mu_old) for T in np.setdiff1d(range(world.NtCoarse), Elements_to_be_updated): patch = Patch(world, ell, T) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctors_old[T], aPatch, kPatch, k2Patch) KmsijT_list[T] = csi.Kmsij MmsijT_list[T] = csi.Mmsij BdmsijT_list[T] = csi.Bdmsij muT_list[T] = csi.muTPrime if np.size(Elements_to_be_updated) != 0: #print('---- update correctors') patchT_irrelevant, correctorsListTNew, KmsijTNew, MmsijTNew, BdmsijTNew, muTPrimeNew = zip( *mapper(UpdateCorrectors, Elements_to_be_updated)) #print('---- update correctorsList') correctorsListT_list = list(np.copy(correctors_old)) i = 0 for T in Elements_to_be_updated: KmsijT_list[T] = KmsijTNew[i] correctorsListT_list[T] = correctorsListTNew[i] MmsijT_list[T] = MmsijTNew[i] BdmsijT_list[T] = BdmsijTNew[i] muT_list[T] = muTPrimeNew[i] i += 1 KmsijT = tuple(KmsijT_list) correctorsListT = tuple(correctorsListT_list) MmsijT = tuple(MmsijT_list) BdmsijT = tuple(BdmsijT_list) muTPrime = tuple(muT_list) return correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime else: KmsijT = tuple(KmsijT_list) MmsijT = tuple(MmsijT_list) BdmsijT = tuple(BdmsijT_list) muTPrime = tuple(muT_list) return correctors_old, KmsijT, MmsijT, BdmsijT, muTPrime if it == 0: patchT, correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime = zip( *mapper(computeLocalContribution, range(world.NtCoarse))) else: E_vh = list(mapper(computeIndicators, range(world.NtCoarse))) print( '---- maximal value error estimator for basis correctors {}' .format(np.max(E_vh))) E = {i: E_vh[i] for i in range(np.size(E_vh)) if E_vh[i] > 0} # loop over elements with possible recomputation of correctors correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime = UpdateElements( 2. * np.max(E_vh), E, KmsijT, MmsijT, BdmsijT, correctorsListT, muTPrime) # no updates print('---- finished computation of correctors') KLOD = pglod.assembleMsStiffnessMatrix( world, patchT, KmsijT) # ms stiffness matrix k2MLOD = pglod.assembleMsStiffnessMatrix(world, patchT, MmsijT) # ms mass matrix kBdLOD = pglod.assembleMsStiffnessMatrix( world, patchT, BdmsijT) # ms boundary matrix MFEM = fem.assemblePatchMatrix(NWorldCoarse, world.MLocCoarse) BdFEM = fem.assemblePatchBoundaryMatrix( NWorldCoarse, fem.localBoundaryMassMatrixGetter(NWorldCoarse)) print('---- coarse matrices assembled') nodes = np.arange(world.NpCoarse) fix = util.boundarypIndexMap(NWorldCoarse, boundaryConditions == 0) free = np.setdiff1d(nodes, fix) assert (nodes.all() == free.all()) # compute global interpolation matrix patchGlobal = Patch(world, NFine[0] + 2, 0) IH = interp.L2ProjectionPatchMatrix(patchGlobal, boundaryConditions) assert (IH.shape[0] == NpCoarse) basis = fem.assembleProlongationMatrix(NWorldCoarse, NCoarseElement) fHQuad = basis.T * MFineFEM * f + basis.T * BdFineFEM * g print('---- solving coarse system') # coarse system lhsH = KLOD[free][:, free] - k2MLOD[ free][:, free] + 1j * kBdLOD[free][:, free] rhsH = fHQuad[free] xFree = sparse.linalg.spsolve(lhsH, rhsH) basisCorrectors = pglod.assembleBasisCorrectors( world, patchT, correctorsListT) modifiedBasis = basis - basisCorrectors xFull = np.zeros(world.NpCoarse, dtype='complex128') xFull[free] = xFree uLodCoarse = basis * xFull uLodFine = modifiedBasis * xFull uOldUps = np.copy(uLodFine) k2FineUOld = np.copy(k2FineU) # visualization if it == maxit - 1 and N == 2**4: grid = uLodFine.reshape(NFine + 1, order='C') plt.figure(3) plt.title('LOD_inf, Hlvl=4 - Ex 2') plt.imshow(grid.real, extent=(xC.min(), xC.max(), yC.min(), yC.max()), cmap=plt.cm.hot, origin='lower', vmin=-.6, vmax=.6) plt.colorbar() Err = np.sqrt( np.dot((uSol - uLodFine).conj(), KFineFEM * (uSol - uLodFine)) + k**2 * np.dot((uSol - uLodFine).conj(), MFineFEM * (uSol - uLodFine))) ErrEnergy = Err / np.sqrt( np.dot((uSol).conj(), KFineFEM * (uSol)) + k**2 * np.dot((uSol).conj(), MFineFEM * (uSol))) print('---- ', np.abs(ErrEnergy), '\n***********************************************') # save errors in arrays relErrEnergyNoUpdate[counter - 1, it] = ErrEnergy print('\n') ###################################################################################### print( '***computing multiscale approximations where all correctors in the part of the domain with active nonlinearity are recomputed***' ) relErrEnergyFullUpdate = np.zeros([len(NList), maxit]) counter = 0 for N in NList: counter += 1 print('H = %.4e' % (1. / N)) NWorldCoarse = np.array([N, N]) NCoarseElement = NFine // NWorldCoarse world = World(NWorldCoarse, NCoarseElement, boundaryConditions) NpCoarse = np.prod(NWorldCoarse + 1) uOldUps = np.zeros(NpFine, dtype='complex128') for it in np.arange(maxit): print('-- it = %d:' % it) knonlinUpre = np.abs(uOldUps) knonlinU = func.evaluateCQ1(NFine, knonlinUpre, xt) k2FineU = np.copy(k2Fine) k2FineU[indicesInEps] *= ( 1. + epsFine[indicesInEps] * knonlinU[indicesInEps]**2) print('---- starting computation of correctors') def computeLocalContribution(TInd): patch = Patch(world, ell, TInd) IPatch = lambda: interp.L2ProjectionPatchMatrix( patch, boundaryConditions) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) correctorsList = lod.computeBasisCorrectors_helmholtz( patch, IPatch, aPatch, kPatch, k2Patch) # adapted for Helmholtz setting csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctorsList, aPatch, kPatch, k2Patch) # adapted for Helmholtz setting return patch, correctorsList, csi.Kmsij, csi.Mmsij, csi.Bdmsij, csi.muTPrime def computeIndicators(TInd): k2FineUPatch = lambda: coef.localizeCoefficient( patchT[TInd], k2FineU) k2FineUOldPatch = lambda: coef.localizeCoefficient( patchT[TInd], k2FineUOld) E_vh = lod.computeErrorIndicatorCoarse_helmholtz( patchT[TInd], muTPrime[TInd], k2FineUOldPatch, k2FineUPatch) return E_vh def UpdateCorrectors(TInd): patch = Patch(world, ell, TInd) IPatch = lambda: interp.L2ProjectionPatchMatrix( patch, boundaryConditions) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) correctorsList = lod.computeBasisCorrectors_helmholtz( patch, IPatch, aPatch, kPatch, k2Patch) csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctorsList, aPatch, kPatch, k2Patch) # adapted for Helmholtz setting return patch, correctorsList, csi.Kmsij, csi.Mmsij, csi.Bdmsij, csi.muTPrime def UpdateElements(tol, E, Kmsij_old, Mmsij_old, Bdmsij_old, correctors_old, mu_old): print('---- apply tolerance') Elements_to_be_updated = [] for (i, eps) in E.items(): if eps > tol: Elements_to_be_updated.append(i) if len(E) > 0: print( '---- total percentage of element correctors to be updated: %.4f' % (100 * np.size(Elements_to_be_updated) / len(mu_old)), flush=True) print('---- update local contributions') KmsijT_list = list(np.copy(Kmsij_old)) MmsijT_list = list(np.copy(Mmsij_old)) BdmsijT_list = list(np.copy(Bdmsij_old)) muT_list = np.copy(mu_old) for T in np.setdiff1d(range(world.NtCoarse), Elements_to_be_updated): patch = Patch(world, ell, T) aPatch = lambda: coef.localizeCoefficient(patch, aFine) kPatch = lambda: coef.localizeCoefficient(patch, kFine) k2Patch = lambda: coef.localizeCoefficient(patch, k2FineU) csi = lod.computeBasisCoarseQuantities_helmholtz( patch, correctors_old[T], aPatch, kPatch, k2Patch) KmsijT_list[T] = csi.Kmsij MmsijT_list[T] = csi.Mmsij BdmsijT_list[T] = csi.Bdmsij muT_list[T] = csi.muTPrime if np.size(Elements_to_be_updated) != 0: #print('---- update correctors') patchT_irrelevant, correctorsListTNew, KmsijTNew, MmsijTNew, BdmsijTNew, muTPrimeNew = zip( *mapper(UpdateCorrectors, Elements_to_be_updated)) #print('---- update correctorsList') correctorsListT_list = list(np.copy(correctors_old)) i = 0 for T in Elements_to_be_updated: KmsijT_list[T] = KmsijTNew[i] correctorsListT_list[T] = correctorsListTNew[i] MmsijT_list[T] = MmsijTNew[i] BdmsijT_list[T] = BdmsijTNew[i] muT_list[T] = muTPrimeNew[i] i += 1 KmsijT = tuple(KmsijT_list) correctorsListT = tuple(correctorsListT_list) MmsijT = tuple(MmsijT_list) BdmsijT = tuple(BdmsijT_list) muTPrime = tuple(muT_list) return correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime else: KmsijT = tuple(KmsijT_list) MmsijT = tuple(MmsijT_list) BdmsijT = tuple(BdmsijT_list) muTPrime = tuple(muT_list) return correctors_old, KmsijT, MmsijT, BdmsijT, muTPrime if it == 0: patchT, correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime = zip( *mapper(computeLocalContribution, range(world.NtCoarse))) else: E_vh = list(mapper(computeIndicators, range(world.NtCoarse))) print( '---- maximal value error estimator for basis correctors {}' .format(np.max(E_vh))) E = {i: E_vh[i] for i in range(np.size(E_vh)) if E_vh[i] > 0} # loop over elements with possible recomputation of correctors correctorsListT, KmsijT, MmsijT, BdmsijT, muTPrime = UpdateElements( 0., E, KmsijT, MmsijT, BdmsijT, correctorsListT, muTPrime) # no updates print('---- finished computation of correctors') KLOD = pglod.assembleMsStiffnessMatrix( world, patchT, KmsijT) # ms stiffness matrix k2MLOD = pglod.assembleMsStiffnessMatrix(world, patchT, MmsijT) # ms mass matrix kBdLOD = pglod.assembleMsStiffnessMatrix( world, patchT, BdmsijT) # ms boundary matrix MFEM = fem.assemblePatchMatrix(NWorldCoarse, world.MLocCoarse) BdFEM = fem.assemblePatchBoundaryMatrix( NWorldCoarse, fem.localBoundaryMassMatrixGetter(NWorldCoarse)) print('---- coarse matrices assembled') nodes = np.arange(world.NpCoarse) fix = util.boundarypIndexMap(NWorldCoarse, boundaryConditions == 0) free = np.setdiff1d(nodes, fix) assert (nodes.all() == free.all()) # compute global interpolation matrix patchGlobal = Patch(world, NFine[0] + 2, 0) IH = interp.L2ProjectionPatchMatrix(patchGlobal, boundaryConditions) assert (IH.shape[0] == NpCoarse) basis = fem.assembleProlongationMatrix(NWorldCoarse, NCoarseElement) fHQuad = basis.T * MFineFEM * f + basis.T * BdFineFEM * g print('---- solving coarse system') # coarse system lhsH = KLOD[free][:, free] - k2MLOD[ free][:, free] + 1j * kBdLOD[free][:, free] rhsH = fHQuad[free] xFree = sparse.linalg.spsolve(lhsH, rhsH) basisCorrectors = pglod.assembleBasisCorrectors( world, patchT, correctorsListT) modifiedBasis = basis - basisCorrectors xFull = np.zeros(world.NpCoarse, dtype='complex128') xFull[free] = xFree uLodCoarse = basis * xFull uLodFine = modifiedBasis * xFull uOldUps = np.copy(uLodFine) k2FineUOld = np.copy(k2FineU) # visualization if it == maxit - 1 and N == 2**4: grid = uLodFine.reshape(NFine + 1, order='C') plt.figure(7) plt.title('LOD_inf, Hlvl=4 - Ex 2') plt.imshow(grid.real, extent=(xC.min(), xC.max(), yC.min(), yC.max()), cmap=plt.cm.hot, origin='lower', vmin=-.6, vmax=.6) plt.colorbar() Err = np.sqrt( np.dot((uSol - uLodFine).conj(), KFineFEM * (uSol - uLodFine)) + k**2 * np.dot((uSol - uLodFine).conj(), MFineFEM * (uSol - uLodFine))) ErrEnergy = Err / np.sqrt( np.dot((uSol).conj(), KFineFEM * (uSol)) + k**2 * np.dot((uSol).conj(), MFineFEM * (uSol))) print('---- ', np.abs(ErrEnergy), '\n***********************************************') # save errors in arrays relErrEnergyFullUpdate[counter - 1, it] = ErrEnergy print('\n') ###################################################################################### print('***computing FEM approximations***') FEMrelErrEnergy = np.zeros([len(NList), maxit]) counter = 0 for N in NList: counter += 1 print('H = %.4e' % (1. / N)) NWorldCoarse = np.array([N, N]) NCoarseElement = NFine // NWorldCoarse world = World(NWorldCoarse, NCoarseElement, boundaryConditions) NpCoarse = np.prod(NWorldCoarse + 1) xT = util.tCoordinates(NWorldCoarse) xP = util.pCoordinates(NWorldCoarse) uOld = np.zeros(NpCoarse, dtype='complex128') # compute coarse coefficients by averaging NtC = np.prod(NWorldCoarse) aCoarse = np.zeros(NtC) kCoarse = k * np.ones(xT.shape[0]) k2Coarse = np.zeros(NtC) epsCoarse = np.zeros(NtC) for Q in range(NtC): patch = Patch(world, 0, Q) aPatch = coef.localizeCoefficient(patch, aFine) epsPatch = coef.localizeCoefficient(patch, epsFine) k2Patch = coef.localizeCoefficient(patch, k2Fine) aCoarse[Q] = np.sum(aPatch) / (len(aPatch)) k2Coarse[Q] = np.sum(k2Patch) / (len(k2Patch)) epsCoarse[Q] = np.sum(epsPatch) / (len(epsPatch)) # coarse matrices KFEM = fem.assemblePatchMatrix(NWorldCoarse, fem.localStiffnessMatrix(NWorldCoarse), aCoarse) kBdFEM = fem.assemblePatchBoundaryMatrix( NWorldCoarse, fem.localBoundaryMassMatrixGetter(NWorldCoarse), kCoarse) MFEM = fem.assemblePatchMatrix(NWorldCoarse, world.MLocCoarse) BdFEM = fem.assemblePatchBoundaryMatrix( NWorldCoarse, fem.localBoundaryMassMatrixGetter(NWorldCoarse)) for it in np.arange(maxit): print('-- it = %d:' % it) knonlinUpre = np.abs(uOld) knonlinU = func.evaluateCQ1(NWorldCoarse, knonlinUpre, xT) k2CoarseU = np.copy(k2Coarse) k2CoarseU *= (1. + epsCoarse * knonlinU**2) # update weighted mass matrix k2MFEM = fem.assemblePatchMatrix(NWorldCoarse, fem.localMassMatrix(NWorldCoarse), k2CoarseU) nodes = np.arange(world.NpCoarse) fix = util.boundarypIndexMap(NWorldCoarse, boundaryConditions == 0) free = np.setdiff1d(nodes, fix) assert (nodes.all() == free.all()) basis = fem.assembleProlongationMatrix(NWorldCoarse, NCoarseElement) fHQuad = basis.T * MFineFEM * f + basis.T * BdFineFEM * g print('---- solving coarse system') # coarse system lhsH = KFEM[free][:, free] - k2MFEM[ free][:, free] + 1j * kBdFEM[free][:, free] rhsH = fHQuad[free] xFree = sparse.linalg.spsolve(lhsH, rhsH) xFull = np.zeros(world.NpCoarse, dtype='complex128') xFull[free] = xFree uCoarseInt = basis * xFull uOld = np.copy(xFull) # visualization if it == maxit - 1 and N == 2**4: grid = uCoarseInt.reshape(NFine + 1, order='C') plt.figure(4) plt.title('FEM, Hlvl=4 - Ex 2') plt.imshow(grid.real, extent=(xC.min(), xC.max(), yC.min(), yC.max()), cmap=plt.cm.hot, origin='lower', vmin=-.6, vmax=.6) plt.colorbar() Err = np.sqrt( np.dot((uSol - uCoarseInt).conj(), KFineFEM * (uSol - uCoarseInt)) + k**2 * np.dot( (uSol - uCoarseInt).conj(), MFineFEM * (uSol - uCoarseInt))) ErrEnergy = Err / np.sqrt( np.dot((uSol).conj(), KFineFEM * (uSol)) + k**2 * np.dot((uSol).conj(), MFineFEM * (uSol))) print('---- ', np.abs(ErrEnergy), '\n***********************************************') # save errors in arrays FEMrelErrEnergy[counter - 1, it] = ErrEnergy print('\n') # error plots errLOD_2 = np.min(relErrEnergy, 1) errLOD0_2 = np.min(relErrEnergyNoUpdate, 1) errLODall_2 = np.min(relErrEnergyFullUpdate, 1) errFEM_2 = np.min(FEMrelErrEnergy, 1) Hs = 0.5**np.arange(1, maxCoarseLvl + 1) plt.figure(5) plt.title('Relative energy errors w.r.t H - Ex 2') plt.plot(Hs, errLOD_2, 'x-', color='blue', label='LOD_ad') plt.plot(Hs, errLOD0_2, 'x-', color='green', label='LOD_inf') plt.plot(Hs, errLODall_2, 'x-', color='orange', label='LOD_0') plt.plot(Hs, errFEM_2, 'x-', color='red', label='FEM') plt.plot([0.5, 0.0078125], [0.75, 0.01171875], color='black', linestyle='dashed', label='order 1') plt.yscale('log') plt.xscale('log') plt.legend() plt.show()
aBack_ref = func.evaluateDQ0(NFine, aFine_pert, xtFine_pert) plt.figure("Coefficient") drawCoefficient_origin(NFine, aFine_ref) plt.figure("a_perturbed") drawCoefficient_origin(NFine, aFine_pert) plt.figure("a_back") drawCoefficient_origin(NFine, aBack_ref) # aFine_trans is the transformed perturbed reference coefficient aFine_trans = np.einsum('tji, t, tkj, t -> tik', psi.Jinv(xtFine), aFine_ref, psi.Jinv(xtFine), psi.detJ(xtFine)) f_pert = np.ones(np.prod(NFine+1)) f_ref = func.evaluateCQ1(NFine, f_pert, xpFine_pert) f_trans = np.einsum('t, t -> t', f_ref, psi.detJ(xpFine)) #d3sol(NFine,f, 'right hand side NT') d3sol(NFine, f_trans, 'right hand side T') NWorldCoarse = np.array([N, N]) boundaryConditions = np.array([[0, 0],[0, 0]]) NCoarseElement = NFine // NWorldCoarse world = World(NWorldCoarse, NCoarseElement, boundaryConditions) # Naming of solutions # ._pert is a solution in the perturbed domain # ._trans is a solution in the reference domain, after transformation