Exemplo n.º 1
0
int main(int argc, char* argv[])
{
    // Process command-line args

    if (argc < 7 || argc % 2 != 1) {
        std::cout << "Solve a Maxwell Dirichlet problem in an exterior domain.\n"
                  << "Usage: " << argv[0]
                  << " <mesh_file> <n_threads> <aca_eps> <solver_tol>"
                  << " <singular_order_increment>"
                  << " [<regular_order_increment_1> <min_relative_distance_1>]"
                  << " [<regular_order_increment_2> <min_relative_distance_2>]"
                  << " [...] <regular_order_increment_n>"
                  << std::endl;
        return 1;
    }
    int maxThreadCount = atoi(argv[2]);
    double acaEps = atof(argv[3]);
    double solverTol = atof(argv[4]);
    int singOrderIncrement = atoi(argv[5]);
    if (acaEps > 1. || acaEps < 0.) {
        std::cout << "Invalid aca_eps: " << acaEps << std::endl;
        return 1;
    }
    if (solverTol > 1. || solverTol < 0.) {
        std::cout << "Invalid solver_tol: " << solverTol << std::endl;
        return 1;
    }

    AccuracyOptionsEx accuracyOptions;
    std::vector<double> maxNormDists;
    std::vector<int> orderIncrements;
    for (int i = 6; i < argc - 1; i += 2) {
        orderIncrements.push_back(atoi(argv[i]));
        maxNormDists.push_back(atof(argv[i + 1]));
    }
    orderIncrements.push_back(atoi(argv[argc - 1]));
    accuracyOptions.setDoubleRegular(maxNormDists, orderIncrements);
    accuracyOptions.setDoubleSingular(singOrderIncrement);
    accuracyOptions.setSingleRegular(2);

    // Load mesh

    GridParameters params;
    params.topology = GridParameters::TRIANGULAR;
    shared_ptr<Grid> grid = GridFactory::importGmshGrid(params, argv[1]);

    // Initialize the space

    RaviartThomas0VectorSpace<BFT> HdivSpace(grid);

    // Set assembly mode and options

    AssemblyOptions assemblyOptions;
    assemblyOptions.setMaxThreadCount(maxThreadCount);
    if (acaEps > 0.) {
        AcaOptions acaOptions;
        acaOptions.eps = acaEps;
        assemblyOptions.switchToAcaMode(acaOptions);
    }

    NumericalQuadratureStrategy<BFT, RT> quadStrategy(accuracyOptions);
    Context<BFT, RT> context(make_shared_from_ref(quadStrategy), assemblyOptions);

    // Construct operators

    BoundaryOperator<BFT, RT> slpOp = maxwell3dSingleLayerBoundaryOperator<BFT>(
                make_shared_from_ref(context),
                make_shared_from_ref(HdivSpace),
                make_shared_from_ref(HdivSpace),
                make_shared_from_ref(HdivSpace),
                k,
                "SLP");
    BoundaryOperator<BFT, RT> dlpOp = maxwell3dDoubleLayerBoundaryOperator<BFT>(
                make_shared_from_ref(context),
                make_shared_from_ref(HdivSpace),
                make_shared_from_ref(HdivSpace),
                make_shared_from_ref(HdivSpace),
                k,
                "DLP");
    BoundaryOperator<BFT, RT> idOp = maxwell3dIdentityOperator<BFT, RT>(
                make_shared_from_ref(context),
                make_shared_from_ref(HdivSpace),
                make_shared_from_ref(HdivSpace),
                make_shared_from_ref(HdivSpace),
                "Id");

    // Construct a grid function representing the Dirichlet data

    GridFunction<BFT, RT> dirichletData(
                make_shared_from_ref(context),
                make_shared_from_ref(HdivSpace),
                make_shared_from_ref(HdivSpace),
                surfaceNormalDependentFunction(DirichletData()));

    dirichletData.exportToVtk(VtkWriter::CELL_DATA, "Dirichlet_data",
                              "input_dirichlet_data_cell");
    dirichletData.exportToVtk(VtkWriter::VERTEX_DATA, "Dirichlet_data",
                              "input_dirichlet_data_vertex");

    // Construct a grid function representing the right-hand side

    GridFunction<BFT, RT> rhs = -((0.5 * idOp + dlpOp) * dirichletData);

    // Solve the equation

    Solution<BFT, RT> solution;
#ifdef WITH_AHMED
    if (solverTol > 0.) {
        DefaultIterativeSolver<BFT, RT> solver(slpOp);

        AcaApproximateLuInverse<RT> slpOpLu(
                     DiscreteAcaBoundaryOperator<RT>::castToAca(
                         *slpOp.weakForm()),
                         /* LU factorisation accuracy */ 0.01);
        Preconditioner<RT> prec =
                     discreteOperatorToPreconditioner<RT>(
                         make_shared_from_ref(slpOpLu));

        solver.initializeSolver(defaultGmresParameterList(solverTol, 10000), prec);
        solution = solver.solve(rhs);
    } else {
        DefaultDirectSolver<BFT, RT> solver(slpOp);
        solution = solver.solve(rhs);
    }
#else // WITH_AHMED
    DefaultDirectSolver<BFT, RT> solver(slpOp);
    solution = solver.solve(rhs);
#endif
    std::cout << solution.solverMessage() << std::endl;

    // Extract the solution

    const GridFunction<BFT, RT>& neumannData = solution.gridFunction();

    neumannData.exportToVtk(VtkWriter::CELL_DATA, "Neumann_data",
                        "calculated_neumann_data_cell");
    neumannData.exportToVtk(VtkWriter::VERTEX_DATA, "Neumann_data",
                        "calculated_neumann_data_vertex");

    // Compare the solution against the analytical result
    GridFunction<BFT, RT> exactNeumannData(
                make_shared_from_ref(context),
                make_shared_from_ref(HdivSpace),
                make_shared_from_ref(HdivSpace),
                surfaceNormalDependentFunction(ExactNeumannData()));
    exactNeumannData.exportToVtk(VtkWriter::CELL_DATA, "Neumann_data",
                                 "exact_neumann_data_cell");
    exactNeumannData.exportToVtk(VtkWriter::VERTEX_DATA, "Neumann_data",
                                 "exact_neumann_data_vertex");
    EvaluationOptions evaluationOptions;
    CT absoluteError = L2NormOfDifference(
                neumannData, surfaceNormalDependentFunction(ExactNeumannData()),
                quadStrategy, evaluationOptions);
    CT exactSolNorm = L2NormOfDifference(
                0. * neumannData, surfaceNormalDependentFunction(ExactNeumannData()),
                quadStrategy, evaluationOptions);
    std::cout << "Relative L^2 error: " << absoluteError / exactSolNorm
              << "\nAbsolute L^2 error: " << absoluteError << std::endl;

    // Evaluate the solution at a few points

    Maxwell3dSingleLayerPotentialOperator<BFT> slpPotOp(k);
    Maxwell3dDoubleLayerPotentialOperator<BFT> dlpPotOp(k);

    const int dimWorld = 3;
    const int pointCount = 3;
    arma::Mat<CT> points(dimWorld, pointCount * pointCount);
    for (int i = 0; i < pointCount; ++i)
        for (int j = 0; j < pointCount; ++j) {
            points(0, i * pointCount + j) = 3. + i / CT(pointCount - 1);
            points(1, i * pointCount + j) = 2. + j / CT(pointCount - 1);
            points(2, i * pointCount + j) = 0.5;
        }

    arma::Mat<RT> slpContrib = slpPotOp.evaluateAtPoints(
        neumannData, points, quadStrategy, evaluationOptions);
    arma::Mat<RT> dlpContrib = dlpPotOp.evaluateAtPoints(
        dirichletData, points, quadStrategy, evaluationOptions);
    arma::Mat<RT> values = -slpContrib - dlpContrib;

    // Evaluate the analytical solution at the same points

    ExactSolution exactSolution;
    arma::Mat<RT> exactValues(dimWorld, pointCount * pointCount);
    for (int i = 0; i < pointCount * pointCount; ++i) {
        arma::Col<RT> activeResultColumn = exactValues.unsafe_col(i);
        exactSolution.evaluate(points.unsafe_col(i), activeResultColumn);
    }

    // Compare the numerical and analytical solutions

    std::cout << "Numerical | analytical\n";
    for (int i = 0; i < pointCount * pointCount; ++i)
        std::cout << values(0, i) << " "
                  << values(1, i) << " "
                  << values(2, i) << " | "
                  << exactValues(0, i) << " "
                  << exactValues(1, i) << " "
                  << exactValues(2, i) << "\n";
}