Raw File
test_forms.cpp
/* -*- mode: c++; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; show-trailing-whitespace: t  -*-

 This file is part of the Feel++ library

 Author(s): Christophe Prud'homme <christophe.prudhomme@feelpp.org>
 Date: 16 Jan 2016

 Copyright (C) 2016 Feel++ Consortium

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
#define BOOST_TEST_MODULE test_forms
#include <feel/feelcore/testsuite.hpp>

#include <feel/feelfilters/loadmesh.hpp>
#include <feel/feelfilters/exporter.hpp>
#include <feel/feelfilters/unithypercube.hpp>
#include <feel/feeldiscr/pdh.hpp>
#include <feel/feeldiscr/pdhv.hpp>

/** use Feel namespace */
using namespace Feel;

inline
po::options_description makeOptions()
{
    po::options_description options( "Test Forms  Options" );
    return options;
}

inline
AboutData
makeAbout()
{
    AboutData about( "test_forms" ,
                     "test_forms" ,
                     "0.2",
                     "nD(n=2,3) test forms",
                     Feel::AboutData::License_GPL,
                     "Copyright (c) 2016 Feel++ Consortium" );

    about.addAuthor( "C Prud'homme", "developer", "christophe.prudhomme@feelpp.org", "" );
    return about;
}



FEELPP_ENVIRONMENT_WITH_OPTIONS( makeAbout(), makeOptions() );
BOOST_AUTO_TEST_SUITE( forms_suite )

using dim_t = boost::mpl::list<boost::mpl::int_<2>, boost::mpl::int_<3> >;
//using dim_t = boost::mpl::list<boost::mpl::int_<2>>;
//using dim_t = boost::mpl::list<boost::mpl::int_<3>>;


BOOST_AUTO_TEST_CASE_TEMPLATE( test_form2_faces, T, dim_t )
{
    using Feel::cout;
    BOOST_MESSAGE( "test_form2_faces starts for dim=" << T::value);
    auto meshnd = unitHypercube<T::value>();
    auto mesh = createSubmesh( _mesh=meshnd, _range=faces(meshnd), _update=0 );
    size_type nFaceInParallelMeshnd = nelements(faces(meshnd),true) - nelements(interprocessfaces(meshnd),true)/2;
    size_type nInternalFaceInPara1llelMeshnd = nelements(faces(meshnd),true) - nelements(interprocessfaces(meshnd),true)/2;
    BOOST_CHECK_EQUAL( nelements(elements(mesh),true), nFaceInParallelMeshnd  );
    auto Vh=Pdhv<1>(meshnd,true);
    auto u = Vh->element();
    auto Wh=Pdh<1>(meshnd,true);
    auto p = Wh->element();
    p.on(_range=elements(meshnd),_expr=cst(1.));
    auto Mh=Pdh<1>(mesh,true);
    auto l=Mh->element();
    l.on(_range=elements(mesh),_expr=cst(1.));

    // all the 4 integrals below should be the same
    // compute \int 1 over internalfaces
    auto I = integrate( _range=internalfaces(meshnd), _expr=cst(1.)).evaluate()(0,0)
        +integrate( _range=boundaryfaces(meshnd), _expr=cst(1.)).evaluate()(0,0);
    // compute \int 1 over d-1 mesh
    auto I1 = integrate( _range=elements(mesh), _expr=cst(1.)).evaluate()(0,0);
    // compute \int 1 over internalfaces using left element
    auto I2 = integrate( _range=internalfaces(meshnd), _expr=leftfacev(cst(1.))).evaluate()(0,0)
        +integrate( _range=boundaryfaces(meshnd), _expr=cst(1.)).evaluate()(0,0);
    // compute \int 1 over internalfaces using right element
    auto I3 = integrate( _range=internalfaces(meshnd), _expr=rightfacev(cst(1.))).evaluate()(0,0)
        +integrate( _range=boundaryfaces(meshnd), _expr=cst(1.)).evaluate()(0,0);
    cout << "I=" << I << " I1=" << I1 << " I2=" << I2 << " I3=" << I3 << std::endl;
    BOOST_CHECK_CLOSE( I, I1, 1e-10 );
    BOOST_CHECK_CLOSE( I, I2, 1e-10 );
    BOOST_CHECK_CLOSE( I, I3, 1e-10 );

    auto e=inner(P(),one());
    LOG(INFO) << "a start";
    auto a = form2(_test=Mh, _trial=Wh );
    a = integrate( _range=internalfaces(meshnd), _expr=(e*id(l))*(leftfacet(idt(p)/e)))
        + integrate( _range=boundaryfaces(meshnd), _expr=(e*id(l))*(idt(p)/e));
    a.close();
    cout << "a(1,1) = " << a(l,p) << std::endl;
    BOOST_CHECK_CLOSE( a(l,p), I1, 1e-10 );
    LOG(INFO) << "a done";

    LOG(INFO) << "ai start";
    a = integrate( _range=internalfaces(meshnd), _expr=(e*id(l))*(leftfacet(idt(p)/e)));
    a.close();
    cout << "ai(1,1) = " << a(l,p) << std::endl;
    LOG(INFO) << "ai done";

    LOG(INFO) << "ab start";
    a = integrate( _range=boundaryfaces(meshnd), _expr=(e*id(l))*(leftfacet(idt(p)/e)));
    a.close();
    cout << "ab(1,1) = " << a(l,p) << std::endl;
    LOG(INFO) << "ab done";

    LOG(INFO) << "a1 start";
    auto a1 = form2(_test=Mh, _trial=Mh );
    a1 = integrate( _range=internalfaces(meshnd), _expr=e*id(l)*idt(l)/(2*e))
        + integrate( _range=boundaryfaces(meshnd), _expr=e*id(l)*idt(l)/e);
    a1.close();
    auto a1en = a1(l,l);
    BOOST_CHECK_CLOSE( a1en, I1, 1e-10 );
    cout << "a1(1,1)=" << a1en << std::endl;
    LOG(INFO) << "a1 done";

    auto a11 = form2(_test=Mh, _trial=Mh );
    a11 = integrate( _range=elements(mesh), _expr=id(l)*idt(l));
    a11.close();
    auto a11en = a11(l,l);
    BOOST_CHECK_CLOSE( a11en, I1, 1e-10 );
    cout << "a11(1,1)=" << a11en << " int =" << I1 << std::endl;

    auto a111 = form2(_test=Mh, _trial=Mh );
    a111 = integrate( _range=internalfaces(meshnd), _expr=id(l)*idt(l)/2)
        + integrate( _range=boundaryfaces(meshnd), _expr=id(l)*idt(l));
    a111.close();
    auto a111en = a111(l,l);
    BOOST_CHECK_CLOSE( a111en, I1, 1e-10 );
    cout << "a111(1,1)=" << a111en << " int =" << I1 << std::endl;

    // - Tests A22 = <ph, w> with ph, w \in Wh
    auto a2 = form2(_test=Wh, _trial=Wh );
    a2 = integrate( _range=internalfaces(meshnd), _expr=leftface(e*id(p))*leftfacet(idt(p)/e))
        +integrate( _range=boundaryfaces(meshnd), _expr=(e*id(p))*(idt(p)/e));
    a2.close();
    auto a2en = a2(p,p);
    BOOST_CHECK_CLOSE( a2en, I1, 1e-10 );
    cout << "a2(1,1)=" << a2en << std::endl;

    // - Same as a2, but with rightface instead of leftface.
    auto a3 = form2(_test=Wh, _trial=Wh );
    a3 = integrate(_range=internalfaces(meshnd), _expr=rightface(e*id(p))*rightfacet(idt(p)/e))
        +integrate( _range=boundaryfaces(meshnd), _expr=(e*id(p))*(idt(p)/e));
    a3.close();
    auto a3en = a3(p,p);
    BOOST_CHECK_CLOSE( a3en, I1, 1e-10 );
    cout << "a3(1,1)=" << a3en << std::endl;

    auto a23 = form2(_test=Wh, _trial=Wh );
    a23 = integrate(_range=internalfaces(meshnd), _expr=rightface(e*id(p))*leftfacet(idt(p)/e));
    a23.close();
    auto a23en = a23(p,p);
    BOOST_CHECK_SMALL( a23en, 1e-10 );
    cout << "a23(1,1)=" << a23en << std::endl;

    auto a231 = form2(_test=Wh, _trial=Wh, _pattern=size_type(Pattern::EXTENDED) );
    a231 = integrate(_range=internalfaces(meshnd), _expr=rightface(e*id(p))*leftfacet(idt(p)/e))
        +integrate( _range=boundaryfaces(meshnd), _expr=(e*id(p))*(idt(p)/e));
    a231.close();
    auto a231en = a231(p,p);
    BOOST_CHECK_CLOSE( a231en, I1, 1e-10 );
    cout << "a231(1,1)=" << a231en << std::endl;

    // - Tests A23 = <phat, w>, with phat \in Mh, w \in Wh
    //
    auto a4 = form2(_test=Wh, _trial=Mh );
    //auto a4 = form2(_test=Wh, _trial=Mh );
    a4 = integrate( _range=internalfaces(meshnd), _expr=leftface(e*id(p))*idt(l)/e );
    a4.close();
    auto a4en = a4(p, l);
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a4l(1,1)=" << a4en );
    a4 = integrate( _range=internalfaces(meshnd), _expr=rightface(e*id(p))*idt(l)/e );
    a4.close();
    a4en = a4(p, l);
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a4r(1,1)=" << a4en );
    a4 = integrate( _range=internalfaces(meshnd), _expr=0.5*(leftface(e*id(p))+rightface(e*id(p)))*idt(l)/e );
    a4.close();
    a4en = a4(p, l);
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a4lr(1,1)=" << a4en );

    // - Tests A32 = <ph, \mu>, with ph \in Wh, \mu \in Mh
    auto a5 = form2(_test=Mh, _trial=Wh );
    a5 = integrate(_range=internalfaces(meshnd), _expr=leftfacet(e*idt(p))*id(l)/e );
    a5.close();
    auto a5en = a5(l, p);
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a5l(1,1)=" << a5en );
    a5 = integrate(_range=internalfaces(meshnd), _expr=rightfacet(e*idt(p))*id(l)/e );
    a5.close();
    a5en = a5(l, p);
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a5r(1,1)=" << a5en );

    // - Tests (p, p)_Omega. Should give the measure of the domain
    auto a6 = form2(_test=Wh, _trial=Wh);
    a6 = integrate(_range=elements(meshnd), _expr=idt(p)*id(p));
    a6.close();
    auto a6en = a6(p, p);
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a6(1,1)=" << a6en );

    double Ib = integrate(_range=boundaryfaces(meshnd), _expr=cst(1.)).evaluate()(0,0);

    // The five following tests should all provide the (n-1)-Lebesgue
    // measure of the boundary of the domain.
    // The goal is to check whether we need to multiply by 0.5 or 0.25 or nothing in
    // boundary integrals. Also
    auto a7 = form2( _test=Wh, _trial=Wh);
    a7 = integrate(_range=boundaryfaces(meshnd), _expr=idt(p)*id(p));
    a7.close();
    auto a7eval = a7(p,p);
    BOOST_CHECK_CLOSE( a7eval, Ib, 1e-10 );
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a7(1,1)=" << a7eval );

    // a8
    auto a8 = form2( _test=Mh, _trial=Mh);
    a8 = integrate(_range=boundaryfaces(meshnd), _expr=idt(l)*id(l));
    a8.close();
    auto a8eval = a8(l,l);
    BOOST_CHECK_CLOSE( a8eval, Ib, 1e-10 );
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a8(1,1)=" << a8eval );

    auto a9 = form2(_test=Mh, _trial=Wh);
    a9 = integrate(_range=boundaryfaces(meshnd), _expr=idt(p)*id(l));
    a9.close();
    auto a9eval = a9(l,p);
    BOOST_CHECK_CLOSE( a9eval, Ib, 1e-10 );
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a9(1,1)=" << a9eval );

    auto a10 = form1(_test=Mh);
    a10 = integrate(_range=boundaryfaces(meshnd), _expr=id(l));
    a10.close();
    auto a10eval = a10(l);
    BOOST_CHECK_CLOSE( a10eval, Ib, 1e-10 );
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a10(1)=" << a10eval );

    auto a12 = form1(_test=Wh);
    a12 = integrate(_range=boundaryfaces(meshnd), _expr=id(p));
    a12.close();
    auto a12eval = a12(p);
    BOOST_CHECK_CLOSE( a12eval, Ib, 1e-10 );
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a12(1)=" << a12eval );



    // ------------------------------------------------------------------------------------

    // The following tests help to understand what we have to do when mixing
    // integrals that require the extended pattern with others that do not

    LOG(INFO) << "a7b starts";
    // Works fine
    auto a7b = form2( _test=Wh, _trial=Wh);
    a7b = integrate(_range=boundaryfaces(meshnd), _expr=idt(p)*id(p));
    a7b.close();
    auto a7beval = a7b(p,p);
    BOOST_CHECK_CLOSE( a7beval, Ib, 1e-10 );
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a7b(1,1)=" << a7beval );
    LOG(INFO) << "a7b ends";

    auto a8b = form2( _test=Mh, _trial=Mh);
    a8b = integrate(_range=boundaryfaces(meshnd), _expr=idt(l)*id(l));
    a8b.close();
    auto a8beval = a8b(l,l);
    BOOST_CHECK_CLOSE( a8beval, Ib, 1e-10 );
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a8b(1,1)=" << a8beval );

    LOG(INFO) << "a9b starts";
    auto a9b = form2(_test=Mh, _trial=Wh, _pattern=size_type(Pattern::EXTENDED));
    a9b = integrate(_range=boundaryfaces(meshnd), _expr=idt(p)*id(l));
    a9b.close();
    auto a9beval = a9b(l,p);
    BOOST_CHECK_CLOSE( a9beval, Ib, 1e-10 );
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a9b(1,1)=" << a9beval );
    LOG(INFO) << "a9b ends";

    auto a10b = form1(_test=Mh, _pattern=size_type(Pattern::EXTENDED));
    a10b = integrate(_range=boundaryfaces(meshnd), _expr=id(l));
    a10b.close();
    auto a10beval = a10b(l);
    BOOST_CHECK_CLOSE( a10beval, Ib, 1e-10 );
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a10b(1)=" << a10beval );

    LOG(INFO) << "a12b starts";
    auto a12b = form1(_test=Wh, _pattern=size_type(Pattern::EXTENDED));
    a12b = integrate(_range=boundaryfaces(meshnd), _expr=id(p));
    a12b.close();
    auto a12beval = a12b(p);
    BOOST_CHECK_CLOSE( a12beval, Ib, 1e-10 );
    if ( Environment::isMasterRank() )
        BOOST_TEST_MESSAGE( "a12b(1)=" << a12beval );
    LOG(INFO) << "a12b ends";
    BOOST_MESSAGE( "test_form2_faces ends for dim=" << T::value);
}


BOOST_AUTO_TEST_SUITE_END()
back to top