Exemple #1
0
def ritzProjectionToFinePatchWithGivenSaddleSolver(world,
                                                   iPatchWorldCoarse,
                                                   NPatchCoarse,
                                                   APatchFull,
                                                   bPatchFullList,
                                                   IPatch,
                                                   saddleSolver):
    d = np.size(NPatchCoarse)
    NPatchFine = NPatchCoarse * world.NCoarseElement
    NpFine = np.prod(NPatchFine + 1)

    # Find what patch faces are common to the world faces, and inherit
    # boundary conditions from the world for those. For the other
    # faces, all DoFs fixed (Dirichlet)
    boundaryMapWorld = world.boundaryConditions == 0

    inherit0 = iPatchWorldCoarse == 0
    inherit1 = (iPatchWorldCoarse + NPatchCoarse) == world.NWorldCoarse

    boundaryMap = np.ones([d, 2], dtype='bool')
    boundaryMap[inherit0, 0] = boundaryMapWorld[inherit0, 0]
    boundaryMap[inherit1, 1] = boundaryMapWorld[inherit1, 1]

    # Using schur complement solver for the case when there are no
    # Dirichlet conditions does not work. Fix if necessary.
    assert (np.any(boundaryMap == True))

    fixed = util.boundarypIndexMap(NPatchFine, boundaryMap)

    # projectionsList = saddleSolver.solve(APatch, IPatch, bPatchList)

    projectionsList = saddleSolver.solve(APatchFull, IPatch, bPatchFullList, fixed, NPatchCoarse, world.NCoarseElement)

    return projectionsList
Exemple #2
0
    def test_trivial(self):
        NPatchCoarse = np.array([3,3])
        NCoarseElement = np.array([2,2])
        NPatchFine = NPatchCoarse*NCoarseElement
        Nt = np.prod(NPatchFine)
        Np = np.prod(NPatchFine+1)
        fixed = util.boundarypIndexMap(NPatchFine)

        world = World(NPatchCoarse, NCoarseElement)
        patch = Patch(world, 3, 0)
        
        aFlatPatchFine = np.ones(Nt)
        ALoc = fem.localStiffnessMatrix(NPatchFine)
        APatchFull = fem.assemblePatchMatrix(NPatchFine, ALoc, aFlatPatchFine)

        PPatch = fem.assembleProlongationMatrix(NPatchCoarse, NCoarseElement)

        IPatchNodal = interp.nodalPatchMatrix(patch)
        #IPatchuncL2 = interp.uncoupledL2ProjectionPatchMatrix(np.array([0, 0]), NPatchCoarse, NPatchCoarse, NCoarseElement)
        IPatchL2 = interp.L2ProjectionPatchMatrix(patch)

        for IPatch in [IPatchNodal, IPatchL2]:
            np.random.seed(0)
            bPatchFullList = []
            self.assertTrue(not lod.ritzProjectionToFinePatch(patch, APatchFull, bPatchFullList, IPatch))

            bPatchFullList = [np.zeros(Np)]
            projections = lod.ritzProjectionToFinePatch(patch, APatchFull, bPatchFullList, IPatch)
            self.assertEqual(len(projections), 1)
            self.assertTrue(np.allclose(projections[0], 0*projections[0]))

            bPatchFull = np.random.rand(Np)
            bPatchFullList = [bPatchFull]
            projections = lod.ritzProjectionToFinePatch(patch, APatchFull, bPatchFullList, IPatch)
            self.assertTrue(np.isclose(np.linalg.norm(IPatch*projections[0]), 0))
            
            self.assertTrue(np.isclose(np.dot(projections[0], APatchFull*projections[0]),
                                       np.dot(projections[0], bPatchFullList[0])))

            self.assertTrue(np.isclose(np.linalg.norm(projections[0][fixed]), 0))

            bPatchFullList = [bPatchFull, -bPatchFull]
            projections = lod.ritzProjectionToFinePatch(patch, APatchFull, bPatchFullList, IPatch)
            self.assertTrue(np.allclose(projections[0], -projections[1]))

            bPatchFullList = [np.random.rand(Np), np.random.rand(Np)]
            projections = lod.ritzProjectionToFinePatch(patch, APatchFull, bPatchFullList, IPatch)
            self.assertTrue(np.isclose(np.dot(projections[1], APatchFull*projections[0]),
                                       np.dot(projections[1], bPatchFullList[0])))

            bPatchFull = np.random.rand(Np)
            bPatchFullList = [bPatchFull]
            projectionCheckAgainst = lod.ritzProjectionToFinePatch(patch, APatchFull, bPatchFullList, IPatch)[0]

            for saddleSolver in [#lod.nullspaceOneLevelHierarchySolver(NPatchCoarse, NCoarseElement),
                                 lod.SchurComplementSolver()]:
                projection = lod.ritzProjectionToFinePatch(patch, APatchFull, bPatchFullList,
                                                           IPatch, saddleSolver)[0]
                self.assertTrue(np.isclose(np.max(np.abs(projectionCheckAgainst-projection)), 0))
Exemple #3
0
    def test_computeFullDomain(self):
        NWorldCoarse = np.array([2, 3, 4], dtype='int64')
        NWorldCoarse = np.array([1, 1, 1], dtype='int64')
        NCoarseElement = np.array([4, 2, 3], dtype='int64')
        NWorldFine = NWorldCoarse*NCoarseElement
        NpWorldFine = np.prod(NWorldFine+1)
        NpWorldCoarse = np.prod(NWorldCoarse+1)
        NtWorldFine = np.prod(NWorldCoarse*NCoarseElement)

        np.random.seed(0)

        world = World(NWorldCoarse, NCoarseElement)
        d = np.size(NWorldCoarse)
        IWorld = interp.nodalPatchMatrix(0*NWorldCoarse, NWorldCoarse, NWorldCoarse, NCoarseElement)
        aWorld = np.exp(np.random.rand(NtWorldFine))
        coefficientWorld = coef.coefficientFine(NWorldCoarse, NCoarseElement, aWorld)
        k = np.max(NWorldCoarse)

        elementpIndexMap = util.lowerLeftpIndexMap(np.ones_like(NWorldCoarse), NWorldCoarse)
        elementpIndexMapFine = util.lowerLeftpIndexMap(NCoarseElement, NWorldFine)
        
        coarsepBasis = util.linearpIndexBasis(NWorldCoarse)
        finepBasis = util.linearpIndexBasis(NWorldFine)

        correctors = np.zeros((NpWorldFine, NpWorldCoarse))
        basis = np.zeros((NpWorldFine, NpWorldCoarse))
        
        for iElementWorldCoarse in it.product(*[np.arange(n, dtype='int64') for n in NWorldCoarse]):
            iElementWorldCoarse = np.array(iElementWorldCoarse)
            ec = lod.elementCorrector(world, k, iElementWorldCoarse)
            ec.computeCorrectors(coefficientWorld, IWorld)
            
            worldpIndices = np.dot(coarsepBasis, iElementWorldCoarse) + elementpIndexMap
            correctors[:,worldpIndices] += np.column_stack(ec.fsi.correctorsList)

            worldpFineIndices = np.dot(finepBasis, iElementWorldCoarse*NCoarseElement) + elementpIndexMapFine
            basis[np.ix_(worldpFineIndices, worldpIndices)] = world.localBasis

        AGlob = fem.assemblePatchMatrix(NWorldFine, world.ALocFine, aWorld)

        alpha = np.random.rand(NpWorldCoarse)
        vH  = np.dot(basis, alpha)
        QvH = np.dot(correctors, alpha)

        # Check norm inequality
        self.assertTrue(np.dot(QvH.T, AGlob*QvH) <= np.dot(vH.T, AGlob*vH))

        # Check that correctors are really fine functions
        self.assertTrue(np.isclose(np.linalg.norm(IWorld*correctors, ord=np.inf), 0))

        v = np.random.rand(NpWorldFine, NpWorldCoarse)
        v[util.boundarypIndexMap(NWorldFine)] = 0
        # The chosen interpolation operator doesn't ruin the boundary conditions.
        vf = v-np.dot(basis, IWorld*v)
        vf = vf/np.sqrt(np.sum(vf*(AGlob*vf), axis=0))
        # Check orthogonality
        self.assertTrue(np.isclose(np.linalg.norm(np.dot(vf.T, AGlob*(correctors - basis)), ord=np.inf), 0))
Exemple #4
0
def solveCoarse_fem(world, aFine, bFine, MbFine, U, tau, boundaryConditions,
                    i):
    NWorldCoarse = world.NWorldCoarse
    NWorldFine = world.NWorldCoarse * world.NCoarseElement
    NCoarseElement = world.NCoarseElement

    NpFine = np.prod(NWorldFine + 1)
    NpCoarse = np.prod(NWorldCoarse + 1)

    if MbFine is None:
        MbFine = np.zeros(NpFine)

    boundaryMap = boundaryConditions == 0
    fixedCoarse = util.boundarypIndexMap(NWorldCoarse, boundaryMap=boundaryMap)
    freeCoarse = np.setdiff1d(np.arange(NpCoarse), fixedCoarse)

    AFine = fem.assemblePatchMatrix(NWorldFine, world.ALocFine, aFine)
    BFine = fem.assemblePatchMatrix(NWorldFine, world.ALocFine, bFine)
    MFine = fem.assemblePatchMatrix(NWorldFine, world.MLocFine)

    bFine = MFine * MbFine

    basis = fem.assembleProlongationMatrix(NWorldCoarse, NCoarseElement)
    ACoarse = basis.T * (AFine * basis)
    BCoarse = basis.T * (BFine * basis)
    MCoarse = basis.T * (MFine * basis)
    bCoarse = basis.T * bFine

    ACoarseFree = ACoarse[freeCoarse][:, freeCoarse]
    BCoarseFree = BCoarse[freeCoarse][:, freeCoarse]
    MCoarseFree = MCoarse[freeCoarse][:, freeCoarse]
    bCoarseFree = bCoarse[freeCoarse]

    A = (1. / tau**2) * MCoarseFree + (1. / tau) * ACoarseFree + BCoarseFree
    if i == 0:
        b = bCoarseFree + (1. / tau) * ACoarseFree * U[i][freeCoarse] + (
            1. / tau) * MCoarseFree * ((2. / tau) * U[i][freeCoarse])
    else:
        b = bCoarseFree + (1. / tau) * ACoarseFree * U[i][freeCoarse] + (
            1. / tau) * MCoarseFree * ((2. / tau) * U[i][freeCoarse] -
                                       (1. / tau) * U[i - 1][freeCoarse])
    uCoarseFree = linalg.linSolve(A, b)
    uCoarseFull = np.zeros(NpCoarse)
    uCoarseFull[freeCoarse] = uCoarseFree
    uCoarseFull = uCoarseFull

    return uCoarseFull
Exemple #5
0
def reference_sol(world, fine, tau, tot_time_steps, init_val, aFine, bFine, f):

    NFine = np.array([fine, fine])
    NpFine = np.prod(NFine + 1)
    bc = world.boundaryConditions
    NWorldFine = world.NWorldCoarse * world.NCoarseElement

    # set initial value
    U = [init_val]
    U.append(init_val)

    # assemble matrices
    S = fem.assemblePatchMatrix(NWorldFine, world.ALocFine, aFine)
    K = fem.assemblePatchMatrix(NWorldFine, world.ALocFine, bFine)
    M = fem.assemblePatchMatrix(NWorldFine, world.MLocFine)

    # find free indices
    boundary_map = bc == 0
    fixed = util.boundarypIndexMap(NWorldFine, boundary_map)
    free = np.setdiff1d(np.arange(NpFine), fixed)

    # create free matrices
    Sf = S[free][:, free]
    Kf = K[free][:, free]
    Mf = M[free][:, free]
    Lf = (M * f)[free]

    for i in range(tot_time_steps):

        # reference system
        A = (1. / (tau ** 2)) * Mf + (1. / tau) * Sf + Kf
        b = Lf + (1. / tau) * Sf * U[1][free] + (2. / (tau ** 2)) * Mf * U[1][free] - \
            (1. / (tau ** 2)) * Mf * U[0][free]

        # solve system
        UFineFree = linalg.linSolve(A, b)
        UFineFull = np.zeros(NpFine)
        UFineFull[free] = UFineFree

        # append solution
        U[0] = U[1]
        U[1] = UFineFull

    return U[-1]
Exemple #6
0
def solveDampedFine_fem(world, aFine, bFine, f, uSol, tau, boundaryConditions,
                        i):
    NWorldCoarse = world.NWorldCoarse
    NWorldFine = world.NWorldCoarse * world.NCoarseElement
    NpFine = np.prod(NWorldFine + 1)
    prevU = uSol[-1]
    if f is None:
        f = np.zeros(NpFine)

    boundaryMap = boundaryConditions == 0
    fixedFine = util.boundarypIndexMap(NWorldFine, boundaryMap=boundaryMap)
    freeFine = np.setdiff1d(np.arange(NpFine), fixedFine)

    AFine = fem.assemblePatchMatrix(NWorldFine, world.MLocFine, aFine)
    BFine = fem.assemblePatchMatrix(NWorldFine, world.ALocFine, bFine)
    MFine = fem.assemblePatchMatrix(NWorldFine, world.MLocFine)

    bFine = MFine * f

    AFineFree = AFine[freeFine][:, freeFine]
    BFineFree = BFine[freeFine][:, freeFine]
    MFineFree = MFine[freeFine][:, freeFine]
    bFineFree = bFine[freeFine]

    A = (1. / tau**2) * MFineFree + (1. / tau) * AFineFree + BFineFree
    if i == 0:
        b = bFineFree + (1. / tau) * AFineFree * prevU[freeFine] + (
            1. / tau) * MFineFree * ((2. / tau) * prevU[freeFine])
    else:
        b = bFineFree + (1. / tau) * AFineFree * prevU[freeFine] + (
            1. / tau) * MFineFree * ((2. / tau) * prevU[freeFine] -
                                     (1. / tau) * uSol[i - 1][freeFine])

    uFineFree = linalg.linSolve(A, b)
    uFineFull = np.zeros(NpFine)
    uFineFull[freeFine] = uFineFree
    uFineFull = uFineFull

    return uFineFull
Exemple #7
0
    def test_ritzProjectionToFinePatchBoundaryConditions(self):
        NPatchCoarse = np.array([4, 4])
        NCoarseElement = np.array([10, 10])
        world = World(NPatchCoarse, NCoarseElement)
        patch = Patch(world, 4, 0)
            
        NPatchFine = NPatchCoarse*NCoarseElement
        NpFine = np.prod(NPatchFine + 1)
        
        APatchFull = fem.assemblePatchMatrix(NPatchCoarse*NCoarseElement, world.ALocFine)
        bPatchFullList = [np.ones(NpFine)]

        fixed = util.boundarypIndexMap(NPatchFine)
        
        for IPatch in [interp.L2ProjectionPatchMatrix(patch),
                       interp.nodalPatchMatrix(patch)]:

            schurComplementSolver = lod.SchurComplementSolver()
            schurComplementSolution = lod.ritzProjectionToFinePatch(patch,
                                                                    APatchFull, bPatchFullList,
                                                                    IPatch,
                                                                    schurComplementSolver)[0]
            self.assertTrue(np.isclose(np.max(np.abs(schurComplementSolution[fixed])), 0))
Exemple #8
0
def ritzProjectionToFinePatch(patch,
                              APatchFull,
                              bPatchFullList,
                              IPatch,
                              saddleSolver=None):
    if saddleSolver is None:
        saddleSolver = DirectSolver()  # Fast for small patch problems

    world = patch.world
    d = np.size(patch.NPatchCoarse)
    NPatchFine = patch.NPatchFine
    NpFine = patch.NpFine

    # Find what patch faces are common to the world faces, and inherit
    # boundary conditions from the world for those. For the other
    # faces, all DoFs fixed (Dirichlet)
    boundaryMapWorld = world.boundaryConditions == 0

    inherit0 = patch.iPatchWorldCoarse == 0
    inherit1 = (patch.iPatchWorldCoarse +
                patch.NPatchCoarse) == world.NWorldCoarse

    boundaryMap = np.ones([d, 2], dtype='bool')
    boundaryMap[inherit0, 0] = boundaryMapWorld[inherit0, 0]
    boundaryMap[inherit1, 1] = boundaryMapWorld[inherit1, 1]

    # Using schur complement solver for the case when there are no
    # Dirichlet conditions does not work. Fix if necessary.

    fixed = util.boundarypIndexMap(NPatchFine, boundaryMap)

    projectionsList = saddleSolver.solve(APatchFull, IPatch, bPatchFullList,
                                         fixed, patch.NPatchCoarse,
                                         world.NCoarseElement)

    return projectionsList
    S = fem.assemblePatchMatrix(NWorldFine, world.ALocFine, aFine)
    K = fem.assemblePatchMatrix(NWorldFine, world.ALocFine, bFine)
    M = fem.assemblePatchMatrix(NWorldFine, world.MLocFine)

    SmsFull = ms_basis.T * S * ms_basis
    KmsFull = ms_basis.T * K * ms_basis
    MmsFull = ms_basis.T * M * ms_basis

    free = util.interiorpIndexMap(NWorldCoarse)

    SmsFree = SmsFull[free][:, free]
    KmsFree = KmsFull[free][:, free]
    MmsFree = MmsFull[free][:, free]

    boundaryMap = boundaryConditions == 0
    fixedFine = util.boundarypIndexMap(NWorldFine, boundaryMap)
    freeFine = np.setdiff1d(np.arange(NpFine), fixedFine)

    # load vector
    f = np.ones(NpFine)
    LFull = M * f
    LmsFull = ms_basis.T * LFull
    LmsFree = LmsFull[free]

    RmsFreeList = []
    for i in xrange(numTimeSteps):
        print 'LOD N=%d, i=%d' %(N,i)

        n = i + 1

        # linear system
Exemple #10
0
    def test_pgtransport(self):
        NWorldCoarse = np.array([16, 16])
        NCoarseElement = np.array([8, 8])
        NWorldFine = NWorldCoarse * NCoarseElement
        boundaryConditions = np.array([[1, 1], [0, 0]])

        d = 2

        world = World(NWorldCoarse, NCoarseElement, boundaryConditions)

        # Load coefficient
        aLogBase = np.loadtxt(
            os.path.dirname(os.path.realpath(__file__)) +
            '/data/randomfield64x64')
        #aBase = np.loadtxt(os.path.dirname(os.path.realpath(__file__)) + '/data/upperness_x.txt')
        #aBase = aBase[:60*220]
        #aLogBase = np.random.rand(128*128)
        aBase = np.exp(3 * aLogBase)

        drawCoefficient(NWorldFine, aBase)
        plt.title('a')

        # Compute coordinates
        coordsFine = util.pCoordinates(NWorldFine)
        xFine = coordsFine[:, 0]
        yFine = coordsFine[:, 1]

        # Compute fixed and free dofs
        allDofs = np.arange(world.NpFine)
        fixed = util.boundarypIndexMap(NWorldFine, boundaryConditions == 0)
        free = np.setdiff1d(allDofs, fixed)

        # Compute matrices
        AFull = fem.assemblePatchMatrix(NWorldFine, world.ALocFine, aBase)
        A = AFull[free][:, free]

        # Compute rhs
        gFine = 1 - yFine
        bFull = -AFull * gFine
        b = bFull[free]

        # Solve fine system
        u0Free = sparse.linalg.spsolve(A, b)
        u0Full = np.zeros(world.NpFine)
        u0Full[free] = u0Free

        uFull = u0Full + gFine

        ## First, compute flux on fine mesh
        def computeAvgVelocitiesTF(NFluxElement):
            fluxWorld = World(NWorldFine / NFluxElement, NFluxElement,
                              boundaryConditions)

            if True:
                avgFluxTF = transport.computeHarmonicMeanFaceFlux(
                    fluxWorld.NWorldCoarse, fluxWorld.NWorldCoarse,
                    NFluxElement, aBase, uFull)
                avgFluxTF = transport.computeAverageFaceFlux(
                    fluxWorld.NWorldCoarse, avgFluxTF)
                conservativeFluxTF = transport.computeConservativeFlux(
                    fluxWorld, avgFluxTF)

            if False:
                avgFluxTF = transport.computeElementFaceFlux(
                    fluxWorld.NWorldCoarse, fluxWorld.NWorldCoarse,
                    NFluxElement, aBase, uFull)
                avgFluxTF = transport.computeAverageFaceFlux(
                    fluxWorld.NWorldCoarse, avgFluxTF)

            return avgFluxTF, conservativeFluxTF

        avgFluxTF, conservativeFluxTF = computeAvgVelocitiesTF(NCoarseElement)
        avgFluxtf, conservativeFluxtf = computeAvgVelocitiesTF(
            np.ones_like(NCoarseElement))

        def fractionalFlow(s):
            return s**3

        boundarys = np.array([[0, 0], [1, 0]])

        sT = np.zeros(world.NtCoarse)
        st = np.zeros(world.NtFine)

        nTime = 1e5
        endTime = 1
        dTime = endTime / float(nTime)
        volt = np.prod(1. / world.NWorldFine)
        volT = np.prod(1. / world.NWorldCoarse)

        plt.figure()
        h1 = plt.gcf().number
        plt.figure()
        h2 = plt.gcf().number
        plt.figure()
        h3 = plt.gcf().number

        for timeStep in np.arange(nTime):

            def computeElementNetFluxT(NFluxElement, avgFluxTF, sT):
                fluxWorld = World(NWorldFine / NFluxElement, NFluxElement,
                                  boundaryConditions)
                netFluxT = transport.computeElementNetFlux(
                    fluxWorld, avgFluxTF, sT, boundarys, fractionalFlow)
                return netFluxT

            netFluxT = computeElementNetFluxT(NCoarseElement,
                                              conservativeFluxTF, sT)
            netFluxt = computeElementNetFluxT(np.ones_like(NCoarseElement),
                                              conservativeFluxtf, st)

            sT = sT + dTime / volT * netFluxT
            #sT[sT > 1] = 1.
            #sT[sT < 0] = 0.

            st = st + dTime / volt * netFluxt
            #st[st > 1] = 1.
            #st[st < 0] = 0.

            if timeStep % 1000 == 0 or timeStep == nTime - 1:
                plt.figure(h1)
                drawSaturation(NWorldCoarse, sT)
                plt.title('sT')
                plt.gcf().canvas.draw()

                plt.figure(h2)
                drawSaturation(NWorldFine, st)
                plt.title('st')
                plt.gcf().canvas.draw()

                plt.figure(h3)
                stProjected = projectSaturation(NWorldCoarse, NCoarseElement,
                                                st)
                drawSaturation(NWorldCoarse, stProjected)
                plt.title('st projected')
                plt.gcf().canvas.draw()

                print np.sqrt(np.mean((stProjected - sT)**2))

                plt.pause(0.0001)
        plt.show()
Exemple #11
0
    def test_00coarseFlux(self):
        NWorldFine = np.array([20, 20])
        NpFine = np.prod(NWorldFine + 1)
        NtFine = np.prod(NWorldFine)
        NWorldCoarse = np.array([4, 4])
        NCoarseElement = NWorldFine / NWorldCoarse
        NtCoarse = np.prod(NWorldCoarse)
        NpCoarse = np.prod(NWorldCoarse + 1)

        boundaryConditions = np.array([[0, 0], [1, 1]])
        world = World(NWorldCoarse, NCoarseElement, boundaryConditions)

        np.random.seed(0)

        aBaseSquare = np.exp(5 * np.random.random_sample(NWorldFine[1]))
        aBaseCube = np.tile(aBaseSquare[..., np.newaxis], [NWorldFine[0], 1])
        aBaseCube = aBaseCube[..., np.newaxis]

        aBase = aBaseCube.flatten()

        IPatchGenerator = lambda i, N: interp.L2ProjectionPatchMatrix(
            i, N, NWorldCoarse, NCoarseElement, boundaryConditions)

        aCoef = coef.coefficientFine(NWorldCoarse, NCoarseElement, aBase)

        k = 4
        printLevel = 0
        pglod = pg.PetrovGalerkinLOD(world, k, IPatchGenerator, 0, printLevel)
        pglod.updateCorrectors(aCoef)

        KmsFull = pglod.assembleMsStiffnessMatrix()

        coords = util.pCoordinates(NWorldCoarse)
        xC = coords[:, 0]
        g = 1 - xC
        bFull = -KmsFull * g

        boundaryMap = boundaryConditions == 0
        fixed = util.boundarypIndexMap(NWorldCoarse, boundaryMap)
        free = np.setdiff1d(np.arange(0, NpCoarse), fixed)
        KmsFree = KmsFull[free][:, free]

        bFree = bFull[free]
        xFree = sparse.linalg.spsolve(KmsFree, bFree)
        xFull = np.zeros(NpCoarse)
        xFull[free] = xFree
        uFull = xFull + g

        lodFluxTF = pglod.computeFaceFluxTF(uFull)

        ## Compute fine solution
        coords = util.pCoordinates(NWorldFine)
        xF = coords[:, 0]
        gFine = 1 - xF
        uFineFull, AFine, _ = femsolver.solveFine(world, aBase, None, -gFine,
                                                  boundaryConditions)
        uFineFull = uFineFull + gFine
        fineFluxTF = transport.computeHarmonicMeanFaceFlux(
            NWorldCoarse, NWorldCoarse, NCoarseElement, aBase, uFineFull)

        self.assertTrue(np.allclose(lodFluxTF, fineFluxTF, rtol=1e-7))
Exemple #12
0
    def test_3d(self):
        return
        NWorldFine = np.array([60, 220, 50])
        NpFine = np.prod(NWorldFine + 1)
        NtFine = np.prod(NWorldFine)
        NWorldCoarse = np.array([6, 22, 5])
        NCoarseElement = NWorldFine / NWorldCoarse
        NtCoarse = np.prod(NWorldCoarse)
        NpCoarse = np.prod(NWorldCoarse + 1)

        boundaryConditions = np.array([[1, 1], [0, 0], [1, 1]])
        world = World(NWorldCoarse, NCoarseElement, boundaryConditions)

        aBase = np.loadtxt(
            os.path.dirname(os.path.realpath(__file__)) +
            '/data/upperness_x.txt')
        #aBase = aBase[::8]

        print 'a'
        coords = util.pCoordinates(NWorldFine)
        gFine = 1 - coords[:, 1]
        uFineFull, AFine, _ = femsolver.solveFine(world, aBase, None, -gFine,
                                                  boundaryConditions)
        print 'b'

        rCoarse = np.ones(NtCoarse)

        self.assertTrue(np.size(aBase) == NtFine)

        if True:
            IPatchGenerator = lambda i, N: interp.L2ProjectionPatchMatrix(
                i, N, NWorldCoarse, NCoarseElement, boundaryConditions)
            aCoef = coef.coefficientCoarseFactor(NWorldCoarse, NCoarseElement,
                                                 aBase, rCoarse)

            k = 2
            printLevel = 1
            pglod = pg.PetrovGalerkinLOD(world, k, IPatchGenerator, 1e-1,
                                         printLevel)
            pglod.updateCorrectors(aCoef, clearFineQuantities=True)

            KmsFull = pglod.assembleMsStiffnessMatrix()

            coords = util.pCoordinates(NWorldCoarse)
            g = 1 - coords[:, 1]
            bFull = -KmsFull * g

            boundaryMap = boundaryConditions == 0
            fixed = util.boundarypIndexMap(NWorldCoarse, boundaryMap)
            free = np.setdiff1d(np.arange(0, NpCoarse), fixed)

            KmsFree = KmsFull[free][:, free]
            bFree = bFull[free]

            xFree = sparse.linalg.spsolve(KmsFree, bFree)

            uCoarse = np.zeros(NpCoarse)
            uCoarse[free] = xFree
            uCoarse += g
            uCube = np.reshape(uCoarse, (NWorldCoarse + 1)[::-1])
            uCube = np.ascontiguousarray(np.transpose(uCube, axes=[2, 1, 0]))

            imageToVTK("./image", pointData={"u": uCube})

        if False:
            coord = util.pCoordinates(NWorldCoarse)
            uCoarse = coord[:, 1].flatten()
            uCube = np.reshape(uCoarse, (NWorldCoarse + 1)[::-1])
            uCube = np.ascontiguousarray(np.transpose(uCube, axes=[2, 1, 0]))
            imageToVTK("./image", pointData={"u": uCube})
Exemple #13
0
    def test_2d_flux(self):
        # Stripes perpendicular to flow direction gives effective
        # permeability as the harmonic mean of the permeabilities of
        # the stripes.
        NWorldFine = np.array([20, 20])
        NpFine = np.prod(NWorldFine + 1)
        NtFine = np.prod(NWorldFine)
        NWorldCoarse = np.array([2, 2])
        NCoarseElement = NWorldFine / NWorldCoarse
        NtCoarse = np.prod(NWorldCoarse)
        NpCoarse = np.prod(NWorldCoarse + 1)

        boundaryConditions = np.array([[0, 0], [1, 1]])
        world = World(NWorldCoarse, NCoarseElement, boundaryConditions)

        np.random.seed(0)

        aBaseSquare = np.exp(5 * np.random.random_sample(NWorldFine[1]))
        aBaseCube = np.tile(aBaseSquare[..., np.newaxis], [NWorldFine[0], 1])
        aBaseCube = aBaseCube[..., np.newaxis]

        aBase = aBaseCube.flatten()

        IPatchGenerator = lambda i, N: interp.L2ProjectionPatchMatrix(
            i, N, NWorldCoarse, NCoarseElement, boundaryConditions)

        aCoef = coef.coefficientFine(NWorldCoarse, NCoarseElement, aBase)

        k = 2
        printLevel = 0
        pglod = pg.PetrovGalerkinLOD(world, k, IPatchGenerator, 0, printLevel)
        pglod.updateCorrectors(aCoef)

        KmsFull = pglod.assembleMsStiffnessMatrix()

        coords = util.pCoordinates(NWorldCoarse)
        xC = coords[:, 0]
        g = 1 - xC
        bFull = -KmsFull * g

        boundaryMap = boundaryConditions == 0
        fixed = util.boundarypIndexMap(NWorldCoarse, boundaryMap)
        free = np.setdiff1d(np.arange(0, NpCoarse), fixed)
        KmsFree = KmsFull[free][:, free]

        bFree = bFull[free]
        xFree = sparse.linalg.spsolve(KmsFree, bFree)
        xFull = np.zeros(NpCoarse)
        xFull[free] = xFree

        MGammaLocGetter = fem.localBoundaryMassMatrixGetter(NWorldCoarse)
        MGammaFull = fem.assemblePatchBoundaryMatrix(NWorldCoarse,
                                                     MGammaLocGetter,
                                                     boundaryMap=boundaryMap)

        # Solve (F, w) = a(u0, w) + a(g, w) in space of fixed DoFs only
        KmsFixedFull = KmsFull[fixed]
        cFixed = KmsFixedFull * (xFull + g)
        MGammaFixed = MGammaFull[fixed][:, fixed]
        FFixed = sparse.linalg.spsolve(MGammaFixed, cFixed)
        FFull = np.zeros(NpCoarse)
        FFull[fixed] = FFixed

        self.assertTrue(
            np.isclose(np.mean(FFixed[FFixed > 0]), stats.hmean(aBaseSquare)))
Exemple #14
0
    def test_2d_exactSolution(self):
        NWorldFine = np.array([30, 40])
        NpFine = np.prod(NWorldFine + 1)
        NtFine = np.prod(NWorldFine)
        NWorldCoarse = np.array([3, 4])
        NCoarseElement = NWorldFine / NWorldCoarse
        NtCoarse = np.prod(NWorldCoarse)
        NpCoarse = np.prod(NWorldCoarse + 1)

        boundaryConditions = np.array([[0, 0], [1, 1]])
        world = World(NWorldCoarse, NCoarseElement, boundaryConditions)

        np.random.seed(0)

        aBaseSquare = np.exp(5 * np.random.random_sample(NWorldFine[0]))
        aBaseCube = np.tile(aBaseSquare, [NWorldFine[1], 1])
        aBaseCube = aBaseCube[..., np.newaxis]

        aBase = aBaseCube.flatten()

        IPatchGenerator = lambda i, N: interp.L2ProjectionPatchMatrix(
            i, N, NWorldCoarse, NCoarseElement, boundaryConditions)

        rCoarse = np.ones(NtCoarse)
        aCoef = coef.coefficientCoarseFactor(NWorldCoarse, NCoarseElement,
                                             aBase, rCoarse)

        k = 4
        printLevel = 0
        epsilonTol = 0.05
        pglod = pg.PetrovGalerkinLOD(world, k, IPatchGenerator, epsilonTol,
                                     printLevel)
        pglod.updateCorrectors(aCoef, clearFineQuantities=False)

        boundaryMap = boundaryConditions == 0
        fixed = util.boundarypIndexMap(NWorldCoarse, boundaryMap)
        free = np.setdiff1d(np.arange(0, NpCoarse), fixed)

        coords = util.pCoordinates(NWorldCoarse)
        xC = coords[:, 0]
        yC = coords[:, 1]
        g = 1 - xC

        firstIteration = True

        # First case is to not modify. Error should be 0
        # The other cases modify one, a few or half of the coarse elements to different degrees.
        rCoarseModPairs = [([], []), ([0], [2.]), ([10], [3.]),
                           ([4, 3, 2], [1.3, 1.5, 1.8])]
        rCoarseModPairs.append((range(NtCoarse / 2), [2] * NtCoarse))
        rCoarseModPairs.append((range(NtCoarse / 2), [0.9] * NtCoarse))
        rCoarseModPairs.append((range(NtCoarse / 2), [0.95] * NtCoarse))

        for i, rCoarseModPair in zip(count(), rCoarseModPairs):
            for ind, val in zip(rCoarseModPair[0], rCoarseModPair[1]):
                rCoarse[ind] *= val

            aCoef = coef.coefficientCoarseFactor(NWorldCoarse, NCoarseElement,
                                                 aBase, rCoarse)
            pglod.updateCorrectors(aCoef, clearFineQuantities=False)

            KmsFull = pglod.assembleMsStiffnessMatrix()
            bFull = -KmsFull * g

            KmsFree = KmsFull[free][:, free]

            bFree = bFull[free]
            xFree = sparse.linalg.spsolve(KmsFree, bFree)

            basis = fem.assembleProlongationMatrix(NWorldCoarse,
                                                   NCoarseElement)
            basisCorrectors = pglod.assembleBasisCorrectors()
            modifiedBasis = basis - basisCorrectors

            xFull = np.zeros(NpCoarse)
            xFull[free] = xFree
            uLodFine = modifiedBasis * (xFull + g)

            gFine = basis * g
            uFineFull, AFine, MFine = femsolver.solveFine(
                world, aCoef.aFine, None, -gFine, boundaryConditions)
            uFineFull += gFine

            errorFineA = np.sqrt(
                np.dot(uFineFull - uLodFine, AFine * (uFineFull - uLodFine)))
            errorFineM = np.sqrt(
                np.dot(uFineFull - uLodFine, MFine * (uFineFull - uLodFine)))
            if firstIteration:
                self.assertTrue(np.isclose(errorFineA, 0))
                self.assertTrue(np.isclose(errorFineM, 0))

                # Also compute upscaled solution and compare with uFineFull
                uLodFineUpscaled = basis * (
                    xFull + g) - pglod.computeCorrection(ARhsFull=basis *
                                                         (xFull + g))
                self.assertTrue(np.allclose(uLodFineUpscaled, uLodFine))

                firstIteration = False
            else:
                # For this problem, it seems that
                # error < 1.1*errorTol
                self.assertTrue(errorFineA <= 1.1 * epsilonTol)
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()