From e7bec66b54ac1df2960a9507e2eade85ef8b990f Mon Sep 17 00:00:00 2001 From: Michael Innerberger <michael.innerberger@asc.tuwien.ac.at> Date: Mon, 4 Jul 2022 15:56:12 +0200 Subject: [PATCH] Add modified Zarantonello iteration (allows for larger delta) --- experiments/iterativeModifiedZarantonello.m | 159 ++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 experiments/iterativeModifiedZarantonello.m diff --git a/experiments/iterativeModifiedZarantonello.m b/experiments/iterativeModifiedZarantonello.m new file mode 100644 index 0000000..6ab3536 --- /dev/null +++ b/experiments/iterativeModifiedZarantonello.m @@ -0,0 +1,159 @@ +% ****************************************************************************** +% Adaptive FEM algorithm for a non-symmetric/indefinite problem using a +% modified Zarantonello iteration (where the energy scalar product is used +% instead of the Laplace operator). +% ****************************************************************************** + +%% paramters +nEmax = 1e4; +theta = 0.5; +coeff = 150; +lambda = 0.1; +delta = 0.03; + +%% initialization +mesh = Mesh.loadFromGeometry('Lshape'); +mesh.refineUniform(1); +fes = FeSpace(mesh, LowestOrderH1Fe()); +u = FeFunction(fes); +u.setData(0); +uref = FeFunction(fes); +uold = FeFunction(fes); +update = FeFunction(fes); + +%% problem data +blf = BilinearForm(fes); +blf.a = Constant(mesh, 5); + +blfZ = BilinearForm(fes); +blfZ.a = Constant(mesh, 1); + +[lf, perturbation] = setUpConvectionProblem(fes, uold, coeff); +% [lf, perturbation] = setUpHelmholtzProblem(fes, uold, coeff); + +lfRef = LinearForm(fes); +lfRef.f = Constant(mesh, 1); + +P = LoFeProlongation(fes); + +%% adaptive loop +ell = 0; +[nElements, estimator, exactDiff, nIter] = deal(zeros(1000,1)); +meshSufficientlyFine = false; +while ~meshSufficientlyFine + ell = ell + 1; + freeDofs = getFreeDofs(fes); + A = assemble(blf); + A = A(freeDofs,freeDofs); + Z = assemble(blfZ); + Z = Z(freeDofs,freeDofs); + + K = assemble(perturbation); + Aref = A + K(freeDofs,freeDofs); + Fref = assemble(lfRef); + uref.setFreeData(Aref \ Fref(freeDofs)); + + % inner iteration: sufficiently many kacanov iterations + n = 0; + solutionAccurateEnough = false; + while ~solutionAccurateEnough + n = n + 1; + uold.setData(u.data); + F = assemble(lf); + res = A*u.data(freeDofs)' - F(freeDofs); + update.setFreeData(A \ res); + u.setData(u.data - delta*update.data); + eta2 = estimate(blf, lf, u); + + v = u.data(freeDofs) - uold.data(freeDofs); + iterationDiff = sqrt(v * A * v'); + + solutionAccurateEnough = (iterationDiff < delta*lambda*sqrt(sum(eta2))); + end + + nElements(ell) = mesh.nElements; + estimator(ell) = sqrt(sum(eta2)); + v = u.data(freeDofs) - uref.data(freeDofs); + exactDiff(ell) = sqrt(v * A * v'); + nIter(ell) = n; + printLogMessage('number of elements: %d, estimator: %.2e after %d iterations', ... + mesh.nElements, estimator(ell), n); + + meshSufficientlyFine = (mesh.nElements > nEmax); + + if ~meshSufficientlyFine + marked = markDoerflerBinning(eta2, theta); + mesh.refineLocally(addLargestElement(marked, mesh), 'NVB'); + u.setData(prolongate(P, u)); + end +end + +%% plot solution and estimator +if mesh.nElements < 2e5 + plot(u); +end + +figure() +idx = 1:ell; +yyaxis left +ylabel('error / estimator') +loglog(nElements(idx), estimator(idx), '-o', 'LineWidth', 2) +hold on +loglog(nElements(idx), exactDiff(idx), '-x', 'LineWidth', 2) +shift = estimator(1)*nElements(1); +loglog(nElements(idx), shift*nElements(idx).^(-1/2), '--', 'LineWidth', 2, 'Color', 'k') +yyaxis right +semilogx(nElements(idx), nIter(idx), '-x', 'LineWidth', 2) +ylim([0, max(nIter)+1]) +legend('\eta_H', '|u_H - u^{k}_H|_{H^1}', '#T_H^{-1/2}', 'iteration count') +ylabel('number of iterations') +xlabel('#T_H') +title('Kacanov iteration for non-symmetric / indefinite problem') + + +%% local function for residual a posteriori error estimation +% \eta(T)^2 = h_T^2 * || f ||_{L^2(T)}^2 + h_T * || [A*Du] ||_{L^2(E)}^2 +function indicators = estimate(blf, lf, u) + mesh = blf.fes.mesh; + + f = CompositeFunction(@(f) f.^2, lf.f); + qrTri = QuadratureRule.ofOrder(2); + volumeRes = integrateElement(f, qrTri); + + qrEdge = QuadratureRule.ofOrder(1, '1D'); + f = CompositeFunction(@(A,Du) A.* Du, blf.a, Gradient(u)); + edgeRes = integrateNormalJump(f, qrEdge, @(j) j.^2, {}, ':'); + dirichlet = vertcat(mesh.boundaries{:}); + edgeRes(dirichlet) = 0; + + %% combine the resdiuals suitably + hT = sqrt(getAffineTransformation(mesh).area); + indicators = hT.^2 .* volumeRes + ... + hT .* sum(edgeRes(mesh.element2edges), Dim.Vector); +end + +% -\Delta u + [c;c]*\nabla u = 1 +function [lf, perturbation] = setUpConvectionProblem(fes, uold, coeff) + lf = LinearForm(fes); + perturbation = BilinearForm(fes); + + lf.f = CompositeFunction(@(Du) 1 - vectorProduct(coeff*[1;1], Du), Gradient(uold)); + perturbation.b = Constant(fes.mesh, coeff*[1;1]); +end + +% -\Delta u - c^2*u = 1 +function [lf, perturbation] = setUpHelmholtzProblem(fes, uold, coeff) + lf = LinearForm(fes); + perturbation = BilinearForm(fes); + + lf.f = CompositeFunction(@(u) 1 + coeff^2*u, uold); + lf.qrf = QuadratureRule.ofOrder(2); + perturbation.c = Constant(fes.mesh, -coeff^2); + perturbation.qrc = QuadratureRule.ofOrder(2); +end + +function newMarked = addLargestElement(marked, mesh) + trafo = getAffineTransformation(mesh); + [~,maxElement] = max(trafo.area); + newMarked = union(marked, maxElement); +end -- GitLab