diff --git a/utils/misc/laplace.cpp b/utils/misc/laplace.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c187f56cb40853977f4d632b001461e986115560 --- /dev/null +++ b/utils/misc/laplace.cpp @@ -0,0 +1,638 @@ +#include <stdio.h> +#include <gmsh/Gmsh.h> +#include <gmsh/GModel.h> +#include <gmsh/MElement.h> +#include <gmsh/GmshMatrix.h> +class gLevelset; +#ifdef HAVE_GLEVELSETS +#include <Levelset.h> +#include <Integration3D.h> +#endif + +// My First test with Gmsh's API +// A Laplace Equation (booh) +// Vector ort scalar, in any dimension and with +// any polynomial order + +// This code will quantify the gain of assembling matrices +// either in reference coordinate system, or in the real one + +typedef Double_Matrix gmshSmallMatrix ; +typedef Double_Matrix gmshMatrix ; +typedef Double_Vector gmshVector ; + +extern double inv3x3 (double a[3][3], double a[3][3]); + +// An ad hoc structure to store the triangulation +// issued of a levelset cut +// num is the new vertex +// num1 and num2 are vertices of the cut edge in the initial mesh +class gmshTopoVertex +{ + static double tol; + int num; + double x,y,z; + MVertex *v; +public: + gmshTopoVertex (double _x, double _y, double _z): + num(-1),x(_x),y(_y),z(_z) + { + } + void setMVertex(MVertex *_v){v=_v;} + MVertex* getMVertex()const {return v;} + void setNum(int n){num=n;} + int getNum()const {return num;} + bool operator < (const gmshTopoVertex & other) const{ + if (x - other.x < -tol) return true; + if (x - other.x > tol) return false; + if (y - other.y < -tol) return true; + if (y - other.y > tol) return false; + if (z - other.z < -tol) return true; + return false; + } + double X() const {return x;}; + double Y() const {return y;}; + double Z() const {return z;}; +}; + +double gmshTopoVertex::tol = 1.e-6; + +// try to add a "poisson" term INSIDE the elements +#ifdef HAVE_GLEVELSETS +void IntegrationPoints (MElement*e, + gLevelset*ls, + int integrationOrder, + std::vector<IntegrationPoint>&ipV , + std::vector<IntegrationPoint>&ipS ) +{ + switch ( e->getTypeForMSH()){ + case MSH_TET_4 : + { + vector<CuttingPoint> cp; + vector<Tetra> subTetras; + vector<Quad> surfQuads; + vector<Triangle> surfTriangles; + Tetra T (e->getVertex(0)->x(), + e->getVertex(0)->y(), + e->getVertex(0)->z(), + e->getVertex(1)->x(), + e->getVertex(1)->y(), + e->getVertex(1)->z(), + e->getVertex(2)->x(), + e->getVertex(2)->y(), + e->getVertex(2)->z(), + e->getVertex(3)->x(), + e->getVertex(3)->y(), + e->getVertex(3)->z()); + T.cut (*ls, ipV, ipS, cp, integrationOrder,integrationOrder,integrationOrder, subTetras, surfQuads, surfTriangles); + } + break; + + default : + throw; + } +} +void gmshCutMesh (MElement*e, + gLevelset*ls, + std::set<gmshTopoVertex> &tVerts, + std::multimap<MElement*,MElement*> &cut) +{ + switch ( e->getTypeForMSH()){ + case MSH_TET_4 : + { + vector<CuttingPoint> cp; + vector<Tetra> subTetras; + vector<Quad> surfQuads; + vector<Triangle> surfTriangles; + int integrationOrder = 1; + std::vector<IntegrationPoint> ipV; + std::vector<IntegrationPoint> ipS; + + Tetra T (e->getVertex(0)->x(), + e->getVertex(0)->y(), + e->getVertex(0)->z(), + e->getVertex(1)->x(), + e->getVertex(1)->y(), + e->getVertex(1)->z(), + e->getVertex(2)->x(), + e->getVertex(2)->y(), + e->getVertex(2)->z(), + e->getVertex(3)->x(), + e->getVertex(3)->y(), + e->getVertex(3)->z()); + T.cut (*ls, ipV, ipS, cp, integrationOrder,integrationOrder,integrationOrder, subTetras, surfQuads, surfTriangles); + for (int i=0;i<surfTriangles.size();i++){ + gmshTopoVertex v0 ( surfTriangles[i].x(0),surfTriangles[i].y(0),surfTriangles[i].z(0)); + gmshTopoVertex v1 ( surfTriangles[i].x(1),surfTriangles[i].y(1),surfTriangles[i].z(1)); + gmshTopoVertex v2 ( surfTriangles[i].x(2),surfTriangles[i].y(2),surfTriangles[i].z(2)); + std::set<gmshTopoVertex>::const_iterator it0 = tVerts.find(v0); + std::set<gmshTopoVertex>::iterator it1 = tVerts.find(v1); + std::set<gmshTopoVertex>::iterator it2 = tVerts.find(v2); + MVertex *mv0,*mv1,*mv2; + if (it0 == tVerts.end()){ + v0.setNum(tVerts.size()); + mv0 = new MVertex (v0.X(),v0.Y(),v0.Z(),0,v0.getNum()); + v0.setMVertex (mv0); + tVerts.insert(v0); + } + else mv0 = it0->getMVertex(); + if (it1 == tVerts.end()){ + v1.setNum(tVerts.size()); + mv1 = new MVertex (v1.X(),v1.Y(),v1.Z(),0,v1.getNum()); + v1.setMVertex (mv1); + tVerts.insert(v1); + } + else mv1 = it1->getMVertex(); + if (it2 == tVerts.end()){ + v2.setNum(tVerts.size()); + mv2 = new MVertex (v2.X(),v2.Y(),v2.Z(),0,v2.getNum()); + v2.setMVertex (mv2); + tVerts.insert(v2); + } + else mv2 = it2->getMVertex(); + + MTriangle *tri = new MTriangle(mv0,mv1,mv2); + cut.insert(std::make_pair(e,tri)); + } + } + break; + + default : + throw; + } +} + + +void gmshBuildSurfaceMesh(GModel *_gm, + gLevelset *ls, + std::set<gmshTopoVertex> &tVerts, + std::multimap<MElement*,MElement*> &cut) { + if (_gm->getNumRegions()){ + for(GModel::riter it = _gm->firstRegion(); it != _gm->lastRegion(); ++it){ + for (int i = 0;i<(*it)->getNumMeshElements();i++){ + MElement *e = (*it)->getMeshElement(i); + gmshCutMesh (e,ls,tVerts,cut); + } + } + } + else throw; +} + +#endif + + +class gmshVertexEvaluator +{ + double _val; + public : + gmshVertexEvaluator(double val = 0):_val(val){} + virtual double operator () (MVertex *) const {return _val;} + virtual double operator () (double x, double y, double z) const {return _val;} +}; + +class gmshTermOfFormulation { +protected: + GModel *_gm; +public: + gmshTermOfFormulation (GModel *gm) : _gm(gm){} + virtual void addToRightHandSide (gmshVector &r) const = 0; + virtual void addToJacobian (gmshMatrix &J) const = 0; +}; + +class gmshNodalFemTerm : public gmshTermOfFormulation { +protected: + virtual int sizeOfC(MElement*) const = 0; + virtual int sizeOfR(MElement*) const = 0; + virtual int localToGlobalR (MElement *e, int iVertex, int icomp) const = 0; + virtual int localToGlobalR (MElement *e, int i) const = 0; + virtual int localToGlobalC (MElement *e, int j) const = 0; + virtual void elementMatrix ( MElement *e, gmshSmallMatrix & m) const = 0; + virtual void elementVector ( MElement *e, gmshVector & m) const = 0; + void addToJacobian (gmshMatrix &J, GEntity *ge) const; + void addToRightHandSide (gmshVector &J, GEntity *ge) const; + std::map<std::pair<int,int>, double> dirichlet; + gLevelset *_ls; +public: + gmshNodalFemTerm (GModel *gm) : gmshTermOfFormulation(gm),_ls(0){} + void addToRightHandSide (gmshVector &r) const; + void addToJacobian (gmshMatrix &J) const; + void uglyDirichlet (gmshMatrix &J,gmshVector &r) const; + void addDirichlet (int physical, int dim, int comp, const gmshVertexEvaluator & e); + void addNeumann (int physical, int dim, int icomp, const gmshVertexEvaluator & e, gmshVector &r); + void setLevelset(gLevelset *ls) {_ls = ls;} + virtual int sizeOfR () const = 0; + virtual int sizeOfC () const = 0; + virtual void getComponents (int iVertex, int *components) const = 0; +}; + +void gmshNodalFemTerm::addDirichlet(int physical, int dim, int comp, const gmshVertexEvaluator & e) { + std::vector<MVertex *> v; + _gm->getMeshVertices (physical, dim,v); + for (int i=0;i<v.size();i++) + dirichlet[std::make_pair(v[i]->getNum(),comp)] = e(v[i]); +} + +void gmshNodalFemTerm::addNeumann(int physical, int dim, int comp, const gmshVertexEvaluator & fct, gmshVector &r) { + std::map<int, std::vector<GEntity*> > groups[4]; + _gm->getPhysicalGroups(groups); + std::map<int, std::vector<GEntity*> >::iterator it = groups[dim].find(physical); + if (it == groups[dim].end())return; + double jac[3][3]; + + for (int i=0;i<it->second.size();++i){ + GEntity *ge = it->second[i]; + for (int j=0; j<ge->getNumMeshElements();j++){ + MElement *e = ge->getMeshElement(j); + int integrationOrder = 2*e->getPolynomialOrder(); + int nbNodes = e->getNumVertices(); + int npts; + IntPt *GP; + e->getIntegrationPoints(integrationOrder, &npts, &GP); + for (int ip=0;ip<npts;ip++){ + const double u = GP[ip].pt[0]; + const double v = GP[ip].pt[1]; + const double w = GP[ip].pt[2]; + const double weight = GP[ip].weight; + const double detJ = e->getJacobian (u,v,w,jac); + double x = 0; + double y = 0; + double z = 0; + for (int k=0;k<nbNodes;k++){ + double sf; + e->getShapeFunction (k,u,v,w,sf); + x += e->getVertex(k)->x() * sf; + y += e->getVertex(k)->y() * sf; + z += e->getVertex(k)->z() * sf; + } + const double FCT = fct (x,y,z); + for (int k=0;k<nbNodes;k++){ + double sf; + e->getShapeFunction (k,u,v,w,sf); + // printf("l2g (%d,%d) = %d (%d)\n", k,comp,localToGlobalR(e,k,comp),r.size()); + r(localToGlobalR(e,k,comp)) += detJ * weight * sf * FCT; + } + } + } + } +} + +void gmshNodalFemTerm::uglyDirichlet (gmshMatrix &J,gmshVector &r) const{ + std::map<std::pair<int,int>, double>::const_iterator it = dirichlet.begin(); + int C[256]; + for ( ; it != dirichlet.end() ; ++it){ + getComponents (it->first.first,C); + double val = it->second; + int row = C[it->first.second]; + // printf("vertex %d comp %d iRow = %d\n",it->first.first,it->first.second,row); + const double BIG = J(row,row) * 1.e8; + J(row,row) = BIG; + r(row) += BIG * val; + } +} + +// first symmetric implementation, will be better next +void gmshNodalFemTerm::addToJacobian (gmshMatrix &J) const { + if (_gm->getNumRegions()){ + for(GModel::riter it = _gm->firstRegion(); it != _gm->lastRegion(); ++it){ + addToJacobian(J,*it); + } + } + else if(_gm->getNumFaces()){ + for(GModel::fiter it = _gm->firstFace(); it != _gm->lastFace(); ++it){ + addToJacobian(J,*it); + } + } +} + +// first symmetric implementation, will be better next +void gmshNodalFemTerm::addToRightHandSide (gmshVector &RHS) const { + if (_gm->getNumRegions()){ + for(GModel::riter it = _gm->firstRegion(); it != _gm->lastRegion(); ++it){ + addToRightHandSide(RHS,*it); + } + } + else if(_gm->getNumFaces()){ + for(GModel::fiter it = _gm->firstFace(); it != _gm->lastFace(); ++it){ + addToRightHandSide(RHS,*it); + } + } +} + +void gmshNodalFemTerm::addToRightHandSide (gmshVector &RHS, GEntity *ge) const { + for(unsigned int i = 0; i < ge->getNumMeshElements(); i++){ + MElement *e = ge->getMeshElement (i); + int nbR = sizeOfR(e); + gmshVector V (nbR); + elementVector (e, V); + // assembly + for (int j=0;j<nbR;j++){ + RHS ( localToGlobalR (e,j) ) += V ( j ); + } + } +} + +void gmshNodalFemTerm::addToJacobian (gmshMatrix &Jac, GEntity *ge) const { + for(unsigned int i = 0; i < ge->getNumMeshElements(); i++){ + MElement *e = ge->getMeshElement (i); + const int nbR = sizeOfR(e); + const int nbC = sizeOfC(e); + gmshSmallMatrix localMatrix (nbR,nbC); + elementMatrix (e,localMatrix); + // assembly + for (int j=0;j<nbR;j++){ + int J = localToGlobalR (e,j); + for (int k=0;k<nbC;k++){ + int K = localToGlobalC (e,k); + Jac(J,K) += localMatrix (j,k); + } + } + } +} +// LAPLACE +class gmshLaplaceTerm : public gmshNodalFemTerm { +protected: + virtual int sizeOfR (MElement *e) const {return e->getNumVertices();} + virtual int sizeOfC (MElement *e) const {return e->getNumVertices();} + virtual int localToGlobalR (MElement *e, int i) const {return e->getVertex(i)->getNum()-1;} + virtual int localToGlobalC (MElement *e, int j) const {return e->getVertex(j)->getNum()-1;} + virtual int localToGlobalR (MElement *e, int iVertex, int icomp) const {return localToGlobalR (e, iVertex);} + void elementMatrix ( MElement *e, gmshSmallMatrix & m) const; + void elementVector ( MElement *e, gmshVector & v) const; +public: + gmshLaplaceTerm (GModel *gm) : gmshNodalFemTerm(gm){} + virtual int sizeOfR () const {return _gm->getNumMeshVertices();} + virtual int sizeOfC () const {return _gm->getNumMeshVertices();} + virtual void getComponents (int iVertex, int *components) const {components[0] = iVertex - 1;}; +}; + + +void gmshLaplaceTerm:: elementMatrix ( MElement *e, gmshSmallMatrix & m) const{ + int nbNodes = e->getNumVertices(); + int integrationOrder = 2*(e->getPolynomialOrder()-1); + int npts; + IntPt *GP; + double jac [3][3]; + double invjac [3][3]; + double Grads[256][3],grad[3]; + e->getIntegrationPoints(integrationOrder, &npts, &GP); + + m.set_all(0.0); + + for (int i=0;i<npts;i++){ + const double u = GP[i].pt[0]; + const double v = GP[i].pt[1]; + const double w = GP[i].pt[2]; + const double weight = GP[i].weight; + const double detJ = e->getJacobian (u,v,w,jac); + inv3x3 ( jac, invjac) ; + for (int j=0;j<nbNodes;j++){ + e->getGradShapeFunction (j,u,v,w,grad); + Grads[j][0] = invjac[0][0] * grad[0] + invjac[0][1] * grad[1] + invjac[0][2] * grad[2]; + Grads[j][1] = invjac[1][0] * grad[0] + invjac[1][1] * grad[1] + invjac[1][2] * grad[2]; + Grads[j][2] = invjac[2][0] * grad[0] + invjac[2][1] * grad[1] + invjac[2][2] * grad[2]; + } + for (int j=0;j<nbNodes;j++){ + for (int k=0;k<=j;k++){ + m(j,k) += (Grads[j][0]*Grads[k][0]+ + Grads[j][1]*Grads[k][1]+ + Grads[j][2]*Grads[k][2]) * weight * detJ; + } + } + } + for (int j=0;j<nbNodes;j++) + for (int k=0;k<j;k++) + m(k,j) = m(j,k); +} + + + +void gmshLaplaceTerm:: elementVector ( MElement *e, gmshVector & m) const{ + int nbNodes = e->getNumVertices(); + int integrationOrder = 2*(e->getPolynomialOrder()-1); + double jac [3][3]; + m.scale(0.0); +#ifdef HAVE_GLEVELSETS + std::vector<IntegrationPoint> ipV,ipS; + IntegrationPoints (e,_ls,integrationOrder,ipV,ipS); + for (int i=0;i<ipS.size();i++){ + const double u = ipS[i].xl(); + const double v = ipS[i].yl(); + const double w = ipS[i].zl(); + const double weight = ipS[i].weight(); + // const double detJ = e->getJacobian (u,v,w,jac); + for (int j=0;j<nbNodes;j++){ + double sf ; e->getShapeFunction (j,u,v,w,sf); + m(j) += weight * sf; + } + } +#else + int npts; + IntPt *GP; + e->getIntegrationPoints(integrationOrder, &npts, &GP); + for (int i=0;i<npts;i++){ + const double u = GP[i].pt[0]; + const double v = GP[i].pt[1]; + const double w = GP[i].pt[2]; + const double weight = GP[i].weight; + const double detJ = e->getJacobian (u,v,w,jac); + for (int j=0;j<nbNodes;j++){ + double sf ; e->getShapeFunction (j,u,v,w,sf); + m(j) += weight * detJ * sf; + } + } +#endif +} + +// LAPLACE +class gmshLaplaceVectorTerm : public gmshNodalFemTerm { + double _E,_nu; +protected: + virtual int sizeOfR (MElement *e) const {return 3*e->getNumVertices();} + virtual int sizeOfC (MElement *e) const {return 3*e->getNumVertices();} + virtual int localToGlobalR (MElement *e, int i) const { + int iComp = i/e->getNumVertices(); + int ithLocalVertex = i%e->getNumVertices(); + // printf("%d -> %d %d\n",i,ithLocalVertex,iComp); + return 3*(e->getVertex(ithLocalVertex)->getNum()-1)+iComp; + } + virtual int localToGlobalR (MElement *e, int iVertex, int icomp) const { + return localToGlobalR (e, icomp*e->getNumVertices()+iVertex); + } + virtual int localToGlobalC (MElement *e, int j) const {return localToGlobalR (e,j);} + void elementMatrix ( MElement *e, gmshSmallMatrix & m) const; + void elementVector ( MElement *e, gmshVector & v) const; +public: + gmshLaplaceVectorTerm (GModel *gm, double E, double nu) : gmshNodalFemTerm(gm),_E(E),_nu(nu){} + virtual int sizeOfR () const {return 3*_gm->getNumMeshVertices();} + virtual int sizeOfC () const {return 3*_gm->getNumMeshVertices();} + virtual void getComponents (int iVertex, int *components) const { + components[0] = 3*(iVertex - 1) + 0; + components[1] = 3*(iVertex - 1) + 1; + components[2] = 3*(iVertex - 1) + 2; + } +}; + + +void gmshLaplaceVectorTerm:: elementMatrix ( MElement *e, gmshSmallMatrix & m) const{ + int nbNodes = e->getNumVertices(); + int integrationOrder = 2*(e->getPolynomialOrder()-1); + int npts; + IntPt *GP; + double jac [3][3]; + double invjac [3][3]; + double Grads[256][3],grad[3]; + e->getIntegrationPoints(integrationOrder, &npts, &GP); + + m.set_all(0.0); + + double FACT = _E / (1 + _nu); + double C11 = FACT * (1 - _nu) / (1 - 2 * _nu); + double C12 = FACT * _nu / (1 - 2 * _nu); + double C44 = (C11 - C12) / 2; + const double C[6][6] = + { {C11, C12, C12, 0, 0, 0}, + {C12, C11, C12, 0, 0, 0}, + {C12, C12, C11, 0, 0, 0}, + { 0, 0, 0, C44, 0, 0}, + { 0, 0, 0, 0, C44, 0}, + { 0, 0, 0, 0, 0, C44} }; + + gmshSmallMatrix H(6,6); + gmshSmallMatrix B (6,3*nbNodes); + gmshSmallMatrix BTH (3*nbNodes,6); + gmshSmallMatrix BT (3*nbNodes,6); + for (int i=0;i<6;i++) + for (int j=0;j<6;j++) + H(i,j) = C[i][j]; + + for (int i=0;i<npts;i++){ + const double u = GP[i].pt[0]; + const double v = GP[i].pt[1]; + const double w = GP[i].pt[2]; + const double weight = GP[i].weight; + const double detJ = e->getJacobian (u,v,w,jac); + inv3x3 ( jac, invjac) ; + B.set_all(0.0); + BT.set_all(0.0); + for (int j=0;j<nbNodes;j++){ + e->getGradShapeFunction (j,u,v,w,grad); + Grads[j][0] = invjac[0][0] * grad[0] + invjac[0][1] * grad[1] + invjac[0][2] * grad[2]; + Grads[j][1] = invjac[1][0] * grad[0] + invjac[1][1] * grad[1] + invjac[1][2] * grad[2]; + Grads[j][2] = invjac[2][0] * grad[0] + invjac[2][1] * grad[1] + invjac[2][2] * grad[2]; + BT(j,0) = B(0,j) = Grads[j][0]; + BT(j,3) = B(3,j) = Grads[j][1]; + BT(j,4) = B(4,j) = Grads[j][2]; + + BT(j+nbNodes,1) = B(1,j+nbNodes) = Grads[j][1]; + BT(j+nbNodes,3) = B(3,j+nbNodes) = Grads[j][0]; + BT(j+nbNodes,5) = B(5,j+nbNodes) = Grads[j][2]; + + BT(j+2*nbNodes,2) = B(2,j+2*nbNodes) = Grads[j][2]; + BT(j+2*nbNodes,4) = B(4,j+2*nbNodes) = Grads[j][0]; + BT(j+2*nbNodes,5) = B(5,j+2*nbNodes) = Grads[j][1]; + } + BTH.set_all(0.0); + BTH.blas_dgemm (BT,H); + m.blas_dgemm (BTH,B,weight*detJ,1.0); + } +// for (int i=0;i<12;i++){ +// for (int j=0;j<12;j++){ +// printf("%12.5E ",m(i,j)); +// } +// printf("\n"); +// } +// printf("\n"); +} + +void gmshLaplaceVectorTerm:: elementVector ( MElement *e, gmshVector & m) const{ +} + +int main(int argc, char **argv) +{ + // globals are still present in Gmsh + GmshInitialize(argc, argv); + + // Creation of a geometric model + GModel *m = new GModel(); + // a Mesh is read + m->readMSH(argv[1]); + int nbNodes = m->getNumMeshVertices(); + int dim = m->getNumRegions() ? 3 : 2; + + gmshLaplaceVectorTerm Laplace(m,1.e10,.3); + int sP = Laplace.sizeOfR(); + +#ifdef HAVE_GLEVELSETS + gLevelset *ls1 = new gLevelsetSphere (-.35,.5,.5,.2); + gLevelset *ls2 = new gLevelsetSphere (-.5,.5,.5,.2); + std::vector<const gLevelset*> vls; + vls.push_back(ls1); + vls.push_back(ls2); + gLevelsetUnion *ls = new gLevelsetUnion (vls); + Laplace.setLevelset (ls); + std::set<gmshTopoVertex> tVerts; + std::multimap<MElement*,MElement*> cut; + gmshBuildSurfaceMesh(m,ls,tVerts,cut); + printf("%d noeuds %d triangles\n",tVerts.size(),cut.size()); + { + FILE *fp = fopen ("cut.msh","w"); + fprintf(fp, "$MeshFormat\n2 0 8\n$EndMeshFormat\n"); + fprintf(fp, "$Nodes\n"); + fprintf(fp, "%d\n",tVerts.size()); + std::set<gmshTopoVertex>::iterator it = tVerts.begin(); + int K=1; + for ( ; it != tVerts.end() ; ++it){ + it->getMVertex()->setIndex(K++); + it->getMVertex()->writeMSH(fp); + } + fprintf(fp, "$EndNodes\n"); + fprintf(fp, "$Elements\n"); + fprintf(fp, "%d\n",cut.size()); + std::multimap<MElement*,MElement*>::iterator it2 = cut.begin(); + for ( ; it2 != cut.end() ; ++it2){ + it2->second->writeMSH(fp,2.0); + } + fprintf(fp, "$EndElements\n"); + fclose(fp); + } + // return 1; +#endif + // Laplace.addDirichlet (200,dim-1,0,gmshVertexEvaluator(0.01)); + Laplace.addDirichlet (100,dim-1,0,gmshVertexEvaluator(0.0)); + Laplace.addDirichlet (100,dim-1,1,gmshVertexEvaluator(0.0)); + Laplace.addDirichlet (100,dim-1,2,gmshVertexEvaluator(0.0)); + + gmshMatrix k (sP,sP); + gmshVector x (sP); + gmshVector b (sP); + + Laplace.addNeumann (200,dim-1,0,gmshVertexEvaluator(0.01),b); + + clock_t t1 = clock(); + Laplace.addToJacobian(k); + Laplace.addToRightHandSide(b); + Laplace.uglyDirichlet (k,b); + clock_t t2 = clock(); + printf("%lf seconds for assembling the operator\n",(double)(t2-t1)/CLOCKS_PER_SEC); + k.lu_solve (b,x); + clock_t t3 = clock(); + printf("%lf seconds for solving the system (%d unknowns)\n",(double)(t3-t2)/CLOCKS_PER_SEC,k.size1()); + + FILE *fp = fopen("res.msh","w"); + fprintf(fp, "$MeshFormat\n2 0 8\n$EndMeshFormat\n"); + fprintf(fp, "$NodeData\n"); + fprintf(fp, "1\n\"%s\"\n", "toto"); + fprintf(fp, "1\n%.16g\n", 0.0); + fprintf(fp, "3\n%d\n%d\n%d\n", 0, 3, m->getNumMeshVertices()); + int c[100]; + for (int i=0;i<nbNodes;i++){ + Laplace.getComponents(i+1,c); + fprintf(fp, "%d %22.15E %22.15E %22.15E\n",i+1, x(c[0]),x(c[1]),x(c[2])); + } + fprintf(fp, "$EndNodeData\n"); + fclose (fp); + clock_t t4 = clock(); + printf("%lf seconds for saving the solution\n",(double)(t4-t3)/CLOCKS_PER_SEC); + GmshFinalize(); +} +