Skip to content
Snippets Groups Projects
Select Git revision
  • 7bad641bff1555905fdd9a2c5c72db633bd7dd51
  • master default
  • cgnsUnstructured
  • partitioning
  • poppler
  • HighOrderBLCurving
  • gmsh_3_0_4
  • gmsh_3_0_3
  • gmsh_3_0_2
  • gmsh_3_0_1
  • gmsh_3_0_0
  • gmsh_2_16_0
  • gmsh_2_15_0
  • gmsh_2_14_1
  • gmsh_2_14_0
  • gmsh_2_13_2
  • gmsh_2_13_1
  • gmsh_2_12_0
  • gmsh_2_11_0
  • gmsh_2_10_1
  • gmsh_2_10_0
  • gmsh_2_9_3
  • gmsh_2_9_2
  • gmsh_2_9_1
  • gmsh_2_9_0
  • gmsh_2_8_6
26 results

GenericFace.cpp

Blame
  • Forked from gmsh / gmsh
    Source project has a limited visibility.
    main.cpp 25.45 KiB
    #include "AnalyticalFunction.h"
    
    #include <gmshddm/Formulation.h>
    #include <gmshddm/GmshDdm.h>
    #include <pybind11/complex.h>
    #include <pybind11/embed.h>
    #include <pybind11/stl.h>
    using namespace gmshfem;
    using namespace gmshfem::field;
    using namespace gmshfem::function;
    using namespace gmshfem::analytics;
    using namespace gmshfem::post;
    using namespace gmshfem::equation;
    //***************************************
    // Create surface mesh
    //***************************************
    class BemppMesh
    {
     private:
      int _tagSurface;
      int _dim;
      std::unordered_map< unsigned int, unsigned int >
        _nodeConnectBemppMeshToGmshMesh;
      std::vector< unsigned int > _elementsNode0;
      std::vector< unsigned int > _elementsNode1;
      std::vector< unsigned int > _elementsNode2;
      std::vector< double > _nodesCoordX;
      std::vector< double > _nodesCoordY;
      std::vector< double > _nodesCoordZ;
      unsigned int _renameNode(unsigned int nodeNum,
                               std::unordered_map< unsigned int, unsigned int >
                                 &nodeConnectGmshMeshToBemppMesh)
      {
        auto it = nodeConnectGmshMeshToBemppMesh.find(nodeNum);
        if(it != nodeConnectGmshMeshToBemppMesh.end()) {
          return it->second;
        }
        else {
          unsigned int size = nodeConnectGmshMeshToBemppMesh.size();
          nodeConnectGmshMeshToBemppMesh.insert(
            std::pair< unsigned int, unsigned int >(nodeNum, size));
          _nodeConnectBemppMeshToGmshMesh.insert(
            std::pair< unsigned int, unsigned int >(size, nodeNum));
          return size;
        }
      }
      void _createSurfaceMesh()
      {
        gmshfem::common::Timer time;
        time.tick();
        std::vector< int > vEntities;
        gmsh::model::getEntitiesForPhysicalGroup(_dim, _tagSurface, vEntities);
        std::unordered_map< unsigned int, unsigned int >
          nodeConnectGmshMeshToBemppMesh;
        for(unsigned int ent = 0; ent < vEntities.size(); ent++) {
          std::vector< int > elementTypes;
          std::vector< std::vector< std::size_t > > elementTags;
          std::vector< std::vector< std::size_t > > nodeTags;
          gmsh::model::mesh::getElements(elementTypes, elementTags, nodeTags, _dim,
                                         vEntities[ent]);
          std::vector< std::size_t > nodeElem = nodeTags[0];
    
          int numElem = elementTags[0].size();
          _elementsNode0.reserve(_elementsNode0.size() + numElem);
          _elementsNode1.reserve(_elementsNode1.size() + numElem);
          _elementsNode2.reserve(_elementsNode2.size() + numElem);
          unsigned int numNode0;
          unsigned int numNode1;
          unsigned int numNode2;
          for(int i = 0; i < numElem; i++) {
            numNode0 = _renameNode(nodeElem[3 * i], nodeConnectGmshMeshToBemppMesh);
            numNode1 =
              _renameNode(nodeElem[3 * i + 1], nodeConnectGmshMeshToBemppMesh);
            numNode2 =
              _renameNode(nodeElem[3 * i + 2], nodeConnectGmshMeshToBemppMesh);
            _elementsNode0.push_back(numNode0);
            _elementsNode1.push_back(numNode1);
            _elementsNode2.push_back(numNode2);
          }
        }
        _nodesCoordX.reserve(nodeConnectGmshMeshToBemppMesh.size());
        _nodesCoordY.reserve(nodeConnectGmshMeshToBemppMesh.size());
        _nodesCoordZ.reserve(nodeConnectGmshMeshToBemppMesh.size());
        for(unsigned int i = 0; i < nodeConnectGmshMeshToBemppMesh.size(); i++) {
          std::vector< double > coord;
          std::vector< double > parametricCoord;
          int doo;
          int dii;
          gmsh::model::mesh::getNode(_nodeConnectBemppMeshToGmshMesh[i], coord,
                                     parametricCoord, doo, dii);
          _nodesCoordX.push_back(coord[0]);
          _nodesCoordY.push_back(coord[1]);
          _nodesCoordZ.push_back(coord[2]);
        }
        time.tock();
        msg::info << "bem mesh created in " << time << msg::endl;
      }
    
     public:
      BemppMesh(const int &tagSurface) :
        _tagSurface(tagSurface), _dim(2)
      {
        _createSurfaceMesh();
      }
      ~BemppMesh() {}
    
      const std::vector< unsigned int > &getElementsNode0() const
      {
        return _elementsNode0;
      }
      const std::vector< unsigned int > &getElementsNode1() const
      {
        return _elementsNode1;
      }
      const std::vector< unsigned int > &getElementsNode2() const
      {
        return _elementsNode2;
      }
      const std::unordered_map< unsigned int, unsigned int > &
      getnodeConnectBemppMeshToGmshMesh() const
      {
        return _nodeConnectBemppMeshToGmshMesh;
      }
      const std::vector< double > &getnodesCoordX() const
      {
        return _nodesCoordX;
      }
      const std::vector< double > &getnodesCoordY() const
      {
        return _nodesCoordY;
      }
      const std::vector< double > &getnodesCoordZ() const
      {
        return _nodesCoordZ;
      }
    };
    //***************************************
    // BemFormulation
    //***************************************
    #pragma GCC visibility push(hidden)
    class BemFormulation
      : public gmshfem::problem::Formulation< std::complex< double > >
    {
     private:
      bool _firstIt;
      pybind11::module _bem;
      gmshfem::field::FieldInterface< std::complex< double > > *_E;
      gmshfem::field::FieldInterface< std::complex< double > > *_H;
      BemppMesh _surfaceMesh;
      std::vector< int > _typeKeys;
      std::vector< unsigned long long > _entityKeys;
      std::complex< double > _Zi;
      std::complex< double > _Ze;
      double _ki;
      double _ke;
      Field< std::complex< double >, Form::Form2 > *_interfaceFieldG;
      std::vector< double > _ChangeOfBasisVectorBemToGmsh;
      double *_bembemL2errorM;
      double *_bembemL2errorJ;
      double _opT;
    
     public:
      BemFormulation(const std::string &name,
                     gmshfem::field::FieldInterface< std::complex< double > > *E,
                     gmshfem::field::FieldInterface< std::complex< double > > *H,
                     const BemppMesh &surfaceMesh, const std::complex< double > &Zi,
                     const std::complex< double > &Ze, const double &ki,
                     const double &ke, Field< std::complex< double >, Form::Form2 > *g,
                     double *bembemL2errorM, double *bembemL2errorJ,
                     const double &opT) :
        gmshfem::problem::Formulation< std::complex< double > >(name),
        _firstIt(true), _E(E), _H(H), _surfaceMesh(surfaceMesh), _Zi(Zi),
        _Ze(Ze), _ki(ki), _ke(ke), _interfaceFieldG(g),
        _ChangeOfBasisVectorBemToGmsh(), _bembemL2errorM(bembemL2errorM),
        _bembemL2errorJ(bembemL2errorJ), _opT(opT)
      {
        // load our bem.py module
        _bem = pybind11::module::import("bem");
      }
    
      gmshfem::common::Timer
      pre(const gmshfem::problem::DofsSort::Algorithm algo =
            gmshfem::common::Options::instance()->dofsSortAlgorithm)
      {
        msg::info << "Bem pre-process" << _name << "..." << msg::endl;
        gmshfem::common::Timer time;
        time.tick();
    
        if(_firstIt) {
          _bem.attr("pre")(
            _ke, _surfaceMesh.getElementsNode0(), _surfaceMesh.getElementsNode1(),
            _surfaceMesh.getElementsNode2(), _surfaceMesh.getnodesCoordX(),
            _surfaceMesh.getnodesCoordY(), _surfaceMesh.getnodesCoordZ(), _opT,
            _Ze, _surfaceMesh.getnodeConnectBemppMeshToGmshMesh());
    
          pybind11::object edgeNumFollowingBemDofOrderPython =
            _bem.attr("getEdgeNumInBemDofOrder")();
          _entityKeys = pybind11::cast< std::vector< unsigned long long > >(
            edgeNumFollowingBemDofOrderPython);
          _typeKeys.resize(_entityKeys.size(), 1);
          pybind11::object ChangeOfBasisVectorPython =
            _bem.attr("getChangeOfBasisVector")();
          _ChangeOfBasisVectorBemToGmsh =
            pybind11::cast< std::vector< double > >(ChangeOfBasisVectorPython);
          _bem.attr("clearGlobalVariable")();
    
          for(unsigned int i = 0; i < _entityKeys.size(); ++i) {
            dofs::UnknownDof *dof = new dofs::UnknownDof(
              _typeKeys[i] + GMSHFEM_DOF_FIELD_OFFSET * _E->tag(),
              _entityKeys[i]);
            dof->numDof(i + 1);
            _E->setDof(dof);
          }
          for(unsigned int i = 0; i < _entityKeys.size(); ++i) {
            dofs::UnknownDof *dof = new dofs::UnknownDof(
              _typeKeys[i] + GMSHFEM_DOF_FIELD_OFFSET * _H->tag(),
              _entityKeys[i]);
            dof->numDof(i + 1);
            _H->setDof(dof);
          }
          _firstIt = false;
          time.tock();
          msg::info << _entityKeys.size() << " unknown dofs created in " << time
                    << "s:" << msg::endl;
        }
        else {
          time.tock();
          msg::info << "Bem pre-process" << _name << "...Done" << msg::endl;
        }
    
        return time;
      }
    
      gmshfem::common::Timer solve(const bool reusePreconditioner = false)
      {
        msg::info << "bem solve" << msg::endl;
        gmshfem::common::Timer time;
        time.tick();
        unsigned int nDof = _entityKeys.size();
        std::vector< std::complex< double > > g_gmshfem(nDof);
        std::vector< std::complex< double > > g_bem;
        g_bem.resize(nDof);
        _interfaceFieldG->getValues(_typeKeys, _entityKeys, g_gmshfem, 0, nDof);
        // low order basis Hdiv in gmshfem (ei low order hcurl basis): n^ei
        // low order basis Hdiv in bempp (ei low order hcurl basis): ei^n
        for(unsigned int i = 0; i < nDof; i++) {
          g_bem[i] = -(g_gmshfem[i]) * _ChangeOfBasisVectorBemToGmsh[i];
        }
        bool physicalSource;
        bool artificialSource;
        getAttribute("ddm::physicalCommutator", physicalSource);
        getAttribute("ddm::artificialCommutator", artificialSource);
        pybind11::object pythonVect =
          _bem.attr("solveIE")(g_bem, physicalSource, artificialSource, _opT);
        std::vector< std::complex< double > > EH_bem =
          pybind11::cast< std::vector< std::complex< double > > >(pythonVect);
        std::vector< std::complex< double > > E_gmshfem(nDof);
        std::vector< std::complex< double > > H_gmshfem(nDof);
        for(unsigned int i = 0; i < nDof; i++) {
          E_gmshfem[i] = EH_bem[i] / _ChangeOfBasisVectorBemToGmsh[i];
        }
        for(unsigned int i = 0; i < nDof; i++) {
          H_gmshfem[i] = EH_bem[i + nDof] / _ChangeOfBasisVectorBemToGmsh[i];
        }
        _E->assignValues(E_gmshfem);
        _H->assignValues(H_gmshfem);
        if(artificialSource && physicalSource) {
          pybind11::object errorPython =
            _bem.attr("getL2errorJM")(g_bem, _Zi, _ki, _ke, _Ze, _opT);
          std::vector< double > error(2);
          error = pybind11::cast< std::vector< double > >(errorPython);
          *_bembemL2errorM = error[0];
          *_bembemL2errorJ = error[1];
        }
        time.tock();
        msg::info << "bem solve in " << time << "s" << msg::endl;
        return time;
      }
    };
    #pragma GCC visibility pop
    
    //***************************************
    // Geometry
    //***************************************
    void meshSphere(double const &lc, const int &tagSurface, const int &tagVolume,
                    const double &r)
    {
      gmsh::model::add("sphere");
      gmsh::model::occ::addPoint(0.5, 0, 0, 1);
      gmsh::model::occ::addSphere(0, 0, 0, r, 1);
      gmsh::model::occ::synchronize();
      gmsh::model::addPhysicalGroup(3, {1}, tagVolume);
      gmsh::model::setPhysicalName(3, 1, "volume");
      gmsh::model::addPhysicalGroup(2, {1}, tagSurface);
      gmsh::model::setPhysicalName(2, tagSurface, "surface");
      gmsh::option::setNumber("Mesh.CharacteristicLengthMin", lc);
      gmsh::option::setNumber("Mesh.CharacteristicLengthMax", lc);
      gmsh::model::mesh::generate(3);
    }
    
    int main(int argc, char **argv)
    {
    
      gmshddm::common::GmshDdm gmshDdm(argc, argv);
      /****
       *  start python interpreter
       ****/
      pybind11::scoped_interpreter guard{};
      /****
       * input Data
       ****/
      double pi = 3.14159265359;
      double epsrext = 1;
      double murext = 1;
      double epsrint = 4;
      double murint = 1;
      double mu0 = 4 * pi * 1e-7;
      double eps0 = 8.854187817e-12;
      double muext = murext * mu0;
      double epsext = eps0 * epsrext;
      double muint = murint * mu0;
      double epsint = eps0 * epsrint;
      double frequency =
        4 / (2. * pi * std::sqrt(epsint * muint));
      double w = 2 * pi * frequency;
      std::complex< double > im(0., 1.);
      std::complex< double > k1e = im * w * epsext;
      std::complex< double > k2e = im * w * muext;
      double ke = std::sqrt(real(-k1e * k2e));
      std::complex< double > k1i = im * w * epsint;
      std::complex< double > k2i = im * w * muint;
      double ki = std::sqrt(real(-k1i * k2i));
      double Zi = std::sqrt(muint / epsint);
      double Ze = std::sqrt(muext / epsext);
      int tagSurface = 1;
      int tagVolume = 3;
      double r = 1;
      int FEorderAlpha = 2;
      int FEorderBeta = 3;
      double GMRESTol = 4;
      double pointsByWl = 10;
      int pade = 1;
      double angleDivisor = 2.;
      int padeOrder = 2;
      gmshDdm.userDefinedParameter(FEorderAlpha, "FEorderAlpha");
      gmshDdm.userDefinedParameter(FEorderBeta, "FEorderBeta");
      gmshDdm.userDefinedParameter(pointsByWl, "pointsByWl");
      gmshDdm.userDefinedParameter(pade, "pade");
      double lc = 2 * pi / (pointsByWl * std::max(ki, ke));
      std::string gauss =
        "Gauss" + std::to_string(2 * (std::max(FEorderAlpha, FEorderBeta) + 1));
      gmshDdm.userDefinedParameter(gauss, "gauss");
      std::vector< unsigned int > degree = {0, unsigned(FEorderBeta)};
      double mL2Error = 0;
      double jL2Error = 0;
      double opT = Ze;
      double Tp = 1 / opT;
      double Tm = 1 / Ze;
      /****
       * Generate mesh
       ****/
      meshSphere(lc, tagSurface, tagVolume, r);
      /****
       * create surface mesh
       ****/
      BemppMesh surfaceMesh(tagSurface);
      /****
       * ddm part
       ******/
      msg::info << "********************************" << msg::endl;
      msg::info << " Wave properties:" << msg::endl;
      msg::info << " - kint = " << ki << " [1/m]." << msg::endl;
      msg::info << " - kout = " << ke << " [1/m]." << msg::endl;
      msg::info << " Problem properties:" << msg::endl;
      msg::info << " - Ze : " << Ze << msg::endl;
      msg::info << " - Zi : " << Zi << msg::endl;
      msg::info << " - FEorderAlpha = " << FEorderAlpha << "" << msg::endl;
      msg::info << " - FEorderBeta = " << FEorderBeta << "" << msg::endl;
      msg::info << " Mesh properties:" << msg::endl;
      msg::info << " - Approximate number of points by wavelength = " << pointsByWl
                << "" << msg::endl;
      msg::info << " GMRES tolerance:" << msg::endl;
      msg::info << " - " << GMRESTol << msg::endl;
      msg::info << " Use Pade:" << msg::endl;
      msg::info << " - " << pade << msg::endl;
      msg::info << "********************************" << msg::endl;
      // create domains
      gmshddm::domain::Subdomain omega(2);
      gmshddm::domain::Interface sigma(2);
      omega(0) = gmshfem::domain::Domain(3, tagVolume);
      omega(1) = gmshfem::domain::Domain(2, tagSurface);
      sigma(0, 1) = gmshfem::domain::Domain(2, tagSurface);
      sigma(1, 0) = gmshfem::domain::Domain(2, tagSurface);
      // Create fields
      gmshddm::field::SubdomainField< std::complex< double >,
                                      gmshfem::field::Form::Form1 >
        E("E", omega | sigma,
          gmshfem::field::FunctionSpaceTypeForm1::HierarchicalHCurl, FEorderAlpha);
      Field< std::complex< double >, Form::Form1 > Hbem(
        "Hbem", omega(1), FunctionSpaceTypeForm1::HierarchicalHCurl, 0);
      gmshddm::field::InterfaceField< std::complex< double >,
                                      gmshfem::field::Form::Form2 >
        g("g", sigma, gmshfem::field::FunctionSpaceTypeForm2::P_HierarchicalHCurl,
          degree);
    
      std::vector< gmshfem::problem::Formulation< std::complex< double > > * > vol(2);
      vol[0] = new gmshfem::problem::Formulation< std::complex< double > >("int");
      vol[1] = new BemFormulation("ext", &E(1), &Hbem, surfaceMesh, Zi, Ze, ki, ke,
                                  &g(0, 1), &mL2Error, &jL2Error, opT);
      // Define interface formulations
      std::vector< std::unordered_map<
        unsigned int, gmshfem::problem::Formulation< std::complex< double > > * > >
        sur(2);
      sur[0][1] =
        new gmshfem::problem::Formulation< std::complex< double > >("interface_01");
      sur[1][0] =
        new gmshfem::problem::Formulation< std::complex< double > >("interface_10");
      // Define ddm formulation
      gmshddm::problem::Formulation< std::complex< double > > formulation(
        "weak coupling", vol, sur);
      VectorFunction< std::complex< double > > n = normal< std::complex< double > >();
      // Tell to the formulation that g is field that have to be exchanged
      // between subdomains
      formulation.addInterfaceField(g);
      // interior problem formulation
      formulation(0).integral(curl(dof(E(0))), curl(tf(E(0))), omega(0), gauss);
      formulation(0).integral(-ki * ki * dof(E(0)), tf(E(0)), omega(0), gauss);
      // Boundary conditions
      formulation(0).integral(-im * ki * Zi * formulation.artificialSource(g(1, 0)),
                              tf(E(0)), sigma(0, 1), gauss);
      formulation(0, 1).integral(dof(g(0, 1)), tf(g(0, 1)), sigma(0, 1), gauss);
      formulation(0, 1).integral(-Tp * n % (E(0) % n), tf(g(0, 1)), sigma(0, 1),
                                 gauss);
      formulation(0, 1).integral(-formulation.artificialSource(g(1, 0)),
                                 tf(g(0, 1)), sigma(0, 1), gauss);
      formulation(1, 0).integral(dof(g(1, 0)), tf(g(1, 0)), sigma(1, 0), gauss);
      formulation(1, 0).integral(Tp * E(1), tf(g(1, 0)), sigma(1, 0), gauss);
      formulation(1, 0).integral(-formulation.artificialSource(g(0, 1)), tf(g(1, 0)), sigma(1, 0), gauss);
      std::vector< FieldInterface< std::complex< double > > * > fieldBucket;
      if(pade == 0) {
        formulation(0).integral(-im * ki * Zi * Tm * dof(E(0)), tf(E(0)),
                                sigma(0, 1), gauss);
        formulation(1, 0).integral(Tm * E(1), tf(g(1, 0)), sigma(1, 0), gauss);
        formulation(0, 1).integral(-Tm * n % (E(0) % n), tf(g(0, 1)), sigma(0, 1),
                                   gauss);
      }
      else {
        // all what we need for pade approximations
        const double angle = pi / angleDivisor;
        const double M = 2. * padeOrder + 1.;
        std::complex< double > exp1 =
          std::complex< double >(std::cos(-angle / 2), std::sin(-angle / 2));
        std::complex< double > expC =
          std::complex< double >(std::cos(angle / 2.), std::sin(angle / 2.));
        std::complex< double > exp3 =
          std::complex< double >(std::cos(-angle), std::sin(-angle));
        std::complex< double > C0 = expC;
        std::vector< std::complex< double > > Aj(padeOrder, 0.);
        std::vector< std::complex< double > > Bj(padeOrder, 0.);
        std::complex< double > kepsilonsquare = std::complex< double >(
          ke, 0.4 * pow(ke, 1. / 3.) * pow((1 / r), 2. / 3.));
        kepsilonsquare *= kepsilonsquare;
        for(int i = 0; i < padeOrder; i++) {
          std::complex< double > aj = std::sin((i + 1) * pi / M);
          aj = aj * aj * 2. / M;
          std::complex< double > bj = std::cos((i + 1) * pi / M);
          bj *= bj;
          std::complex< double > den = 1. + bj * (exp3 - 1.);
          Aj[i] = exp1 * aj / (den * den);
          Bj[i] = exp3 * bj / den;
          C0 += expC * aj * (exp3 - 1.) / den;
        }
        // Declare Auxiliary  fields
        Field< std::complex< double >, Form::Form1 > *E_auxi0 =
          new Field< std::complex< double >, Form::Form1 >(
            "E_auxi0", sigma(0, 1),
            gmshfem::field::FunctionSpaceTypeForm1::HierarchicalHCurl,
            FEorderBeta);
        Field< std::complex< double >, Form::Form1 > *E_auxi1 =
          new Field< std::complex< double >, Form::Form1 >(
            "E_auxi1", sigma(1, 0),
            gmshfem::field::FunctionSpaceTypeForm1::HierarchicalHCurl,
            0);
        fieldBucket.push_back(E_auxi0);
        fieldBucket.push_back(E_auxi1);
        std::vector< Field< std::complex< double >, Form::Form0 > * > zeta01;
        std::vector< Field< std::complex< double >, Form::Form1 > * > phi01;
        std::vector< Field< std::complex< double >, Form::Form1 > * > phi10;
        std::vector< Field< std::complex< double >, Form::Form0 > * > zeta10;
        for(int i = 0; i < padeOrder; ++i) {
          phi01.push_back(new Field< std::complex< double >, Form::Form1 >(
            "phi01_" + std::to_string(i), sigma(0, 1),
            gmshfem::field::FunctionSpaceTypeForm1::HierarchicalHCurl,
            0));
          zeta01.push_back(new Field< std::complex< double >, Form::Form0 >(
            "zeta01_" + std::to_string(i), sigma(0, 1),
            gmshfem::field::FunctionSpaceTypeForm0::HierarchicalH1, 1));
          phi10.push_back(new Field< std::complex< double >, Form::Form1 >(
            "phi10_" + std::to_string(i), sigma(1, 0),
            gmshfem::field::FunctionSpaceTypeForm1::HierarchicalHCurl,
            0));
          zeta10.push_back(new Field< std::complex< double >, Form::Form0 >(
            "zeta10_" + std::to_string(i), sigma(1, 0),
            gmshfem::field::FunctionSpaceTypeForm0::HierarchicalH1, 1));
          fieldBucket.push_back(zeta10.back());
          fieldBucket.push_back(phi10.back());
          fieldBucket.push_back(zeta01.back());
          fieldBucket.push_back(phi01.back());
        }
    
        // Boundary conditions
        formulation(0).integral(im * ki * Zi / Ze * dof(*E_auxi0), tf(E(0)),
                                sigma(0, 1), gauss);
        // Auxiliary equations E_auxi0
        formulation(0).integral(C0 * dof(*E_auxi0), tf(*E_auxi0), sigma(0, 1),
                                gauss);
        formulation(0).integral(dof(E(0)), tf(*E_auxi0), sigma(0, 1), gauss);
        formulation(0).integral(-1. / kepsilonsquare * curl(dof(E(0))),
                                curl(tf(*E_auxi0)), sigma(0, 1), gauss);
    
        for(int i = 0; i < padeOrder; ++i) {
          formulation(0).integral(Aj[i] * grad(dof(*zeta01[i])), tf(*E_auxi0),
                                  sigma(0, 1), gauss);
          formulation(0).integral(-Aj[i] / kepsilonsquare * curl(dof(*phi01[i])),
                                  curl(tf(*E_auxi0)), sigma(0, 1), gauss);
          // Auxiliary equations phi01
          formulation(0).integral(dof(*phi01[i]), tf(*phi01[i]), sigma(0, 1),
                                  gauss);
          formulation(0).integral(Bj[i] * grad(dof(*zeta01[i])), tf(*phi01[i]),
                                  sigma(0, 1), gauss);
          formulation(0).integral(-Bj[i] / kepsilonsquare * curl(dof(*phi01[i])),
                                  curl(tf(*phi01[i])), sigma(0, 1), gauss);
    
          formulation(0).integral(-dof(*E_auxi0), tf(*phi01[i]), sigma(0, 1),
                                  gauss);
          // Auxiliary equations zeta01
          formulation(0).integral(dof(*zeta01[i]), tf(*zeta01[i]), sigma(0, 1),
                                  gauss);
          formulation(0).integral(1. / kepsilonsquare * dof(*phi01[i]),
                                  grad(tf(*zeta01[i])), sigma(0, 1), gauss);
        }
        formulation(0, 1).integral(1. / Ze * (*E_auxi0), tf(g(0, 1)), sigma(0, 1),
                                   gauss);
        formulation(1, 0).integral(-1. / Ze * dof(*E_auxi1), tf(g(1, 0)),
                                   sigma(1, 0), gauss);
        // Auxiliary equations E_auxi1
        formulation(1, 0).integral(C0 * dof(*E_auxi1), tf(*E_auxi1), sigma(1, 0),
                                   gauss);
        formulation(1, 0).integral(-(E(1) % n) % n, tf(*E_auxi1), sigma(1, 0),
                                   gauss);
        formulation(1, 0).integral(-1. / kepsilonsquare * curl(E(1)),
                                   curl(tf(*E_auxi1)), sigma(1, 0), gauss);
        for(int i = 0; i < padeOrder; ++i) {
    
          formulation(1, 0).integral(Aj[i] * grad(dof(*zeta10[i])), tf(*E_auxi1),
                                     sigma(1, 0), gauss);
    
          formulation(1, 0).integral(-Aj[i] / kepsilonsquare * curl(dof(*phi10[i])),
                                     curl(tf(*E_auxi1)), sigma(1, 0), gauss);
          // Auxiliary equations phi10
          formulation(1, 0).integral(dof(*phi10[i]), tf(*phi10[i]), sigma(1, 0),
                                     gauss);
          formulation(1, 0).integral(Bj[i] * grad(dof(*zeta10[i])), tf(*phi10[i]),
                                     sigma(1, 0), gauss);
    
          formulation(1, 0).integral(-Bj[i] / kepsilonsquare * curl(dof(*phi10[i])),
                                     curl(tf(*phi10[i])), sigma(1, 0), gauss);
          formulation(1, 0).integral(-dof(*E_auxi1), tf(*phi10[i]), sigma(1, 0),
                                     gauss);
          // Auxiliary equations zeta10
          formulation(1, 0).integral(dof(*zeta10[i]), tf(*zeta10[i]), sigma(1, 0),
                                     gauss);
          formulation(1, 0).integral(1. / kepsilonsquare * dof(*phi10[i]),
                                     grad(tf(*zeta10[i])), sigma(1, 0), gauss);
        }
      }
    
      // Solve the DDM formulation
      formulation.pre();
      formulation.solve("gmres", pow(10, -GMRESTol), 100, true);
    
      for(unsigned int i = 0; i < fieldBucket.size(); ++i) {
        delete fieldBucket[i];
      }
      msg::info << "***************************************************************************************" <<msg::endl;
      msg::info << "Differences in L2-norm between the strong BEM-BEM coupling and the weak FEM-BEM coupling"<<msg::endl;
      msg::info << "***************************************************************************************" <<msg::endl;
      msg::info <<"e_bembem_M: "  << mL2Error << msg::endl;
      msg::info << "e_bembem_J: " << jL2Error << msg::endl;
    
      msg::info << "***************************************************************************************" <<msg::endl;
      msg::info << "Errors in L2-norm between the analytial solution and the weak FEM-BEM coupling"<<msg::endl;
      msg::info << "***************************************************************************************" <<msg::endl;
      AnalyticalFunction< maxwell3D::MMagneticSurfaceCurrent< std::complex< double > > >
        Mexact(ki, ke, k2i, k2e, r);
      msg::info << "e_analy_M: "
                << real(sqrt(
                     integrate(pow(abs(xComp(Mexact) - xComp(E(1) % n)), 2) +
                                 pow(abs(yComp(Mexact) - yComp(E(1) % n)), 2) +
                                 pow(abs(zComp(Mexact) - zComp(E(1) % n)), 2),
                               omega(1), gauss) /
                     integrate(pow(abs(xComp(Mexact)), 2) +
                                 pow(abs(yComp(Mexact)), 2) +
                                 pow(abs(zComp(Mexact)), 2),
                               omega(1), gauss)))
                << msg::endl;
    
      AnalyticalFunction<
        maxwell3D::JElectricSurfaceCurrent< std::complex< double > > >
        Jexact(ki, ke, k2i, k2e, r);
      msg::info << "e_analy_J: "<<real(
        sqrt(integrate(pow(abs(xComp(Jexact) - xComp(Hbem % n)), 2) +
                         pow(abs(yComp(Jexact) - yComp(Hbem % n)), 2) +
                         pow(abs(zComp(Jexact) - zComp(Hbem % n)), 2),
                       omega(1), gauss) /
             integrate(pow(abs(xComp(Jexact)), 2) +
                         pow(abs(yComp(Jexact)), 2) +
                         pow(abs(zComp(Jexact)), 2),
                       omega(1), gauss)))<< msg::endl;;
    
      return 0;
    }