BOOST_AUTO_TEST_CASE_TEMPLATE(aca_of_synthetic_maxwell_single_layer_operator_agrees_with_dense_assembly_in_asymmetric_case, ValueType, complex_result_types) { typedef ValueType RT; typedef typename ScalarTraits<ValueType>::RealType RealType; typedef RealType BFT; GridParameters params; params.topology = GridParameters::TRIANGULAR; shared_ptr<Grid> grid = GridFactory::importGmshGrid( params, "../../meshes/sphere-h-0.4.msh", false /* verbose */); RT waveNumber = initWaveNumber<RT>(); shared_ptr<Space<BFT> > vectorPwiseLinears( new RaviartThomas0VectorSpace<BFT>(grid)); shared_ptr<Space<BFT> > vectorPwiseLinears2( new RaviartThomas0VectorSpace<BFT>(grid)); AccuracyOptions accuracyOptions; accuracyOptions.doubleRegular.setRelativeQuadratureOrder(2); accuracyOptions.singleRegular.setRelativeQuadratureOrder(2); shared_ptr<NumericalQuadratureStrategy<BFT, RT> > quadStrategy( new NumericalQuadratureStrategy<BFT, RT>(accuracyOptions)); AssemblyOptions assemblyOptionsDense; assemblyOptionsDense.setVerbosityLevel(VerbosityLevel::LOW); shared_ptr<Context<BFT, RT> > contextDense( new Context<BFT, RT>(quadStrategy, assemblyOptionsDense)); BoundaryOperator<BFT, RT> opDense = maxwell3dSingleLayerBoundaryOperator<BFT>( contextDense, vectorPwiseLinears, vectorPwiseLinears, vectorPwiseLinears, waveNumber); arma::Mat<RT> weakFormDense = opDense.weakForm()->asMatrix(); AssemblyOptions assemblyOptionsAca; assemblyOptionsAca.setVerbosityLevel(VerbosityLevel::LOW); AcaOptions acaOptions; acaOptions.mode = AcaOptions::LOCAL_ASSEMBLY; assemblyOptionsAca.switchToAcaMode(acaOptions); shared_ptr<Context<BFT, RT> > contextAca( new Context<BFT, RT>(quadStrategy, assemblyOptionsAca)); // Internal domain different from dualToRange BoundaryOperator<BFT, RT> opAca = maxwell3dSingleLayerBoundaryOperator<BFT>( contextAca, vectorPwiseLinears, vectorPwiseLinears, vectorPwiseLinears2, waveNumber); arma::Mat<RT> weakFormAca = opAca.weakForm()->asMatrix(); BOOST_CHECK(check_arrays_are_close<ValueType>( weakFormDense, weakFormAca, 2. * acaOptions.eps)); }
BOOST_AUTO_TEST_CASE_TEMPLATE(aca_of_synthetic_modified_helmholtz_hypersingular_operator_agrees_with_dense_assembly_in_symmetric_case, ValueType, result_types) { typedef ValueType RT; typedef typename ScalarTraits<ValueType>::RealType RealType; typedef RealType BFT; GridParameters params; params.topology = GridParameters::TRIANGULAR; shared_ptr<Grid> grid = GridFactory::importGmshGrid( params, "../../meshes/sphere-h-0.4.msh", false /* verbose */); RT waveNumber = initWaveNumber<RT>(); shared_ptr<Space<BFT> > pwiseConstants( new PiecewiseConstantScalarSpace<BFT>(grid)); shared_ptr<Space<BFT> > pwiseLinears( new PiecewiseLinearContinuousScalarSpace<BFT>(grid)); AccuracyOptions accuracyOptions; accuracyOptions.doubleRegular.setRelativeQuadratureOrder(2); accuracyOptions.singleRegular.setRelativeQuadratureOrder(2); shared_ptr<NumericalQuadratureStrategy<BFT, RT> > quadStrategy( new NumericalQuadratureStrategy<BFT, RT>(accuracyOptions)); AssemblyOptions assemblyOptionsDense; assemblyOptionsDense.setVerbosityLevel(VerbosityLevel::LOW); shared_ptr<Context<BFT, RT> > contextDense( new Context<BFT, RT>(quadStrategy, assemblyOptionsDense)); BoundaryOperator<BFT, RT> opDense = modifiedHelmholtz3dHypersingularBoundaryOperator<BFT, RT, RT>( contextDense, pwiseLinears, pwiseConstants, pwiseLinears, waveNumber); arma::Mat<RT> weakFormDense = opDense.weakForm()->asMatrix(); AssemblyOptions assemblyOptionsAca; assemblyOptionsAca.setVerbosityLevel(VerbosityLevel::LOW); AcaOptions acaOptions; acaOptions.mode = AcaOptions::LOCAL_ASSEMBLY; assemblyOptionsAca.switchToAcaMode(acaOptions); shared_ptr<Context<BFT, RT> > contextAca( new Context<BFT, RT>(quadStrategy, assemblyOptionsAca)); BoundaryOperator<BFT, RT> opAca = modifiedHelmholtz3dHypersingularBoundaryOperator<BFT, RT, RT>( contextAca, pwiseLinears, pwiseConstants, pwiseLinears, waveNumber); arma::Mat<RT> weakFormAca = opAca.weakForm()->asMatrix(); BOOST_CHECK(check_arrays_are_close<ValueType>( weakFormDense, weakFormAca, 2. * acaOptions.eps)); }
BOOST_AUTO_TEST_CASE_TEMPLATE(symmetric_matches_nonsymmetric_in_aca_mode, ValueType, result_types) { typedef ValueType RT; typedef typename Fiber::ScalarTraits<ValueType>::RealType RealType; typedef RealType BFT; if (boost::is_same<RT, std::complex<float> >::value) { // The AHMED support for single-precision complex symmetric matrices // is broken BOOST_CHECK(true); return; } GridParameters params; params.topology = GridParameters::TRIANGULAR; shared_ptr<Grid> grid = GridFactory::importGmshGrid( params, "../../examples/meshes/sphere-h-0.4.msh", false /* verbose */); PiecewiseLinearContinuousScalarSpace<BFT> pwiseLinears(grid); PiecewiseConstantScalarSpace<BFT> pwiseConstants(grid); AssemblyOptions assemblyOptions; assemblyOptions.setVerbosityLevel(VerbosityLevel::LOW); AcaOptions acaOptions; acaOptions.minimumBlockSize = 4; assemblyOptions.switchToAcaMode(acaOptions); AccuracyOptions accuracyOptions; accuracyOptions.doubleRegular.setRelativeQuadratureOrder(4); accuracyOptions.doubleSingular.setRelativeQuadratureOrder(2); NumericalQuadratureStrategy<BFT, RT> quadStrategy(accuracyOptions); Context<BFT, RT> context(make_shared_from_ref(quadStrategy), assemblyOptions); const RT waveNumber = initWaveNumber<RT>(); BoundaryOperator<BFT, RT> opNonsymmetric = modifiedHelmholtz3dSingleLayerBoundaryOperator<BFT, RT, RT>( make_shared_from_ref(context), make_shared_from_ref(pwiseLinears), make_shared_from_ref(pwiseConstants), make_shared_from_ref(pwiseLinears), waveNumber, "", NO_SYMMETRY); BoundaryOperator<BFT, RT> opSymmetric = modifiedHelmholtz3dSingleLayerBoundaryOperator<BFT, RT, RT>( make_shared_from_ref(context), make_shared_from_ref(pwiseLinears), make_shared_from_ref(pwiseConstants), make_shared_from_ref(pwiseLinears), waveNumber, "", SYMMETRIC); arma::Mat<RT> matNonsymmetric = opNonsymmetric.weakForm()->asMatrix(); arma::Mat<RT> matSymmetric = opSymmetric.weakForm()->asMatrix(); BOOST_CHECK(check_arrays_are_close<RT>( matNonsymmetric, matSymmetric, 2 * acaOptions.eps)); }
BOOST_AUTO_TEST_CASE_TEMPLATE(L2Norm_works_for_constant_function_and_piecewise_constants, ResultType, result_types) { typedef ResultType RT; typedef typename ScalarTraits<RT>::RealType BFT; typedef typename ScalarTraits<RT>::RealType CT; GridParameters params; params.topology = GridParameters::TRIANGULAR; shared_ptr<Grid> grid = GridFactory::importGmshGrid( params, "../../meshes/sphere-h-0.1.msh", false /* verbose */); shared_ptr<Space<BFT> > space( new PiecewiseConstantScalarSpace<BFT>(grid)); AccuracyOptions accuracyOptions; shared_ptr<NumericalQuadratureStrategy<BFT, RT> > quadStrategy( new NumericalQuadratureStrategy<BFT, RT>(accuracyOptions)); AssemblyOptions assemblyOptions; assemblyOptions.setVerbosityLevel(VerbosityLevel::LOW); shared_ptr<Context<BFT, RT> > context( new Context<BFT, RT>(quadStrategy, assemblyOptions)); Bempp::GridFunction<BFT, RT> fun(context, space, space, surfaceNormalIndependentFunction( ConstantFunction<RT>())); CT norm = fun.L2Norm(); CT expectedNorm = sqrt(2. * 2. * 4. * M_PI); BOOST_CHECK_CLOSE(norm, expectedNorm, 1 /* percent */); }
BOOST_AUTO_TEST_CASE_TEMPLATE(cubic_function_can_be_expanded_in_cubic_space, ResultType, result_types) { typedef ResultType RT; typedef typename ScalarTraits<RT>::RealType BFT; typedef typename ScalarTraits<RT>::RealType CT; GridParameters params; params.topology = GridParameters::TRIANGULAR; shared_ptr<Grid> grid = GridFactory::importGmshGrid( params, "../../examples/meshes/sphere-h-0.2.msh", false /* verbose */); shared_ptr<Space<BFT> > space( new PiecewisePolynomialDiscontinuousScalarSpace<BFT>(grid, 3)); AccuracyOptions accuracyOptions; accuracyOptions.singleRegular.setRelativeQuadratureOrder(2); shared_ptr<NumericalQuadratureStrategy<BFT, RT> > quadStrategy( new NumericalQuadratureStrategy<BFT, RT>(accuracyOptions)); AssemblyOptions assemblyOptions; assemblyOptions.setVerbosityLevel(VerbosityLevel::LOW); shared_ptr<Context<BFT, RT> > context( new Context<BFT, RT>(quadStrategy, assemblyOptions)); GridFunction<BFT, RT> function( context, space, space, surfaceNormalIndependentFunction(CubicFunction<RT>())); CT absoluteError, relativeError; estimateL2Error( function, surfaceNormalIndependentFunction(CubicFunction<RT>()), *quadStrategy, absoluteError, relativeError); BOOST_CHECK_SMALL(relativeError, 1000 * std::numeric_limits<CT>::epsilon() /* percent */); }
DefaultLocalAssemblerForIntegralOperatorsOnSurfacesManager( bool cacheSingularIntegrals) { // Create a Bempp grid shared_ptr<Grid> grid = createGrid(); // These important thing is that the domain and dualToRange spaces are // different piecewiseConstantSpace = std::auto_ptr<PiecewiseConstantSpace>( new PiecewiseConstantSpace(grid)); piecewiseLinearSpace = std::auto_ptr<PiecewiseLinearSpace>( new PiecewiseLinearSpace(grid)); op = std::auto_ptr<Operator>(new Operator( make_shared_from_ref(*piecewiseConstantSpace), make_shared_from_ref(*piecewiseLinearSpace), make_shared_from_ref(*piecewiseLinearSpace), "SLP")); // Construct local assembler Fiber::AccuracyOptions options; options.doubleRegular.setRelativeQuadratureOrder(1); quadStrategy = std::auto_ptr<QuadratureStrategy>(new QuadratureStrategy); AssemblyOptions assemblyOptions; assemblyOptions.setVerbosityLevel(VerbosityLevel::LOW); assemblyOptions.enableSingularIntegralCaching(cacheSingularIntegrals); assembler = op->makeAssembler(*quadStrategy, assemblyOptions); }
BOOST_AUTO_TEST_CASE_TEMPLATE(interpolated_matches_noniterpolated, BasisFunctionType, basis_function_types) { typedef BasisFunctionType BFT; typedef typename Fiber::ScalarTraits<BFT>::ComplexType RT; typedef typename Fiber::ScalarTraits<BFT>::ComplexType KT; typedef typename Fiber::ScalarTraits<BFT>::RealType CT; GridParameters params; params.topology = GridParameters::TRIANGULAR; shared_ptr<Grid> grid = GridFactory::importGmshGrid( params, "meshes/two_disjoint_triangles.msh", false /* verbose */); PiecewiseLinearContinuousScalarSpace<BFT> pwiseLinears(grid); PiecewiseConstantScalarSpace<BFT> pwiseConstants(grid); AssemblyOptions assemblyOptions; assemblyOptions.setVerbosityLevel(VerbosityLevel::LOW); AccuracyOptions accuracyOptions; accuracyOptions.doubleRegular.setAbsoluteQuadratureOrder(5); accuracyOptions.doubleSingular.setAbsoluteQuadratureOrder(5); NumericalQuadratureStrategy<BFT, RT> quadStrategy(accuracyOptions); Context<BFT, RT> context(make_shared_from_ref(quadStrategy), assemblyOptions); const KT waveNumber(3.23, 0.31); BoundaryOperator<BFT, RT> opNoninterpolated = modifiedHelmholtz3dSingleLayerBoundaryOperator<BFT, KT, RT>( make_shared_from_ref(context), make_shared_from_ref(pwiseLinears), make_shared_from_ref(pwiseLinears), make_shared_from_ref(pwiseLinears), waveNumber, "", NO_SYMMETRY, false); BoundaryOperator<BFT, RT> opInterpolated = modifiedHelmholtz3dSingleLayerBoundaryOperator<BFT, KT, RT>( make_shared_from_ref(context), make_shared_from_ref(pwiseLinears), make_shared_from_ref(pwiseLinears), make_shared_from_ref(pwiseLinears), waveNumber, "", NO_SYMMETRY, true); arma::Mat<RT> matNoninterpolated = opNoninterpolated.weakForm()->asMatrix(); arma::Mat<RT> matInterpolated = opInterpolated.weakForm()->asMatrix(); const CT eps = std::numeric_limits<CT>::epsilon(); BOOST_CHECK(check_arrays_are_close<RT>( matNoninterpolated, matInterpolated, 100 * eps)); }
DefaultLocalAssemblerForIntegralOperatorsOnSurfacesManager( bool cacheSingularIntegrals) { // Create a Bempp grid shared_ptr<Grid> grid = createGrid(); // Create context Fiber::AccuracyOptions options; options.doubleRegular.setRelativeQuadratureOrder(1); quadStrategy.reset(new QuadratureStrategy); AssemblyOptions assemblyOptions; assemblyOptions.setVerbosityLevel(VerbosityLevel::LOW); assemblyOptions.enableSingularIntegralCaching(cacheSingularIntegrals); Context<BFT, RT> context(quadStrategy, assemblyOptions); // These important thing is that the domain and dualToRange spaces are // different piecewiseConstantSpace.reset(new PiecewiseConstantSpace(grid)); piecewiseLinearSpace.reset(new PiecewiseLinearSpace(grid)); bop = laplace3dSingleLayerBoundaryOperator<BFT, RT>( make_shared_from_ref(context), piecewiseConstantSpace, piecewiseLinearSpace, piecewiseLinearSpace, "SLP"); const Operator& op = static_cast<const Operator&>(*bop.abstractOperator()); // This would be more elegant than the above, but it doesn't // work on Mac because of a problem with RTTI across // shared-library boundaries. // op = boost::dynamic_pointer_cast<const Operator>(bop.abstractOperator()); // Construct local assembler assembler = op.makeAssembler(*quadStrategy, assemblyOptions); }
BOOST_AUTO_TEST_CASE_TEMPLATE(works, BasisFunctionType, basis_function_types) { typedef BasisFunctionType BFT; typedef typename Fiber::ScalarTraits<BFT>::ComplexType RT; typedef typename Fiber::ScalarTraits<BFT>::RealType CT; GridParameters params; params.topology = GridParameters::TRIANGULAR; shared_ptr<Grid> grid = GridFactory::importGmshGrid( params, "meshes/two_disjoint_triangles.msh", false /* verbose */); PiecewiseLinearContinuousScalarSpace<BFT> pwiseLinears(grid); PiecewiseConstantScalarSpace<BFT> pwiseConstants(grid); AssemblyOptions assemblyOptions; assemblyOptions.setVerbosityLevel(VerbosityLevel::LOW); AccuracyOptions accuracyOptions; accuracyOptions.doubleRegular.setAbsoluteQuadratureOrder(5); accuracyOptions.doubleSingular.setAbsoluteQuadratureOrder(5); NumericalQuadratureStrategy<BFT, RT> quadStrategy(accuracyOptions); Context<BFT, RT> context(make_shared_from_ref(quadStrategy), assemblyOptions); const RT waveNumber(1.23, 0.31); BoundaryOperator<BFT, RT> slpOpConstants = Bempp::helmholtz3dSingleLayerBoundaryOperator<BFT>( make_shared_from_ref(context), make_shared_from_ref(pwiseConstants), make_shared_from_ref(pwiseConstants), make_shared_from_ref(pwiseConstants), waveNumber); BoundaryOperator<BFT, RT> slpOpLinears = helmholtz3dSingleLayerBoundaryOperator<BFT>( make_shared_from_ref(context), make_shared_from_ref(pwiseLinears), make_shared_from_ref(pwiseLinears), make_shared_from_ref(pwiseLinears), waveNumber); BoundaryOperator<BFT, RT> hypOp = helmholtz3dHypersingularBoundaryOperator<BFT>( make_shared_from_ref(context), make_shared_from_ref(pwiseLinears), make_shared_from_ref(pwiseLinears), make_shared_from_ref(pwiseLinears), waveNumber); // Get the matrix repr. of the hypersingular operator arma::Mat<RT> hypMat = hypOp.weakForm()->asMatrix(); // Construct the expected hypersingular operator matrix. For this, we need: // * the surface curls of all basis functions (which are constant) typedef Fiber::SurfaceCurl3dElementaryFunctor<CT> ElementaryFunctor; typedef Fiber::ElementaryBasisTransformationFunctorWrapper<ElementaryFunctor> Functor; Functor functor; size_t basisDeps = 0, geomDeps = 0; functor.addDependencies(basisDeps, geomDeps); arma::Mat<CT> points(2, 1); points.fill(0.); typedef Fiber::PiecewiseLinearContinuousScalarBasis<3, BFT> Basis; Basis basis; Fiber::BasisData<BFT> basisData; basis.evaluate(basisDeps, points, Fiber::ALL_DOFS, basisData); Fiber::GeometricalData<CT> geomData[2]; std::unique_ptr<GridView> view = grid->leafView(); std::unique_ptr<EntityIterator<0> > it = view->entityIterator<0>(); it->entity().geometry().getData(geomDeps, points, geomData[0]); it->next(); it->entity().geometry().getData(geomDeps, points, geomData[1]); Fiber::DefaultCollectionOfBasisTransformations<Functor> transformations(functor); Fiber::CollectionOf3dArrays<BFT> surfaceCurl[2]; transformations.evaluate(basisData, geomData[0], surfaceCurl[0]); transformations.evaluate(basisData, geomData[1], surfaceCurl[1]); // * the single-layer potential matrix for constant basis functions arma::Mat<RT> slpMatConstants = slpOpConstants.weakForm()->asMatrix(); // * the single-layer potential matrix for linear basis functions arma::Mat<RT> slpMatLinears = slpOpLinears.weakForm()->asMatrix(); arma::Mat<RT> expectedHypMat(6, 6); for (size_t testElement = 0; testElement < 2; ++testElement) for (size_t trialElement = 0; trialElement < 2; ++trialElement) for (size_t r = 0; r < 3; ++r) for (size_t c = 0; c < 3; ++c) { RT curlMultiplier = 0.; for (size_t dim = 0; dim < 3; ++dim) curlMultiplier += surfaceCurl[testElement][0](dim, r, 0) * surfaceCurl[trialElement][0](dim, c, 0); RT valueMultiplier = 0.; for (size_t dim = 0; dim < 3; ++dim) valueMultiplier += geomData[testElement].normals(dim, 0) * geomData[trialElement].normals(dim, 0); expectedHypMat(3 * testElement + r, 3 * trialElement + c) = curlMultiplier * slpMatConstants(testElement, trialElement) - waveNumber * waveNumber * valueMultiplier * slpMatLinears(3 * testElement + r, 3 * trialElement + c); } BOOST_CHECK(check_arrays_are_close<RT>(expectedHypMat, hypMat, 1e-6)); }