*** Wartungsfenster jeden ersten Mittwoch vormittag im Monat ***

Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
storingLevelOrientedData.m 5.38 KiB
function leveldata = storingLevelOrientedData(doPlots)
%%MAINLEVELDATA Example of an adaptive FEM algorithm with storing and
%displaying level-oriented dataa

    %% proceed optional input
    if nargin < 1
        doPlots = true;
    end

    %% paramters
    nEmax = 1e4;
    theta = 0.5;
    
    %% initialization
    mesh = Mesh.loadFromGeometry('Lshape');
    fes = FeSpace(mesh, LowestOrderH1Fe());
    u = FeFunction(fes);

    %% initialize output data structure
    pathToStorage = 'results';
    leveldata = LevelData(pathToStorage);
    leveldata.problem = 'Poisson';
    leveldata.domain = 'Lshape';
    leveldata.method = 'S1';
    leveldata.identifier = 'example';

    %% problem data
    blf = BilinearForm();
    lf = LinearForm();
    blf.a = Constant(mesh, [1;0;0;1]);
    blf.b = Constant(mesh, [0;0]);
    blf.c = Constant(mesh, 0);
    lf.f = Constant(mesh, 1);
    lf.fvec = Constant(mesh, [0;0]);
    
    % reference value for energy norm of exact solution
    normExactSquared = 0.2140750232;

    %% adaptive loop
    meshSufficientlyFine = false;
    while ~meshSufficientlyFine
        %% compute data for rhs coefficient and assemble forms
        A = assemble(blf, fes);
        F = assemble(lf, fes);
        
        %% solve FEM system
        freeDofs = getFreeDofs(fes);
        tic;
        u.setFreeData(A(freeDofs,freeDofs) \ F(freeDofs));
        runtimeSolve = toc;

        %% approximate error
        err = sqrt(normExactSquared - u.data * A * u.data');

        %% compute refinement indicators
        tic;
        eta2 = estimate(blf, lf, u);
        eta = sqrt(sum(eta2));
        runtimeEstimate = toc;

        %% compute efficiency index
        eff = err / eta;

        %% storing error quantities and general data
        leveldata.append('ndof', uint32(length(freeDofs)), ...
                         'eta', eta, ...
                         'err', err, ...
                         'coordinates', mesh.coordinates, ...
                         'elements', mesh.elements);
        %% storing results of timing
        leveldata.setTime(leveldata.nLevel, ...
                          'runtimeSolve', runtimeSolve, ...
                          'runtimeEstimate', runtimeEstimate);

        %% storing absolute values
        leveldata.setAbsolute(leveldata.nLevel, 'eff', eff);

        %% print information on current level to command line
        leveldata.printLevel();

        %% save intermediate results to file 
        % (prevents data loss in case of crashes)
        leveldata.saveToFile();
      
        %% stoping criterion
        meshSufficientlyFine = (mesh.nElements > nEmax);
        
        %% refine mesh
        if ~meshSufficientlyFine
            marked = markDoerflerBinning(eta2, theta);
            mesh.refineLocally(marked, 'NVB');
        end
    end

    %% post-processing variables
    leveldata.setTime(':', 'runtimeTotal', ...
                      sum(leveldata.get(':', 'runtimeSolve', 'runtimeEstimate'), 2));

    %% plot results
    if doPlots
        % plot error quantities (in general, converging to zeros)
        figure();
        leveldata.plot('ndof');
    
        % plot runtimes (in general, diverging to infinity)
        figure();
        leveldata.plotTime('ndof');
    
        % plot absolute values in semi-logarithmic plot
        figure();
        leveldata.plotAbsolute('ndof');
    
        % plot of all triangulations
        figure();
        leveldata.plotTriangulation();
    
        %% export error plot to file
        leveldata.plotToFile('ndof');

        %% export refinement video
        % (generates video of about 110 MB)
        %leveldata.plotTriangulationToFile();
    end

    %% save all values to comma-separated table
    leveldata.saveToTable();
end




%% local function for residual a posteriori error estimation
% This function shows how to build a residual error estimator with the provided
% tools. Not hiding this in its own class has the advantage that estimation is
% very flexible with respect to the involved terms.
% \eta(T)^2 = h_T^2 * || -div(a*Du) + b*Du + c*u - f + div(fvec) ||_{L^2(T)}^2
%               + h_T * || [ a*Du - fvec ] ||_{L^2(E)}^2
function indicators = estimate(blf, lf, u)
    fes = u.fes;
    mesh =  fes.mesh;
    
    %% compute volume residual element-wise
    % Here, one can optimize the estimator for the given situation. In the case
    % p=1 with constant diffusion, the diffusion term vanishes in the residual.
    % Also div(fvec) vanishes if fvec is element-wise constant.
    f = CompositeFunction(...
        @(b, c, f, u, Du) (vectorProduct(b, Du) + c .* u - f).^2, ...
        blf.b, blf.c, lf.f, u, Gradient(u));
    qrTri = QuadratureRule.ofOrder(4);
    volumeRes = integrateElement(f, qrTri);
    
    %% compute edge residual edge-wise
    % Here, none of the terms vanish, so they must be computed. This can be done
    % with a lower order than the element-residuals.
    f = CompositeFunction(...
        @(a, fvec, Du) vectorProduct(a, Du, [2,2], [2,1]) - fvec, ...
        blf.a, lf.fvec, Gradient(u));
    qrEdge = QuadratureRule.ofOrder(1, '1D');
    edgeRes = integrateNormalJump(f, qrEdge, @(j) j.^2, {}, ':');
    dirichlet = getCombinedBndEdges(mesh, fes.bnd.dirichlet);
    edgeRes(dirichlet) = 0;
    
    %% combine the resdiuals suitably
    hT = sqrt(getAffineTransformation(mesh).area);
    indicators = hT.^2 .* volumeRes + ...
        hT .* sum(edgeRes(mesh.element2edges), Dim.Vector);
end