diff --git a/Numeric/fullMatrix.cpp b/Numeric/fullMatrix.cpp index 848b14e91ff9c0c3bd454a64ad715a300c2f6f3b..52c4c867092e34164e88e144cac849ad5d6910c9 100644 --- a/Numeric/fullMatrix.cpp +++ b/Numeric/fullMatrix.cpp @@ -39,7 +39,7 @@ extern "C" { } template<> -void fullMatrix<double>::mult(const fullMatrix<double> &b, fullMatrix<double> &c) +void fullMatrix<double>::mult(const fullMatrix<double> &b, fullMatrix<double> &c)const { int M = c.size1(), N = c.size2(), K = _c; int LDA = _r, LDB = b.size1(), LDC = c.size1(); @@ -50,7 +50,7 @@ void fullMatrix<double>::mult(const fullMatrix<double> &b, fullMatrix<double> &c template<> void fullMatrix<std::complex<double> >::mult(const fullMatrix<std::complex<double> > &b, - fullMatrix<std::complex<double> > &c) + fullMatrix<std::complex<double> > &c)const { int M = c.size1(), N = c.size2(), K = _c; int LDA = _r, LDB = b.size1(), LDC = c.size1(); diff --git a/Numeric/fullMatrix.h b/Numeric/fullMatrix.h index 88328d151e2d9ba0c317ec145c60cfc5a6ca8bcd..023995badfffa3c0cc3effc14801ab8fbc988096 100644 --- a/Numeric/fullMatrix.h +++ b/Numeric/fullMatrix.h @@ -79,11 +79,11 @@ class fullMatrix int _r, _c; scalar *_data; public: - fullMatrix(fullMatrix<scalar> &original, int r_start, int r){ - _r = r; - _c = original._c; + fullMatrix(fullMatrix<scalar> &original, int c_start, int c){ + _c = c; + _r = original._r; _own_data = false; - _data = original._data + r_start * _c; + _data = original._data + c_start * _r; } fullMatrix(int r, int c) : _r(r), _c(c) { @@ -132,7 +132,7 @@ class fullMatrix for(int j = j0, destj = destj0; j < j0 + nj; j++, destj++) (*this)(desti, destj) = a(i, j); } - void mult(const fullMatrix<scalar> &b, fullMatrix<scalar> &c) + void mult(const fullMatrix<scalar> &b, fullMatrix<scalar> &c)const #if !defined(HAVE_BLAS) { c.scale(0.); diff --git a/Solver/CMakeLists.txt b/Solver/CMakeLists.txt index aad2bad669a4a6f6b7069257509a48e0c6dedf3b..efcc0f1ced387796bc3c9bef31b457db1b161c08 100644 --- a/Solver/CMakeLists.txt +++ b/Solver/CMakeLists.txt @@ -12,6 +12,7 @@ set(SRC eigenSolver.cpp dgGroupOfElements.cpp dgAlgorithm.cpp + dgConservationLawAdvection.cpp ) file(GLOB HDR RELATIVE ${CMAKE_SOURCE_DIR}/Solver *.h) diff --git a/Solver/dgAlgorithm.cpp b/Solver/dgAlgorithm.cpp index f0626de940661e85437fd0acb483b860decbe3d1..b4e51694ff118e341a57d6a6e464a7dc4d278fdb 100644 --- a/Solver/dgAlgorithm.cpp +++ b/Solver/dgAlgorithm.cpp @@ -9,22 +9,24 @@ void dgAlgorithm::residualVolume ( //dofManager &dof, // the DOF manager (maybe useless here) const dgConservationLaw &claw, // the conservation law - const dgGroupOfElements & group ) // the residual + const dgGroupOfElements & group, + const fullMatrix<double> &solution, + fullMatrix<double> &residual // the residual + ) { // ----- 1 ---- get the solution at quadrature points // ----- 1.1 --- allocate a matrix of size (nbFields * nbElements, nbQuadraturePoints) - int nbFields = group.getNbFields(); - fullMatrix<double> solutionQP (group.getNbElements() * nbFields, group.getNbIntegrationPoints()); + int nbFields = claw.nbFields(); + fullMatrix<double> solutionQP (group.getNbIntegrationPoints(),group.getNbElements() * nbFields); // ----- 1.2 --- multiply the solution by the collocation matrix - group.getSolution().mult ( group.getCollocationMatrix() , solutionQP); + group.getCollocationMatrix().mult(solution , solutionQP); // ----- 1.3 --- if the conservation law is diffusive, compute the gradients too fullMatrix<double> *gradientSolutionQP= 0; if (claw.diffusiveFlux()){ - gradientSolutionQP = new fullMatrix<double> (group.getNbElements() * nbFields * 3, group.getNbIntegrationPoints()); - group.getGradientOfSolution().mult ( group.getCollocationMatrix() , *gradientSolutionQP); + gradientSolutionQP = new fullMatrix<double> (group.getNbIntegrationPoints(), group.getNbElements() * nbFields * 3); + //group.getGradientOfSolution().mult ( group.getCollocationMatrix() , *gradientSolutionQP); } - // ----- 2 ---- compute all fluxes (diffusive and convective) at integration points // ----- 2.1 --- allocate elementary fluxes (compued in XYZ coordinates) fullMatrix<double> fConv[3] = {fullMatrix<double>( group.getNbIntegrationPoints(), nbFields ), @@ -33,43 +35,62 @@ void dgAlgorithm::residualVolume ( //dofManager &dof, // the DOF manager (maybe fullMatrix<double> fDiff[3] = {fullMatrix<double>( group.getNbIntegrationPoints(), nbFields ), fullMatrix<double>( group.getNbIntegrationPoints(), nbFields ), fullMatrix<double>( group.getNbIntegrationPoints(), nbFields )}; - // ----- 2.2 --- allocate parametric fluxes (compued in UVW coordinates) for all elements at all integration points + fullMatrix<double> Source = fullMatrix<double> (group.getNbIntegrationPoints(),group.getNbElements() * nbFields); + // ----- 2.2 --- allocate parametric fluxes (computed in UVW coordinates) for all elements at all integration points fullMatrix<double> Fuvw[3] = {fullMatrix<double> (group.getNbElements() * nbFields, group.getNbIntegrationPoints()), fullMatrix<double> (group.getNbElements() * nbFields, group.getNbIntegrationPoints()), fullMatrix<double> (group.getNbElements() * nbFields, group.getNbIntegrationPoints())}; // ----- 2.3 --- iterate on elements - for (int iElement=0 ; iElement<group.getNbElements() ;++iElement) { + for (int iElement=0 ; iElement<group.getNbElements() ;++iElement) { // ----- 2.3.1 --- build a small object that contains elementary solution, jacobians, gmsh element - fullMatrix<double> solutionQPe (solutionQP, iElement*claw.nbFields(),claw.nbFields() ); + fullMatrix<double> solutionQPe (solutionQP, iElement*nbFields, nbFields ); fullMatrix<double> *gradSolutionQPe; - if (claw.diffusiveFlux()) gradSolutionQPe = new fullMatrix<double>(*gradientSolutionQP, 3*iElement*claw.nbFields(),3*claw.nbFields() ); + if (claw.diffusiveFlux()) gradSolutionQPe = new fullMatrix<double>(*gradientSolutionQP, 3*iElement*nbFields,3*nbFields ); else gradSolutionQPe = new fullMatrix<double>; dgElement DGE( group.getElement(iElement), solutionQPe, *gradSolutionQPe, group.getIntegrationPointsMatrix()); - // ----- 2.3.2 --- compute fluxes in XYZ coordinates - if (claw.convectiveFlux()) (*claw.convectiveFlux())(DGE,fConv); - if (claw.diffusiveFlux()) (*claw.diffusiveFlux())(DGE,fDiff); - - // ----- 2.3.3 --- compute fluxes in UVW coordinates - for (int iUVW=0;iUVW<group.getDimUVW();iUVW++) { - // ----- 2.3.3.1 --- get a proxy on the big local flux matrix - fullMatrix<double> fuvwe(Fuvw[iUVW], iElement*claw.nbFields(),claw.nbFields()); - // ----- 2.3.3.1 --- compute \vec{f}^{UVW} =\vec{f}^{XYZ} J^{-1} and multiply bt detJ - for (int iXYZ=0;iXYZ<group.getDimXYZ();iXYZ++) { - for (int iPt =0; iPt< group.getNbIntegrationPoints(); iPt++) { - // get the right inv jacobian matrix dU/dX element - const double invJ = group.getInvJ (iElement, iPt, iXYZ, iUVW); - // get the detJ at this point - const double detJ = group.getDetJ (iElement, iPt); - const double factor = invJ * detJ; - // compute fluxes in the reference coordinate system at this integration point - for (int k=0;k<nbFields;k++) { - fuvwe(iPt,k) += ( fConv[iXYZ](iPt,k) + fDiff[iXYZ](iPt,k)) * factor; - } - } - } + if(claw.convectiveFlux() || claw.diffusiveFlux()){ + // ----- 2.3.2 --- compute fluxes in XYZ coordinates + if (claw.convectiveFlux()) (*claw.convectiveFlux())(DGE,fConv); + if (claw.diffusiveFlux()) (*claw.diffusiveFlux())(DGE,fDiff); + + // ----- 2.3.3 --- compute fluxes in UVW coordinates + for (int iUVW=0;iUVW<group.getDimUVW();iUVW++) { + // ----- 2.3.3.1 --- get a proxy on the big local flux matrix + fullMatrix<double> fuvwe(Fuvw[iUVW], iElement*nbFields,nbFields); + // ----- 2.3.3.1 --- compute \vec{f}^{UVW} =\vec{f}^{XYZ} J^{-1} and multiply bt detJ + for (int iXYZ=0;iXYZ<group.getDimXYZ();iXYZ++) { + for (int iPt =0; iPt< group.getNbIntegrationPoints(); iPt++) { + // get the right inv jacobian matrix dU/dX element + const double invJ = group.getInvJ (iElement, iPt, iXYZ, iUVW); + // get the detJ at this point + const double detJ = group.getDetJ (iElement, iPt); + const double factor = invJ * detJ; + // compute fluxes in the reference coordinate system at this integration point + for (int k=0;k<nbFields;k++) { + fuvwe(iPt,k) += ( fConv[iXYZ](iPt,k) + fDiff[iXYZ](iPt,k)) * factor; + } + } + } + } + } + if (claw.sourceTerm()){ + fullMatrix<double> source(Source, iElement*claw.nbFields(),claw.nbFields()); + (*claw.sourceTerm())(DGE,&source); + //we assume constant mass matrix and constant mapping for now + /*for (int iPt =0; iPt< group.getNbIntegrationPoints(); iPt++) { + const double detJ = group.getDetJ (iElement, iPt); + for (int k=0;k<nbFields;k++) + source(iPt,k) *= detJ; + }*/ } + delete gradSolutionQPe; } // ----- 3 ---- do the redistribution at nodes using as many BLAS3 operations as there are local coordinates - for (int iUVW=0;iUVW<group.getDimUVW();iUVW++) - group.getResidual().gemm(group.getFluxRedistributionMatrix(iUVW), Fuvw[iUVW]); + if(claw.convectiveFlux() || claw.diffusiveFlux()){ + for (int iUVW=0;iUVW<group.getDimUVW();iUVW++) + residual.gemm(group.getFluxRedistributionMatrix(iUVW),Fuvw[iUVW]); + } + if(claw.sourceTerm()){ + residual.gemm(group.getSourceRedistributionMatrix(),Source); + } } diff --git a/Solver/dgAlgorithm.h b/Solver/dgAlgorithm.h index dc487b640ec98f775f4e49e4efa164ae2c64a2be..745cd42e5b980d367524d4f7e7ce9710a85b4ff0 100644 --- a/Solver/dgAlgorithm.h +++ b/Solver/dgAlgorithm.h @@ -9,9 +9,11 @@ class dgConservationLaw; class dgAlgorithm { public : - void residualVolume ( /*dofManager &dof,*/ - const dgConservationLaw &law, - const dgGroupOfElements & group); + void residualVolume ( //dofManager &dof, // the DOF manager (maybe useless here) + const dgConservationLaw &claw, // the conservation law + const dgGroupOfElements & group, + const fullMatrix<double> &solution, + fullMatrix<double> &residual); void residualInterface ( /*dofManager &dof,*/ const dgConservationLaw &law, const dgGroupOfFaces & group); diff --git a/Solver/dgConservationLaw.h b/Solver/dgConservationLaw.h index 1625b34e25d3a4b6f9502c6f27c2569d37a47c38..05eb28348a0b8fe5ca81e921b3e58551dd08240c 100644 --- a/Solver/dgConservationLaw.h +++ b/Solver/dgConservationLaw.h @@ -6,7 +6,7 @@ + \nabla \cdot (\vec{g}(u,\nabla u,forcings) -> diffusive flux g + r(u,forcings) -> source term r */ - +#include "fullMatrix.h" class dgElement; class dgFace; @@ -23,6 +23,7 @@ class dgFaceTerm{ }; class dgConservationLaw { + protected : int _nbf; dgTerm *_diffusive, *_convective, *_source, *_maxConvectiveSpeed; dgFaceTerm *_riemannSolver; @@ -42,5 +43,6 @@ public: }; +dgConservationLaw *dgNewConservationLawAdvection(); #endif diff --git a/Solver/dgConservationLawAdvection.cpp b/Solver/dgConservationLawAdvection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c1d9eb7d4cd8151d12402f2f220b7ebc1fb1ec8 --- /dev/null +++ b/Solver/dgConservationLawAdvection.cpp @@ -0,0 +1,29 @@ +#include "dgConservationLaw.h" +#include "fullMatrix.h" +#include "dgGroupOfElements.h" +#include "SPoint3.h" +#include "MElement.h" +class testSourceTerm : public dgTerm { + void operator () (const dgElement &el, fullMatrix<double> fcx[]) const{ + const fullMatrix<double> &sol = el.solution(); + const fullMatrix<double> &qp = el.integration(); + SPoint3 p; + for(int i=0; i< sol.size1(); i++) { + el.element()->pnt(qp(i,0),qp(i,1),qp(i,2),p); + //printf("%e - %e (%i)\n",p.x(),sol(i,0),sol.size2()); + fcx[0](i,0) = (p.x()*p.x()+p.y()*p.y()) - sol(i,0); + } + } +}; + +class dgConservationLawAdvection : public dgConservationLaw { + public: + dgConservationLawAdvection() { + _nbf = 1; + _source = new testSourceTerm; + } +}; + +dgConservationLaw *dgNewConservationLawAdvection() { + return new dgConservationLawAdvection; +} diff --git a/Solver/dgGroupOfElements.cpp b/Solver/dgGroupOfElements.cpp index d9bcef14d86ded9208440c1ccdeca68a07a23553..e2f102bca491faf0c265524278a9c790ae389c84 100644 --- a/Solver/dgGroupOfElements.cpp +++ b/Solver/dgGroupOfElements.cpp @@ -44,7 +44,8 @@ static fullMatrix<double> * dgGetFaceIntegrationRuleOnElement ( dgGroupOfElements::dgGroupOfElements(const std::vector<MElement*> &e, int polyOrder) : _elements(e), _fs(*_elements[0]->getFunctionSpace(polyOrder)), - _integration(dgGetIntegrationRule (_elements[0], polyOrder)) + _integration(dgGetIntegrationRule (_elements[0], polyOrder) + ) { // this is the biggest piece of data ... the mappings _mapping = new fullMatrix<double> (_elements.size(), 10 * _integration->size1()); @@ -56,7 +57,7 @@ dgGroupOfElements::dgGroupOfElements(const std::vector<MElement*> &e, int polyOr e->getJacobian ((*_integration)(j,0), (*_integration)(j,1), (*_integration)(j,2), - ijac); + jac); detjac=inv3x3(jac,ijac); (*_mapping)(i,10*j + 0) = ijac[0][0]; (*_mapping)(i,10*j + 1) = ijac[0][1]; @@ -77,10 +78,10 @@ dgGroupOfElements::dgGroupOfElements(const std::vector<MElement*> &e, int polyOr _redistributionFluxes[1] = new fullMatrix<double> (_fs.coefficients.size1(),_integration->size1()); _redistributionFluxes[2] = new fullMatrix<double> (_fs.coefficients.size1(),_integration->size1()); _redistributionSource = new fullMatrix<double> (_fs.coefficients.size1(),_integration->size1()); - _collocation = new fullMatrix<double> (_fs.coefficients.size1(), _integration->size1()); + _collocation = new fullMatrix<double> (_integration->size1(),_fs.coefficients.size1()); + _imass = new fullMatrix<double> (_fs.coefficients.size1(),_fs.coefficients.size1()); double g[256][3],f[256]; - for (int j=0;j<_integration->size1();j++) { _fs.df((*_integration)(j,0), (*_integration)(j,1), @@ -90,13 +91,17 @@ dgGroupOfElements::dgGroupOfElements(const std::vector<MElement*> &e, int polyOr (*_integration)(j,2), f); const double weight = (*_integration)(j,3); for (int k=0;k<_fs.coefficients.size1();k++){ - (*_redistributionFluxes[0])(k,j) = g[j][0] * weight; - (*_redistributionFluxes[1])(k,j) = g[j][1] * weight; - (*_redistributionFluxes[2])(k,j) = g[j][2] * weight; - (*_redistributionSource)(k,j) = f[j] * weight; - (*_collocation)(k,j) = f[k]; + (*_redistributionFluxes[0])(k,j) = g[k][0] * weight; + (*_redistributionFluxes[1])(k,j) = g[k][1] * weight; + (*_redistributionFluxes[2])(k,j) = g[k][2] * weight; + (*_redistributionSource)(k,j) = f[k] * weight; + (*_collocation)(j,k) = f[k]; + for (int l=0;l<_fs.coefficients.size1();l++) { + (*_imass)(k,l) += f[k]*f[l]*weight; + } } } + _imass->invertInPlace(); } dgGroupOfElements::~dgGroupOfElements(){ @@ -107,6 +112,7 @@ dgGroupOfElements::~dgGroupOfElements(){ delete _redistributionSource; delete _mapping; delete _collocation; + delete _imass; } // dgGroupOfFaces diff --git a/Solver/dgGroupOfElements.h b/Solver/dgGroupOfElements.h index c8042a0862059f678d22450a6aaf04ae5024ab9c..61fc87e429054d8fbbffa542792e37f464c7a78a 100644 --- a/Solver/dgGroupOfElements.h +++ b/Solver/dgGroupOfElements.h @@ -19,18 +19,23 @@ class MEdge; class functionSpace; class dgElement { - const MElement *_element; + MElement *_element; // solution at points const fullMatrix<double> &_solution, &_integration, &_gradients; public: - dgElement (const MElement *e, const fullMatrix<double> &sol, const fullMatrix<double> &integ) + dgElement (MElement *e, const fullMatrix<double> &sol, const fullMatrix<double> &integ) : _element(e), _solution(sol), _integration(integ), _gradients(sol) {} - dgElement (const MElement *e, const fullMatrix<double> &sol, const fullMatrix<double> &grads, const fullMatrix<double> &integ) + dgElement (MElement *e, const fullMatrix<double> &sol, const fullMatrix<double> &grads, const fullMatrix<double> &integ) : _element(e), _solution(sol), _integration(integ), _gradients(grads) {} + const fullMatrix<double> &solution() const { return _solution; } + const fullMatrix<double> &integration() const { return _integration; } + MElement *element() const { return _element;} }; + +// store topological and geometrical data for 1 group for 1 discretisation class dgGroupOfElements { // N elements in the group std::vector<MElement*> _elements; @@ -50,15 +55,10 @@ class dgGroupOfElements { fullMatrix<double> *_redistributionFluxes[3]; // redistribution for the source term fullMatrix<double> *_redistributionSource; - // the "finite element" gradient of the solution for this group (not owned) - fullMatrix<double> *_gradSolution; - // the solution for this group (not owned) - fullMatrix<double> *_solution; - // the residual for this group (not owned) - fullMatrix<double> *_residual; + fullMatrix<double> *_imass; // dimension of the parametric space and of the real space // may be different if the domain is a surface in 3D (manifold) - int _dimUVW, _dimXYZ, _nbFields; + int _dimUVW, _dimXYZ; // forbid the copy // dgGroupOfElements (const dgGroupOfElements &e, int order) {} // dgGroupOfElements & operator = (const dgGroupOfElements &e) {} @@ -66,23 +66,16 @@ public: dgGroupOfElements (const std::vector<MElement*> &e, int pOrder); virtual ~dgGroupOfElements (); inline int getNbElements() const {return _elements.size();} - inline int getNbFields() const {return _nbFields;} - inline int getNbNodes() const {return _collocation->size1();} - inline int getNbIntegrationPoints() const {return _collocation->size2();} + inline int getNbNodes() const {return _collocation->size2();} + inline int getNbIntegrationPoints() const {return _collocation->size1();} inline int getDimUVW () const {return _dimUVW;} inline int getDimXYZ () const {return _dimXYZ;} - inline const MElement* getElement (int iElement) const {return _elements[iElement];} + inline MElement* getElement (int iElement) const {return _elements[iElement];} inline const fullMatrix<double> & getIntegrationPointsMatrix () const {return *_integration;} inline const fullMatrix<double> & getCollocationMatrix () const {return *_collocation;} inline const fullMatrix<double> & getFluxRedistributionMatrix (int i) const {return *_redistributionFluxes[i];} inline const fullMatrix<double> & getSourceRedistributionMatrix () const {return *_redistributionSource;} - inline fullMatrix<double> & getSolution () const {return *_solution;} - inline fullMatrix<double> & getGradientOfSolution () const {return *_gradSolution;} - // get a proxy on the solution for element iElement - inline fullMatrix<double> getSolution (int iElement) const {return fullMatrix<double>(*_solution, iElement*_nbFields, _nbFields);} - inline fullMatrix<double> & getResidual () const {return *_solution;} - // get a proxy on the residual for element iElement - inline fullMatrix<double> getResidual (int iElement) const {return fullMatrix<double>(*_residual, iElement*_nbFields, _nbFields);} + inline const fullMatrix<double> & getInverseMassMatrix () const {return *_imass;} inline double getDetJ (int iElement, int iGaussPoint) const {return (*_mapping)(iElement, 10*iGaussPoint + 9);} inline double getInvJ (int iElement, int iGaussPoint, int i, int j) const {return (*_mapping)(iElement, 10*iGaussPoint + i + 3*j);} inline fullMatrix<double> getMapping (int iElement) const {return fullMatrix<double>(*_mapping, iElement, 1);} @@ -141,4 +134,5 @@ public: }; + #endif diff --git a/Solver/dgMainTest.cc b/Solver/dgMainTest.cc new file mode 100644 index 0000000000000000000000000000000000000000..f93e71a079742bba2304ae82afccf7368357f22b --- /dev/null +++ b/Solver/dgMainTest.cc @@ -0,0 +1,61 @@ +#include <stdio.h> +#include <vector> +#include "GModel.h" +#include "dgGroupOfElements.h" +#include "dgAlgorithm.h" +#include "dgConservationLaw.h" +#include "Gmsh.h" + + +#include "MElement.h" +void print (const char *filename, std::vector<MElement *> &els, double *v); +std::vector<MElement *> get_all_tri(GModel *model); + + +int main(int argc, char **argv){ + GmshMergeFile("input/mesh1.msh"); + std::vector<MElement *> all_tri=get_all_tri(GModel::current()); + dgGroupOfElements group(all_tri,1); + fullMatrix<double> sol(3,all_tri.size()); + fullMatrix<double> residu(3,all_tri.size()); + dgAlgorithm algo; + dgConservationLaw *law = dgNewConservationLawAdvection(); + algo.residualVolume(*law,group,sol,residu); + sol.gemm(group.getInverseMassMatrix(),residu); + print("test.pos",all_tri,&sol(0,0)); +} + + + +std::vector<MElement *> get_all_tri(GModel *model){ + std::vector<GEntity*> entities; + model->getEntities(entities); + std::vector<MElement *> all_tri; + for(std::vector<GEntity *>::iterator itent=entities.begin(); itent!=entities.end(); itent++){ + if ((*itent)->dim()!=2) continue; + for (int iel=0; iel<(*itent)->getNumMeshElements(); iel++) + all_tri.push_back((*itent)->getMeshElement(iel)); + } + return all_tri; +} + +void print (const char *filename, std::vector<MElement *> &els, double *v) { + FILE *file = fopen(filename,"w"); + fprintf(file,"View \"%s\" {\n", filename); + int i=0; + for(std::vector<MElement *>::iterator itel= els.begin();itel!=els.end();itel++){ + MElement *el = *itel; + fprintf(file,"ST ("); + for (int iv=0; iv<el->getNumVertices(); iv++) { + MVertex *vertex = el->getVertex(iv); + SPoint3 coord = vertex->point(); + fprintf(file,"%e, %e, %e%c ",coord.x(),coord.y(),coord.z(),iv==el->getNumVertices()-1?')':','); + } + fprintf(file,"{"); + for (int iv=0; iv<el->getNumVertices(); iv++) + fprintf(file,"%e%c ",v[i++],iv==el->getNumVertices()-1?'}':','); + fprintf(file,";\n"); + } + fprintf(file,"};"); + fclose(file); +}