Code

1. First equation code

Below is the complete code for the first equation solving :

#include <feel/feeldiscr/pch.hpp>
#include <feel/feelfilters/loadmesh.hpp>
#include <feel/feelfilters/exporter.hpp>
#include <feel/feelvf/vf.hpp>

int main(int argc, char **argv)
{
        using namespace Feel;
        po::options_description options("Laplacian options");
        options.add_options()("hc", po::value<std::string>()->default_value("1"), "convective heat transfer coefficient")("Tinf", po::value<std::string>()->default_value("1"), "Temperature far from boundary");
        Environment env(_argc = argc, _argv = argv, _desc = options,
                        _about = about(_name = "test1",
                                       _author = "Feel++ Consortium",
                                       _email = "feelpp-devel@feelpp.org"));

        auto A0 = expr<3, 1>(soption(_name = "functions.a"));
        Feel::cout << "A0=" << A0 << std::endl;

        auto gI = expr<3, 1>(soption(_name = "functions.i"));
        Feel::cout << "gI=" << gI << std::endl;

        auto gO = expr<3, 1>(soption(_name = "functions.o"));
        Feel::cout << "gO=" << gO << std::endl;

        auto gradV = expr<3, 1>(soption(_name = "functions.v"));
        Feel::cout << "gradV=" << gradV << std::endl;

        auto Ad = expr<3, 1>(soption(_name = "functions.d"));
        Feel::cout << "Ad=" << Ad << std::endl;

        auto mu = expr(soption(_name = "functions.m"));
        Feel::cout << "mu=" << mu << std::endl;

        auto sigma = expr(soption(_name = "functions.s"));
        Feel::cout << "sigma=" << sigma << std::endl;

        auto Aexact_g = expr<3, 1>(soption(_name = "functions.e"));
        Feel::cout << "Aexact=" << Aexact_g << std::endl;

        double dt = doption(_name = "ts.time-step");
        std::cout << "time-step=" << dt << std::endl;

        double tmax = doption(_name = "ts.time-final");
        std::cout << "time-final=" << tmax << std::endl;

        auto mesh = loadMesh(_mesh = new Mesh<Simplex<3>>);
        auto cond_mesh = createSubmesh(mesh, markedelements(mesh, "Omega_C"));

        auto Ah = Pchv<1>(mesh);

        auto A = Ah->element(A0);

        auto phi = Ah->element();

        auto Aexact = Ah->element();

        auto l1 = form1(_test = Ah);

        double t = 0;

        auto e = exporter(_mesh = mesh);
        auto a1 = form2(_trial = Ah, _test = Ah);

        Aexact_g.setParameterValues({{"t", t}});
        Aexact = project(_space = Ah, _expr = Aexact_g);

        gradV.setParameterValues({{"t", t}});
        e->step(t)->add("A", A0);
        e->step(t)->add("Aexact", Aexact);
        e->save();

        double L2Aexact = normL2(_range = elements(mesh), _expr = Aexact_g);
        double H1error = 0;
        double L2error = 0;
        Feel::cout << "H1 error at t = " << t << ": " << H1error << std::endl;
        Feel::cout << "L2 error at t = " << t << ": " << L2error << std::endl;

        for (t = dt; t < tmax; t += dt)
        {
                Aexact_g.setParameterValues({{"t", t}});
                Aexact = project(_space = Ah, _expr = Aexact_g);
                gradV.setParameterValues({{"t", t}});
                gO.setParameterValues({{"t", t}});
                gI.setParameterValues({{"t", t}});
                Ad.setParameterValues({{"t", t}});

                l1.zero();
                a1.zero();
                l1 = integrate(_range = elements(cond_mesh),
                               _expr = sigma * inner(id(phi), idv(A) - dt * gradV));
                a1 = integrate(_range = elements(mesh),
                               _expr = (dt / mu) * inner(curl(phi), curlt(A)));
                a1 += integrate(_range = elements(cond_mesh),
                                _expr = sigma * inner(id(phi), idt(A)));
                a1 += on(_range = markedfaces(mesh, "Gamma_I"), _rhs = l1, _element = phi,
                         _expr = gI);
                a1 += on(_range = markedfaces(mesh, "Gamma_O"), _rhs = l1, _element = phi,
                         _expr = gO);
                a1 += on(_range = markedfaces(mesh, "Gamma_C"), _rhs = l1, _element = phi,
                         _expr = Ad);

                a1.solve(_rhs = l1, _solution = A);

                e->step(t)->add("A", A);
                e->step(t)->add("Aexact", Aexact_g);
                e->save();

                L2Aexact = normL2(_range = elements(mesh), _expr = Aexact_g);
                L2error = normL2(elements(mesh), (idv(A) - idv(Aexact)));
                H1error = normH1(elements(mesh), _expr = (idv(A) - idv(Aexact)), _grad_expr = (gradv(A) - gradv(Aexact)));

                Feel::cout << t << "" << L2error << " " << L2error / L2Aexact << " " << H1error << std::endl;
        }
}

2. Second equation

Below is the complete code for the second equation solving :

#include <feel/feeldiscr/pch.hpp>
#include <feel/feelfilters/loadmesh.hpp>
#include <feel/feelfilters/exporter.hpp>
#include <feel/feelvf/vf.hpp>


int main(int argc, char**argv )
{
     using namespace Feel;
    po::options_description options( "Laplacian options" );
    options.add_options()
      ( "hc", po::value<std::string>()->default_value( "1" ), "convective heat transfer coefficient" )
      ( "Tinf", po::value<std::string>()->default_value( "1" ), "Temperature far from boundary" );
     Environment env( _argc=argc, _argv=argv,_desc=options,
                      _about=about(_name="test2",
                                   _author="Feel++ Consortium",
                                   _email="feelpp-devel@feelpp.org"));

    auto V0 = expr(soption(_name = "functions.v"));
    Feel::cout << "V0=" << V0 << std::endl;

    auto gI = expr(soption(_name="functions.i"));
    Feel::cout << "gI=" << gI << std::endl;

    auto gO = expr(soption(_name="functions.o"));
    Feel::cout << "gO=" << gO << std::endl;

    auto Ad = expr(soption(_name = "functions.d"));
    Feel::cout << "Ad=" << Ad << std::endl;

    auto dA = expr<3,1>(soption(_name="functions.a"));
    Feel::cout << "dA=" << dA << std::endl;

    auto sigma = expr(soption(_name="functions.s"));
    Feel::cout << "sigma=" << sigma << std::endl;

    auto Vexact_g = expr(soption(_name = "functions.e"));
    Feel::cout << "Vexact=" << Vexact_g << std::endl;

    double dt = doption(_name = "ts.time-step");
    std::cout << "time-step=" << dt << std::endl;

    double tmax = doption(_name = "ts.time-final");
    std::cout << "time-final=" << tmax << std::endl;

    auto mesh = loadMesh(_mesh=new Mesh<Simplex<3>>);
    auto cond_mesh = createSubmesh(mesh,markedelements(mesh,"Omega_C"));

    auto Ah = Pchv<1>( mesh );
    auto Vh = Pch<1>( cond_mesh );

    auto V = Vh->element(V0);
    auto psi = Vh->element();
    auto Vexact = Vh->element();

    auto a2 = form2( _trial=Vh, _test=Vh);
    auto l2 = form1( _test=Vh );
    auto e = exporter( _mesh=mesh );

    double t = 0;

    Vexact_g.setParameterValues({{"t", t}});
    Vexact = project(_space = Vh, _expr = Vexact_g);

    dA.setParameterValues({{"t", t}});
    e->step(t)->add("V", V0);
    e->step(t)->add("Vexact", Vexact);
    e->save();

    double L2Vexact = normL2(_range = elements(mesh), _expr = Vexact_g);
    double H1error = 0;
    double L2error = 0;
    Feel::cout << "H1 error at t = " << t << ": " << H1error << std::endl;
    Feel::cout << "L2 error at t = " << t << ": " << L2error << std::endl;

    for (t = dt; t < tmax; t += dt){
        Vexact_g.setParameterValues({{"t", t}});
        Vexact = project(_space = Vh, _expr = Vexact_g);
        dA.setParameterValues({{"t", t}});
        gO.setParameterValues({{"t", t}});
        gI.setParameterValues({{"t", t}});
        Ad.setParameterValues({{"t", t}});

        l2.zero();
        a2.zero();

        l2 = integrate(_range=elements(cond_mesh),
                    _expr = sigma * inner( -dA, trans(grad(psi)) ));

        a2 = integrate(_range=elements(cond_mesh),
                    _expr = sigma * inner(gradt(V), grad(psi) ));

        a2 += on(_range=markedfaces(cond_mesh,"Gamma_I"), _rhs=l2, _element=psi,
                _expr= gI );
        a2 += on(_range=markedfaces(cond_mesh,"Gamma_O"), _rhs=l2, _element=psi,
                _expr= gO );
        a2 += on(_range=markedfaces(cond_mesh,"Gamma_C"), _rhs=l2, _element=psi,
                _expr= Ad );

        a2.solve(_rhs=l2,_solution=V);
        e->step(t)->add( "V", V);
        e->step(t)->add("Vexact", Vexact_g);
        e->save();

        L2Vexact = normL2(_range = elements(mesh), _expr = Vexact_g);
        L2error = normL2(elements(mesh), (idv(V) - idv(Vexact)));
        H1error = normH1(elements(mesh), _expr = (idv(V) - idv(Vexact)), _grad_expr = (gradv(V) - gradv(Vexact)));

        Feel::cout << t << "" << L2error << " " << L2error / L2Vexact << " " << H1error << std::endl;

    }
}

3. Coupled system

Below is the code for the coupled system solving, which doesnt work for the moment :

#include <feel/feelcore/environment.hpp>
#include <feel/feelcore/checker.hpp>

#include <feel/feeldiscr/pch.hpp>
#include <feel/feelfilters/loadmesh.hpp>
#include <feel/feelfilters/exporter.hpp>
#include <feel/feelvf/vf.hpp>

#include <feel/feelalg/vectorblock.hpp>
#include <feel/feeldiscr/product.hpp>
#include <feel/feelvf/blockforms.hpp>



int main(int argc, char**argv )
{
  using namespace Feel;
  po::options_description options( "MQS options" );
  options.add_options()
    ( "sigma", po::value<std::string>()->default_value( "1" ), "electrical conductivity" )
    ( "mu_mag", po::value<std::string>()->default_value( "1" ), "relative magnetic permeability" )
    ( "A0", po::value<std::string>()->default_value( "{0,0,0}" ), "initial A" )
    ( "V0", po::value<std::string>()->default_value( "0" ), "initial V" )
    ( "Aexact", po::value<std::string>()->default_value( "{0,0,0}" ), "exact A" )
    ( "Vexact", po::value<std::string>()->default_value( "0" ), "exact V" )
    ( "Ad", po::value<std::string>()->default_value( "{0,0,0}" ), "Ad" )
    ( "v0", po::value<std::string>()->default_value( "0" ), "v0" )
    ( "v1", po::value<std::string>()->default_value( "0" ), "v1" );

  Environment env( _argc=argc, _argv=argv,_desc=options,
		   _about=about(_name="mqs",
				_author="Feel++ Consortium",
				_email="feelpp-devel@feelpp.org"));

  // Dirichlet for Magnetic potential
  auto Ad = expr<3,1>(soption(_name="Ad"));
  Feel::cout << "Ad=" << Ad << std::endl;

  // Dirichlet for electric potential
  auto v1 = expr(soption(_name="v1"));
  Feel::cout << "v1=" << v1 << std::endl;

  auto v0 = expr(soption(_name="v0"));
  Feel::cout << "vO=" << v0 << std::endl;

  //Recuperer time frame

  double dt = doption(_name = "ts.time-step");
  std::cout << "time-step=" << dt << std::endl;

  double tmax = doption(_name = "ts.time-final");
  std::cout << "time-final=" << tmax << std::endl;

  // Init solution for Magnetic Potential
  auto A0 = expr<3,1>(soption(_name="A0"));
  Feel::cout << "A0=" << A0 << std::endl;

  // Init solution for Potential
  auto V0 = expr(soption(_name="V0"));
  Feel::cout << "V0=" << V0 << std::endl;

  // Define sigma and mu
  auto sigma = expr(soption(_name = "sigma"));
  Feel::cout << "sigma=" << sigma << std::endl;

  auto mur = expr(soption(_name = "mu_mag"));
  Feel::cout << "mur=" << mur << std::endl;

  // Enforce a solution
  auto Aexact_g = expr<3, 1>(soption(_name = "Aexact"));
  Feel::cout << "Aexact=" << Aexact_g << std::endl;

  auto Vexact_g = expr(soption(_name = "Vexact"));
  Feel::cout << "Vexact=" << Vexact_g << std::endl;

  // Load Mesh and define Product space

  auto mesh = loadMesh(_mesh=new Mesh<Simplex<3>>);
  auto cond_mesh = createSubmesh(mesh,markedelements(mesh,"Omega_C"));

  auto Ah = Pchv<1>( mesh );
  auto Vh = Pch<1>( cond_mesh );

  auto A = Ah->element(A0);
  auto V = Vh->element(V0);

  auto Aexact = Ah->element();
  auto Vexact = Vh->element();

  auto phi = Ah->element();
  auto psi = Vh->element();

  auto Zh = product(Ah,Vh);
  auto U = Zh.element();
#if 0
  auto cAh = Zh[0_c];
  auto cVh = Zh[1_c];
#endif


  auto rhs = blockform1( Zh );
  auto lhs = blockform2( Zh );

  double t = 0;

  auto e = exporter( _mesh=mesh );

  Aexact_g.setParameterValues({{"t", t}});
  Aexact = project(_space = Ah, _expr = Aexact_g);

  Vexact_g.setParameterValues({{"t", t}});
  Vexact = project(_space = Vh, _expr = Vexact_g);

  e->step(t)->add("A", A0);
  e->step(t)->add("Aexact", Aexact);
  e->step(t)->add("V", V0);
  e->step(t)->add("Vexact", Vexact);
  e->save();

  double L2Aexact = normL2(_range = elements(mesh), _expr = Aexact_g);
  double H1Aerror = 0;
  double L2Aerror = 0;
  double L2Vexact = normL2(_range = elements(mesh), _expr = Vexact_g);
  double H1Verror = 0;
  double L2Verror = 0;

  auto mu0 = 4.e-7 * M_PI ; // SI Unit : H/m = m.kg/s2/A2

  for (t = dt; t < tmax; t += dt){
    Aexact_g.setParameterValues({{"t", t}});
    Aexact = project(_space = Ah, _expr = Aexact_g);
    Vexact_g.setParameterValues({{"t", t}});
    Vexact = project(_space = Vh, _expr = Vexact_g);
    v0.setParameterValues({{"t", t}});
    v1.setParameterValues({{"t", t}});
    Ad.setParameterValues({{"t", t}});

    lhs.zero();
    rhs.zero();
    tic();
    // Ampere law: sigma dA/dt + rot(1/(mu-r*mu_0) rotA) + sigma grad(V) = Js
    lhs(0_c, 0_c) = integrate( _range=elements(mesh),
		     _expr = dt * inner(curl(phi) , curlt(A)) );
    lhs(0_c, 0_c) += integrate( _range=elements(cond_mesh),
		     _expr = mur * mu0 * sigma * inner(id(phi) , idt(A) ));

    lhs(0_c, 1_c) = integrate(_range=elements(cond_mesh),
         _expr = dt * mu0 * mur * sigma*inner(id(phi),trans(gradt(V))) );

    rhs(0_c) = integrate(_range=elements(cond_mesh),
                        _expr = mu0 * mur * sigma * inner(id(phi) , idv(A)));

    // Current conservation: div( -sigma grad(V) -sigma*dA/dt) = Qs
    lhs(1_c, 0_c) = integrate( _range=elements(cond_mesh),
			       _expr = sigma * inner(idt(A), trans(grad(psi))) );

    lhs(1_c, 1_c) = integrate( _range=elements(cond_mesh),
			       _expr = sigma * dt * inner(gradt(V), grad(psi)) );

    rhs(1_c) = integrate(_range=elements(cond_mesh),
                        _expr = sigma * inner(idv(A), trans(grad(psi))) );

    /* Add Boundary conditions */
#if 0
    lhs(0_c, 0_c) += on(_range=markedfaces(mesh,"Infty"), _rhs=rhs(0_c), _element=phi, _expr= Ad);
#endif

#if 1
    /* 1/4th of a torus + Air */
    lhs(0_c, 0_c) += on(_range=markedfaces(mesh,"V0"), _rhs=rhs(0_c), _element=phi, _expr= Ad);
    lhs(0_c, 0_c) += on(_range=markedfaces(mesh,"V1"), _rhs=rhs(0_c), _element=phi, _expr= Ad);
    lhs(0_c, 0_c) += on(_range=markedfaces(mesh,"Gamma_C"), _rhs=rhs(0_c), _element=phi, _expr= Ad);
#endif

    lhs(1_c, 1_c) += on(_range=markedfaces(cond_mesh,"V0"), _rhs=rhs(1_c), _element=psi, _expr= v0);
    lhs(1_c, 1_c) += on(_range=markedfaces(cond_mesh,"V1"), _rhs=rhs(1_c), _element=psi, _expr= v1);
    lhs(1_c, 1_c) += on(_range=markedfaces(cond_mesh,"Gamma_C"), _rhs=rhs(1_c), _element=psi, _expr= Vexact_g);
    toc("assembling", true);

    /* Solve */
    tic();
    lhs.solve(_rhs=rhs,_solution=U);
    toc("solve", true);

    tic();
    e->step(t)->add( "A", U(0_c));
    e->step(t)->add( "V", U(1_c));
    e->step(t)->add( "Aexact", Aexact);
    e->step(t)->add( "Vexact", Vexact);
    e->save();
    toc("export", true);

    L2Aexact = normL2(_range = elements(mesh), _expr = Aexact_g);
    L2Aerror = normL2(elements(mesh), (idv(U(0_c)) - idv(Aexact)));
    H1Aerror = normH1(elements(mesh), _expr = (idv(U(0_c)) - idv(Aexact)), _grad_expr = (gradv(U(0_c)) - gradv(Aexact)));

    Feel::cout << "A error: " << "t="<< t << " " << L2Aerror << " " << L2Aerror / L2Aexact << " " << H1Aerror << std::endl;

    L2Vexact = normL2(_range = elements(mesh), _expr = Vexact_g);
    L2Verror = normL2(elements(mesh), (idv(U(1_c)) - idv(Vexact)));
    H1Verror = normH1(elements(mesh), _expr = (idv(U(1_c)) - idv(Vexact)), _grad_expr = (gradv(U(1_c)) - gradv(Vexact)));

    Feel::cout << "V error: " << "t="<< t << " " << L2Verror << " " << L2Verror / L2Vexact << " " << H1Verror << std::endl;

    #if 0
    A = U(0_c);
    V = U(1_c);
    #endif
  }
}