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"; }