[Pkg-scicomp-commits] [SCM] MAdLib, a mesh adaptation library. branch, master, updated. debian/1.2.2-1-10-ga07b5fe
Christophe Prud'homme
prudhomm at debian.org
Sun Oct 11 13:45:27 UTC 2009
The following commit has been merged in the master branch:
commit 7c8a3d4a195c7663c1c0247d37fdb7033fa40d4b
Author: Christophe Prud'homme <prudhomm at debian.org>
Date: Sun Oct 11 12:14:30 2009 +0200
Imported Upstream version 1.2.3
diff --git a/Adapt/AdaptInterface.cc b/Adapt/AdaptInterface.cc
new file mode 100644
index 0000000..0bf46d5
--- /dev/null
+++ b/Adapt/AdaptInterface.cc
@@ -0,0 +1,1512 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "AdaptInterface.h"
+#include "MAdResourceManager.h"
+#include "MAdTimeManager.h"
+#include "NodalDataManager.h"
+#include "MAdStatistics.h"
+#include "ModelConstraintManager.h"
+#include "MAdMessage.h"
+#include "History.h"
+
+// standard C/C++
+#include <iostream>
+#include <stdlib.h>
+#include <fstream>
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "MeshDataBaseParallelInterface.h"
+#endif
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::set;
+using std::vector;
+using std::multiset;
+using std::string;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void MeshAdapterAbortFct(void * data) {
+ ((MeshAdapter *) data) -> abort();
+ }
+
+ // -------------------------------------------------------------------
+ MeshAdapter::MeshAdapter(pMesh m, pSField sf):
+ mesh(m),
+ eSplitOp(0), eCollapseOp(0), fCollapseOp(0), descOp(0),
+ eSwapOp(0), fSwapOp(0), vMoveOp(0), rRegionOp(0), sliverFOp(0),
+ sliverROp(0), geoTracker(0),
+ mpm(MeshParametersManagerSgl::instance()),
+ verbosity(2), updateSFFrequency(0), outPrefix(""), debugLevel(0)
+ {
+ SFManager = new SizeFieldManager(mesh,sf);
+
+ MAdMsgSgl ::instance().registerAbortFct(MeshAdapterAbortFct,this);
+ MAdTimeManagerSgl ::instance().initialize();
+ MAdStatisticsSgl ::instance().initialize();
+ CallBackManagerSgl ::instance().initialize();
+ NodalDataManagerSgl ::instance().initialize(mesh);
+ MeshQualityManagerSgl::instance().initialize(mesh,SFManager->getSizeField(),MEANRATIO);
+ HistorySgl ::instance().initialize();
+ HistorySgl ::instance().closeJournal();
+ ModelConstraintManagerSgl::instance().initialize(M_model(mesh));
+ MeshParametersManagerSgl::instance().initialize();
+
+ if (mesh) buildOperators();
+
+ setDefaultValues();
+
+ if ( debugLevel >= 1 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+ }
+
+ // -------------------------------------------------------------------
+ MeshAdapter::~MeshAdapter()
+ {
+ removeOperators();
+ if (geoTracker) delete geoTracker;
+ if (SFManager) delete SFManager;
+
+ MAdTimeManagerSgl ::instance().finalize();
+ MAdStatisticsSgl ::instance().finalize();
+ CallBackManagerSgl ::instance().finalize();
+ NodalDataManagerSgl ::instance().finalize();
+ MeshQualityManagerSgl::instance().finalize();
+ HistorySgl ::instance().finalize();
+ ModelConstraintManagerSgl::instance().finalize();
+ MeshParametersManagerSgl::instance().finalize();
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setDefaultValues()
+ {
+ algorithm = CPS_SWP_SLV_SPT;
+ maxIterationsNumber = 10;
+
+ setEdgeLenSqBounds ( 1./3. , 3. );
+
+ if ( M_dim(mesh) == 2 ) {
+ setNoSwapQuality ( 0.2 );
+ }
+ else { // to be checked
+ setNoSwapQuality ( 0.1 );
+ }
+ mpm.setSwapMinImproveRatio ( 1.0 );
+
+ mpm.setSliverTriBound ( 0.01 );
+ mpm.setSliverTetBound ( 0.02 );
+
+ // infinite loops control
+ setSliverPermissionInESplit ( true, 10. );
+ setSliverPermissionInECollapse ( true, 0.1 );
+
+ setCollapseOnBoundary ( true, 1.e-6 );
+ setSwapOnBoundary ( true, 1.e-6 );
+
+#ifdef PARALLEL
+ load_balance_algorithm = DEFAULT_ALGORITHM;
+ dataExchanger = NULL;
+#endif
+
+ updateSFFrequency = 0;
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::printParameters() const
+ {
+ mpm.diagnostics();
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setEdgeLenSqBounds(double lower, double upper)
+ {
+ if ( sqrt(lower) > 0.5*sqrt(upper) ) {
+ cout << "Warning: edge length interval is too small ("
+ << sqrt(lower) << ", " << sqrt(upper) <<")\n";
+ }
+
+ mpm.setLowerLengthSqBound(lower);
+ mpm.setUpperLengthSqBound(upper);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setCollapseOnBoundary(bool accept, double tolerance)
+ {
+ eCollapseOp->collapseOnBoundary(accept,tolerance);
+ fCollapseOp->collapseOnBoundary(accept,tolerance);
+ sliverROp ->collapseOnBoundary(accept,tolerance);
+ sliverFOp ->collapseOnBoundary(accept,tolerance);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setSwapOnBoundary(bool accept, double tolerance)
+ {
+ eSwapOp ->swapOnBoundary(accept,tolerance);
+ sliverROp->swapOnBoundary(accept,tolerance);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setMaxIterationsNumber(int max)
+ {
+ maxIterationsNumber = max;
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setNoSwapQuality(double noSwapQuality)
+ {
+ mpm.setNoSwapQuality(noSwapQuality);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setSwapMinImproveRatio(double ratio)
+ {
+ mpm.setSwapMinImproveRatio(ratio);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setSliverQuality(double sliverQuality)
+ {
+ mpm.setSliverTriBound(sliverQuality);
+ mpm.setSliverTetBound(sliverQuality);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setSliverPermissionInESplit(bool perm, double bound)
+ {
+ mpm.setSliverPermissionInESplit(perm, bound);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setSliverPermissionInECollapse(bool perm, double bound)
+ {
+ mpm.setSliverPermissionInECollapse(perm, bound);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setGeoTracking(bool track, bool cavityEqualMesh,
+ int cavityThickness, double chi)
+ {
+ if ( track && !geoTracker) {
+ geoTracker = new geoMatcher(mesh);
+ geoTracker->setCavityEqualMesh(cavityEqualMesh,cavityThickness);
+ geoTracker->setStiffnessAlterationCoef(chi);
+ }
+ else if ( !track && geoTracker) {
+ delete geoTracker;
+ geoTracker = NULL;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setInfiniteLength(double length)
+ {
+ mpm.setBigLength(length);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setSFUpdateFrequency(int freq)
+ {
+ updateSFFrequency = freq;
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setVerbosity(int _verbosity)
+ {
+ verbosity = _verbosity;
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::clearConstraints() const
+ {
+ DeleteConstraint(mesh);
+ ModelConstraintManagerSgl::instance().clear();
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setConstraint(pEntity e) const
+ {
+ EN_constrain(e);
+
+ switch (EN_type(e)) {
+ case 1:
+ EN_constrain( (pEntity)E_vertex((pEdge)e,0) );
+ EN_constrain( (pEntity)E_vertex((pEdge)e,1) );
+ break;
+ case 2:
+ setConstraint( (pEntity)F_edge((pFace)e,0) );
+ setConstraint( (pEntity)F_edge((pFace)e,1) );
+ setConstraint( (pEntity)F_edge((pFace)e,2) );
+ break;
+ case 3:
+ setConstraint( (pEntity)R_face((pRegion)e,0) );
+ setConstraint( (pEntity)R_face((pRegion)e,1) );
+ setConstraint( (pEntity)R_face((pRegion)e,2) );
+ setConstraint( (pEntity)R_face((pRegion)e,3) );
+ break;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setConstraint(int type, int id) const
+ {
+ ModelConstraintManagerSgl::instance().constrain(type,id);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::removeConstraint(int type, int id) const
+ {
+ ModelConstraintManagerSgl::instance().unconstrain(type,id);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setConstraint(pGEntity e) const
+ {
+ ModelConstraintManagerSgl::instance().constrain(e);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::removeConstraint(pGEntity e) const
+ {
+ ModelConstraintManagerSgl::instance().unconstrain(e);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::removeOperators()
+ {
+ if (eSplitOp) { delete eSplitOp; eSplitOp=0; }
+ if (eCollapseOp) { delete eCollapseOp; eCollapseOp=0; }
+ if (fCollapseOp) { delete fCollapseOp; fCollapseOp=0; }
+ if (descOp) { delete descOp; descOp=0; }
+ if (eSwapOp) { delete eSwapOp; eSwapOp=0; }
+ if (fSwapOp) { delete fSwapOp; fSwapOp=0; }
+ if (vMoveOp) { delete vMoveOp; vMoveOp=0; }
+ if (rRegionOp) { delete rRegionOp; rRegionOp=0; }
+ if (sliverFOp) { delete sliverFOp; sliverFOp=0; }
+ if (sliverROp) { delete sliverROp; sliverROp=0; }
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::buildOperators()
+ {
+ removeOperators();
+
+ eSplitOp = new edgeSplitOp (mesh,SFManager->getSizeField());
+ eCollapseOp = new edgeCollapseOp (mesh,SFManager->getSizeField());
+ fCollapseOp = new faceCollapseOp (mesh,SFManager->getSizeField());
+ descOp = new DESCOp (mesh,SFManager->getSizeField());
+ eSwapOp = new edgeSwapOp (mesh,SFManager->getSizeField());
+ fSwapOp = new faceSwapOp (mesh,SFManager->getSizeField());
+ vMoveOp = new vertexMoveOp (mesh,SFManager->getSizeField(),false);
+ rRegionOp = new regionRemoveOp (mesh,SFManager->getSizeField());
+ sliverROp = new sliverRegionHandler (mesh,SFManager->getSizeField());
+ sliverFOp = new sliverFaceHandler (mesh,SFManager->getSizeField());
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::addCallback(CBFunction CB, void* userData,
+ CBFunc_move CB_move, void* userData_move)
+ {
+ CallBackManagerSgl::instance().registerCallBack(CB,userData);
+ if (CB_move) {
+ CallBackManagerSgl::instance().registerCallBackMove(CB_move,userData_move);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::addSizeField(pSField sf)
+ {
+ SFManager->addSizeField(sf);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setSizeFieldSmoothing(bool enable, double maxGrad)
+ {
+ SFManager->setSmoothing(enable,maxGrad);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::incrementTime(double dt)
+ {
+ MAdTimeManagerSgl::instance().incrementTime(dt);
+ updateSizeField();
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setTime(double t)
+ {
+ MAdTimeManagerSgl::instance().setTime(t);
+ updateSizeField();
+ }
+
+ // -------------------------------------------------------------------
+ double MeshAdapter::getTime() const {
+ return MAdTimeManagerSgl::instance().getTime();
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::updateSizeField()
+ {
+ SFManager->update();
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::storeInitialCoordinates()
+ {
+ if ( getTime() != 0. ) {
+ cout << "Warning: storing coordinates at time " << getTime() << endl;
+ }
+ NodalDataManagerSgl::instance().storeCoordinates();
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::removeStoredCoordinates()
+ {
+ NodalDataManagerSgl::instance().removeCoordinates();
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::registerObjects(mobileObjectSet* objs)
+ {
+ set<mobileObject*> allObj = objs->getObjects();
+
+ set<mobileObject*>::const_iterator it = allObj.begin();
+ for (; it != allObj.end(); it++) {
+ set<LocalSizeField* > sizes = (*it)->getSizes();
+ set<LocalSizeField* >::iterator it = sizes.begin();
+ for (; it != sizes.end(); it++) {
+ SFManager->addSizeField(*it);
+ }
+ }
+
+ objects = objs;
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::registerData (string name,
+ const vector<double> data) const
+ {
+ NodalDataManagerSgl::instance().registerData(name,data);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::registerVData (string name,
+ const vector<vector<double> > data) const
+ {
+ NodalDataManagerSgl::instance().registerVData(name,data);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::getMeshData (string name,
+ vector<double> * data) const
+ {
+ NodalDataManagerSgl::instance().getMeshData(name,data);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::getMeshVData (string name,
+ vector<vector<double> > * data) const
+ {
+ NodalDataManagerSgl::instance().getMeshVData(name,data);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::removeData (string name) const
+ {
+ NodalDataManagerSgl::instance().removeData(name);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::removeVData (string name) const
+ {
+ NodalDataManagerSgl::instance().removeVData(name);
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // LEVEL 1 OPERATIONS
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ bool MeshAdapter::splitEdge(pEdge edge, bool checkSize)
+ {
+ // set edge to split
+ double reducSq = eSplitOp->setSplitEdge(edge);
+
+ // check that the edge is not splitted in short edges
+ if ( checkSize )
+ {
+ double lenSq = SFManager->getSizeField()->SF_E_lengthSq(edge);
+ if ( ( reducSq * lenSq ) <= mpm.getLowerLengthSqBound() ) return false;
+ }
+
+ // do the checks
+ double worstShape;
+ if ( !eSplitOp->evaluate(&worstShape) ) return false;
+
+ // check that we do not create a worse sliver ( if asked for )
+ // if we can create new slivers, check that the edge is long enough to allow it
+ if ( worstShape < mpm.getSliverTetBound() )
+ {
+ double oriWorst;
+ MeshQualityManagerSgl::instance().E_worstShape(edge, &oriWorst);
+ if ( worstShape < oriWorst ) {
+ if ( !mpm.getSliverPermissionInESplit() ) return false;
+ if ( mpm.getSliverUpperLengthSqBound() > 0. &&
+ mpm.getSliverUpperLengthSqBound() > SFManager->getSizeField()->SF_E_lengthSq(edge) )
+ {
+ return false;
+ }
+ }
+ }
+
+ // do the job
+ eSplitOp->apply();
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshAdapter::collapseEdge(pEdge edge)
+ {
+ double shapes[2] = {-1.,-1.};
+ int ok[2] = {0,0};
+
+ for (int iDir=0; iDir<2; iDir++) {
+
+ pVertex vDel = E_vertex(edge,iDir);
+ pVertex vTgt = E_vertex(edge,1-iDir);
+ eCollapseOp->setCollapseEdge(edge,vDel,vTgt);
+
+ // do the checks
+ ok[iDir] = eCollapseOp->evaluate(&(shapes[iDir]));
+
+ // check that we do not create a worse sliver ( if asked for )
+ // if we can create new slivers, check that the edge is short enough to allow it
+ if ( shapes[iDir] < mpm.getSliverTetBound() )
+ {
+ double oriWorst;
+ MeshQualityManagerSgl::instance().E_worstShape(edge, &oriWorst);
+ if ( shapes[iDir] < oriWorst ) {
+ if ( !mpm.getSliverPermissionInECollapse() ) ok[iDir] = 0;
+ if ( mpm.getSliverLowerLengthSqBound() > 0. &&
+ mpm.getSliverLowerLengthSqBound() < SFManager->getSizeField()->SF_E_lengthSq(edge) )
+ {
+ ok[iDir] = 0;
+ }
+ }
+ }
+ }
+
+ // find the best direction
+ int best = -1; double worst = -1.;
+ if ( ok[0] ) { best = 0; worst = shapes[0]; }
+ if ( ok[1] && shapes[1] > worst ) {
+ best = 1;
+ worst = shapes[1];
+ }
+
+ // if possible apply an edge collapse
+ if ( best >= 0 ) {
+ pVertex vDel = E_vertex(edge,best);
+ pVertex vTgt = E_vertex(edge,1-best);
+ eCollapseOp->setCollapseEdge(edge,vDel,vTgt);
+ eCollapseOp->apply();
+ return true;
+ }
+
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshAdapter::collapseFace(pFace face, pEdge edge)
+ {
+ for( int ClpsOnvt = 1; ClpsOnvt >=0; ClpsOnvt-- )
+ {
+ fCollapseOp->reset(face, edge, ClpsOnvt);
+
+ // do the checks
+ double worstShape;
+ if ( !fCollapseOp->evaluate(&worstShape) ) continue;
+
+ // check that we do not create a sliver
+ if ( worstShape < mpm.getSliverTetBound() ) continue;
+
+ // do the job
+ fCollapseOp->apply();
+ return true;
+ }
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshAdapter::DSplitCollapseEdge(pRegion pr, pEdge edge1, pEdge edge2)
+ {
+ descOp->setDESC(pr,edge1,edge2);
+
+ // do the checks
+ double worstShape;
+ if ( !descOp->evaluate(&worstShape) ) return false;
+
+ // check that we do not create a sliver
+ if ( worstShape < mpm.getSliverTetBound() ) return false;
+
+ // do the job
+ descOp->apply();
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshAdapter::swapEdge(pEdge edge)
+ {
+ eSwapOp->setSwapEdge(edge);
+
+ // do the checks
+ double worstShape;
+ if ( !eSwapOp->evaluate(&worstShape) ) return false;
+
+ // check that we do not create a sliver
+ if ( worstShape < mpm.getSliverTetBound() ) return false;
+
+ // do the job
+ eSwapOp->apply();
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshAdapter::swapFace(pFace face)
+ {
+ fSwapOp->setSwapFace(face);
+
+ // do the checks
+ double worstShape;
+ if ( !fSwapOp->evaluate(&worstShape) ) return false;
+
+ // check that we do not create a sliver
+ if ( worstShape < mpm.getSliverTetBound() ) return false;
+
+ // do the job
+ fSwapOp->apply();
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshAdapter::moveVertex (pVertex v, double dxyz[3])
+ {
+ return vMoveOp->move(v,dxyz);
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshAdapter::removeRegion(pRegion region)
+ {
+ rRegionOp->setRegion(region);
+
+ // do the checks
+ double worstShape;
+ if ( !rRegionOp->evaluate(&worstShape) ) return false;
+
+ // check that we do not create a sliver
+ if ( worstShape < mpm.getSliverTetBound() ) return false;
+
+ // do the job
+ rRegionOp->apply();
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshAdapter::putVertex (pVertex v, double xyz[3])
+ {
+ double oriPos[3], dxyz[3];
+ V_coord(v,oriPos);
+ for (int i=0; i<3; i++) dxyz[i] = xyz[i] - oriPos[i];
+ return moveVertex(v,dxyz);
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshAdapter::moveVertices (multiset<vDisplacement,vDisplacementLess>& vDisps)
+ {
+ return vMoveOp->move(vDisps);
+ }
+
+ // -------------------------------------------------------------------
+ // LEVEL 2 OPERATIONS
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double MeshAdapter::LaplaceSmoothing(LaplSmooType type)
+ {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+ MAdStatistics& stat = MAdStatisticsSgl ::instance();
+
+ double t0 = tm.getTime();
+
+ double convergenceCriterion = 1e-2;
+ double L2Disp = 0.;
+ LaplaceSmoothingOp* laplOp = new LaplaceSmoothingOp(mesh,SFManager->getSizeField());
+ laplOp->run(type,&L2Disp);
+ double L2Disp0 = L2Disp; int i = 0;
+ double L2DispTot = 0.;
+ while ( ( L2Disp > convergenceCriterion * L2Disp0 ) && ( L2Disp > MAdTOL ) ) {
+ laplOp->run(type,&L2Disp);
+ i++;
+ L2DispTot += L2Disp;
+ }
+ if (laplOp) delete laplOp;
+
+ double dt = tm.getTime() - t0;
+ if ( verbosity >= 2 ) {
+ cout << "Performed a Laplace smoothing: total L2 norm of the displacements: "<<L2DispTot<<" in "<<dt<<" seconds\n";
+ }
+
+ if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+ return L2DispTot;
+ }
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::eSplitLoop()
+ {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+ MAdStatistics& stat = MAdStatisticsSgl ::instance();
+
+ double t0 = tm.getTime();
+
+ int nSplit = 0;
+ int countE = 0; int oriNbEdges = M_numEdges(mesh);
+ EIter ei = M_edgeIter(mesh);
+ pEdge edge;
+ while ( (countE < oriNbEdges) && ( edge = EIter_next(ei) ) ) {
+ double lengthSq = SFManager->getSizeField()->SF_E_lengthSq(edge);
+ if ( lengthSq > mpm.getUpperLengthSqBound() ) if (splitEdge(edge,true)) nSplit++;
+ countE++;
+ }
+ EIter_delete(ei);
+
+ double dt = tm.getTime() - t0;
+ stat.addCPUESplits(dt);
+ stat.addNumESplits(nSplit);
+ if ( verbosity >= 2 ) {
+ cout << "Performed "<< nSplit<<" edge splits in "<<dt<<" seconds\n";
+ }
+
+ if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+ // --- Geometry tracking ---
+ if (nSplit) snapVertices();
+
+ return nSplit;
+ }
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::eCollapseLoop()
+ {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+ MAdStatistics& stat = MAdStatisticsSgl ::instance();
+
+ double t0 = tm.getTime();
+
+ int nCollapse = 0;
+ int countE = 0; int oriNbEdges = M_numEdges(mesh);
+ EIter ei = M_edgeIter(mesh);
+ pEdge edge;
+ while ( (countE < oriNbEdges) && ( edge = EIter_next(ei) ) ) {
+ double lengthSq = SFManager->getSizeField()->SF_E_lengthSq(edge);
+ if ( lengthSq < mpm.getLowerLengthSqBound() ) if (collapseEdge(edge)) nCollapse++;
+ countE++;
+ }
+ EIter_delete(ei);
+
+ double dt = tm.getTime() - t0;
+ stat.addCPUECollapses(dt);
+ stat.addNumECollapses(nCollapse);
+ if ( verbosity >= 2 ) {
+ cout << "Performed "<< nCollapse<<" edge collapses in "<<dt<<" seconds\n";
+ }
+
+ if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+ return nCollapse;
+ }
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::eSplitCollapseLoop()
+ {
+ int nSplit = 0;
+ int nCollapse = 0;
+ int countE = 0; int oriNbEdges = M_numEdges(mesh);
+ EIter ei = M_edgeIter(mesh);
+ pEdge edge;
+ while ( (countE < oriNbEdges) && ( edge = EIter_next(ei) ) ) {
+ double lengthSq = SFManager->getSizeField()->SF_E_lengthSq(edge);
+ if ( lengthSq > mpm.getUpperLengthSqBound() ) if (splitEdge(edge,true)) nSplit++;
+ if ( lengthSq < mpm.getLowerLengthSqBound() ) if (collapseEdge(edge)) nCollapse++;
+ countE++;
+ }
+ EIter_delete(ei);
+
+ if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+ return nSplit+nCollapse;
+ }
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::edgeSwapLoop()
+ {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+ MAdStatistics& stat = MAdStatisticsSgl ::instance();
+
+ double t0 = tm.getTime();
+
+ int nb_eswap = 0;
+ pEdge edge;
+ EIter ei = M_edgeIter(mesh);
+ int ne = M_numEdges(mesh);
+ int i = 0;
+ while( ( edge = EIter_next(ei) ) )
+ {
+ if( i > ne ) break;
+ i++;
+
+ if( EN_constrained((pEntity)edge) ) continue;
+ if( E_numRegions(edge) > eSwapOp->getMaxNumRgns() ) continue;
+
+ double worstShape;
+ MeshQualityManagerSgl::instance().E_worstShape(edge, &worstShape);
+
+ if( worstShape > mpm.getNoSwapQuality() ) continue;
+
+ eSwapOp->setSwapEdge(edge);
+
+ double newWorstShape;
+ if( eSwapOp->evaluate(&newWorstShape) )
+ {
+ if( newWorstShape > mpm.getSwapMinImproveRatio()*worstShape )
+ {
+ if( ( eSwapOp->getMaxLenSq() < mpm.getUpperLengthSqBound() ) &&
+ ( eSwapOp->getMinLenSq() > mpm.getLowerLengthSqBound() ) )
+ {
+ eSwapOp->apply();
+ nb_eswap++;
+ }
+ }
+ }
+ }
+ EIter_delete(ei);
+
+ double dt = tm.getTime() - t0;
+ stat.addCPUESwaps(dt);
+ stat.addNumESwaps(nb_eswap);
+ if ( verbosity >= 2 ) {
+ cout << "Performed "<< nb_eswap<<" edge swaps in "<<dt<<" seconds\n";
+ }
+
+ if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+ return nb_eswap;
+ }
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::faceSwapLoop()
+ {
+ int nfswap = 0;
+ pFace face;
+ FIter fi = M_faceIter(mesh);
+ int nf = M_numFaces(mesh);
+ int i = 0;
+ while ( ( face = FIter_next(fi) ) ) {
+ if( i > nf ) break;
+ i++;
+
+ if( EN_constrained((pEntity)face) ) continue;
+
+ double oriWorst;
+ MeshQualityManagerSgl::instance().F_worstShape(face, &oriWorst);
+
+ if ( oriWorst > mpm.getNoSwapQuality() ) continue;
+
+ fSwapOp->setSwapFace(face);
+ double newWorst;
+ if( fSwapOp->evaluate(&newWorst) ) {
+ if ( newWorst > mpm.getSwapMinImproveRatio()*oriWorst ) {
+ fSwapOp->apply();
+ nfswap++;
+ }
+ }
+ }
+ FIter_delete(fi);
+
+ if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+ return nfswap;
+ }
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::splitEveryEdgeOnce()
+ {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+ double t0 = tm.getTime();
+
+ // list initial edges
+ std::set<pEdge> initEdges;
+ EIter ei = M_edgeIter(mesh);
+ pEdge edge;
+ while ( ( edge = EIter_next(ei) ) ) initEdges.insert(edge);
+ EIter_delete(ei);
+
+ // split every edge
+ int numOp = 0;
+ std::set<pEdge>::const_iterator it = initEdges.begin();
+ for (; it != initEdges.end(); it++ ) {
+ if ( splitEdge( *it ) ) numOp++;
+ }
+
+ double dt = tm.getTime() - t0;
+ if ( verbosity >= 2 ) {
+ cout << "Performed "<< numOp<<" edge splits in "<<dt<<" seconds\n";
+ }
+
+ if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+ // --- Geometry tracking ---
+ if (numOp) snapVertices();
+
+ return numOp;
+ }
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::removeSlivers()
+ {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+ MAdStatistics& stat = MAdStatisticsSgl ::instance();
+
+ double t0 = tm.getTime();
+
+ int nbBefore, nbAfter;
+ if (M_dim(mesh) == 3) sliverROp->removeSliverRegions(&nbBefore,&nbAfter);
+ else sliverFOp->removeSliverFaces (&nbBefore,&nbAfter);
+
+ double dt = tm.getTime() - t0;
+ stat.addCPURSlivers(dt);
+ if ( verbosity >= 2 ) {
+ cout << "Removed slivers " << nbBefore << " -> " << nbAfter << " in "<<dt<<" seconds\n";
+ }
+
+ if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+ return ( nbBefore - nbAfter );
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::snapVertices()
+ {
+ if (geoTracker) {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+ double t0 = tm.getTime();
+
+ // --- prepare the node motion ---
+ geoTracker->buildCavity();
+ geoTracker->setDirichletBC();
+ geoTracker->compute();
+
+// #warning "debug"
+// geoTracker->forceRelocation();
+
+ // --- perform the node motion ---
+ double ratio = 0.;
+ int achieved = -1;
+ while ( achieved != 2 )
+ {
+ achieved = geoTracker->advance(&ratio,1.e-12);
+
+ if ( achieved == 0 ) {
+ MAdMsgSgl::instance().warning(-1,__FILE__,
+ "Could not advance snapping, achieved: %d, ratio: %f",achieved,ratio);
+ }
+ else {
+ MAdMsgSgl::instance().info(-1,__FILE__,
+ "Advance snapping, achieved: %d, ratio: %f",achieved,ratio);
+ }
+ if ( debugLevel >= 4 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+ if ( achieved <= 1 ) {
+ // Apply the operations that do not add vertices or manage their
+ // target locations (complicated!)
+ bool slivR, slivF;
+ if ( sliverROp ) slivR = sliverROp->getNewVertexPermission();
+ if ( sliverFOp ) slivF = sliverFOp->getNewVertexPermission();
+ if ( sliverROp ) sliverROp->newVertexPermission(false);
+ if ( sliverFOp ) sliverFOp->newVertexPermission(false);
+ if ( !removeSlivers() ) {
+ if ( !optimiseElementShape() ) {
+ string filename = outPrefix + "dirichlet.txt";
+ std::ofstream dirichletOut(filename.c_str());
+ geoTracker->printDirichlet(dirichletOut);
+ dirichletOut.close();
+ filename = outPrefix + "relocations.txt";
+ std::ofstream relocationsOut(filename.c_str());
+ geoTracker->printRelocations(relocationsOut);
+ relocationsOut.close();
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Could not snap vertices, ratio reached: %f",ratio);
+ geoTracker->reportFailure(ratio);
+ break;
+ }
+ }
+ if ( sliverROp ) sliverROp->newVertexPermission( slivR );
+ if ( sliverFOp ) sliverFOp->newVertexPermission( slivF );
+ if ( debugLevel >= 4 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+ }
+ }
+
+ geoTracker->clear();
+
+ double dt = tm.getTime() - t0;
+ MAdMsgSgl::instance().info(__LINE__,__FILE__,
+ "Performed vertex snapping in %f seconds",dt);
+ }
+
+ if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+ }
+
+ // -------------------------------------------------------------------
+ // LEVEL 3 OPERATIONS
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::optimiseEdgeLength()
+ {
+ int nbMaxItOptiLen = 10;
+ int nSplColl = 0;
+ for (int iter=0; iter < nbMaxItOptiLen; iter++ ) {
+ int nSC = eSplitCollapseLoop();
+ cout << "Applied "<<nSC<<" split or collapses\n";
+ if (!nSC) break;
+ nSplColl += nSC;
+ }
+ return nSplColl;
+ }
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::optimiseElementShape()
+ {
+ int nbMaxItOptiShp = 10;
+ int nESwapTot = 0, nFSwapTot = 0;
+ int nESwap = 0, nFSwap = 0;
+ for (int iter=0; iter < nbMaxItOptiShp; iter++ ) {
+ // find ill-shaped elements around each edge
+ nESwap = edgeSwapLoop();
+ cout << "Applied " << nESwap<< " edge swaps"<<endl;
+ if ( M_dim(mesh) == 3 ) {
+ // find ill-shaped elements around each face
+ nFSwap = faceSwapLoop();
+ cout << "Applied " << nFSwap<< " face swaps"<<endl;
+ }
+
+ if (nESwap+nFSwap == 0) break;
+ nESwapTot += nESwap;
+ nFSwapTot += nFSwap;
+ }
+ return ( nESwapTot + nFSwapTot );
+ }
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::splitLongestEdges()
+ {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+ MAdStatistics& stat = MAdStatisticsSgl ::instance();
+
+ double t0 = tm.getTime();
+
+ int nSplitTot = 0;
+ double boundSq = 2.*mpm.getUpperLengthSqBound();
+
+ while (1)
+ {
+ int nSplit = 0;
+
+ EIter ei = M_edgeIter(mesh);
+ pEdge edge;
+ double lengthSq;
+ while ( ( edge = EIter_next(ei) ) ) {
+ lengthSq = SFManager->getSizeField()->SF_E_lengthSq(edge);
+ if ( lengthSq > boundSq ) if (splitEdge(edge,true)) nSplit++;
+ }
+ EIter_delete(ei);
+
+ nSplitTot += nSplit;
+ if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+ if ( nSplit == 0 ) break;
+ }
+
+ double dt = tm.getTime() - t0;
+ stat.addCPUESplits(dt);
+ stat.addNumESplits(nSplitTot);
+ if ( verbosity >= 2 ) {
+ cout << "Performed "<< nSplitTot<<" (very long) edge splits in "<<dt<<" seconds\n";
+ }
+
+ // --- Geometry tracking ---
+ if (nSplitTot) snapVertices();
+
+ return nSplitTot;
+ }
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::runOneIter()
+ {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+
+ // --- constrain parallel interfaces ---
+#ifdef PARALLEL
+ {
+ double t0= tm.getTime();
+ UpdateParallelConstraint(mesh);
+ double dt = tm.getTime() - t0;
+ MAdMsgSgl::instance().info(__LINE__,__FILE__,
+ "Performed constraint of parallel interfaces in %f seconds",dt);
+ MPI_Barrier(MPI_COMM_WORLD);
+ }
+#endif
+
+ // --- perform local mesh modifications ---
+ int numTopoChg = 0;
+
+ // first, split very long edges (avoid infinite loops split/collapse)
+// numTopoChg += splitLongestEdges();
+
+ if ( algorithm == CPS_SWP_SLV_SPT )
+ {
+ numTopoChg += eCollapseLoop(); // Collapse short edges
+ numTopoChg += edgeSwapLoop(); // Swap edges to improve elements quality
+ numTopoChg += removeSlivers(); // Remove slivers
+ numTopoChg += eSplitLoop(); // Split long edges
+ }
+
+ if ( algorithm == SPT_SWP_SLV_CPS )
+ {
+ numTopoChg += eSplitLoop(); // Split long edges
+ numTopoChg += edgeSwapLoop(); // Swap edges to improve elements quality
+ numTopoChg += removeSlivers(); // Remove slivers
+ numTopoChg += eCollapseLoop(); // Collapse short edges
+ }
+
+ if ( algorithm == SLV_CPS_SWP_SPT )
+ {
+ numTopoChg += removeSlivers(); // Remove slivers
+ numTopoChg += eCollapseLoop(); // Collapse short edges
+ numTopoChg += edgeSwapLoop(); // Swap edges to improve elements quality
+ numTopoChg += eSplitLoop(); // Split long edges
+ }
+
+ // --- Reposition the vertices ---
+// LaplaceSmoothing(OPTIMAL);
+// LaplaceSmoothing(FAST);
+
+#ifdef PARALLEL
+ // --- move parallel interfaces ---
+ {
+ MPI_Barrier(MPI_COMM_WORLD);
+ double t0 = tm.getTime();
+ DeleteParallelConstraint(mesh);
+ double dt = tm.getTime() - t0;
+ if( verbosity >= 2 ) {
+ MAdMsgSgl::instance().info(__LINE__,__FILE__,
+ "Performed unconstraint of parallel interface in %f seconds",dt);
+ }
+
+ t0 = tm.getTime();
+ switch( load_balance_algorithm ) {
+ case DEFAULT_ALGORITHM:
+ Balance2( mesh, *dataExchanger );
+ break;
+ case METIS_ALGORITHM:
+#ifdef _HAVE_PARMETIS_
+ BalanceMetis2( mesh, *dataExchanger );
+#else
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Could not balance load: Parmetis not enabled");
+#endif
+ break;
+ default:
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Unknown load balancing algorithm: %d",
+ load_balance_algorithm);
+ }
+ dt = tm.getTime() - t0;
+ if( verbosity >= 2 ) {
+ MAdMsgSgl::instance().info(__LINE__,__FILE__,
+ "Performed load balancing in %f seconds",dt);
+ }
+ }
+#endif
+
+ // --- check the mesh (debug) ---
+ if ( debugLevel >= 2 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+ return numTopoChg;
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::uglyTheMesh(double avgQualThresh, int maxIt)
+ {
+ MeshQualityManagerSgl::instance().evaluateStatistics();
+ double meanQuality = MeshQualityManagerSgl::instance().getMeanShape();
+
+ int iter = 0;
+ while ( (meanQuality > avgQualThresh) && (iter < maxIt) ) {
+
+ int numOp = 0;
+ int oriNumFaces = M_numFaces(mesh);
+ int count = 0;
+ FIter fi = M_faceIter(mesh);
+ pFace pf;
+ while ( ( pf = FIter_next(fi) ) && ( count < oriNumFaces ) ) {
+ int flag = 0;
+ for (int j=0; j<3; j++) {
+ pEdge pe = F_edge(pf,j);
+ for( int ClpsOnvt = 0; ClpsOnvt < 2; ClpsOnvt++ ) {
+ fCollapseOp->reset(pf, pe, ClpsOnvt);
+ double worstShape;
+ if ( fCollapseOp->evaluate(&worstShape) ) {
+ fCollapseOp->apply();
+ flag = 1;
+ break;
+ }
+ }
+ if ( flag ) {
+ numOp++;
+ break;
+ }
+ }
+ count++;
+ }
+ FIter_delete(fi);
+ cout << "Num face collapses: "<<numOp<<endl;
+
+ meanQuality = MeshQualityManagerSgl::instance().getMeanShape();
+ iter++;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! Removes elements with negative volume and returns \ingroup adaptation
+ //! number of remaining negative volumes
+ int MeshAdapter::removeNegativeElements()
+ {
+ int nNeg = 0;
+ int nRem = 0;
+ RIter rIt= M_regionIter(mesh);
+ while ( pRegion region = RIter_next(rIt) ) {
+ if (R_volume(region) < 0.) {
+ nNeg++;
+ if ( removeRegion(region) ) nRem++;
+ }
+ }
+ RIter_delete(rIt);
+
+ cout << "Negative elements removal: "
+ << nNeg << " detected, "
+ << nRem << " removed\n";
+
+ return (nNeg - nRem);
+ }
+
+ // -------------------------------------------------------------------
+ // LEVEL 4 OPERATIONS
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::run()
+ {
+ // --- Adaptation procedure ---
+
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+ double t0= tm.getTime();
+
+ cout << "\n +++ Starting a MDB mesh adaptation procedure +++\n";
+ if ( verbosity >= 2 ) cout<<"\n";
+
+ for (int iter=1; iter <= maxIterationsNumber; iter++) {
+
+ if ( verbosity >= 1 ) {
+ cout<<" --- Mesh adaptation iteration "<<iter<<" ---\n"<<endl;
+ }
+ int num = runOneIter();
+
+#ifdef PARALLEL
+ int numGlob = 0;
+ MPI_Allreduce(&num,&numGlob,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
+#endif
+
+ if ( updateSFFrequency && (iter%updateSFFrequency) == 0 ) updateSizeField();
+
+ if ( verbosity >= 2 ) cout<<"\n";
+#ifdef PARALLEL
+ if ( numGlob == 0 ) break;
+#else
+ if ( num == 0 ) break;
+#endif
+
+ if ( iter == maxIterationsNumber && num != 0 )
+ {
+ MAdStatisticsSgl::instance().addInfiniteLoops(1);
+ if ( verbosity >= 1 ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Infinite loop detected");
+ }
+ break;
+ }
+ }
+
+ // --- Load balancing ---
+#ifdef PARALLEL
+ MPI_Barrier(MPI_COMM_WORLD);
+ if( load_balance_algorithm != METIS_ALGORITHM ) {
+#ifdef _HAVE_PARMETIS_
+ BalanceMetis2( mesh, *dataExchanger );
+#endif
+ }
+#endif
+
+ if ( debugLevel >= 1 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+ cout << "\n +++ Ending a MDB mesh adaptation procedure ("
+ << tm.getTime() - t0 << " seconds) +++\n";
+ if ( verbosity >= 2 ) cout<<"\n";
+ }
+
+#ifdef PARALLEL
+ // -------------------------------------------------------------------
+ void MeshAdapter::setLoadBalancingAlgorithm( loadBalanceAlgorithm lbAlgo )
+ {
+ load_balance_algorithm = lbAlgo;
+ }
+ // -------------------------------------------------------------------
+ void MeshAdapter::setDataExchanger( MDB_DataExchanger* dataExch )
+ {
+ dataExchanger = dataExch;
+ }
+#endif
+
+ // -------------------------------------------------------------------
+ int MeshAdapter::partlyMoveObjects(double t, double dt, double* part)
+ {
+ return objects->partlyMove(*vMoveOp,t,dt,part);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::moveObjectsAndReposition(double t, double dt,
+ double chi, bool meshIsCavity,
+ int cavityThickness)
+ {
+ objects->setupElasticRepositioning(mesh, t, dt, chi,
+ meshIsCavity, cavityThickness);
+ double ratio = 0.;
+ int achieved = -1;
+ while ( achieved != 2 ) {
+ achieved = objects->reposition(&ratio);
+ MAdMsgSgl::instance().info(-1,__FILE__,
+ "Advanced repositioning, achieved: %d, ratio: %f",achieved,ratio);
+
+ if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+ if ( achieved <= 1 ) {
+ if ( !removeSlivers() ) {
+ if ( !optimiseElementShape() ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Could not advance objects, ratio reached: %f",ratio);
+ }
+ }
+ }
+ }
+
+ if ( debugLevel >= 1 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ void MeshAdapter::nodalDataDiagnostics(std::ostream& out) const
+ {
+ NodalDataManagerSgl::instance().diagnostics(out);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::openJournal() const
+ {
+ HistorySgl::instance().openJournal();
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::setReferenceJournal(std::string& name) const
+ {
+ HistorySgl::instance().loadJournal(name);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::flushJournal(std::ostream& out) const
+ {
+ HistorySgl::instance().flushJournal(out);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::enableSliverReports()
+ {
+ if ( !sliverROp ) {
+ std::cerr<<"Error: no sliver region handler\n";
+ exit(0);
+ }
+
+ sliverROp->enableReport(outPrefix);
+
+ if ( !sliverFOp ) {
+ std::cerr<<"Error: no sliver face handler\n";
+ exit(0);
+ }
+
+ sliverFOp->enableReport(outPrefix);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::testSliverOperators(bool test)
+ {
+ sliverROp->setTestAllOperators(test);
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshAdapter::checkTheMesh(int verbosity, std::ostream& out,
+ MeshStatus * status) const
+ {
+ MAdMsgSgl::instance().info(-1,__FILE__,
+ "Checking mesh validity (debug level = %d)",
+ debugLevel);
+ return checkMesh(mesh,CHECK_ALL,verbosity,out,status);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::infoMobileObjects(std::ostream& out) const
+ {
+ objects->describe(out);
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+
+ void MeshAdapter::setOutputPrefix(string prefix)
+ {
+ outPrefix = prefix;
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::writePos(string fn, MAdOutputData type) const
+ {
+ string fullName = outPrefix + fn;
+ MAdGmshOutput(mesh, (const pSField) SFManager->getSizeField(),
+ fullName.c_str(), type);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::writeMsh(string fn) const
+ {
+ string fullName = outPrefix + fn;
+ M_writeMsh(mesh,fullName.c_str(),2,NULL);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::writeVolumicCurvature(string fnb) const
+ {
+ std::set<LocalSizeField*> localSF = SFManager->getLocalSizeFields();
+ std::set<LocalSizeField*>::const_iterator it = localSF.begin();
+ for (; it != localSF.end(); it++)
+ {
+ string fullName = outPrefix + fnb + "_" + (*it)->getName() + ".pos";
+ MAdGmshOutput(mesh, (const pSField) *it, fullName.c_str(),
+ OD_CURVATURE_DIV);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::getStatistics(double * meanQuality,
+ double * worstQuality) const
+ {
+ MeshQualityManagerSgl::instance().evaluateStatistics();
+ *meanQuality = MeshQualityManagerSgl::instance().getMeanShape();
+ *worstQuality = MeshQualityManagerSgl::instance().getWorstShape();
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::printStatistics(std::ostream& out) const
+ {
+ MeshQualityManagerSgl::instance().evaluateStatistics();
+ MeshQualityManagerSgl::instance().printStatistics(out);
+ out << "\n\n";
+ MAdStatisticsSgl::instance().print(out);
+ out << "\n\n";
+ if (geoTracker) geoTracker->printFailures(out);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshAdapter::printSliverRegionStatistics(std::ostream& out) const
+ {
+ if ( sliverROp ) sliverROp->printStats(out);
+ // if ( sliverROp ) sliverROp->printOperatorsTest(out);
+ }
+ // -------------------------------------------------------------------
+ void MeshAdapter::abort(int line, const char* file) const
+ {
+ cerr << "\n"
+ << " ****************************\n"
+ << " MeshAdapter is aborting... \n"
+ << " ****************************\n\n";
+
+ string stName = outPrefix + "aborted_statistics";
+ std::ofstream stOut(stName.c_str());
+ printStatistics(stOut);
+
+ string slName = outPrefix + "aborted_slivers";
+ std::ofstream slOut(slName.c_str());
+ printSliverRegionStatistics(slOut);
+
+ string jName = outPrefix + "aborted_journal";
+ std::ofstream jOut(jName.c_str());
+ flushJournal(jOut);
+
+ writePos("aborted.pos",OD_MEANRATIO);
+ writeMsh("aborted.msh");
+
+ if ( file && line >=0 ) {
+ MAdMsgSgl::instance().info(-1,__FILE__,
+ "Abort function called from file %s (line %d)",
+ file,line);
+ }
+ else {
+ MAdMsgSgl::instance().info(-1,__FILE__,"Abort!");
+ }
+
+ flush(cout);
+ flush(cerr);
+
+ exit(EXIT_FAILURE);
+ }
+
+ // -------------------------------------------------------------------
+
+} // End of namespace MAd
+
diff --git a/Adapt/AdaptInterface.h b/Adapt/AdaptInterface.h
new file mode 100644
index 0000000..cd19aad
--- /dev/null
+++ b/Adapt/AdaptInterface.h
@@ -0,0 +1,342 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ADAPTINTERFACE
+#define _H_ADAPTINTERFACE
+
+// from Adapt
+#include "MAdOutput.h"
+#include "MobileObject.h"
+#include "MeshParametersManager.h"
+#include "SizeFieldManager.h"
+#include "CallBackManager.h"
+#include "CheckMesh.h"
+#include "GeoMatcher.h"
+
+// from Adapt - operators
+#include "MAdOperatorBase.h"
+#include "EdgeSplitOp.h"
+#include "EdgeCollapseOp.h"
+#include "FaceCollapseOp.h"
+#include "DESCOp.h"
+#include "EdgeSwapOp.h"
+#include "FaceSwapOp.h"
+#include "VertexMoveOp.h"
+#include "RegionRemoveOp.h"
+#include "SliverFaceHandler.h"
+#include "SliverRegionHandler.h"
+#include "NodesRepositioningOp.h"
+#include "LaplaceSmoothingOp.h"
+
+// from Mesh
+#include "MSops.h"
+#ifdef PARALLEL
+#include "MeshDataBaseComm.h"
+#endif
+
+#include <set>
+#include <string>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+
+ enum algorithmDefinition {
+ SPT_SWP_SLV_CPS,
+ CPS_SWP_SLV_SPT,
+ SLV_CPS_SWP_SPT
+ };
+#ifdef PARALLEL
+ enum loadBalanceAlgorithm {
+ DEFAULT_ALGORITHM,
+ METIS_ALGORITHM
+ };
+#endif
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ class MeshAdapter {
+
+ public:
+
+ MeshAdapter(pMesh m, pSField sf=NULL);
+ ~MeshAdapter();
+
+ // --------------------------------------------
+
+ // gives an overview of the current parameters
+ void printParameters() const;
+
+ void addCallback(CBFunction CB, void* userData,
+ CBFunc_move CB_move=0, void* userData_move=0);
+ void addSizeField(pSField sf);
+
+ // whether or not the global size field is smoothed and maximum gradient
+ void setSizeFieldSmoothing(bool, double maxGrad=1.);
+
+ // set the maximum number of iterations available to reach the 'convergence'
+ // of the global mesh adaptation procedure
+ void setMaxIterationsNumber(int max);
+
+#ifdef PARALLEL
+ // set load balancing algorithm
+ void setLoadBalancingAlgorithm( loadBalanceAlgorithm lbAlgo );
+ // set the data Exchanger
+ void setDataExchanger( MDB_DataExchanger* dataExch);
+#endif
+
+ // impose the interval governing edges length in the transformed space
+ void setEdgeLenSqBounds(double lower, double upper);
+
+ // set permission for operators to modify slightly boundaries
+ // (default: false) and tolerance for the relative volume/area
+ // modifications.
+ // Edge collapse and face collapse:
+ void setCollapseOnBoundary(bool accept=true, double tolerance=1.e-6);
+ // Edge swap:
+ void setSwapOnBoundary(bool accept=true, double tolerance=1.e-6);
+
+ // impose the element quality from which a swap is not required
+ void setNoSwapQuality(double noSwapQuality);
+
+ // impose a threshold rate of improvement for edge and face swaps
+ void setSwapMinImproveRatio(double ratio);
+
+ // impose the maximum quality of a sliver
+ void setSliverQuality(double sliverQuality);
+
+ // Allow or forbid operations creating a sliver.
+ // If allowed and a bound is prescribed, it is allowed only if the edge is
+ // longer/shorter than the bound (bound is expressed as the square of
+ // adimensional edge length)
+ void setSliverPermissionInESplit (bool perm, double lenSqBound=-1.);
+ void setSliverPermissionInECollapse(bool perm, double lenSqBound=-1.);
+
+ // tell if you want to project new vertices on geometric entities
+ void setGeoTracking(bool enable, bool cavityEqualMesh=false,
+ int cavityThickness=2, double chi=1.0);
+
+ // set a value for a very huge edge length (default=1.e14)
+ void setInfiniteLength(double length);
+
+ // frequency at which the size fields are updated inside the global loop
+ // (useful for local and analytical SF)
+ void setSFUpdateFrequency(int freq);
+
+ // Set verbosity:
+ // < 0 : no detail
+ // 1 : global procedure details
+ // > 2 : iterations details
+ void setVerbosity(int _verbosity);
+
+ // constraint a mesh/geometric entity and all its downward entities
+ void clearConstraints() const;
+ void setConstraint(pEntity e) const;
+ void setConstraint(pGEntity ge) const;
+ void setConstraint(int type, int id) const;
+ // unconstrain a geometric entity
+ void removeConstraint(int type, int id) const;
+ void removeConstraint(pGEntity ge) const;
+
+ // manage the physical time
+ void incrementTime(double dt);
+ void setTime(double t);
+ double getTime() const;
+ void updateSizeField();
+
+ // functions to keep track of the initial coordinates
+ void storeInitialCoordinates();
+ void removeStoredCoordinates();
+
+ // add predefined mobile objects
+ void registerObjects(mobileObjectSet* objs);
+
+ // will attach/get the datas to the nodes of the mesh
+ // order in vector is the node iterator order
+ void registerData (std::string name, const std::vector<double>) const;
+ void registerVData (std::string name, const std::vector<std::vector<double> >) const;
+ void getMeshData (std::string name, std::vector<double> *) const;
+ void getMeshVData (std::string name, std::vector<std::vector<double> > *) const;
+ void removeData (std::string name) const;
+ void removeVData (std::string name) const;
+
+ public:
+
+ // ---------------- OPERATIONS ----------------
+
+ // ----- Level 1 -----
+ // ---> Elementary operations
+
+ // Split the edge and if 'checkSize' is true, check that the two resulting
+ // edges are not short edges.
+ bool splitEdge (pEdge e, bool checkSize=false);
+ bool collapseEdge (pEdge e);
+ bool collapseFace(pFace f, pEdge e);
+ bool DSplitCollapseEdge(pRegion pr, pEdge edge1, pEdge edge2);
+ bool swapEdge (pEdge e);
+ bool swapFace (pFace f);
+ bool removeRegion(pRegion region);
+ bool moveVertex (pVertex v, double dxyz[3]);
+ bool putVertex (pVertex v, double xyz[3]);
+ bool moveVertices (std::multiset<vDisplacement,vDisplacementLess>& vDisps);
+
+ // ----- Level 2 -----
+ // ---> Loops on one elementary operation
+
+ // node repositioning
+ double LaplaceSmoothing(LaplSmooType type);
+
+ // topology operations
+ int eSplitLoop();
+ int eCollapseLoop();
+ int eSplitCollapseLoop();
+ int edgeSwapLoop();
+ int faceSwapLoop();
+ int splitEveryEdgeOnce();
+
+ // slivers handling
+ int removeSlivers();
+
+ // geometry matching
+ void snapVertices();
+
+ // ----- Level 3 -----
+ // ---> Procedures with a global objective
+ int optimiseEdgeLength();
+ int optimiseElementShape();
+ int splitLongestEdges();
+ int runOneIter();
+ void uglyTheMesh(double avgQualThresh, int maxIt);
+ int removeNegativeElements();
+
+ // ----- Level 4 -----
+ // ---> Global procedure
+ void run();
+
+ // ----- objects motion -----
+ // move boundaries without repositioning nodes in the volume
+ int partlyMoveObjects (double t, double dt, double* part);
+ // move boundaries and reposition all nodes with an elasticity analogy
+ // chi: stiffness alteration coefficient (-1 = none)
+ // meshIsCavity: true = elastic computation on whole mesh
+ // cavityThickness: nb layers of elements if mesh is not the cavity
+ void moveObjectsAndReposition (double t, double dt, double chi=-1.,
+ bool meshIsCavity=true,
+ int cavityThickness=3);
+
+ // --------------------------------------------
+
+ public:
+
+ // ------ Diagnostics ------
+
+ // get informations on mesh quality
+ void getStatistics(double * meanQuality, double * worstQuality) const;
+
+ // about all datas attached to the nodes
+ void nodalDataDiagnostics(std::ostream& out) const;
+
+ // journals listing all operations tested or applied
+ void setDebugLevel(int debug) { debugLevel = debug; }
+ void openJournal() const;
+ void setReferenceJournal(std::string& name) const;
+ void flushJournal(std::ostream& out) const;
+
+ // sliver outputs
+ void enableSliverReports();
+ void testSliverOperators(bool test);
+
+ // performs several checks to check the validity of the mesh
+ bool checkTheMesh(int verbose=1,
+ std::ostream& out=std::cout,
+ MeshStatus * status=NULL) const;
+
+ // get infos about mobile objects
+ void infoMobileObjects(std::ostream& out=std::cout) const;
+
+ public:
+
+ // ------ Outputs ------
+
+ // set the path to output directory
+ void setOutputPrefix(std::string prefix);
+
+ // write mesh with required postpro data in 'pos' format (Gmsh)
+ void writePos(std::string fn, MAdOutputData type=OD_CONSTANT) const;
+
+ // write mesh in 'msh' format (Gmsh)
+ void writeMsh(std::string fn) const;
+
+ // write a .pos file with the 'volumic' curvature for every local size field
+ void writeVolumicCurvature(std::string fnBase) const;
+
+ // get global data over the mesh
+ void printStatistics(std::ostream& out) const;
+ void printSliverRegionStatistics(std::ostream& out) const;
+
+ public:
+
+ // save all available informations to output directory and abort
+ void abort(int line=-1, const char* file=NULL) const;
+
+ // --------------------------------------------
+
+ private:
+
+ void setDefaultValues();
+ void buildOperators();
+ void removeOperators();
+
+ private:
+
+ pMesh mesh;
+ SizeFieldManager * SFManager;
+
+ mobileObjectSet * objects;
+
+ // ----- Local mesh modification operators -----
+ edgeSplitOp * eSplitOp;
+ edgeCollapseOp * eCollapseOp;
+ faceCollapseOp * fCollapseOp;
+ DESCOp * descOp;
+ edgeSwapOp * eSwapOp;
+ faceSwapOp * fSwapOp;
+ vertexMoveOp * vMoveOp;
+ regionRemoveOp * rRegionOp;
+ sliverFaceHandler * sliverFOp;
+ sliverRegionHandler * sliverROp;
+
+ // ----- Geometry related -----
+ geoMatcher * geoTracker;
+
+ // ----- Adaptation parameters -----
+ algorithmDefinition algorithm;
+ int maxIterationsNumber;
+ MeshParametersManager& mpm;
+#ifdef PARALLEL
+ loadBalanceAlgorithm load_balance_algorithm;
+ MDB_DataExchanger* dataExchanger;
+#endif
+ int updateSFFrequency;
+
+ // ----- Output parameters -----
+ int verbosity;
+ std::string outPrefix;
+ int debugLevel;
+ };
+
+ // -------------------------------------------------------------------
+
+} // End of namespace MAd
+
+#endif
+
diff --git a/Adapt/Makefile b/Adapt/Makefile
new file mode 100644
index 0000000..aee788c
--- /dev/null
+++ b/Adapt/Makefile
@@ -0,0 +1,100 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../variables
+
+LIB = ../lib/libMAdAdapt${LIBEXT}
+
+INC = ${MAdLib_INCLUDES}\
+ ${DASH}I$(MAdROOT)/Geo\
+ ${DASH}I$(MAdROOT)/Mesh\
+ ${DASH}I$(MAdROOT)/Common\
+ ${DASH}I$(MAdROOT)/Adapt\
+ ${DASH}I$(MAdROOT)/Adapt/constraint\
+ ${DASH}I$(MAdROOT)/Adapt/operator\
+ ${DASH}I$(MAdROOT)/Adapt/output\
+ ${DASH}I$(MAdROOT)/Adapt/quality\
+ ${DASH}I$(MAdROOT)/Adapt/repositioning\
+ ${DASH}I$(MAdROOT)/Adapt/sizeField\
+ ${DASH}I$(MAdROOT)/Adapt/utils
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = AdaptInterface.cc\
+ MeshParametersManager.cc\
+ constraint/Constraint.cc\
+ constraint/ModelConstraintManager.cc\
+ operator/DESCOp.cc\
+ operator/EdgeCollapseOp.cc\
+ operator/EdgeSplitOp.cc\
+ operator/EdgeSwapConfig.cc\
+ operator/EdgeSwapOp.cc\
+ operator/FaceCollapseOp.cc\
+ operator/FaceSwapOp.cc\
+ operator/MAdOperatorBase.cc\
+ operator/OperatorTools.cc\
+ operator/RegionRemoveOp.cc\
+ operator/SliverFaceHandler.cc\
+ operator/SliverRegionHandler.cc\
+ operator/VertexMoveOp.cc\
+ output/MAdOutput.cc\
+ quality/MeanRatioEvaluator.cc\
+ quality/OrientedMeanRatioEvaluator.cc\
+ quality/MeshQualityManager.cc\
+ repositioning/GeoMatcher.cc\
+ repositioning/LaplaceSmoothingOp.cc\
+ repositioning/MAdElasticityOp.cc\
+ repositioning/MobileObject.cc\
+ sizeField/AnalyticalSField.cc\
+ sizeField/AnisoMeshSize.cc\
+ sizeField/DiscreteSF.cc\
+ sizeField/IsoMeshSize.cc\
+ sizeField/LocalSizeField.cc\
+ sizeField/MeshSizeBase.cc\
+ sizeField/NullSField.cc\
+ sizeField/PWLinearSField.cc\
+ sizeField/SizeFieldBase.cc\
+ sizeField/SizeFieldManager.cc\
+ utils/CallBackManager.cc\
+ utils/History.cc\
+ utils/MAdStatistics.cc\
+ utils/MAdTimeManager.cc\
+ utils/NodalDataManager.cc\
+ utils/DistanceFunction.cc\
+ ../Contrib/mathex/mathex.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${LIB}: ${OBJ}
+ ${AR} ${ARFLAGS} ${LIB} ${OBJ}
+ ${RANLIB} ${LIB}
+
+cpobj: ${OBJ}
+ cp -f ${OBJ} ${MAdLib_TMPDIR}/.
+
+.cc${OBJEXT}:
+ ${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+ ${RM} */*.o *.o *.obj ../Contrib/mathex/*.o
+
+purge:
+
+depend:
+ (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+ ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+ ) > Makefile.new
+ cp Makefile Makefile.bak
+ cp Makefile.new Makefile
+ rm -f Makefile.new
\ No newline at end of file
diff --git a/Adapt/MeshParametersManager.cc b/Adapt/MeshParametersManager.cc
new file mode 100644
index 0000000..58c3664
--- /dev/null
+++ b/Adapt/MeshParametersManager.cc
@@ -0,0 +1,161 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MeshParametersManager.h"
+#include "MAdMessage.h"
+
+// standart C/C++
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ MeshParametersManager::MeshParametersManager():
+ lowerLengthSqBound(-1.), upperLengthSqBound(-1.),
+ sliverTetQualityBound(-1.), sliverTriQualityBound(-1.),
+ sliverPermInESplit(false), sliverPermInECollapse(false),
+ sliverLowerLengthSqBound(-1.),sliverUpperLengthSqBound(-1.),
+ noSwapQuality(-1.),swapMinImproveRatio(-1.), bigLength(1.e14)
+ {}
+
+ // -------------------------------------------------------------------
+ void MeshParametersManager::initialize()
+ {
+ }
+
+ // -------------------------------------------------------------------
+ void MeshParametersManager::finalize()
+ {
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+
+ void MeshParametersManager::setLowerLengthSqBound(double lSq)
+ {
+ lowerLengthSqBound = lSq;
+ }
+
+ // -------------------------------------------------------------------
+
+ void MeshParametersManager::setUpperLengthSqBound(double lSq)
+ {
+ upperLengthSqBound = lSq;
+ }
+
+ // -------------------------------------------------------------------
+ double MeshParametersManager::getSliverBound(int dim) const
+ {
+ if (dim==3) return getSliverTetBound();
+ return getSliverTriBound();
+ }
+
+ // -------------------------------------------------------------------
+ double MeshParametersManager::getSliverBound(const pMesh mesh) const
+ {
+ return getSliverBound(M_dim(mesh));
+ }
+
+ // -------------------------------------------------------------------
+
+ void MeshParametersManager::setSliverTriBound(double bound)
+ {
+ sliverTriQualityBound = bound;
+ }
+
+ // -------------------------------------------------------------------
+
+ void MeshParametersManager::setSliverTetBound(double bound)
+ {
+ sliverTetQualityBound = bound;
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+
+ void MeshParametersManager::setSliverPermissionInESplit(bool perm,
+ double bound)
+ {
+ sliverPermInESplit = perm;
+ sliverUpperLengthSqBound = bound;
+ if ( sliverUpperLengthSqBound > 0. &&
+ sliverUpperLengthSqBound < upperLengthSqBound ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Incoherent parameters: upper length square bound for edge splits creating slivers (%f) is lower than the global upper legnth square bound (%f)",
+ sliverUpperLengthSqBound,upperLengthSqBound);
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+ void MeshParametersManager::setSliverPermissionInECollapse(bool perm,
+ double bound)
+ {
+ sliverPermInECollapse = perm;
+ sliverLowerLengthSqBound = bound;
+ if ( sliverLowerLengthSqBound > 0. &&
+ sliverLowerLengthSqBound > lowerLengthSqBound ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Incoherent parameters: lower length square bound for edge collapses creating slivers (%f) is bigger than the global lower legnth square bound (%f)",
+ sliverLowerLengthSqBound,lowerLengthSqBound);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+
+ void MeshParametersManager::diagnostics() const
+ {
+ cout << " *** Parameters for the mesh adaptation *** \n";
+
+ cout << "\n";
+
+ cout << "- Bounds of the edge length squared: \n";
+ cout << "\t Lower: " << lowerLengthSqBound << "\n";
+ cout << "\t Upper: " << upperLengthSqBound << "\n";
+
+ cout << "\n";
+
+ cout << "- Quality bound for the sliver triangles: "
+ << sliverTriQualityBound << "\n";
+
+ cout << "- Quality bound for the sliver tetrahedra: "
+ << sliverTetQualityBound << "\n";
+
+ cout << "\n";
+
+ cout << "Edge splits can create slivers: ";
+ if (sliverPermInESplit) {
+ cout << "yes: ";
+ if ( sliverUpperLengthSqBound < 0) cout << "for any edge.";
+ else cout << "if the edge is longer than "<< sliverUpperLengthSqBound<<" (square of adimensional length)";
+ }
+ else cout << "no";
+ cout << "\n";
+ cout << "Edge collapses can create slivers: ";
+ if (sliverPermInECollapse) {
+ cout << "yes: ";
+ if ( sliverLowerLengthSqBound < 0) cout << "for any edge.";
+ else cout << "the edge is shorter than "<< sliverLowerLengthSqBound<<" (square of adimensional length)";
+ }
+ else cout << "no";
+ cout << "\n";
+
+ cout << "\n";
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/MeshParametersManager.h b/Adapt/MeshParametersManager.h
new file mode 100644
index 0000000..adb0e84
--- /dev/null
+++ b/Adapt/MeshParametersManager.h
@@ -0,0 +1,109 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MESHPARAMETERSMANAGER
+#define _H_MESHPARAMETERSMANAGER
+
+#include "MeshDataBaseInterface.h"
+#include "MAdOperatorBase.h"
+#include "MAdSingleton.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class MeshParametersManager {
+
+ public:
+
+ MeshParametersManager();
+ ~MeshParametersManager() {};
+
+ void initialize();
+ void finalize();
+
+ // ------------------------------------------
+ public:
+
+ void setLowerLengthSqBound(double);
+ void setUpperLengthSqBound(double);
+ void setSliverTriBound(double);
+ void setSliverTetBound(double);
+
+ double getLowerLengthSqBound() const {return lowerLengthSqBound;}
+ double getUpperLengthSqBound() const {return upperLengthSqBound;}
+ double getSliverBound(int dim) const;
+ double getSliverBound(const pMesh) const;
+ double getSliverTriBound() const {return sliverTriQualityBound;}
+ double getSliverTetBound() const {return sliverTetQualityBound;}
+
+ private:
+
+ double lowerLengthSqBound, upperLengthSqBound;
+ double sliverTetQualityBound;
+ double sliverTriQualityBound;
+
+ // ------------------------------------------
+ public:
+
+ void setSliverPermissionInESplit (bool, double bound=-1.);
+ void setSliverPermissionInECollapse (bool, double bound=-1.);
+
+ bool getSliverPermissionInESplit () const {return sliverPermInESplit;}
+ bool getSliverPermissionInECollapse () const {return sliverPermInECollapse;}
+
+ double getSliverLowerLengthSqBound () const {return sliverLowerLengthSqBound;}
+ double getSliverUpperLengthSqBound () const {return sliverUpperLengthSqBound;}
+
+ private:
+
+ bool sliverPermInESplit, sliverPermInECollapse;
+ double sliverLowerLengthSqBound, sliverUpperLengthSqBound;
+
+ // ------------------------------------------
+ public:
+
+ void setNoSwapQuality(double noSwap) {noSwapQuality = noSwap;}
+ void setSwapMinImproveRatio(double ratio) {swapMinImproveRatio = ratio;}
+
+ double getNoSwapQuality() const {return noSwapQuality;}
+ double getSwapMinImproveRatio() const {return swapMinImproveRatio;}
+
+ private:
+
+ double noSwapQuality;
+ double swapMinImproveRatio;
+
+ // ------------------------------------------
+ public:
+
+ void setBigLength(double len) { bigLength = len; }
+ double getBigLength() { return bigLength; }
+
+ private:
+
+ double bigLength;
+
+ // ------------------------------------------
+ public:
+
+ void diagnostics() const;
+
+ };
+
+ // -------------------------------------------------------------------
+
+ typedef MAdSingleton<MeshParametersManager> MeshParametersManagerSgl;
+
+}
+
+#endif
diff --git a/Adapt/constraint/Constraint.cc b/Adapt/constraint/Constraint.cc
new file mode 100644
index 0000000..5071c82
--- /dev/null
+++ b/Adapt/constraint/Constraint.cc
@@ -0,0 +1,433 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "Constraint.h"
+#include "ModelConstraintManager.h"
+
+#include "MeshDataBaseParallelInterface.h"
+
+static unsigned int CONSTRAIN_MARK_ID = 1687354269;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void EN_constrain(pEntity pE)
+ {
+ pE->attachInt(CONSTRAIN_MARK_ID,1);
+ }
+
+ // -------------------------------------------------------------------
+ void EN_unconstrain(pEntity pE)
+ {
+ pE->attachInt(CONSTRAIN_MARK_ID,0);
+ }
+
+ // -------------------------------------------------------------------
+ bool EN_constrained(pEntity pE)
+ {
+ if ( ModelConstraintManagerSgl::instance().constrained(EN_whatIn(pE)) ) {
+ return true;
+ }
+
+ return (bool) pE->getAttachedInt(CONSTRAIN_MARK_ID);
+ }
+
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ void DeleteConstraint(pMesh mesh) {
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ EN_unconstrain((pEntity) pv);
+ }
+ VIter_delete(vit);
+
+ EIter eit = M_edgeIter(mesh);
+ pEdge ped;
+ while ((ped = EIter_next(eit))) {
+ EN_unconstrain((pEntity) ped);
+ }
+ EIter_delete(eit);
+
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ EN_unconstrain((pEntity) pface);
+ }
+ FIter_delete(fit);
+
+ RIter rit = M_regionIter(mesh);
+ pRegion pregion;
+ while ((pregion = RIter_next(rit))) {
+ EN_unconstrain((pEntity) pregion);
+ }
+ RIter_delete(rit);
+ }
+
+ // -------------------------------------------------------------------
+#ifdef PARALLEL
+ void DeleteParallelConstraint(pMesh mesh) {
+
+ VIter vit = M_vertexIter(mesh);
+ while ( pVertex pv = VIter_next(vit) ) {
+ if ( V_isInterface(pv) ) EN_unconstrain((pEntity) pv);
+ }
+ VIter_delete(vit);
+
+ EIter eit = M_edgeIter(mesh);
+ while ( pEdge pe = EIter_next(eit) ) {
+ // if ( E_isInterface(mesh,pe) ) {
+ if ( E_isInterface(pe) ) {
+ EN_unconstrain((pEntity) pe);
+ }
+ }
+ EIter_delete(eit);
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+
+ if ( dim == 3 ) {
+ FIter fit = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fit) ) {
+ // if ( F_isInterface(mesh,pf) ) {
+ if ( F_isInterface(pf) ) {
+ EN_unconstrain((pEntity) pf);
+ }
+ }
+ FIter_delete(fit);
+ }
+ }
+ void UpdateParallelConstraint(pMesh mesh) {
+
+ DeleteParallelConstraint(mesh);
+ // DeleteConstraint(mesh);
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+
+ if ( dim == 3 ) {
+ FIter fit = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fit) ) {
+ // if ( F_isInterface(mesh,pf) ) {
+ if ( F_isInterface(pf) ) {
+ EN_constrain((pEntity) pf);
+ }
+ }
+ FIter_delete(fit);
+ }
+ EIter eit = M_edgeIter(mesh);
+ while ( pEdge pe = EIter_next(eit) ) {
+ // if ( E_isInterface(mesh,pe) ) {
+ if ( E_isInterface(pe) ) {
+ EN_constrain((pEntity) pe);
+ }
+ }
+ EIter_delete(eit);
+ VIter vit = M_vertexIter(mesh);
+ while ( pVertex pv = VIter_next(vit) ) {
+ if ( V_isInterface(pv) ) EN_constrain((pEntity) pv);
+ }
+ VIter_delete(vit);
+ }
+#endif
+
+ // -------------------------------------------------------------------
+ void UpdatePeriodicConstraint2d(pMesh mesh)
+ {
+ pMeshDataId tagPeriod = MD_lookupMeshDataId("PeriodicPoint");
+
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ int ncount = 0;
+ pEdge pe1 = F_edge(pface,0);
+ pVertex p1 = E_vertex(pe1,0);
+ pVertex p2 = E_vertex(pe1,1);
+ void *temp_ptr1,*temp_ptr2;
+ int isPeriodic1 = EN_getDataPtr((pEntity) p1 , tagPeriod, &temp_ptr1);
+ int isPeriodic2 = EN_getDataPtr((pEntity) p2 , tagPeriod, &temp_ptr2);
+ if(isPeriodic1) EN_constrain((pEntity) p1);
+ if(isPeriodic2) EN_constrain((pEntity) p2);
+ if(isPeriodic1 && isPeriodic2){
+ /*est-ce que l'arete image de celle-ci existe ?*/
+ /*ie est-ce l'arete Img(P1)-Img(P2) existe et est differente de ped ?*/
+ const std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+ const std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+ int nump = EN_id(p2);
+ unsigned int k=0;
+ int exist=-1;
+ for(k=0; k<(*recup).size() ; k++) {
+ /*edge p1p2 = p1 Img(p1) ?*/
+ pVertex n1 = (*recup)[k].second;
+ if ( nump == EN_id(n1) ) {
+ continue;
+ }
+ /*edge = Img(p1)Img(p2) existe ?*/
+ unsigned int kk=0;
+ std::vector<int> transfo1 = (*recup)[k].first;
+ for(kk=0; kk<(*recup2).size() ; kk++) {
+ std::vector<int> transfo2 = (*recup2)[kk].first;
+ assert(transfo1.size()==transfo2.size());
+ unsigned int kt = 0;
+ for(kt = 0 ; kt < transfo1.size(); kt++) {
+ if(transfo1[kt] != transfo2[kt]) break;
+ }
+ if(kt!=transfo1.size()) continue;
+ pVertex n2 = (*recup2)[kk].second;
+ if ( !E_exist(n1,n2) && !E_exist(n2,n1) ) {
+ exist = 0;
+ } else {
+ exist = 1;
+ }
+ }
+ }
+ if(exist==1) {
+ ncount++;
+ EN_constrain((pEntity) pe1);
+ }
+ }
+ pEdge pe2 = F_edge(pface,1);
+ p1 = E_vertex(pe2,0);
+ p2 = E_vertex(pe2,1);
+ isPeriodic1 = EN_getDataPtr((pEntity) p1 , tagPeriod, &temp_ptr1);
+ isPeriodic2 = EN_getDataPtr((pEntity) p2 , tagPeriod, &temp_ptr2);
+ if(isPeriodic1) EN_constrain((pEntity) p1);
+ if(isPeriodic2) EN_constrain((pEntity) p2);
+ if(isPeriodic1 && isPeriodic2){
+ /*est-ce que l'arete image de celle-ci existe ?*/
+ /*ie est-ce l'arete Img(P1)-Img(P2) existe et est differente de ped ?*/
+ const std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+ const std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+ int nump = EN_id(p2);
+ unsigned int k=0;
+ int exist=-1;
+ for(k=0; k<(*recup).size() ; k++) {
+ /*edge p1p2 = p1 Img(p1) ?*/
+ pVertex n1 = (*recup)[k].second;
+ if ( nump == EN_id(n1) ){
+ continue;
+ }
+ /*edge = Img(p1)Img(p2) existe ?*/
+ unsigned int kk=0;
+ std::vector<int> transfo1 = (*recup)[k].first;
+ for(kk=0; kk<(*recup2).size() ; kk++) {
+ std::vector<int> transfo2 = (*recup2)[kk].first;
+ assert(transfo1.size()==transfo2.size());
+ unsigned int kt = 0;
+ for(kt = 0 ; kt < transfo1.size(); kt++) {
+ if(transfo1[kt] != transfo2[kt]) break;
+ }
+ if(kt!=transfo1.size()) continue;
+ pVertex n2 = (*recup2)[kk].second;
+ if ( !E_exist(n1,n2) && !E_exist(n2,n1) ) {
+ exist = 0;
+ } else {
+ exist = 1;
+ }
+ }
+ }
+ if(exist==1) {
+ ncount++;
+ EN_constrain((pEntity) pe2);
+ }
+ }
+ pEdge pe3 = F_edge(pface,2);
+ p1 = E_vertex(pe3,0);
+ p2 = E_vertex(pe3,1);
+ isPeriodic1 = EN_getDataPtr((pEntity) p1 , tagPeriod, &temp_ptr1);
+ isPeriodic2 = EN_getDataPtr((pEntity) p2 , tagPeriod, &temp_ptr2);
+ if(isPeriodic1) EN_constrain((pEntity) p1);
+ if(isPeriodic2) EN_constrain((pEntity) p2);
+ if(isPeriodic1 && isPeriodic2){
+ /*est-ce que l'arete image de celle-ci existe ?*/
+ /*ie est-ce l'arete Img(P1)-Img(P2) existe et est differente de ped ?*/
+ const std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+ const std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+ int nump = EN_id(p2);
+ unsigned int k=0,exist=0;
+ for(k=0; k<(*recup).size() ; k++) {
+ /*edge p1p2 = p1 Img(p1) ?*/
+ pVertex n1 = (*recup)[k].second;
+ if ( nump == EN_id(n1) ){
+ continue;
+ }
+ /*edge = Img(p1)Img(p2) existe ?*/
+ unsigned int kk=0;
+ std::vector<int> transfo1 = (*recup)[k].first;
+ for(kk=0; kk<(*recup2).size() ; kk++) {
+ std::vector<int> transfo2 = (*recup2)[kk].first;
+ assert(transfo1.size()==transfo2.size());
+ unsigned int kt = 0;
+ for(kt = 0 ; kt < transfo1.size(); kt++) {
+ if(transfo1[kt] != transfo2[kt]) break;
+ }
+ if(kt!=transfo1.size()) continue;
+ pVertex n2 = (*recup2)[kk].second;
+ if ( E_exist(n1,n2) || E_exist(n2,n1) ) {
+ exist = 1;
+ }
+ }
+ }
+ if(exist==1) {
+ ncount++;
+ EN_constrain((pEntity) pe3);
+ }
+ }
+ if(ncount==3) EN_constrain((pEntity) pface);
+
+ }
+ FIter_delete(fit);
+ }
+
+ // -------------------------------------------------------------------
+ void UpdatePeriodicConstraint3d(pMesh mesh)
+ {
+ pMeshDataId tagPeriod = MD_lookupMeshDataId("PeriodicPoint");
+
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ int ncountr = 0;
+ pFace pface[4];
+ for(int i=0 ; i<4 ; i++) {
+ int nbdry = 1;
+ pface[i] = R_face(pr,i);
+ /*Img(pface[i]) exist ?*/
+ pVertex nod[3];
+ int isPeriodic[3];
+ void *tmp[3];
+ unsigned int j=0;
+ for(j=0 ; j<3 ; j++) {
+ nod[j] = F_vertex(pface[i],j);
+ isPeriodic[j] = EN_getDataPtr((pEntity) nod[j] , tagPeriod, &tmp[j]);
+ if(!isPeriodic[j]) {
+ nbdry=0;
+ continue;
+ }
+ EN_constrain((pEntity) nod[j]);
+ }
+ if(nbdry) {
+ /*find Img(nod[j])*/
+ const std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) tmp[0];
+ const std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) tmp[1];
+ const std::vector<std::pair<std::vector<int> , pVertex> > *recup3 = (std::vector<std::pair<std::vector<int> , pVertex> > *) tmp[2];
+ unsigned int k;
+ int exist=-1,nfound=0;
+ for(k=0; k<(*recup).size() ; k++) {
+ pVertex n1 = (*recup)[k].second;
+ /*ATTENTION CA PEUT ARRIVER DANS LES CAS 3_PERIODIQUES!!!if ( EN_id((pEntity) nod[1]) == EN_id((pEntity) n1) || EN_id((pEntity) nod[2]) == EN_id((pEntity) n1) ){
+ continue;
+ } */
+ unsigned int kk=0;
+ std::vector<int> transfo1 = (*recup)[k].first;
+ for(kk=0; kk<(*recup2).size() ; kk++) {
+ std::vector<int> transfo2 = (*recup2)[kk].first;
+ assert(transfo1.size()==transfo2.size());
+ unsigned int kt = 0;
+ for(kt = 0 ; kt < transfo1.size(); kt++) {
+ if(transfo1[kt] != transfo2[kt]) break;
+ }
+ if(kt!=transfo1.size()) continue;
+ if(!nfound) nfound = 1;
+ pVertex n2 = (*recup2)[kk].second;
+ unsigned int kkk=0;
+ for(kkk=0; kkk<(*recup3).size() ; kkk++) {
+ std::vector<int> transfo2 = (*recup3)[kkk].first;
+ unsigned int kt = 0;
+ for(kt = 0 ; kt < transfo1.size(); kt++) {
+ if(transfo1[kt] != transfo2[kt]) break;
+ }
+ if(kt!=transfo1.size()) continue;
+ pVertex n3 = (*recup3)[kkk].second;
+ nfound = 2;
+ if ( F_exist(n1,n2,n3,0) || F_exist(n1,n3,n2,0) ||
+ F_exist(n2,n1,n3,0) || F_exist(n2,n3,n1,0) ||
+ F_exist(n3,n2,n1,0) || F_exist(n3,n1,n2,0) ) {
+ exist = 1;
+ }
+ }/*end kkk*/
+ }/*end kk*/
+ }/*end k*/
+ if(!nfound) nbdry=0;//printf("on n'a pas trouve la face\n");
+ if(nfound==1) nbdry = 1;//printf("3 ou 2 ? %d\n",nfound);
+ if(nfound==2) nbdry = 0;//printf("3 ou 2 ? %d\n",nfound);
+
+ if(exist==1) {
+ ncountr++;
+ EN_constrain((pEntity) pface[i]);
+ for(int j=0 ; j<3 ; j++) {
+ EN_constrain((pEntity) F_edge(pface[i],j));
+ /* pVertex p1 = F_edge(pface[i],j)->p1;
+ pVertex p2 = F_edge(pface[i],j)->p2;
+ double len = (p1->X-p2->X)*(p1->X-p2->X) + (p1->Y-p2->Y)*(p1->Y-p2->Y) +(p1->Z-p2->Z)*(p1->Z-p2->Z);
+ printf("edge %d %d : %e\n",p1->iD,p2->iD,len); */
+ }
+ continue;
+ } else{
+ /* if(F_numRegions(pface[i]) != 2){ printf("pbs constraint %d %d %d\n",EN_id((pEntity) nod[0])
+ ,EN_id((pEntity) nod[1]),EN_id((pEntity) nod[2]));exit(0); } */
+ }
+ }/*end nbdry*/
+ /*face not constraint*/
+ int ncount = 0;
+ for(int j=0 ; j<3 ; j++) {
+ pEdge ped = F_edge(pface[i],j);
+ pVertex p1 = E_vertex(ped,0);
+ pVertex p2 = E_vertex(ped,1);
+ void *temp_ptr1,*temp_ptr2;
+ int isPeriodic1 = EN_getDataPtr((pEntity) p1 , tagPeriod, &temp_ptr1);
+ int isPeriodic2 = EN_getDataPtr((pEntity) p2 , tagPeriod, &temp_ptr2);
+ if((isPeriodic1 && isPeriodic2)) {
+ const std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+ const std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+ //int nump = EN_id(p2);
+ int nfound = 0;
+ unsigned int k=0;
+ int exist=-1;
+ for(k=0; k<(*recup).size() ; k++) {
+ /*edge p1p2 = p1 Img(p1) ?*/
+ pVertex n1 = (*recup)[k].second;
+ /*if ( nump == EN_id(n1) ){
+ continue;
+ }*/
+ /*edge = Img(p1)Img(p2) existe ?*/
+ unsigned int kk=0;
+ std::vector<int> transfo1 = (*recup)[k].first;
+ for(kk=0; kk<(*recup2).size() ; kk++) {
+ std::vector<int> transfo2 = (*recup2)[kk].first;
+ assert(transfo1.size()==transfo2.size());
+ unsigned int kt = 0;
+ for(kt = 0 ; kt < transfo1.size(); kt++) {
+ if(transfo1[kt] != transfo2[kt]) break;
+ }
+ if(kt!=transfo1.size()) continue;
+ nfound = 1;
+ pVertex n2 = (*recup2)[kk].second;
+ if ( E_exist(n1,n2) || E_exist(n2,n1) ) {
+ exist = 1;
+ }
+ }
+ }/*end k*/
+
+ if(exist==1) {
+ ncount++;
+ EN_constrain((pEntity) ped);
+ }
+ }
+ }
+ }
+ if(ncountr==4) EN_constrain((pEntity) pr);
+ }
+ RIter_delete(rit);
+
+ }
+
+}
+
+//#endif
diff --git a/Adapt/constraint/Constraint.h b/Adapt/constraint/Constraint.h
new file mode 100644
index 0000000..deef2a6
--- /dev/null
+++ b/Adapt/constraint/Constraint.h
@@ -0,0 +1,49 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_CONSTRAINT
+#define _H_CONSTRAINT
+
+#include "MeshDataBaseInterface.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+
+ // --- entity level constraining ---
+
+ void EN_constrain (pEntity);
+ void EN_unconstrain (pEntity);
+ bool EN_constrained (pEntity);
+
+ // --- mesh level constraining ---
+
+#ifdef PARALLEL
+ // Constrain parallel interface elements
+ void UpdateParallelConstraint(pMesh mesh);
+ // unConstrain parallel interface elements
+ void DeleteParallelConstraint(pMesh mesh);
+#endif
+
+ // Constrain periodic interface elements
+ void UpdatePeriodicConstraint3d(pMesh mesh);
+ void UpdatePeriodicConstraint2d(pMesh mesh);
+
+ // Remove all constraints on elements (periodic, parallel and misc.)
+ void DeleteConstraint(pMesh mesh);
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/constraint/ModelConstraintManager.cc b/Adapt/constraint/ModelConstraintManager.cc
new file mode 100644
index 0000000..6571169
--- /dev/null
+++ b/Adapt/constraint/ModelConstraintManager.cc
@@ -0,0 +1,86 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "ModelConstraintManager.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void ModelConstraintManager::initialize(pGModel _model)
+ {
+ model = _model;
+ }
+
+ // -------------------------------------------------------------------
+ void ModelConstraintManager::finalize()
+ {
+ }
+
+ // -------------------------------------------------------------------
+ void ModelConstraintManager::setModel(pGModel _model)
+ {
+ model = _model;
+ }
+
+ // -------------------------------------------------------------------
+ void ModelConstraintManager::clear()
+ {
+ constrEntities.clear();
+ }
+
+ // -------------------------------------------------------------------
+ void ModelConstraintManager::constrain(int type, int id)
+ {
+ pGEntity pGE = GM_entityByTag(model, type, id);
+ constrain(pGE);
+ }
+
+ // -------------------------------------------------------------------
+ void ModelConstraintManager::constrain(pGEntity pGE)
+ {
+ // constrain entity
+ constrEntities.insert(pGE);
+
+#ifdef _HAVE_GMSH_
+ // constrain lower geometrical levels
+ std::list<pGEntity> subGE = GEN_closure(pGE);
+ std::list<pGEntity>::const_iterator subIter = subGE.begin();
+ for (; subIter != subGE.end(); subIter++) constrain(*subIter);
+#endif
+ }
+
+ // -------------------------------------------------------------------
+ void ModelConstraintManager::unconstrain(int type, int id)
+ {
+ pGEntity pGE = GM_entityByTag(model, type, id);
+ unconstrain(pGE);
+ }
+
+ // -------------------------------------------------------------------
+ void ModelConstraintManager::unconstrain(pGEntity pGE)
+ {
+ std::set<pGEntity>::iterator eIter = constrEntities.find(pGE);
+ if ( eIter != constrEntities.end() ) constrEntities.erase(eIter);
+ }
+
+ // -------------------------------------------------------------------
+ bool ModelConstraintManager::constrained(pGEntity pGE)
+ {
+ //GCTODO: check upper-level geometric entities: need model with connectivity
+
+ if ( constrEntities.find(pGE) != constrEntities.end() ) return true;
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/constraint/ModelConstraintManager.h b/Adapt/constraint/ModelConstraintManager.h
new file mode 100644
index 0000000..1348d3f
--- /dev/null
+++ b/Adapt/constraint/ModelConstraintManager.h
@@ -0,0 +1,61 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MODELCONSTRAINTMANAGER
+#define _H_MODELCONSTRAINTMANAGER
+
+#include "ModelInterface.h"
+#include <set>
+
+#include "MAdSingleton.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+
+ class ModelConstraintManager {
+
+ public:
+
+ ModelConstraintManager() {};
+ ~ModelConstraintManager() {};
+
+ void initialize(pGModel);
+ void finalize();
+ void setModel(pGModel);
+
+ public:
+
+ void clear();
+
+ void constrain (int type, int id);
+ void constrain (pGEntity);
+
+ void unconstrain(int type, int id);
+ void unconstrain(pGEntity);
+
+ bool constrained(pGEntity);
+
+ private:
+
+ pGModel model;
+ std::set<pGEntity> constrEntities;
+ };
+
+ // -------------------------------------------------------------------
+
+ typedef MAdSingleton<ModelConstraintManager> ModelConstraintManagerSgl;
+
+}
+
+#endif
diff --git a/Adapt/operator/DESCOp.cc b/Adapt/operator/DESCOp.cc
new file mode 100644
index 0000000..8ee3a71
--- /dev/null
+++ b/Adapt/operator/DESCOp.cc
@@ -0,0 +1,204 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "DESCOp.h"
+#include "OperatorTools.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void DESCOp::setDESC(pRegion r, pEdge e0, pEdge e1)
+ {
+ region = r;
+ splitE[0] = e0;
+ splitE[1] = e1;
+ E_center(splitE[0],xyz); // Collapse on mid-edge e0 only
+ }
+
+ // -------------------------------------------------------------------
+ bool DESCOp::checkConstraints() const
+ {
+ if ( EN_constrained((pEntity)splitE[0]) ||
+ EN_constrained((pEntity)splitE[1]) ) {
+ return false;
+ }
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool DESCOp::checkGeometry()
+ {
+ if( E_whatInType(splitE[1]) != 3 ) return false;
+
+ for( int i=0; i<2; i++ ) {
+
+ int nbV = 0;
+ pVertex verts[2];
+ for(int iF=0; iF < R_numFaces(region); iF++) {
+ pFace face = R_face(region,iF);
+ if( F_inClosure(face,(pEntity)splitE[i]) ) {
+ pRegion oppR = F_region(face,0);
+ if( oppR == region ) oppR = F_region(face,1);
+ if ( oppR ) {
+ verts[nbV] = R_fcOpVt(oppR,face);
+ nbV++;
+ }
+ }
+ }
+
+ pEdge edge = splitE[(i+1)%2];
+ for( int j=0; j<E_numFaces(edge); j++ ) {
+ pVertex oppV = F_edOpVt(E_face(edge,j),edge);
+ for( int k=0; k<nbV; k++ ) {
+ if( oppV == verts[k] ) return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool DESCOp::evaluateShapes()
+ {
+ double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+ pMSize xyzSize = sizeField->getSizeOnEntity((pEntity)region,xyz);
+
+ for(int iE=0; iE<2; iE++) {
+
+ pPList eRegs = E_regions(splitE[iE]);
+
+ void * temp = NULL;
+ while( pRegion pR = (pRegion)PList_next(eRegs,&temp) ) {
+
+ if( pR == region ) continue;
+
+ pPList rVerts = R_vertices(pR);
+
+ // evaluate the two regions resulting from the split
+ for( int iER=0; iER<2; iER++ ) {
+
+ pVertex eV = E_vertex(splitE[iE],iER);
+
+ pMSize rSizes[4];
+ for (int idel = 0; idel<4; idel++) rSizes[idel] = NULL;
+ double rCoords[4][3];
+
+ pVertex pV = NULL;
+ void * iter = NULL;
+ for( int iERV=0; ( pV=(pVertex)PList_next(rVerts,&iter) ); iERV++ ) {
+ if( pV == eV ) {
+ rSizes[iERV] = xyzSize;
+ rCoords[iERV][0] = xyz[0];
+ rCoords[iERV][1] = xyz[1];
+ rCoords[iERV][2] = xyz[2];
+ }
+ else {
+ rSizes[iERV] = sizeField->findSize(pV);
+ V_coord(pV,rCoords[iERV]);
+ }
+ }
+
+ double rShape;
+ if( !mqm.getElementEvaluator()->XYZ_R_shape(rCoords,rSizes,&rShape) ) {
+ PList_delete (rVerts);
+ if( xyzSize ) delete xyzSize;
+ PList_delete(eRegs);
+ return false;
+ }
+
+ if( worstShape > rShape ) worstShape = rShape;
+ }
+
+ PList_delete(rVerts);
+ }
+
+ PList_delete(eRegs);
+ }
+
+ if( xyzSize ) delete xyzSize;
+
+ results->setWorstShape(worstShape);
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void DESCOp::evaluateLengths() const
+ {
+ // get size at new point (interpolation)
+ pMSize xyzSize = sizeField->getSizeOnEntity((pEntity)splitE[0],xyz);
+
+ double lSqMin = MAdBIG, lSqMax = 0.;
+
+ for( int iE=0; iE<2; iE++ ) {
+ for( int i=0; i<E_numFaces(splitE[iE]); i++ ) {
+
+ pVertex oppV = F_edOpVt( E_face(splitE[iE],i), splitE[iE] );
+ const pMSize oppSize = sizeField->findSize(oppV);
+
+ double xyzOpp[3];
+ V_coord(oppV,xyzOpp);
+ double lSq = sizeField->SF_XYZ_lengthSq(xyz, xyzOpp,
+ xyzSize, oppSize);
+ if( lSq > lSqMax ) lSqMax = lSq;
+ if( lSq < lSqMin ) lSqMin = lSq;
+ }
+ }
+
+ results->setMaxLenSq(lSqMax);
+ results->setMinLenSq(lSqMin);
+
+ if( xyzSize ) delete xyzSize;
+ }
+
+
+ // -------------------------------------------------------------------
+ void DESCOp::getCavity(pPList * cavity) const
+ {
+ *cavity = PList_new();
+ PList_append(*cavity,region);
+
+ for(int i=0; i<2; i++) {
+ pPList eRegs = E_regions(splitE[i]);
+ void * iter = NULL;
+ for(pRegion pR; ( pR=(pRegion)PList_next(eRegs,&iter) ); ) {
+ if( pR != region ) {
+ PList_append(*cavity,pR);
+ }
+ }
+ PList_delete(eRegs);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void DESCOp::apply()
+ {
+ pVertex newV[2];
+ for(int iE=0; iE<2; iE++) {
+ newV[iE] = E_split(mesh, splitE[iE], xyz);
+ }
+
+ pVertex vTgt = newV[0];
+
+ pEdge edgeDel = E_exist(vTgt,newV[1]);
+ assert ( edgeDel );
+
+ E_collapse(mesh, edgeDel, newV[1], vTgt);
+
+ HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/DESCOp.h b/Adapt/operator/DESCOp.h
new file mode 100644
index 0000000..c497537
--- /dev/null
+++ b/Adapt/operator/DESCOp.h
@@ -0,0 +1,82 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_DESCOP
+#define _H_DESCOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class DESCOp: public MAdOperatorBase
+ {
+ public:
+
+ DESCOp(pMesh, DiscreteSF *);
+ DESCOp(const DESCOp &);
+ ~DESCOp() {}
+
+ operationType type() const { return MAd_DESPLTCLPS; }
+
+ void setDESC(pRegion, pEdge, pEdge);
+
+ void getCavity(pPList *) const;
+
+ void apply();
+
+ private:
+
+ bool checkConstraints() const;
+ bool checkGeometry();
+ bool evaluateShapes();
+ void evaluateLengths() const;
+
+ private:
+
+ pRegion region;
+ pEdge splitE[2];
+ double xyz[3];
+ };
+
+
+ // -------------------------------------------------------------------
+ inline DESCOp::DESCOp(const DESCOp &_desc):
+ MAdOperatorBase(_desc)
+ {
+ region = _desc.region;
+ splitE[0] = _desc.splitE[0];
+ splitE[1] = _desc.splitE[1];
+
+ xyz[0] = _desc.xyz[0];
+ xyz[1] = _desc.xyz[1];
+ xyz[2] = _desc.xyz[2];
+ }
+
+ // -------------------------------------------------------------------
+ inline DESCOp::DESCOp(pMesh _m, DiscreteSF * _sf):
+ MAdOperatorBase(_m,_sf), region(NULL)
+ {
+ splitE[0] = NULL;
+ splitE[1] = NULL;
+
+ xyz[0] = 0.0;
+ xyz[1] = 0.0;
+ xyz[2] = 0.0;
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/EdgeCollapseOp.cc b/Adapt/operator/EdgeCollapseOp.cc
new file mode 100644
index 0000000..7268214
--- /dev/null
+++ b/Adapt/operator/EdgeCollapseOp.cc
@@ -0,0 +1,399 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "EdgeCollapseOp.h"
+#include "OperatorTools.h"
+#include <map>
+
+using std::map;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ bool edgeCollapseOp::checkConstraints() const
+ {
+ if ( EN_constrained((pEntity)edgeDel) ) return false;
+ if ( EN_constrained((pEntity)vDel ) ) return false;
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool edgeCollapseOp::checkGeometry()
+ {
+ int typeD = V_whatInType(vDel);
+ if ( typeD == 0 ) return false;
+
+ if ( constrainBoundary ) {
+ switch( typeD ) {
+ case 3: break;
+ case 2:
+ {
+ bool ok = true;
+ pPList eRgns = E_regions(edgeDel);
+ if( PList_size(eRgns) != 0 ) ok = false;
+ PList_delete(eRgns);
+ if (!ok) return false;
+ break;
+ }
+ case 1: return false;
+ case 0: return false;
+ }
+ }
+ else {
+ // check in edgeDel
+ if ( V_whatIn(vDel) != E_whatIn(edgeDel) ) return false;
+
+ if ( V_whatInType(vDel) <= 2 )
+ {
+ // check in every tet around edgeDel (= to be collapsed):
+ // - no dimension reduction surface on surface
+ pEdge oppE;
+ pFace newSurfaceFace;
+ pPList vDelFaces = V_faces(vDel);
+ void * temp = NULL;
+ pFace pf;
+ while ( ( pf = (pFace)PList_next(vDelFaces,&temp) ) ) {
+ if ( F_inClosure(pf,edgeDel) ) continue;
+ if ( F_whatInType(pf) == 2 ) {
+ oppE = F_vtOpEd(pf,vDel);
+ newSurfaceFace = F_exist(oppE,vTgt);
+ if ( newSurfaceFace && F_whatInType(newSurfaceFace) == 2 ) {
+ PList_delete(vDelFaces);
+ return false;
+ }
+ }
+ }
+ PList_delete(vDelFaces);
+
+
+ // check in every face around edge del (= to be collapsed):
+ // - the face exists (that's why we loop over edges, not faces)
+ // - no new contact between surface and line
+ // - no new contact between surface and surface
+ // - no dimension reduction line on line
+ //
+ // vTgt
+ //
+ // | \
+ // | \
+ // | \
+ // | \ oppE
+ // edgeDel | \
+ // | pf \
+ // | \
+ // | \
+ //
+ // vDel ----- oppV
+ //
+ // pe
+
+ pVertex oppV;
+ pEdge pe;
+ pPList vDelEdges = V_edges(vDel);
+ temp = NULL;
+ while ( ( pe = (pEdge)PList_next(vDelEdges,&temp) ) ) {
+ if ( pe == edgeDel ) continue;
+ int d1 = E_whatInType(pe);
+ if ( d1 <= 2 ) {
+ oppV = E_otherVertex(pe,vDel);
+ oppE = E_exist(oppV,vTgt);
+ if ( oppE ) {
+ int d2 = E_whatInType(oppE);
+ if ( d2 <= 2 ) {
+ pf = F_exist(oppE,vDel);
+
+ // check if the face exists
+ if ( !pf ) {
+ PList_delete(vDelEdges); return false;
+ }
+
+ // check for line on line dimension reduction
+ if ( d1 == 1 && d2 == 1 ) {
+ PList_delete(vDelEdges); return false;
+ }
+
+ pGEntity fge = F_whatIn(pf);
+
+ // check for new contacts between a line and a surface
+ if ( d1 == 1 && d2 == 2 && fge != E_whatIn(oppE) ) {
+ PList_delete(vDelEdges); return false;
+ }
+ if ( d1 == 2 && d2 == 1 && fge != E_whatIn(pe) ) {
+ PList_delete(vDelEdges); return false;
+ }
+
+ // check for new contacts between 2 surfaces
+ if ( d1 == 2 && d2 == 2 ) {
+ if ( fge != E_whatIn(pe) || fge != E_whatIn(oppE) ) {
+ PList_delete(vDelEdges); return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ PList_delete(vDelEdges);
+
+ }
+ }
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool edgeCollapseOp::evaluateShapes2D()
+ {
+ pPList vDelFaces = V_faces(vDel);
+
+ double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+ map<pGEntity,double> area_after;
+
+ void * temp1 = 0;
+ while ( pFace face = (pFace)PList_next(vDelFaces,&temp1) ) {
+
+ // Faces surrounding edgeDel will be deleted
+ if (F_inClosure(face,(pEntity)edgeDel)) continue;
+
+ // Gather the coordinates and sizes of the new face
+ double xyz[3][3];
+ pMSize fSizes[3] = {NULL,NULL,NULL};
+
+ pPList fVerts = F_vertices(face,1);
+ void * temp2 = 0;
+ int iV = 0;
+ while ( pVertex vertex = (pVertex)PList_next(fVerts, &temp2) ) {
+ if (vertex == vDel) {
+ fSizes[iV] = sizeField->findSize(vTgt);
+ V_coord(vTgt,xyz[iV]);
+ }
+ else {
+ fSizes[iV] = sizeField->findSize(vertex);
+ V_coord(vertex,xyz[iV]);
+ }
+ iV++;
+ }
+ PList_delete(fVerts);
+
+ // Check if the shape is acceptable and compare it to the worst shape
+ double shape = 0.;
+ double normalBefore[3];
+ F_normal(face,normalBefore);
+ if ( !mqm.getElementEvaluator()->XYZ_F_shape(xyz, fSizes, normalBefore, &shape) ) {
+ PList_delete(vDelFaces);
+ return false;
+ }
+ else {
+ if ( shape < worstShape ) worstShape = shape;
+ }
+
+ // Compute the area of the new face
+ if( !constrainBoundary && V_whatInType(vDel) < 2 ) {
+
+ pGEntity g = F_whatIn(face);
+ std::map<pGEntity,double>::iterator it = area_after.find( g );
+ if( it != area_after.end() )
+ (*it).second += XYZ_F_area(xyz,normalBefore);
+ else
+ area_after[g] = XYZ_F_area(xyz,normalBefore);
+ }
+ }
+
+ // If the edge is on a boundary, check that the area of
+ // the old and the new cavities are the same for each Geo entities
+ if( !constrainBoundary && V_whatInType(vDel) < 2 ) {
+ map< pGEntity,double> area_before;
+ map<pGEntity,double>::iterator it, it2;
+
+ void * temp3 = 0;
+ while ( pFace face = (pFace)PList_next(vDelFaces,&temp3) ) {
+ double normal[3];
+ F_normal(face,normal);
+ pGEntity g = F_whatIn(face);
+ it = area_before.find( g );
+ if( it != area_before.end() )
+ (*it).second += F_area(face,normal);
+ else
+ area_before[g] = F_area(face,normal);
+ }
+
+ for( it=area_before.begin(); it!=area_before.end(); ++it )
+ {
+ double before = (*it).second;
+ double after( 0.0 );
+ it2 = area_after.find( (*it).first );
+ if( it2 != area_after.end() )
+ after = (*it2).second;
+
+ // Check area change
+ double dA = fabs( (before-after) / before );
+ if( dA > dATol ) {
+ PList_delete(vDelFaces);
+ return false;
+ }
+ }
+ }
+ results->setWorstShape(worstShape);
+
+ PList_delete(vDelFaces);
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool edgeCollapseOp::evaluateShapes()
+ {
+ pPList vDelRgns = V_regions(vDel);
+
+ // 2D case
+ if( PList_size(vDelRgns)==0 ) {
+ bool flag = evaluateShapes2D();
+ PList_delete(vDelRgns);
+ return flag;
+ }
+
+ // 3D case
+ else {
+
+ double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+ double volAfter = 0.;
+
+ void * temp1 = 0;
+ while ( pRegion region = (pRegion)PList_next(vDelRgns,&temp1) ) {
+
+ // Regions surrounding edgeDel will be deleted
+ if (R_inClosure(region,(pEntity)edgeDel)) continue;
+
+ // Gather the coordinates and sizes of the new region
+ double xyz[4][3];
+ pMSize rSizes[4] = {NULL,NULL,NULL,NULL};
+
+ pPList rVerts = R_vertices(region);
+ void * temp2 = 0;
+ int iV = 0;
+ while ( pVertex vertex = (pVertex)PList_next(rVerts, &temp2) ) {
+ if (vertex == vDel) {
+ rSizes[iV] = sizeField->findSize(vTgt);
+ V_coord(vTgt,xyz[iV]);
+ }
+ else {
+ rSizes[iV] = sizeField->findSize(vertex);
+ V_coord(vertex,xyz[iV]);
+ }
+ iV++;
+ }
+ PList_delete(rVerts);
+
+ // Check if the shape is acceptable and compare it to the worst shape
+ double shape = 0.;
+ if ( !mqm.getElementEvaluator()->XYZ_R_shape(xyz, rSizes, &shape) ) {
+ PList_delete(vDelRgns);
+ return false;
+ }
+ else {
+ if ( shape < worstShape ) worstShape = shape;
+ }
+
+ // Compute the volume of the new region
+ if( !constrainBoundary && V_whatInType(vDel)!=3 ) {
+ volAfter += R_XYZ_volume (xyz);
+ }
+ }
+
+ // If the edge is on a boundary, check that the volume of
+ // the old and the new cavities are the same
+ if( !constrainBoundary && V_whatInType(vDel)!=3 ) {
+
+ double volBefore = 0.;
+
+ void * temp3 = 0;
+ while ( pRegion region = (pRegion)PList_next(vDelRgns,&temp3) ) {
+ volBefore += R_volume (region);
+ }
+
+ double dV = fabs( (volBefore-volAfter) / volBefore );
+ if( dV > dVTol ) {
+ PList_delete(vDelRgns);
+ return false;
+ }
+ }
+
+ results->setWorstShape(worstShape);
+ }
+
+ PList_delete(vDelRgns);
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void edgeCollapseOp::evaluateLengths() const
+ {
+ double minSq = MAdBIG, maxSq = 0.;
+
+ double xyzTgt[3];
+ V_coord(vTgt,xyzTgt);
+ pMSize sizeTgt = sizeField->findSize(vTgt);
+
+ // list nodes linked to target vertex by an edge
+ std::set<pVertex> vTgtLinked;
+ pPList vTgtEdges = V_edges(vTgt);
+ void * temp1 = 0;
+ while ( pEdge edge = (pEdge) PList_next(vTgtEdges,&temp1) ) {
+ vTgtLinked.insert(E_vertex(edge,0));
+ vTgtLinked.insert(E_vertex(edge,1));
+ }
+ PList_delete(vTgtEdges);
+
+ // find nodes linked to vDel and not linked to vTgt
+ pPList vDelEdges = V_edges(vDel);
+ void * temp2 = 0;
+ while ( pEdge edge = (pEdge) PList_next(vDelEdges,&temp2) ) {
+ for (int iV=0; iV<2; iV++) {
+ pVertex pV = E_vertex(edge,iV);
+ if ( pV == vDel ) continue;
+ if ( vTgtLinked.find(pV) != vTgtLinked.end() ) continue;
+
+ double xyzV[3];
+ V_coord(pV,xyzV);
+ pMSize sizeV = sizeField->findSize(pV);
+
+ double newSq = sizeField->SF_XYZ_lengthSq(xyzTgt,xyzV,sizeTgt,sizeV);
+ if( newSq < minSq ) { minSq = newSq; }
+ if( newSq > maxSq ) { maxSq = newSq; }
+ }
+ }
+ PList_delete(vDelEdges);
+
+ results->setMaxLenSq(maxSq);
+ results->setMinLenSq(minSq);
+ }
+
+ // -------------------------------------------------------------------
+ void edgeCollapseOp::getCavity(pPList * cavity) const
+ {
+ if ( dim == 3 ) *cavity = V_regions(vDel);
+ else *cavity = V_faces(vDel);
+ }
+
+ // -------------------------------------------------------------------
+ void edgeCollapseOp::apply()
+ {
+ E_collapse(mesh, edgeDel, vDel, vTgt);
+
+ HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
diff --git a/Adapt/operator/EdgeCollapseOp.h b/Adapt/operator/EdgeCollapseOp.h
new file mode 100644
index 0000000..5790fc4
--- /dev/null
+++ b/Adapt/operator/EdgeCollapseOp.h
@@ -0,0 +1,105 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_EDGECOLLAPSEOP
+#define _H_EDGECOLLAPSEOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class edgeCollapseOp: public MAdOperatorBase
+ {
+ public:
+
+ edgeCollapseOp(pMesh, DiscreteSF *);
+ edgeCollapseOp(const edgeCollapseOp &);
+ ~edgeCollapseOp() {}
+
+ operationType type() const { return MAd_ECOLLAPSE; }
+
+ void collapseOnBoundary(bool, double);
+ void setCollapseEdge(pEdge, pVertex, pVertex);
+
+ void getCavity(pPList *) const;
+
+ void apply();
+
+ private:
+
+ bool checkConstraints() const;
+ bool checkGeometry();
+ bool evaluateShapes();
+ bool evaluateShapes2D();
+ void evaluateLengths() const;
+
+ private:
+
+ pEdge edgeDel;
+ pVertex vDel; // the vertex to be deleted
+ pVertex vTgt; // the target vertex
+
+ bool constrainBoundary;
+ double dVTol, dATol; // tolerance on the relative change of volume or area
+ };
+
+ // -------------------------------------------------------------------
+ inline edgeCollapseOp::edgeCollapseOp(const edgeCollapseOp & _ec):
+ MAdOperatorBase(_ec)
+ {
+ edgeDel = _ec.edgeDel;
+ vDel = _ec.vDel;
+ vTgt = _ec.vTgt;
+ constrainBoundary = _ec.constrainBoundary;
+ dVTol = _ec.dVTol;
+ dATol = _ec.dATol;
+ }
+
+ // -------------------------------------------------------------------
+ inline edgeCollapseOp::edgeCollapseOp(pMesh _m, DiscreteSF * _sf):
+ MAdOperatorBase(_m,_sf)
+ {
+ edgeDel = NULL;
+ vDel = NULL;
+ vTgt = NULL;
+ constrainBoundary = true;
+ dVTol = MAdTOL;
+ dATol = MAdTOL;
+ }
+
+ // -------------------------------------------------------------------
+ inline void edgeCollapseOp::collapseOnBoundary(bool cob, double tolerance)
+ {
+ constrainBoundary = !cob;
+ dVTol = tolerance;
+ dATol = tolerance;
+ }
+
+ // -------------------------------------------------------------------
+ inline void edgeCollapseOp::setCollapseEdge(pEdge _edgeDel,
+ pVertex _vDel,
+ pVertex _vTgt)
+ {
+ edgeDel = _edgeDel;
+ vDel = _vDel;
+ vTgt = _vTgt;
+ results->reset();
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
+
diff --git a/Adapt/operator/EdgeSplitOp.cc b/Adapt/operator/EdgeSplitOp.cc
new file mode 100644
index 0000000..4590560
--- /dev/null
+++ b/Adapt/operator/EdgeSplitOp.cc
@@ -0,0 +1,207 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "EdgeSplitOp.h"
+#include "OperatorTools.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ bool edgeSplitOp::checkConstraints() const
+ {
+ if ( EN_constrained((pEntity)edge) ) return false;
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool edgeSplitOp::checkGeometry()
+ {
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool edgeSplitOp::evaluateShapes()
+ {
+ pPList eRegs = E_regions(edge);
+
+ // 2D case
+ if ( PList_size(eRegs) == 0 ) {
+ bool flag = evaluateShapes2D();
+ PList_delete(eRegs);
+ return flag;
+ }
+
+ // 3D case
+ else {
+
+ double worstShape = MAdBIG;
+
+ void * temp = 0;
+ while ( pRegion region = (pRegion)PList_next(eRegs,&temp) ) {
+
+ pPList rVerts = R_vertices(region);
+
+ // evaluate the two regions resulting from the split
+ for( int iR=0; iR<2; iR++ ) {
+
+ pVertex eV = E_vertex(edge,iR);
+
+ pMSize rSizes[4] = { NULL, NULL, NULL, NULL };
+ double rCoords[4][3];
+
+ pVertex pV = NULL;
+ void * iter = NULL;
+ for( int iRV=0; (pV=(pVertex)PList_next(rVerts,&iter) ); iRV++ ) {
+ if( pV == eV ) {
+ rSizes[iRV] = xyzSize;
+ rCoords[iRV][0] = xyz[0];
+ rCoords[iRV][1] = xyz[1];
+ rCoords[iRV][2] = xyz[2];
+ }
+ else {
+ rSizes[iRV] = sizeField->findSize(pV);
+ V_coord(pV,rCoords[iRV]);
+ }
+ }
+
+ double rShape;
+ if( !mqm.getElementEvaluator()->XYZ_R_shape(rCoords,rSizes,&rShape) ) {
+ PList_delete (eRegs);
+ PList_delete (rVerts);
+ return false;
+ }
+
+ if( worstShape > rShape ) worstShape = rShape;
+ }
+ PList_delete(rVerts);
+ }
+
+ results->setWorstShape(worstShape);
+ }
+
+ PList_delete(eRegs);
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool edgeSplitOp::evaluateShapes2D()
+ {
+ double worstShape = MAdBIG;
+
+ pPList eFaces = E_faces(edge);
+
+ void * temp = NULL;
+ while ( pFace face = (pFace)PList_next(eFaces,&temp) ) {
+
+ pPList fVerts = F_vertices(face,1);
+
+ // evaluate the two faces resulting from the split
+ for( int iF=0; iF<2; iF++ ) {
+
+ pVertex eV = E_vertex(edge,iF);
+
+ pMSize fSizes[3] = { NULL, NULL, NULL };
+ double fCoords[3][3];
+
+ pVertex pV;
+ void * iter = NULL;
+ for( int iFV=0; (pV=(pVertex)PList_next(fVerts,&iter)); iFV++ ) {
+ if( pV == eV ) {
+ fSizes[iFV] = xyzSize;
+ fCoords[iFV][0] = xyz[0];
+ fCoords[iFV][1] = xyz[1];
+ fCoords[iFV][2] = xyz[2];
+ }
+ else {
+ fSizes[iFV] = sizeField->findSize(pV);
+ V_coord(pV,fCoords[iFV]);
+ }
+ }
+
+ double fShape;
+ if( !mqm.getElementEvaluator()->XYZ_F_shape(fCoords,fSizes,0,&fShape) ) {
+ PList_delete (eFaces);
+ PList_delete (fVerts);
+ return false;
+ }
+
+ if( worstShape > fShape ) worstShape = fShape;
+ }
+
+ PList_delete(fVerts);
+ }
+
+ PList_delete(eFaces);
+
+ results->setWorstShape(worstShape);
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void edgeSplitOp::evaluateLengths() const
+ {
+ pVertex verts[2];
+ double vCoords[2][3];
+ pMSize vSizes[2] = {NULL,NULL};
+ for( int iV=0; iV<2; iV++ ) {
+ verts[iV] = E_vertex(edge,iV);
+ V_coord(verts[iV],vCoords[iV]);
+ vSizes[iV] = sizeField->findSize(verts[iV]);
+ }
+
+ pMSize newSize = sizeField->getSizeOnEntity((pEntity)edge,xyz);
+
+ double lSqMax = sizeField->SF_XYZ_lengthSq(xyz, vCoords[0],
+ newSize, vSizes[0]);
+ double lSqMin = lSqMax;
+ double lSq = sizeField->SF_XYZ_lengthSq(xyz, vCoords[1],
+ newSize, vSizes[1]);
+ if( lSq > lSqMax ) lSqMax = lSq;
+ if( lSq < lSqMin ) lSqMin = lSq;
+
+ for( int i=0; i<E_numFaces(edge); i++ ) {
+ pVertex oppV = F_edOpVt(E_face(edge,i), edge);
+ pMSize oppSize = sizeField->findSize(oppV);
+ double xyzOpp[3];
+ V_coord(oppV,xyzOpp);
+ lSq = sizeField->SF_XYZ_lengthSq(xyz, xyzOpp,
+ newSize, oppSize);
+ if( lSq > lSqMax ) lSqMax = lSq;
+ if( lSq < lSqMin ) lSqMin = lSq;
+ }
+
+ if( newSize ) delete newSize;
+
+ results->setMaxLenSq(lSqMax);
+ results->setMinLenSq(lSqMin);
+ }
+
+ // -------------------------------------------------------------------
+ void edgeSplitOp::getCavity(pPList * cavity) const
+ {
+ if ( dim == 3 ) *cavity = E_regions(edge);
+ else *cavity = E_faces(edge);
+ }
+
+ // -------------------------------------------------------------------
+ void edgeSplitOp::apply()
+ {
+ E_split(mesh,edge,xyz,u);
+
+ HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/EdgeSplitOp.h b/Adapt/operator/EdgeSplitOp.h
new file mode 100644
index 0000000..fa0becb
--- /dev/null
+++ b/Adapt/operator/EdgeSplitOp.h
@@ -0,0 +1,92 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_EDGESPLITOP
+#define _H_EDGESPLITOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class edgeSplitOp: public MAdOperatorBase
+ {
+ public:
+
+ edgeSplitOp(pMesh, DiscreteSF *);
+ edgeSplitOp(const edgeSplitOp &);
+ ~edgeSplitOp() { if (xyzSize) delete xyzSize; }
+
+ operationType type() const { return MAd_ESPLIT; }
+
+ // stores the edge to be splitted, computes the location of the split
+ // and returns the (unique) adimensional square length of the resulting edges
+ double setSplitEdge(pEdge);
+
+ void getCavity(pPList *) const;
+
+ void apply();
+
+ private:
+
+ bool checkConstraints() const;
+ bool checkGeometry();
+ bool evaluateShapes();
+ bool evaluateShapes2D();
+ void evaluateLengths() const;
+
+ private:
+
+ pEdge edge;
+ double xyz[3], u; // new vertex location: euclidian and edge parameter
+ pMSize xyzSize; // size at the new vertex
+ };
+
+ // -------------------------------------------------------------------
+ inline edgeSplitOp::edgeSplitOp(const edgeSplitOp & _es):
+ MAdOperatorBase(_es)
+ {
+ edge = _es.edge;
+ xyz[0] = _es.xyz[0];
+ xyz[1] = _es.xyz[1];
+ xyz[2] = _es.xyz[2];
+ u = _es.u;
+ xyzSize = MS_copy(_es.xyzSize);
+ }
+
+ // -------------------------------------------------------------------
+ inline edgeSplitOp::edgeSplitOp(pMesh _m, DiscreteSF * _sf):
+ MAdOperatorBase(_m,_sf), edge(NULL)
+ {
+ xyz[0] = 0.;
+ xyz[1] = 0.;
+ xyz[2] = 0.;
+ u = -1.;
+ xyzSize = NULL;
+ }
+
+ // -------------------------------------------------------------------
+ inline double edgeSplitOp::setSplitEdge(pEdge _edge)
+ {
+ if ( xyzSize ) delete xyzSize;
+ edge = _edge;
+ double lenReduc;
+ u = sizeField->SF_E_center(_edge,xyz,&lenReduc,&xyzSize);
+ return lenReduc;
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/EdgeSwapConfig.cc b/Adapt/operator/EdgeSwapConfig.cc
new file mode 100644
index 0000000..53ff7e4
--- /dev/null
+++ b/Adapt/operator/EdgeSwapConfig.cc
@@ -0,0 +1,75 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Arnaud Francois, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "EdgeSwapConfig.h"
+#include <iostream>
+
+using namespace MAd;
+
+// -------------------------------------------------------------------
+// Edge swap template with 3 faces connected to the edge
+const int EdgeSwap3::triangles[1][3] = { { 0,1,2 } };
+const int EdgeSwap3::triangulations[1][1] = {{0}};
+
+// Edge swap template with 4 faces connected to the edge
+const int EdgeSwap4::triangles[4][3] = { {0,1,2}, {0,2,3}, {0,1,3}, {1,2,3} };
+const int EdgeSwap4::triangulations[2][2] = { {0, 1}, {2, 3} };
+
+// Edge swap template with 5 faces connected to the edge
+const int EdgeSwap5::triangles[10][3]= { {0,1,2}, {0,2,3}, {0,3,4}, {0,1,4}, {1,3,4},
+ {1,2,3}, {2,3,4}, {0,2,4}, {0,1,3}, {1,2,4} };
+const int EdgeSwap5::triangulations[5][3] = { {0,1,2}, {3,4,5}, {0,6,7}, {2,5,8}, {3,6,9} } ;
+
+// Edge swap template with 6 faces connected to the edge
+const int EdgeSwap6::triangles[20][3]= { {0,1,2}, {0,2,3}, {0,3,4}, {0,4,5},
+ {0,2,5}, {2,4,5}, {2,3,4}, {0,3,5}, {3,4,5}, {0,2,4}, {2,3,5}, {1,2,3},
+ {0,1,3}, {0,1,5}, {1,4,5}, {1,3,4}, {0,1,4}, {1,3,5}, {1,2,4}, {1,2,5} };
+const int EdgeSwap6::triangulations[14][4] = { {0,1,2,3}, {0,4,5,6}, {0,1,7,8},
+ {0,3,6,9}, {0,4,8,10}, {2,3,11,12}, {11,13,14,15}, {7,8,11,12}, {3,11,15,16},
+ {8,11,13,17}, {6,13,14,18}, {3,6,16,18}, {5,6,13,19}, {8,10,13,19} };
+
+// Edge swap template with 7 faces connected to the edge
+const int EdgeSwap7::triangles[35][3] = { {0,1,2}, {0,2,3}, {0,3,4}, {0,4,5},
+ {0,5,6}, {0,3,6}, {3,5,6}, {3,4,5}, {0,4,6}, {4,5,6}, {0,3,5}, {3,4,6},
+ {0,2,4}, {2,3,4}, {0,2,6}, {2,5,6}, {2,4,5}, {0,2,5}, {2,4,6}, {2,3,5},
+ {2,3,6}, {0,1,3}, {1,2,3}, {0,1,4}, {1,3,4}, {0,1,6}, {1,5,6}, {1,4,5},
+ {0,1,5}, {1,4,6}, {1,3,5}, {1,3,6}, {1,2,4}, {1,2,5}, {1,2,6} };
+const int EdgeSwap7::triangulations[42][5] = { {0,1,2,3,4}, {0,1,5,6,7},
+ {0,1,2,8,9}, {0,1,4,7,10}, {0,1,5,9,11}, {0,3,4,12,13}, {0,13,14,15,16},
+ {0,8,9,12,13}, {0,4,13,16,17}, {0,9,13,14,18}, {0,7,14,15,19},{0,4,7,17,19},
+ {0,6,7,14,20}, {0,9,11,14,20}, {2,3,4,21,22}, {5,6,7,21,22}, {2,8,9,21,22},
+ {4,7,10,21,22}, {5,9,11,21,22}, {3,4,22,23,24}, {22,24,25,26,27},
+ {8,9,22,23,24}, {4,22,24,27,28}, {9,22,24,25,29}, {7,22,25,26,30},
+ {4,7,22,28,30}, {6,7,22,25,31}, {9,11,22,25,31}, {3,4,13,23,32},
+ {13,25,26,27,32}, {8,9,13,23,32}, {4,13,27,28,32}, {9,13,25,29,32},
+ {13,16,25,26,33}, {4,13,16,28,33}, {13,15,16,25,34}, {9,13,18,25,34},
+ {7,19,25,26,33}, {4,7,19,28,33}, {7,15,19,25,34}, {6,7,20,25,34},
+ {9,11,20,25,34} };
+
+// -------------------------------------------------------------------
+void EdgeSwapConfiguration::set( int i )
+{
+ switch( i )
+ {
+ case 0: c = &cNull; break;
+ case 3: c = &c3; break;
+ case 4: c = &c4; break;
+ case 5: c = &c5; break;
+ case 6: c = &c6; break;
+ case 7: c = &c7; break;
+ default:
+ std::cerr << "Error: Swap configuration not implemented for n="<< i << std::endl;
+ throw;
+ }
+}
+
+// -------------------------------------------------------------------
diff --git a/Adapt/operator/EdgeSwapConfig.h b/Adapt/operator/EdgeSwapConfig.h
new file mode 100644
index 0000000..975e8c0
--- /dev/null
+++ b/Adapt/operator/EdgeSwapConfig.h
@@ -0,0 +1,173 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Arnaud Francois, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_EDGESWAPCONFIG
+#define _H_EDGESWAPCONFIG
+
+namespace MAd
+{
+ // -------------------------------------------------------------------
+ class EdgeSwapTemplate // 3D case
+ {
+ public:
+ EdgeSwapTemplate() {}
+ virtual ~EdgeSwapTemplate() {}
+ virtual int getConfig(){ return 0; } // nb of faces attached to edge
+ virtual int nb_triangulations() = 0; // nb of possible triangulations
+ virtual int nb_triangles() = 0; // nb of different triangles
+ virtual int nb_tri_triangulation() = 0; // nb of triangles in a triangulation
+ virtual const int* triangle( int i ) = 0; // return the triangle i
+ virtual const int* triangulation( int i ) = 0; // return the triangulation i
+ };
+
+ // -------------------------------------------------------------------
+ // Null edge swap template
+ class EdgeSwap0 : public EdgeSwapTemplate
+ {
+ public:
+ EdgeSwap0() { }
+ int getConfig(){ return 0; }
+ int nb_triangles(){ return -1; }
+ int nb_triangulations(){ return -1; }
+ int nb_tri_triangulation(){ return -1; }
+ const int* triangle( int i) { return 0; }
+ const int* triangulation( int i) { return 0; }
+ };
+
+ // -------------------------------------------------------------------
+ // Edge swap template with 3 faces connected to the edge
+ class EdgeSwap3 : public EdgeSwapTemplate
+ {
+ public:
+ EdgeSwap3() { }
+ int getConfig(){ return 3; }
+ int nb_triangles(){ return 1; }
+ int nb_triangulations(){ return 1; }
+ int nb_tri_triangulation(){ return 1; }
+ const int* triangle( int i) { return triangles[i]; }
+ const int* triangulation( int i) { return triangulations[i]; }
+ private:
+ static const int triangles[1][3];
+ static const int triangulations[1][1];
+ };
+
+ // -------------------------------------------------------------------
+ // Edge swap template with 4 faces connected to the edge
+ class EdgeSwap4 : public EdgeSwapTemplate
+ {
+ public:
+ EdgeSwap4() { }
+ int getConfig(){ return 4; }
+ int nb_triangles(){ return 4; }
+ int nb_triangulations(){ return 2; }
+ int nb_tri_triangulation(){ return 2; }
+ const int* triangle( int i) { return triangles[i]; }
+ const int* triangulation( int i) { return triangulations[i]; }
+ private:
+ static const int triangles[4][3];
+ static const int triangulations[2][2];
+ };
+
+ // -------------------------------------------------------------------
+ // Edge swap template with 5 faces connected to the edge
+ class EdgeSwap5 : public EdgeSwapTemplate
+ {
+ public:
+ EdgeSwap5() { }
+ int getConfig(){ return 5; }
+ int nb_triangles(){ return 10; }
+ int nb_triangulations(){ return 5; }
+ int nb_tri_triangulation(){ return 3; }
+ const int* triangle( int i) { return triangles[i]; }
+ const int* triangulation( int i) { return triangulations[i]; }
+ private:
+ static const int triangles[10][3];
+ static const int triangulations[5][3];
+ };
+
+ // -------------------------------------------------------------------
+ // Edge swap template with 6 faces connected to the edge
+ class EdgeSwap6 : public EdgeSwapTemplate
+ {
+ public:
+ EdgeSwap6() { }
+ int getConfig(){ return 6; }
+ int nb_triangles(){ return 20; }
+ int nb_triangulations(){ return 14; }
+ int nb_tri_triangulation(){ return 4; }
+ const int* triangle( int i) { return triangles[i]; }
+ const int* triangulation( int i) { return triangulations[i]; }
+ protected:
+ static const int triangles[20][3];
+ static const int triangulations[14][4];
+ };
+
+ // -------------------------------------------------------------------
+ // Edge swap template with 7 faces connected to the edge
+ class EdgeSwap7 : public EdgeSwapTemplate
+ {
+ public:
+ EdgeSwap7() { }
+ int getConfig(){ return 7; }
+ int nb_triangles(){ return 35; }
+ int nb_triangulations(){ return 42; }
+ int nb_tri_triangulation(){ return 5; }
+ const int* triangle( int i) { return triangles[i]; }
+ const int* triangulation( int i) { return triangulations[i]; }
+ protected:
+ static const int triangles[35][3];
+ static const int triangulations[42][5];
+ };
+
+ // -------------------------------------------------------------------
+ // Interface
+ class EdgeSwapConfiguration
+ {
+ public:
+
+ EdgeSwapConfiguration( ) { set(0); }
+ EdgeSwapConfiguration( int n ) { set( n ); }
+ EdgeSwapConfiguration( const EdgeSwapConfiguration &x ) { set( x.get() ); }
+ ~EdgeSwapConfiguration() { }
+
+ // select edge swap template with n faces connected to the edge
+ void set( int n );
+
+ // return the nodes of triangle i for the selected configuration
+ const int* triangle( int i ) const { return (*c).triangle(i); }
+
+ // return the node j of triangle i for the selected configuration
+ int triangle( int i, int j ) const { return (*c).triangle(i)[j]; }
+
+ // return the triangle j of triangulation i
+ int triangulation( int i, int j ) const { return (*c).triangulation(i)[j]; }
+
+ int nb_triangles() const { return c->nb_triangles(); }
+ int nb_triangulations() const { return c->nb_triangulations(); }
+ int nb_tri_triangulation() const { return c->nb_tri_triangulation(); }
+
+ int get() const { return c->getConfig(); }
+
+ private:
+ EdgeSwap0 cNull;
+ EdgeSwap3 c3;
+ EdgeSwap4 c4;
+ EdgeSwap5 c5;
+ EdgeSwap6 c6;
+ EdgeSwap7 c7;
+ EdgeSwapTemplate * c;
+ };
+
+ // -------------------------------------------------------------------
+}
+#endif
diff --git a/Adapt/operator/EdgeSwapOp.cc b/Adapt/operator/EdgeSwapOp.cc
new file mode 100644
index 0000000..8cb975d
--- /dev/null
+++ b/Adapt/operator/EdgeSwapOp.cc
@@ -0,0 +1,576 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Arnaud Francois, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "EdgeSwapOp.h"
+#include "MAdDefines.h"
+#include "CallBackManager.h"
+#include "MAdOutput.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+
+#include <iostream>
+#include <sstream>
+using std::cout;
+using std::endl;
+using std::cerr;
+using std::stringstream;
+#include <math.h>
+
+namespace MAd
+{
+ // -------------------------------------------------------------------
+ bool edgeSwapOp::checkConstraints() const
+ {
+ if( EN_constrained((pEntity)edge) ) return false;
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool edgeSwapOp::checkGeometry()
+ {
+ // set the available swap configurations for a given edge
+ // regarding geometry
+ if( M_numRegions(mesh)==0 ) return checkGeometry2D(); // 2D mesh
+ else return checkGeometry3D(); // 3D mesh
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ bool edgeSwapOp::checkGeometry2D()
+ {
+ if ( E_numFaces(edge) != 2 ) return false;
+ if ( E_whatInType(edge) <= 1 ) return false;
+
+ // check for dimension reduction
+ pFace face0 = E_face(edge,0);
+ pVertex pv0 = F_edOpVt(face0,edge);
+ pFace face1 = E_face(edge,1);
+ pVertex pv1 = F_edOpVt(face1,edge);
+ if ( E_exist(pv0,pv1) ) return false;
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ // Set the swap configuration to be used. Return false if the edge swap
+ // operation is not allowed
+ bool edgeSwapOp::checkGeometry3D()
+ {
+ int nbf = E_numFaces(edge); // nb of faces attached to the edge
+ if( nbf < 3 || nbf >7 ) // check if swap configuration is implemented
+ return false;
+
+ // check the dimension of the geometrical entity on which edge is classified
+ bool boundarySwap = false;
+ int gDim = E_whatInType(edge);
+ if( gDim == 1 ) return false;
+ else if ( gDim == 2 )
+ {
+ if ( constrainBoundary ) return false;
+ else {
+ checkVol = true;
+ boundarySwap = true;
+ }
+ }
+
+ // get 'face' that connects to edge. if one classified on a surface, take that
+ // one, otherwise take any (e.g. last one)
+ int nbBFaces = 0;
+ pFace face;
+ pFace bFace=NULL;
+ for( int i=0; i < nbf; i++ )
+ {
+ face = E_face(edge,i);
+ if( F_whatInType(face) == 2 ) {
+ nbBFaces++;
+ bFace = face;
+ }
+ }
+ if (bFace) face = bFace;
+
+ // reject swaps on non-manifold cavities
+ if ( nbBFaces > 2 || nbBFaces == 1 ) {
+ exportCavity("swap_nonmanif1.pos");
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Found a non-manifold domain, rejecting edge swap");
+ return false;
+ }
+
+ // get region connected to face
+ pRegion region = F_region(face,0);
+ if( !region ) region = F_region(face,1);
+
+ // Get vertices of the polyhedron around 'edge'
+ vertices.clear();
+ vertices.resize(nbf);
+ pFace current_face = face;
+ pRegion current_region = region;
+ for( int i=0; i < nbf; i++ )
+ {
+ vertices[i] = F_edOpVt(current_face, edge);
+
+ if (i == (nbf-1)) {
+ if ( boundarySwap && current_region != NULL ) {
+ // non-manifold-domain: a geometrical face with 2 regions
+ exportCavity("swap_nonmanif2.pos");
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Found a non-manifold domain, rejecting edge swap");
+ return false;
+ }
+ }
+ else {
+ pFace next_face = E_otherFace(edge, current_face, current_region);
+ pRegion next_region = F_region(next_face, 0);
+ if( next_region == current_region ) {
+ next_region = F_region(next_face, 1);
+ }
+ current_face = next_face;
+ current_region = next_region;
+ }
+ }
+
+ // Check dimension reduction: if swap on boundary, check that no edge
+ // links the first and last points of the crown.
+ if ( boundarySwap ) {
+ if ( E_exist(vertices[0],vertices[nbf-1]) ) return false;
+ }
+
+ // Find top and bottom vertices from orientation of the polyhedron
+ // v2 is top vertex if ( V01 x V02 ) . V32 > 0
+ pVertex v0 = vertices[0];
+ pVertex v1 = vertices[1];
+ pVertex v2 = E_vertex(edge, 0);
+ pVertex v3 = E_vertex(edge, 1);
+
+ double p[4][3];
+ V_coord( v0, p[0] );
+ V_coord( v1, p[1] );
+ V_coord( v2, p[2] );
+ V_coord( v3, p[3] );
+ double a[3] = { p[1][0]-p[0][0], p[1][1]-p[0][1], p[1][2]-p[0][2] };
+ double b[3] = { p[2][0]-p[0][0], p[2][1]-p[0][1], p[2][2]-p[0][2] };
+ double c[3] = { p[2][0]-p[3][0], p[2][1]-p[3][1], p[2][2]-p[3][2] };
+ double ab[3] = { a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0] }; // a x b
+ if( ab[0]*c[0] + ab[1]*c[1] + ab[2]*c[2] > 0.0 )
+ {
+ vt = v2;
+ vb = v3;
+ }
+ else
+ {
+ vt = v3;
+ vb = v2;
+ }
+
+ swap_config.set( nbf );
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool edgeSwapOp::evaluateShapes()
+ {
+ // select the best triangulation and evaluate worst shape
+ if( M_numRegions(mesh)==0 ) return evaluateShapes2D();
+ else return evaluateShapes3D();
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ // loop over all possible swap configurations and select the best triangulation
+ bool edgeSwapOp::evaluateShapes3D()
+ {
+ // if edge is classified on face type need to check volume
+ double volume = 0.0;
+ if( checkVol )
+ {
+ pRegion region;
+ pPList regions = E_regions (edge);
+ void *temp=0;
+ while( ( region = (pRegion)PList_next(regions, &temp) ) )
+ volume += R_volume (region);
+ PList_delete (regions);
+ }
+ int nb_triangles = swap_config.nb_triangles();
+ // here nb_triangles is maximum 35 (for config = 7),
+ // ansi c++ does not support variable lengths for arrays
+ double shapes[35]; // worst shape for each configuration
+ bool valid_shapes[35];
+ double volumes[35]; // volumes of the new swap configurations
+
+ // -- loop on all possible triangulations and compute associated element shapes --
+ for( int i=0; i< nb_triangles; i++ )
+ {
+ double xyz[4][3];
+ pMSize s[4];
+
+ pVertex v0 = vertices[ swap_config.triangle(i,0) ];
+ pVertex v1 = vertices[ swap_config.triangle(i,1) ];
+ pVertex v2 = vertices[ swap_config.triangle(i,2) ];
+
+ V_coord(v0, xyz[0]);
+ V_coord(v1, xyz[1]);
+ V_coord(v2, xyz[2]);
+ V_coord(vt, xyz[3]);
+
+ s[0] = sizeField->findSize(v0);
+ s[1] = sizeField->findSize(v1);
+ s[2] = sizeField->findSize(v2);
+ s[3] = sizeField->findSize(vt);
+
+ // evaluate 'top' Tet [v0,v1,v2,vt]
+ double shape;
+ bool shape_ok = mqm.getElementEvaluator()->XYZ_R_shape( xyz, s , &shape );
+ valid_shapes[i] = shape_ok;
+ shapes[i] = shape;
+
+ if( !shape_ok ) // no need to compute shape of bottom tet since
+ { // configuration will be rejected
+ valid_shapes[i] = false;
+ continue;
+ }
+
+ // evaluate 'bottom' Tet [v0,v2,v1,vb]
+ V_coord(v2, xyz[1]);
+ V_coord(v1, xyz[2]);
+ V_coord(vb, xyz[3]);
+ s[1] = sizeField->findSize(v2);
+ s[2] = sizeField->findSize(v1);
+ s[3] = sizeField->findSize(vb);
+
+ valid_shapes[i] = mqm.getElementEvaluator()->XYZ_R_shape( xyz, s , &shape );
+
+ // keep worst value of top-bottom tets for swap configuration i in shapes[i]
+ if( shape < shapes[i] ) shapes[i] = shape;
+
+ // volume computation
+ if( checkVol )
+ {
+ volumes[i] = R_XYZ_volume( xyz ); // bottom tet
+ V_coord(vt,xyz[3]);
+ volumes[i] += R_XYZ_volume( xyz ); // top tet
+ }
+ }
+
+ // -- Select best valid edge swap configuration --
+ double optimum = 0.0;
+ for( int i=0; i < swap_config.nb_triangulations(); i++ )
+ {
+ // find worst element shape of this configuration
+ double worst_shape = MAdBIG; // assume the shape is always between 0.0 and 1.0
+ bool valid;
+ for( int j=0; j < swap_config.nb_tri_triangulation(); j++ )
+ {
+ int t = swap_config.triangulation(i,j); // test triangle t
+ valid = valid_shapes[t];
+ if( !valid )
+ break;
+
+ if( shapes[t] < worst_shape )
+ worst_shape = shapes[t];
+ }
+
+ // if shape is not valid, check next swap configuration
+ if( !valid )
+ continue;
+
+ // check volume change
+ if( checkVol )
+ {
+ double new_volume = 0.0;
+ for( int j=0; j < swap_config.nb_tri_triangulation(); j++ )
+ new_volume += volumes[ swap_config.triangulation(i,j) ];
+
+ if( fabs(volume-new_volume)/volume > dVTol )
+ continue;
+ }
+
+ if( worst_shape > optimum )
+ {
+ optimum = worst_shape; // worst shape of the configuration
+ conf = i; // best swap configuration
+ }
+ }
+
+ // no valid swap configuration was found
+ if( optimum <= MAdTOL ) return false;
+
+ results->setWorstShape( optimum );
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool edgeSwapOp::evaluateShapes2D()
+ {
+ double worstShape = MAdBIG;
+
+ // evaluate shape of new triangles
+ pFace f0 = E_face(edge,0);
+ pFace f1 = E_face(edge,1);
+ pVertex v0 = E_vertex(edge,0);
+ pVertex v1 = E_vertex(edge,1);
+ pVertex v2 = F_edOpVt(f0, edge);
+ pVertex v3 = F_edOpVt(f1, edge);
+
+ double xyz[3][3];
+ V_coord(v0, xyz[0]);
+ V_coord(v2, xyz[1]);
+ V_coord(v3, xyz[2]);
+
+ pMSize s[3];
+ s[0] = sizeField->findSize(v0);
+ s[1] = sizeField->findSize(v2);
+ s[2] = sizeField->findSize(v3);
+
+ // evaluate shape of new triangles [v0,v2,v3] && [v1,v2,v3]
+ double normal[3];
+ double e02[3],e03[3];
+ diffVec(xyz[1],xyz[0],e02);
+ diffVec(xyz[2],xyz[0],e03);
+ crossProd(e02,e03,normal);
+ double shape;
+ // [v0,v2,v3]
+ if( !mqm.getElementEvaluator()->XYZ_F_shape(xyz, s, normal, &shape) ) return false;
+ worstShape = shape;
+
+ V_coord(v1, xyz[0]);
+ s[0] = sizeField->findSize(v1);
+
+ normal[0] = -normal[0];
+ normal[1] = -normal[1];
+ normal[2] = -normal[2];
+
+ if( !mqm.getElementEvaluator()->XYZ_F_shape(xyz, s, normal, &shape) ) return false;
+
+ if( worstShape > shape ) worstShape = shape;
+
+ results->setWorstShape(worstShape);
+ // check the area of the new faces in case of '3D' surf mesh
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ // calculate the max/min size after the modification is applied
+ void edgeSwapOp::evaluateLengths() const
+ {
+ double maxSwap, minSwap;
+
+ // consider the new edges created after swap
+ if( M_numRegions(mesh) == 0 ) // 2D mesh
+ {
+ pFace face0 = E_face(edge, 0);
+ pVertex v0 = F_edOpVt(face0,edge);
+ pFace face1 = E_face(edge, 1);
+ pVertex v1 = F_edOpVt(face1,edge);
+ maxSwap = sizeField->SF_VV_lengthSq(v0,v1);
+ minSwap = maxSwap;
+ }
+ else
+ {
+ // 3D mesh
+ minSwap = MAdBIG;
+ maxSwap = 0.;
+
+ // evaluate the triangles of the c'th configuration
+ pVertex v[3];
+ for( int j=0; j < swap_config.nb_tri_triangulation(); j++ )
+ {
+ int t = swap_config.triangulation(conf,j);
+ for( int i=0; i<3; i++ )
+ {
+ v[i] = vertices[ swap_config.triangle(t,i) ];
+ }
+
+ for( int i=0; i<3; i++ )
+ {
+ // (AF) we could also pre-define the new edges to be tested in the EdgeSwapConfig
+ // to avoid the E_exist loop
+ if( !E_exist(v[i],v[(i+1)%3]) ) /// 0-1,1-2,2-0
+ {
+ double lSq = sizeField->SF_VV_lengthSq(v[i], v[(i+1)%3]);
+ if( lSq > maxSwap ) maxSwap = lSq;
+ if( lSq < minSwap ) minSwap = lSq;
+ }
+ }
+ }
+ }
+
+ // initialization
+ double lMinSq = MAdBIG;
+ double lMaxSq = 0.0;
+ if( maxSwap > lMaxSq ) lMaxSq = maxSwap;
+ if( minSwap < lMinSq ) lMinSq = minSwap;
+
+ results->setMaxLenSq(lMaxSq);
+ results->setMinLenSq(lMinSq);
+ }
+
+ // -------------------------------------------------------------------
+ void edgeSwapOp::apply()
+ {
+ if( M_numRegions(mesh) !=0 ) apply3D();
+ else apply2D();
+ HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+ }
+
+ // -------------------------------------------------------------------
+ int edgeSwapOp::apply2D()
+ {
+ // 2D mesh case
+ pPList old_faces = PList_new();
+ pPList new_faces = PList_new();
+
+ pFace f0 = E_face(edge,0);
+ pFace f1 = E_face(edge,1);
+ pVertex v0 = E_vertex(edge,0);
+ pVertex v1 = E_vertex(edge,1);
+ pVertex v2 = F_edOpVt(f0, edge);
+ pVertex v3 = F_edOpVt(f1, edge);
+
+ pGEntity gface = F_whatIn(f0); // classification
+
+ // new triangles [v0,v2,v3] && [v1,v2,v3]
+ pEdge newe = M_createE(mesh, v2, v3, gface);
+ pEdge e02 = mesh->find_edge( v0, v2, (MDB_Triangle*)f0 );
+ pEdge e03 = mesh->find_edge( v0, v3, (MDB_Triangle*)f1 );
+ pEdge e12 = mesh->find_edge( v1, v2, (MDB_Triangle*)f0 );
+ pEdge e13 = mesh->find_edge( v1, v3, (MDB_Triangle*)f1 );
+ pFace newf0 = mesh->add_triangle( e02, newe, e03, gface);
+ pFace newf1 = mesh->add_triangle( e12, newe, e13, gface);
+
+ PList_append(new_faces, newf0);
+ PList_append(new_faces, newf1);
+
+ // call callback
+ CallBackManagerSgl::instance().callCallBacks(old_faces, new_faces, MAd_ESWAP, (pEntity)edge);
+ PList_delete(old_faces);
+ PList_delete(new_faces);
+
+ // deletion
+ M_removeFace(mesh,f0);
+ M_removeFace(mesh,f1);
+ M_removeEdge(mesh,edge);
+
+ edge = 0;
+ conf = -1;
+
+ return 1;
+
+ }
+
+ // -------------------------------------------------------------------
+ int edgeSwapOp::apply3D()
+ {
+ pPList eregs = E_regions(edge); // cavity before swap
+ pGRegion greg = R_whatIn( (pRegion)PList_item(eregs, 0) );
+
+ pPList newRegions = PList_new();
+
+ if( conf < 0 ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Edge swap configuration not defined, call evaluate() first");
+ }
+
+ // create new regions for the selected swap configuration
+ pVertex v[3];
+ for( int i=0; i < swap_config.nb_tri_triangulation(); i++ )
+ {
+ int t = swap_config.triangulation(conf,i);
+ for( int j=0; j<3; j++ )
+ v[j] = vertices[ swap_config.triangle(t,j) ];
+
+ //create new regions
+ pRegion r1 = mesh->add_tet( v[0], v[1],v[2], vt, (pGEntity)greg );
+ pRegion r2 = mesh->add_tet( v[0], v[2],v[1], vb, (pGEntity)greg );
+ PList_append( newRegions, r1 );
+ PList_append( newRegions, r2 );
+ }
+
+ // If swap on a boundary, classify new boundary entities (1 edge, 2 faces)
+ if( E_whatInType(edge) == 2 )
+ {
+ pGEntity bgent = E_whatIn(edge);
+
+ // the new edge to be classified is supposed to be between the first
+ // and the last vertices of the configuration (we started to list nodes
+ // at a classified face in checkGeometry)
+ pEdge bEdge = E_exist(vertices[0],vertices[swap_config.get()-1]);
+ E_setWhatIn(bEdge,bgent);
+
+ // now classify the faces
+ pPList eFaces = E_faces(bEdge);
+ void * temp = NULL;
+ pFace face;
+ pVertex oppV;
+ int count = 0;
+ while ( ( face = (pFace)PList_next(eFaces,&temp) ) ) {
+ oppV = F_edOpVt(face,bEdge);
+ if ( oppV == vt || oppV == vb ) {
+ assert ( F_numRegions(face) == 1 );
+ F_setWhatIn(face,bgent);
+ count++;
+ }
+ }
+ PList_delete(eFaces);
+ assert(count == 2);
+ }
+
+ // call callback
+ CallBackManagerSgl::instance().callCallBacks(eregs, newRegions, MAd_ESWAP, (pEntity)edge );
+ PList_delete(newRegions);
+
+ // remove old regions connected to edge
+ pRegion frgn;
+ void *temp = 0;
+ while( ( frgn = (pRegion)PList_next(eregs, &temp) ) )
+ M_removeRegion(mesh,frgn);
+ PList_delete(eregs);
+
+ // remove old faces connected to edge
+ pFace face;
+ pPList faces = E_faces(edge);
+ void *temp1 = 0;
+ while( ( face = (pFace)PList_next(faces, &temp1) ) )
+ M_removeFace(mesh, face);
+ PList_delete(faces);
+
+ // remove edge
+ M_removeEdge(mesh, edge);
+
+ edge = 0;
+ conf = -1;
+
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+ void edgeSwapOp::getCavity(pPList * cavity) const
+ {
+ if ( dim == 3 ) *cavity = E_regions(edge);
+ else *cavity = E_faces(edge);
+ }
+
+ // -------------------------------------------------------------------
+ void edgeSwapOp::reportSwap( )
+ {
+ stringstream ss;
+ std::string idStr; ss << reportId; ss >> idStr;
+ std::string name = reportPrefix + "swap" + idStr + ".pos";
+ pPList cavity = E_regions( edge );
+ printPosEntities(cavity,name.c_str(),OD_CONSTANT, 0 );
+ PList_delete(cavity);
+ reportId++;
+ }
+
+ // -------------------------------------------------------------------
+}
diff --git a/Adapt/operator/EdgeSwapOp.h b/Adapt/operator/EdgeSwapOp.h
new file mode 100644
index 0000000..e867ff7
--- /dev/null
+++ b/Adapt/operator/EdgeSwapOp.h
@@ -0,0 +1,124 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Arnaud Francois, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_EDGESWAPOP
+#define _H_EDGESWAPOP
+
+#include "MAdOperatorBase.h"
+#include "EdgeSwapConfig.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class edgeSwapOp : public MAdOperatorBase
+ {
+ public:
+
+ edgeSwapOp();
+ edgeSwapOp(pMesh, DiscreteSF *);
+ edgeSwapOp(const edgeSwapOp &);
+ ~edgeSwapOp() {}
+
+ operationType type() const { return MAd_ESWAP; }
+ int getMaxNumRgns() { return 7; }
+
+ void setSwapEdge(pEdge);
+ void swapOnBoundary(bool,double);
+
+ void getCavity(pPList *) const;
+
+ void apply();
+
+ private:
+
+ bool checkConstraints() const;
+ bool checkGeometry();
+ bool evaluateShapes();
+ void evaluateLengths() const;
+
+ bool checkGeometry2D();
+ bool checkGeometry3D();
+ bool evaluateShapes2D();
+ bool evaluateShapes3D();
+
+ int apply3D();
+ int apply2D();
+
+ pEdge edge; // the edge to be swapped
+ int conf; // best swap configuration - set by geomCheck()
+ pVertex vt; // top and bottom vertices of the edge (define the polygon orientation
+ pVertex vb; // w/r to vertices)
+ std::vector<pVertex> vertices; // oriented list of vertices defining the polygon
+
+ EdgeSwapConfiguration swap_config;
+
+ bool constrainBoundary;
+ bool checkVol; // tells if it's interesting to compute the variation of
+ // volume in the cavity (deduced from classif of edge
+ // and constrainBoundary)
+ double dVTol;
+
+ // reporting
+ void reportSwap( );
+ bool report;
+ int reportId;
+ std::string reportPrefix;
+
+ };
+
+ // -------------------------------------------------------------------
+ inline edgeSwapOp::edgeSwapOp(pMesh _m, DiscreteSF * _sf):
+ MAdOperatorBase(_m,_sf), edge(0), conf(-1), vt(0), vb(0),
+ constrainBoundary(true), checkVol(false), dVTol(MAdTOL),
+ report(false), reportId(0), reportPrefix("")
+ {
+ vertices.reserve(7);
+ }
+
+ // -------------------------------------------------------------------
+ inline edgeSwapOp::edgeSwapOp(const edgeSwapOp & _es):
+ MAdOperatorBase(_es), swap_config( _es.swap_config )
+ {
+ edge = _es.edge;
+ conf = _es.conf;
+ vt = _es.vt;
+ vb = _es.vb;
+ vertices = _es.vertices;
+
+ constrainBoundary = _es.constrainBoundary;
+ checkVol = _es.checkVol;
+ dVTol = _es.dVTol;
+
+ report = _es.report;
+ reportId = _es.reportId;
+ reportPrefix = _es.reportPrefix;
+ }
+
+ // -------------------------------------------------------------------
+ inline void edgeSwapOp::setSwapEdge(pEdge e)
+ {
+ edge = e;
+ results->reset();
+ conf = -1;
+ checkVol = false;
+ }
+
+ // -------------------------------------------------------------------
+ inline void edgeSwapOp::swapOnBoundary(bool eswapob, double dV)
+ {
+ constrainBoundary = !eswapob;
+ dVTol = dV;
+ }
+}
+// -------------------------------------------------------------------
+#endif
diff --git a/Adapt/operator/FaceCollapseOp.cc b/Adapt/operator/FaceCollapseOp.cc
new file mode 100644
index 0000000..6d48dc8
--- /dev/null
+++ b/Adapt/operator/FaceCollapseOp.cc
@@ -0,0 +1,495 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "FaceCollapseOp.h"
+#include "OperatorTools.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ bool faceCollapseOp::checkConstraints() const
+ {
+ // find the opposite vertex
+ oppV = F_edOpVt(delFace,delEdge);
+
+ if( EN_constrained((pEntity)delEdge)) return false;
+ if( !clpsOnOppV && EN_constrained((pEntity)oppV) ) return false;
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool faceCollapseOp::checkGeometry()
+ {
+ pGEntity fGE = F_whatIn(delFace);
+ if( clpsOnOppV )
+ {
+ // delEdge and delFace must have the same classification
+ if( E_whatIn(delEdge) != fGE ) return false;
+ }
+ else
+ {
+ // oppV and delFace must have the same classification
+ if( V_whatIn(oppV) != fGE ) return false;
+ }
+
+ // It leaves us with two possibilities:
+ // (a) In case ( clpsOnOppV == true ) :
+ // (1) delFaces and delEdges are classified on a dim 2
+ // (2) delFaces and delEdges are classified on a dim 3
+ // (b) In case ( clpsOnOppV == false ) :
+ // (1) delFaces and oppV are classified on a dim 2
+ // (2) delFaces and oppV are classified on a dim 3
+ // For both (a) and (b):
+ // In case (2) no dimension reduction can occur -> unconditionally valid
+ // In case (1): * if 2D mesh, no dim reduc -> unconditionally valid
+ // * if 3D mesh, two things to check:
+ // A.: check boundaries are not constrained
+ // (otherwise ok but checkVol=true)
+ // B.: check dimension reduction
+
+ if ( dim == 3 && GEN_type(fGE) == 2 )
+ {
+ // check A
+ if( constrainBoundary ) return false;
+ else checkVol = true;
+
+ // check B
+ // - Dimension reduction on node (on oppV, case clpsOnOppV=true): as delEdge
+ // is classified on dim 2, only one surface (fGE) passes
+ // through it. As it is the same as the geom ent of delFace,
+ // oppV already touches it -> no node dim reduction.
+ // - Dimension reduction on lines and surfaces:
+ // occurs if these 2 conditions hold together:
+ // C1: for one of the regions bounding delFace, the face
+ // containing delEdge and which is not delFace is
+ // classified on a surface,
+ // C2: for one of the regions bounding delFace, the edge
+ // of the region opposite to delEdge is classified
+ // on a dimension < 3 (line contact).
+ // C2b (surface contact): for one of the regions bounding
+ // delFace, one of the 2 other faces is classified on
+ // a surface. This is found by Condition 2.
+ // - Dimension reduction occur if these 2 conditions hold together:
+ // C3: the face has only 1 region,
+ // C4: there is a face using delEdge which opposite vertex
+ // is linked to oppV by an edge oppE and oppE is not
+ // used by the only region.
+ bool C1 = false, C2 = false;
+ for (int iR=0; iR<2; iR++)
+ {
+ pRegion reg = F_region(delFace,iR);
+ if ( !reg ) continue;
+
+ // check C1
+ for (int iF=0; iF<4; iF++) {
+ pFace pf = R_face(reg,iF);
+ if ( pf == delFace ) continue;
+ if ( F_inClosure(pf,delEdge) && F_whatInType(pf) == 2 ) C1 = true;
+ }
+
+ // check C2
+ if ( E_whatInType( R_gtOppEdg(reg, delEdge) ) < 3 ) C2 = true;
+ }
+ if ( C1 && C2 ) return false;
+
+ // In case C3 holds
+ if ( F_numRegions(delFace) == 1 )
+ {
+ // check C4
+ pRegion pr = F_region(delFace,0);
+ if ( !pr ) pr = F_region(delFace,1);
+ pPList delEdgeFaces = E_faces(delEdge);
+ void * temp = NULL;
+ pFace pf;
+ while ( ( pf = (pFace) PList_next(delEdgeFaces,&temp) ) )
+ {
+ if ( pf == delFace ) continue;
+ if ( R_inClosure(pr,pf) ) continue;
+ if ( E_exist(oppV, F_edOpVt(pf,delEdge) ) ) {
+ PList_delete(delEdgeFaces); return false;
+ }
+ }
+ PList_delete(delEdgeFaces);
+ }
+ }
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool faceCollapseOp::evaluateShapes()
+ {
+ if( dim != 3 ) return evaluateShapes2D();
+
+ double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+ pRegion delReg[2];
+ delReg[0] = F_region(delFace,0);
+ delReg[1] = F_region(delFace,1);
+
+ double rCoords[4][3];
+ pMSize rSizes[4] = {NULL, NULL, NULL, NULL};
+
+ double volIn = 0.;
+ double volOut = 0.;
+
+ // 1°) General case valid for any clpsOnOppV
+
+ pPList eRegs = E_regions(delEdge);
+ void * temp = NULL;
+ while( pRegion region = (pRegion)PList_next( eRegs, &temp ) ) {
+
+ if (checkVol) { volIn += R_volume (region); }
+
+ if( region==delReg[0] || region==delReg[1] ) continue;
+
+ // check every tet resulting from the split
+ for( int iR=0; iR<2; iR++ ) {
+
+ pVertex eV = E_vertex(delEdge,iR);
+
+ // Loop over all the vertices of region
+ pVertex rV;
+ for( int iRV=0; iRV < R_numVertices(region); iRV++ ) {
+
+ rV = R_vertex( region, iRV );
+
+ if ( rSizes[iRV] ) delete rSizes[iRV];
+
+ if( rV == eV ) { // Set oppV size and pos. instead of end of delEdge
+ if( clpsOnOppV ) { // Collapse on oppV
+ double xyz[3];
+ V_coord(oppV,xyz);
+ for( int k=0; k<3; k++ ) rCoords[iRV][k] = xyz[k];
+ rSizes[iRV] = sizeField->getSize(oppV);
+ }
+ else { // Collapse on newVt
+ for( int k=0; k<3; k++ ) rCoords[iRV][k] = newVPos[k];
+ rSizes[iRV] = sizeField->getSizeOnEntity((pEntity)delEdge,rCoords[iRV]);
+ }
+ }
+ else {
+ rSizes[iRV] = sizeField->getSize(rV);
+ V_coord(rV,rCoords[iRV]);
+ }
+ }
+
+ // Some cleaning and exit if new element is not acceptable
+ double shape;
+ if( ! mqm.getElementEvaluator()->XYZ_R_shape(rCoords,rSizes,&shape) ) {
+ for (int i=0; i<4; i++) {
+ if ( rSizes[i] ) delete rSizes[i];
+ }
+ PList_delete(eRegs);
+ return false;
+ }
+
+ if( worstShape > shape ) worstShape = shape;
+
+ if (checkVol) { volOut += R_XYZ_volume(rCoords); }
+ } // End of loop on sub-tetra
+ } // End loop on regions around delEdge
+ PList_delete(eRegs);
+
+ // 2°) Particular case if collapse edge on new vertex; need other checks
+
+ if( !clpsOnOppV ) {
+
+ // loop over the regions of oppV excepted delReg[0-1]
+ pPList vRegs = V_regions(oppV);
+ void * temp = NULL;
+ while( pRegion region = (pRegion)PList_next(vRegs,&temp) ) {
+
+ if( region==delReg[0] || region==delReg[1] ) continue;
+
+ if (checkVol) { volIn += R_volume(region); }
+
+ pVertex rV;
+ for(int iRV=0; iRV < R_numVertices(region); iRV++) {
+
+ rV = R_vertex(region, iRV);
+
+ if ( rSizes[iRV] ) delete rSizes[iRV];
+
+ if( rV == oppV ) { // Set size and pos. of new vertex on delEdge
+ for(int iC=0; iC<3; iC++) rCoords[iRV][iC] = newVPos[iC];
+ rSizes[iRV] = sizeField->getSizeOnEntity((pEntity)delEdge,rCoords[iRV]);
+ }
+ else {
+ rSizes[iRV] = sizeField->getSize(rV);
+ V_coord(rV,rCoords[iRV]);
+ }
+ }
+
+ if (checkVol) { volOut += R_XYZ_volume(rCoords); }
+
+ // Some cleaning and exit if new element is not acceptable
+ double shape;
+ if( ! mqm.getElementEvaluator()->XYZ_R_shape(rCoords,rSizes,&shape) ) {
+ for (int i=0; i<4; i++) {
+ if ( rSizes[i] ) delete rSizes[i];
+ }
+ PList_delete(vRegs);
+ return false;
+ }
+
+ if( worstShape > shape ) worstShape = shape;
+
+ } // End loop on vRegs
+ PList_delete(vRegs);
+ }
+
+ for (int i=0; i<4; i++) {
+ if ( rSizes[i] ) delete rSizes[i];
+ }
+
+ results->setWorstShape(worstShape);
+
+ if (checkVol) {
+ double dV = fabs( (volIn-volOut) / volIn );
+ if( dV > dVTol ) return false;
+ }
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool faceCollapseOp::evaluateShapes2D()
+ {
+ double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+ // get the normal to the del face
+ double fNormal[3];
+ F_normal(delFace,fNormal);
+
+ double fCoords[3][3];
+ pMSize fSizes[3] = {NULL, NULL, NULL};
+
+ // 1°) General case valid for any clpsOnOppV
+
+ for( int eF=0; eF < E_numFaces(delEdge); eF++ ) {
+
+ pFace face = E_face(delEdge, eF);
+
+ if( face == delFace ) continue;
+
+ for( int iSubF=0; iSubF<2; iSubF++ ) {
+
+ pVertex eV = E_vertex(delEdge,iSubF);
+
+ // Loop over all the vertices of face
+ pVertex fV;
+ for( int iFV=0; iFV<F_numVertices(face); iFV++ ) {
+
+ fV = F_vertex(face, iFV);
+
+ if ( fSizes[iFV] ) delete fSizes[iFV];
+
+ if( fV == eV ) { // Set oppV size and pos. instead of end of delEdge
+ if( clpsOnOppV ) {
+ double xyz[3];
+ V_coord(oppV,xyz);
+ for(int k=0; k<3; k++ ) fCoords[iFV][k] = xyz[k];
+ fSizes[iFV] = sizeField->getSize(oppV);
+ }
+ else { // Collapse on newVt
+ for(int k=0; k<3; k++) fCoords[iFV][k] = newVPos[k];
+ fSizes[iFV] = sizeField->getSizeOnEntity((pEntity)delEdge,fCoords[iFV]);
+ }
+ }
+ else {
+ V_coord(fV,fCoords[iFV]);
+ fSizes[iFV] = sizeField->getSize(fV);
+ }
+ }
+
+ // Some cleaning and exit if new element is not acceptable
+ double shape;
+ if( ! mqm.getElementEvaluator()->XYZ_F_shape(fCoords,fSizes,fNormal,&shape) ) {
+ for (int i = 0; i<3; i++) {
+ if ( fSizes[i] ) delete fSizes[i];
+ }
+ return false;
+ }
+
+ if( worstShape > shape ) worstShape = shape;
+ } // End of loop on sub-tetra
+ } // End loop on regions around delEdge
+
+
+ // 2°) Particular case if collapse edge on new vertex; need other checks
+
+ if( !clpsOnOppV ) {
+
+ pPList vFaces = V_faces(oppV);
+ void * temp = NULL;
+ while( pFace face = (pFace)PList_next( vFaces, &temp ) ) {
+
+ if( face == delFace ) continue;
+
+ pVertex fV;
+ for( int k=0; k < F_numVertices(face); k++ ) {
+
+ fV = F_vertex(face,k);
+
+ if ( fSizes[k] ) delete fSizes[k];
+
+ if( fV == oppV ) { // Set size and pos. of new vertex on delEdge
+ for( int iC=0; iC<3; iC++ ) fCoords[k][iC] = newVPos[iC];
+ fSizes[k] = sizeField->getSizeOnEntity((pEntity)delEdge,fCoords[k]);
+ }
+ else {
+ V_coord(fV,fCoords[k]);
+ fSizes[k] = sizeField->getSize(fV);
+ }
+ }
+
+ // Some cleaning and exit if new element is not acceptable
+ double shape;
+ if( ! mqm.getElementEvaluator()->XYZ_F_shape(fCoords,fSizes,fNormal,&shape) ) {
+ for (int i = 0; i<3; i++) {
+ if ( fSizes[i] ) delete fSizes[i];
+ }
+ return false;
+ }
+
+ if( worstShape > shape ) worstShape = shape;
+ } // End loop on vFaces
+ PList_delete(vFaces);
+ }
+
+ for (int i = 0; i<3; i++) {
+ if ( fSizes[i] ) delete fSizes[i];
+ }
+
+ results->setWorstShape(worstShape);
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void faceCollapseOp::evaluateLengths() const
+ {
+ double minSq = MAdBIG;
+ double maxSq = 0.;
+
+ // Interpolate the desired size at splitting location (for !clpsOnOppV)
+ pMSize sizeNewV = NULL;
+ if (!clpsOnOppV) {
+ sizeNewV = sizeField->getSizeOnEntity((pEntity)delEdge,newVPos);
+ }
+
+ // 1°) General case, all faces touching delEdge are modified for both types
+
+ pFace face;
+ for( int i=0; i<E_numFaces(delEdge); i++ ) {
+
+ face = E_face(delEdge, i);
+
+ if( face == delFace ) continue;
+
+ pVertex vertex = F_edOpVt(face,delEdge);
+
+ double lenSq;
+ if( clpsOnOppV ) {
+ lenSq = sizeField->SF_VV_lengthSq(oppV,vertex);
+ }
+ else {
+ double vxyz[3];
+ V_coord(vertex,vxyz);
+ pMSize vSize = sizeField->findSize(vertex);
+ lenSq = sizeField->SF_XYZ_lengthSq( newVPos, vxyz,
+ sizeNewV, vSize );
+ }
+
+ if( lenSq > maxSq ) maxSq = lenSq;
+ if( lenSq < minSq ) minSq = lenSq;
+ }
+
+ // 2°) For type 0 only, all edges touching oppV are affected as well
+
+ if( !clpsOnOppV ) {
+
+ for( int j=0; j<V_numEdges( oppV ); j++ )
+ {
+ pVertex vertex = E_otherVertex( V_edge(oppV, j), oppV );
+ double vxyz[3];
+ V_coord(vertex,vxyz);
+ pMSize vSize = sizeField->findSize(vertex);
+ double lenSq = sizeField->SF_XYZ_lengthSq( newVPos, vxyz,
+ sizeNewV, vSize );
+
+ if( lenSq > maxSq ) maxSq = lenSq;
+ if( lenSq < minSq ) minSq = lenSq;
+ }
+ }
+
+ results->setMaxLenSq(maxSq);
+ results->setMinLenSq(minSq);
+
+ if (sizeNewV) delete sizeNewV;
+ }
+
+ // -------------------------------------------------------------------
+ void faceCollapseOp::getCavity(pPList * cavity) const
+ {
+ if( clpsOnOppV ) // Delete new vertex
+ {
+ if ( dim == 3 ) *cavity = E_regions(delEdge);
+ else *cavity = E_faces(delEdge);
+ }
+ else // Delete existing vertex
+ {
+ if ( dim == 3 ) {
+ *cavity = V_regions(oppV);
+ pPList eRegs = E_regions(delEdge);
+ void * temp = 0;
+ while ( pRegion region = (pRegion)PList_next(eRegs,&temp) ) {
+ if ( !PList_inList(*cavity,region) ) PList_append(*cavity,region);
+ }
+ PList_delete(eRegs);
+ }
+ else {
+ *cavity = V_faces(oppV);
+ pPList eFaces = E_faces(delEdge);
+ void * temp = 0;
+ while ( pFace face = (pFace)PList_next(eFaces,&temp) ) {
+ if ( !PList_inList(*cavity,face) ) PList_append(*cavity,face);
+ }
+ PList_delete(eFaces);
+
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void faceCollapseOp::apply()
+ {
+ pVertex newV = E_split(mesh, delEdge, newVPos);
+
+
+
+ // determine the edge collapse
+ pEdge edgeDel = E_exist(oppV,newV);
+ pVertex vDel, vTgt;
+ if( clpsOnOppV ) { vDel = newV; vTgt = oppV; }
+ else { vDel = oppV; vTgt = newV; }
+
+ E_collapse(mesh,edgeDel,vDel,vTgt);
+
+ HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/FaceCollapseOp.h b/Adapt/operator/FaceCollapseOp.h
new file mode 100644
index 0000000..12fb2fc
--- /dev/null
+++ b/Adapt/operator/FaceCollapseOp.h
@@ -0,0 +1,127 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_EDGESPLITCOLLAPSEOP
+#define _H_EDGESPLITCOLLAPSEOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class faceCollapseOp: public MAdOperatorBase
+ {
+ public:
+
+ faceCollapseOp(pMesh, DiscreteSF *);
+ faceCollapseOp(const faceCollapseOp &);
+ ~faceCollapseOp() {}
+
+ operationType type() const { return MAd_FCOLLAPSE; }
+
+ void collapseOnBoundary(bool, double);
+ void reset(pFace, pEdge, bool);
+
+ void getCavity(pPList *) const;
+
+ void apply();
+
+ private:
+
+ bool checkConstraints() const;
+ bool checkGeometry();
+ bool evaluateShapes();
+ bool evaluateShapes2D();
+ void evaluateLengths() const;
+
+ private:
+
+ pFace delFace;
+ pEdge delEdge;
+ bool clpsOnOppV;
+ mutable pVertex oppV;
+ double newVPos[3];
+
+ bool constrainBoundary;
+ bool checkVol;
+ double dVTol; // tolerance on the relative change of volume
+ };
+
+
+ // -------------------------------------------------------------------
+ inline faceCollapseOp::faceCollapseOp(const faceCollapseOp & _fc):
+ MAdOperatorBase(_fc)
+ {
+ delFace = _fc.delFace;
+ delEdge = _fc.delEdge;
+ clpsOnOppV = _fc.clpsOnOppV;
+ oppV = _fc.oppV;
+ newVPos[0] = _fc.newVPos[0];
+ newVPos[1] = _fc.newVPos[1];
+ newVPos[2] = _fc.newVPos[2];
+ constrainBoundary = _fc.constrainBoundary;
+ checkVol = _fc.checkVol;
+ dVTol = _fc.dVTol;
+ }
+
+ // -------------------------------------------------------------------
+ inline faceCollapseOp::faceCollapseOp(pMesh _m, DiscreteSF * _sf):
+ MAdOperatorBase(_m,_sf)
+ {
+ delFace = NULL;
+ delEdge = NULL;
+ clpsOnOppV = true;
+ oppV = NULL;
+ newVPos[0] = 0.;
+ newVPos[1] = 0.;
+ newVPos[2] = 0.;
+ constrainBoundary = true;
+ checkVol = false;
+ dVTol = MAdTOL;
+ }
+
+ // -------------------------------------------------------------------
+ // pFace: face which would disapear
+ // pEdge: Edge which would be split
+ // clpsOnOppV: Edge collapse type
+ // True if collapse from SplitEdge to existing vertex
+ // False if collapse from existing vertex to SplitEdge
+ // -------------------------------------------------------------------
+ inline void faceCollapseOp::reset(pFace face, pEdge edge,
+ bool typeClps)
+ {
+ delFace = face;
+ delEdge = edge;
+ clpsOnOppV = typeClps;
+
+ double Exyz[2][3];
+ V_coord(E_vertex(delEdge,0),Exyz[0]);
+ V_coord(E_vertex(delEdge,1),Exyz[1]);
+
+ for(int i=0; i<3; i++) {
+ newVPos[i] = 0.5 * ( Exyz[0][i] + Exyz[1][i] );
+ }
+ }
+
+ // -------------------------------------------------------------------
+ inline void faceCollapseOp::collapseOnBoundary(bool cob, double tolerance)
+ {
+ constrainBoundary = !cob;
+ dVTol = tolerance;
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/FaceSwapOp.cc b/Adapt/operator/FaceSwapOp.cc
new file mode 100644
index 0000000..a21e1bf
--- /dev/null
+++ b/Adapt/operator/FaceSwapOp.cc
@@ -0,0 +1,194 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "FaceSwapOp.h"
+#include "CallBackManager.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ bool faceSwapOp::checkConstraints() const
+ {
+ if ( EN_constrained((pEntity)face) ) return false;
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool faceSwapOp::checkGeometry()
+ {
+ if ( F_whatInType(face) != 3 ) return false;
+ if ( !fRegions[0] || !fRegions[1] ) return false;
+ if ( R_whatIn(fRegions[0]) != R_whatIn(fRegions[1]) ) return false;
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool faceSwapOp::evaluateShapes()
+ {
+ // this case would lead to an edge swap
+ if ( E_exist(fOppVerts[0],fOppVerts[1]) ) return false;
+
+ double worst = mqm.getElementEvaluator()->bestShapeEver();
+
+ pPList r0Verts = R_vertices(fRegions[0]);
+
+ // collect coordinates of the five vertices
+ double xyzR0[4][3];
+ void * temp1 = 0;
+ int iV = 0;
+ while( pVertex pV = (pVertex)PList_next(r0Verts,&temp1) ) {
+ V_coord(pV,xyzR0[iV]);
+ iV++;
+ }
+ double xyzV1[3];
+ V_coord(fOppVerts[1],xyzV1);
+
+ // calculate worst shape of the three new regions
+ pPList fVerts = F_vertices(face,1);
+ void * temp2 = 0;
+ while( pVertex fVertex = (pVertex)PList_next(fVerts,&temp2) ) {
+
+ double xyzNewR[4][3];
+ pMSize newRSizes[4] = { NULL, NULL, NULL, NULL };
+
+ void * temp3 = 0;
+ int iR0V = 0;
+ while( pVertex pVR0 = (pVertex)PList_next(r0Verts,&temp3) ) {
+ if(pVR0 == fVertex) {
+ newRSizes[iR0V] = sizeField->findSize(fOppVerts[1]);
+ for (int iC=0; iC<3; iC++) xyzNewR[iR0V][iC] = xyzV1[iC];
+ iR0V++;
+ }
+ else {
+ newRSizes[iR0V] = sizeField->findSize(pVR0);
+ for (int iC=0; iC<3; iC++) xyzNewR[iR0V][iC] = xyzR0[iR0V][iC];
+ iR0V++;
+ }
+ }
+
+ double shape;
+ if( !mqm.getElementEvaluator()->XYZ_R_shape(xyzNewR,newRSizes,&shape) ) {
+ PList_delete(fVerts);
+ PList_delete(r0Verts);
+ return false;
+ }
+ if(shape < worst) worst = shape;
+ }
+ PList_delete(fVerts);
+ PList_delete(r0Verts);
+
+ results->setWorstShape(worst);
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void faceSwapOp::evaluateLengths() const
+ {
+ double xyz[2][3];
+ pMSize sizes[2] = { NULL, NULL };
+ for(int iV=0; iV<2; iV++) {
+ V_coord(fOppVerts[iV],xyz[iV]);
+ sizes[iV] = sizeField->findSize(fOppVerts[iV]);
+ }
+
+ double min = sizeField->SF_XYZ_lengthSq(xyz[0], xyz[1],
+ sizes[0], sizes[1]);
+ double max = min;
+
+ results->setMinLenSq(min);
+ results->setMaxLenSq(max);
+ }
+
+ // -------------------------------------------------------------------
+ void faceSwapOp::getCavity(pPList * cavity) const
+ {
+ *cavity = PList_new();
+ PList_append(*cavity, fRegions[0]);
+ PList_append(*cavity, fRegions[1]);
+ }
+
+ // -------------------------------------------------------------------
+ void faceSwapOp::apply()
+ {
+ pPList newRegions = PList_new();
+
+ // get the geometric entity on which the cavity is classified
+ pGRegion geoEntity = R_whatIn(fRegions[0]);
+
+ // create new edge
+ pEdge newEdge = M_createE(mesh,fOppVerts[0],fOppVerts[1],(pGEntity)geoEntity);
+
+ // create new faces
+ pFace newFaces[3];
+ pPList fVerts = F_vertices(face,1);
+ void * temp = 0;
+ int iF = 0;
+ while ( pVertex pV = (pVertex)PList_next(fVerts,&temp) ) {
+
+ pEdge fEdges[3];
+ fEdges[0] = E_exist(fOppVerts[0],pV);
+ fEdges[1] = E_exist(pV,fOppVerts[1]);
+ fEdges[2] = newEdge;
+
+ newFaces[iF] = M_createF(mesh,3,fEdges,(pGEntity)geoEntity);
+
+ iF++;
+ }
+
+ pFace boundaryFaces[2][3];
+ for(int iR=0; iR<2; iR++) {
+ for(int iV=0; iV<3; iV++) {
+ boundaryFaces[iR][iV] = R_vtOpFc(fRegions[iR],(pVertex)PList_item(fVerts,iV));
+ }
+ }
+ PList_delete(fVerts);
+
+ // create new regions
+ for (int iR=0; iR<3; iR++) {
+
+ pFace rFaces[4];
+ rFaces[0] = boundaryFaces[0][iR];
+ rFaces[1] = boundaryFaces[1][iR];
+ rFaces[2] = newFaces[(iR+1)%3];
+ rFaces[3] = newFaces[(iR+2)%3];
+
+ pRegion newR = M_createR(mesh,4,rFaces,(pGEntity)geoEntity);
+ PList_append(newRegions, newR);
+ }
+
+ // list deleted regions
+ pPList oldRegions = PList_new();
+ PList_append(oldRegions,fRegions[0]);
+ PList_append(oldRegions,fRegions[1]);
+
+ // call callback functions
+ CallBackManagerSgl::instance().callCallBacks(oldRegions,
+ newRegions,
+ MAd_FSWAP,
+ (pEntity)face);
+ PList_delete(oldRegions);
+ PList_delete(newRegions);
+
+ // delete old cavity
+ M_removeRegion(mesh,fRegions[0]);
+ M_removeRegion(mesh,fRegions[1]);
+ M_removeFace(mesh,face);
+
+ HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+
diff --git a/Adapt/operator/FaceSwapOp.h b/Adapt/operator/FaceSwapOp.h
new file mode 100644
index 0000000..8dda9e9
--- /dev/null
+++ b/Adapt/operator/FaceSwapOp.h
@@ -0,0 +1,89 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_FACESWAPOP
+#define _H_FACESWAPOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class faceSwapOp: public MAdOperatorBase
+ {
+ public:
+
+ faceSwapOp(pMesh, DiscreteSF *);
+ faceSwapOp(const faceSwapOp &);
+ ~faceSwapOp() {}
+
+ operationType type() const { return MAd_FSWAP; }
+
+ void setSwapFace(pFace);
+
+ void getCavity(pPList *) const;
+
+ void apply();
+
+ private:
+
+ bool checkConstraints() const;
+ bool checkGeometry();
+ bool evaluateShapes();
+ void evaluateLengths() const;
+
+ private:
+
+ pFace face; // face to be swapped
+ pRegion fRegions[2]; // its regions
+ pVertex fOppVerts[2]; // opposite vertices in regions
+ };
+
+ // -------------------------------------------------------------------
+ inline faceSwapOp::faceSwapOp(const faceSwapOp & _fs):
+ MAdOperatorBase(_fs), face(_fs.face)
+ {
+ fRegions[0] = _fs.fRegions[0];
+ fRegions[1] = _fs.fRegions[1];
+ fOppVerts[0] = _fs.fOppVerts[0];
+ fOppVerts[1] = _fs.fOppVerts[1];
+ }
+
+ // -------------------------------------------------------------------
+ inline faceSwapOp::faceSwapOp(pMesh _m, DiscreteSF * _sf):
+ MAdOperatorBase(_m,_sf), face(NULL)
+ {
+ fRegions[0] = NULL;
+ fRegions[1] = NULL;
+ fOppVerts[0] = NULL;
+ fOppVerts[1] = NULL;
+ }
+
+ // -------------------------------------------------------------------
+ inline void faceSwapOp::setSwapFace(pFace _face)
+ {
+ face = _face;
+
+ for(int iR=0; iR<2; iR++) {
+ fRegions[iR] = F_region(face,iR);
+ if (fRegions[iR]) fOppVerts[iR] = R_fcOpVt(fRegions[iR],face);
+ }
+
+ results->reset();
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/MAdOperatorBase.cc b/Adapt/operator/MAdOperatorBase.cc
new file mode 100644
index 0000000..11a7d5f
--- /dev/null
+++ b/Adapt/operator/MAdOperatorBase.cc
@@ -0,0 +1,86 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdOperatorBase.h"
+#include "MAdOutput.h"
+
+using std::string;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ bool MAdOperatorBase::evaluate(double * worstShape)
+ {
+ results->reset();
+ *worstShape = mqm.getElementEvaluator()->worstShapeEver();
+
+ History& history = HistorySgl::instance();
+
+ // --- check 1: constraints ---
+ if ( !checkConstraints() ) {
+ history.add((int)type(),OP_CHECKCONSTRAINTS,0);
+ return false;
+ } else {
+ history.add((int)type(),OP_CHECKCONSTRAINTS,1);
+ }
+
+ // --- check 2: geometric model ---
+ if ( !checkGeometry() ) {
+ history.add((int)type(),OP_CHECKGEOMETRY,0);
+ return false;
+ } else {
+ history.add((int)type(),OP_CHECKGEOMETRY,1);
+ }
+
+ // --- check 3: elements validity and shapes ---
+ if ( !evaluateShapes() ) {
+ history.add((int)type(),OP_CHECKSHAPES,0);
+ return false;
+ } else {
+ history.add((int)type(),OP_CHECKSHAPES,1);
+ }
+
+ // --- edge lengths ---
+ evaluateLengths();
+
+ *worstShape = results->getWorstShape();
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void MAdOperatorBase::exportCavity(string filename) const
+ {
+ pPList cavity = PList_new();
+ getCavity(&cavity);
+ if ( dim == 3 ) {
+ void * temp = NULL;
+ pEntity pe;
+ while ( ( pe = PList_next(cavity,&temp) ) ) {
+ if ( EN_type(pe) != 3 ) continue;
+ pRegion pr = (pRegion) pe;
+ pPList rFaces = R_faces(pr);
+ void * temp2 = NULL;
+ pFace face;
+ while ( ( face = (pFace)PList_next(rFaces,&temp2) ) ) {
+ if ( F_whatInType(face) == 2 ) PList_appUnique(cavity,face);
+ }
+ PList_delete(rFaces);
+ }
+ }
+ printPosEntities(cavity,filename,OD_DIMENSION,sizeField);
+ PList_delete(cavity);
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/MAdOperatorBase.h b/Adapt/operator/MAdOperatorBase.h
new file mode 100644
index 0000000..4a2f6f8
--- /dev/null
+++ b/Adapt/operator/MAdOperatorBase.h
@@ -0,0 +1,149 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADOPERATORBASE
+#define _H_MADOPERATORBASE
+
+#include "MAdDefines.h"
+#include "DiscreteSF.h"
+#include "ElementStatistics.h"
+#include "MeshQualityManager.h"
+#include "Constraint.h"
+#include "History.h"
+
+#include <string>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ typedef class MAdOperatorBase * pMAdOperator;
+
+ // -------------------------------------------------------------------
+ class MAdOperatorBase
+ {
+ public:
+
+ MAdOperatorBase();
+ MAdOperatorBase(const MAdOperatorBase &);
+ MAdOperatorBase(pMesh, DiscreteSF *);
+ virtual ~MAdOperatorBase();
+
+ public:
+
+ virtual operationType type() const = 0;
+
+ void setSizeField(DiscreteSF *);
+
+ double getWorstShape() const;
+ double getMinLenSq() const;
+ double getMaxLenSq() const;
+
+ // get a list of all elements that will be modified
+ virtual void getCavity(pPList *) const = 0;
+ void exportCavity(std::string) const;
+
+ // check if the operation can be performed and evaluate it
+ bool evaluate(double *);
+
+ // apply the operation
+ virtual void apply() = 0;
+
+ private:
+
+ // --- Checks and evaluations ---
+ // ! Supposed to be called in that order !
+
+ // checks the operation regarding the constraints on mesh entities
+ // and geometric entities
+ virtual bool checkConstraints() const = 0;
+
+ // checks compatibility of the operation with the geometric model
+ virtual bool checkGeometry() = 0;
+
+ // checks validity of the resulting elements and evaluates their
+ // shapes (saves the worst)
+ virtual bool evaluateShapes() = 0;
+
+ // evaluates the resulting minimal and maximal edge lengths
+ virtual void evaluateLengths() const = 0;
+
+ // ------------------------------
+
+ protected:
+
+ pMesh mesh;
+ DiscreteSF * sizeField;
+
+ // quality evaluator
+ MeshQualityManager& mqm;
+
+ // storage for the results of the evaluation
+ mutable ElementStatistics * results;
+
+ // mesh dimension
+ int dim;
+
+ };
+
+ // -------------------------------------------------------------------
+ inline MAdOperatorBase::MAdOperatorBase():
+ mesh(NULL), sizeField(NULL), mqm(MeshQualityManagerSgl::instance()),
+ results(NULL), dim(0)
+ {}
+
+ // -------------------------------------------------------------------
+ inline MAdOperatorBase::MAdOperatorBase(const MAdOperatorBase & _op):
+ mesh(_op.mesh), sizeField(_op.sizeField),
+ mqm(MeshQualityManagerSgl::instance())
+ {
+ results = new ElementStatistics(*(_op.results));
+ dim = _op.dim;
+ }
+
+ // -------------------------------------------------------------------
+ inline MAdOperatorBase::MAdOperatorBase(pMesh _mesh, DiscreteSF * _sf):
+ mesh(_mesh), sizeField(_sf), mqm(MeshQualityManagerSgl::instance())
+ {
+ results = new ElementStatistics();
+ dim = M_dim(mesh);
+ }
+
+ // -------------------------------------------------------------------
+ inline MAdOperatorBase::~MAdOperatorBase()
+ {
+ if (results) delete results;
+ }
+
+ // -------------------------------------------------------------------
+ inline void MAdOperatorBase::setSizeField(DiscreteSF * _sf)
+ {
+ sizeField = _sf;
+ }
+
+ // -------------------------------------------------------------------
+ inline double MAdOperatorBase::getWorstShape() const
+ { return results->getWorstShape(); }
+
+ // -------------------------------------------------------------------
+ inline double MAdOperatorBase::getMinLenSq() const
+ { return results->getMinLenSq(); }
+
+ // -------------------------------------------------------------------
+ inline double MAdOperatorBase::getMaxLenSq() const
+ { return results->getMaxLenSq(); }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/OperatorTools.cc b/Adapt/operator/OperatorTools.cc
new file mode 100644
index 0000000..dd6ea96
--- /dev/null
+++ b/Adapt/operator/OperatorTools.cc
@@ -0,0 +1,651 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Olivier Pierard, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "OperatorTools.h"
+#include "CallBackManager.h"
+#include "MAdMessage.h"
+
+#include <map>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ bool V_setPosition(pVertex vertex, double target[3])
+ {
+ if( EN_constrained((pEntity)vertex) ) return false;
+ CallBackManagerSgl::instance().callCallBackMoves(vertex,target);
+ pPoint point = V_point(vertex);
+ P_setPos(point,target[0],target[1],target[2]);
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void E_collapse(pMesh mesh,
+ pEdge edgeDel,
+ pVertex vDel,
+ pVertex vTgt)
+ {
+ pPList eRegions = E_regions(edgeDel);
+
+ // --- 2D collapse case ---
+ if( PList_size(eRegions) == 0 ) {
+ PList_delete(eRegions);
+ E_collapseOnGFace(mesh,edgeDel,vDel,vTgt);
+ return;
+ }
+
+ // --- build the new mesh ---
+
+ pPList newRegions = PList_new();
+ pPList vDelRegions = V_regions(vDel);
+ void * temp = NULL;
+ while ( pRegion region = (pRegion)PList_next(vDelRegions,&temp) )
+ {
+ if( PList_inList(eRegions,(pEntity)region) ) continue;
+
+ pFace fExt = R_vtOpFc(region,vDel);
+
+ // create the region
+ pGEntity rGEntity = (pGEntity)R_whatIn(region);
+ pRegion newR = mesh->add_tet(vTgt,F_vertex(fExt,0),F_vertex(fExt,1),F_vertex(fExt,2),rGEntity);
+ PList_append(newRegions, newR);
+ }
+ PList_delete(eRegions);
+
+ // --- classify new boundary entities ---
+ int gDim = E_whatInType(edgeDel);
+
+ // Classify edges on lines
+ if ( gDim == 1 )
+ {
+ pPList vDelEdges = V_edges(vDel);
+ temp = NULL;
+ pEdge pe;
+ int count = 0;
+ while ( ( pe = (pEdge)PList_next(vDelEdges,&temp) ) ) {
+ if ( pe == edgeDel ) continue;
+ if ( E_whatInType(pe) == 1 ) {
+ pGEntity gEdge2 = E_whatIn(pe);
+ pVertex oppV = E_otherVertex(pe,vDel);
+ pEdge newLineEdge = E_exist(vTgt,oppV);
+ E_setWhatIn(newLineEdge,gEdge2);
+ count++;
+ }
+ }
+ PList_delete(vDelEdges);
+ if ( count != 1 ) {
+ V_info(vDel);
+ E_info(edgeDel);
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Count should be equal to 1, count = %d",count);
+ assert (count == 1);
+ }
+ }
+
+ // classify faces on surfaces
+ if ( gDim <= 2 )
+ {
+ pGEntity gFace;
+ pEdge oppE;
+ pFace newSurfaceFace;
+
+ pPList vDelFaces = V_faces(vDel);
+ temp = NULL;
+ pFace pf;
+ while ( ( pf = (pFace)PList_next(vDelFaces,&temp) ) ) {
+ if ( F_inClosure(pf,edgeDel) ) continue;
+ if ( F_whatInType(pf) == 2 ) {
+ gFace = F_whatIn(pf);
+ oppE = F_vtOpEd(pf,vDel);
+ newSurfaceFace = F_exist(oppE,vTgt);
+ F_setWhatIn(newSurfaceFace,gFace);
+ }
+ }
+ PList_delete(vDelFaces);
+ }
+
+ // --- call callback functions ---
+ CallBackManagerSgl::instance().callCallBacks(vDelRegions,
+ newRegions,
+ MAd_ECOLLAPSE,
+ (pEntity)vDel);
+ PList_delete(newRegions);
+
+ // --- delete old cavity ---
+ temp = NULL;
+ while ( pRegion region = (pRegion)PList_next(vDelRegions,&temp) ) {
+ M_removeRegion(mesh,region);
+ }
+ PList_delete(vDelRegions);
+
+ pPList vFaces = V_faces(vDel);
+ temp = NULL;
+ while ( pFace face = (pFace)PList_next(vFaces,&temp) ) {
+ M_removeFace(mesh,face);
+ }
+ PList_delete(vFaces);
+
+ pPList vEdges = V_edges(vDel);
+ temp = NULL;
+ while ( pEdge edge = (pEdge)PList_next(vEdges,&temp) ) {
+ M_removeEdge(mesh,edge);
+ }
+ PList_delete(vEdges);
+
+ M_removeVertex(mesh,vDel);
+ }
+
+
+
+ /*
+// This is the old way to make a collapse
+
+ pPList eRegions = E_regions(edgeDel);
+
+ // --- 2D collapse case ---
+ if( PList_size(eRegions) == 0 ) {
+ PList_delete(eRegions);
+ E_collapseOnGFace(mesh,edgeDel,vDel,vTgt);
+ return;
+ }
+
+ // --- list faces to be merged ---
+
+ std::map<pFace,pFace> fOldToNew; // deleted face -> corresponding new (or target) face
+ std::map<pFace,bool> fDirs; // if direction of (deleted) face has to be changed
+
+ void * temp1 = 0;
+ while ( pRegion region = (pRegion)PList_next(eRegions,&temp1) ) {
+
+ pFace fDel, fTgt;
+
+ pPList rFaces = R_faces(region);
+ void * temp2 = 0;
+ while ( pFace face = (pFace)PList_next(rFaces, &temp2) ) {
+ if (!F_inClosure(face,(pEntity)edgeDel)) {
+ if (F_inClosure(face,(pEntity)vDel)) fDel = face; // deleted face
+ else fTgt = face; // target face
+ }
+ }
+ PList_delete(rFaces);
+
+ fOldToNew[fDel] = fTgt;
+
+ // Choose the direction and classification of target face
+ pEdge edge = F_vtOpEd(fDel,vDel);
+ if( F_whatInType(fDel) < F_whatInType(fTgt) ) {
+ F_setWhatIn( fTgt, F_whatIn(fDel) );
+ if( F_dirUsingEdge(fTgt,edge) != F_dirUsingEdge(fDel,edge) ) {
+ F_chDir(fTgt);
+ }
+ }
+ else {
+ if( F_dirUsingEdge(fTgt,edge) == F_dirUsingEdge(fDel,edge) ) {
+ fDirs[fDel] = true;
+ }
+ else {
+ fDirs[fDel] = false;
+ }
+ }
+ }
+
+ // --- list edges to be merged ---
+
+ std::map<pEdge,pEdge> eOldToNew; // deleted edge -> corresponding new (or target) edge
+ std::map<pEdge,bool> eDirs; // if direction of (deleted) edge has to be changed
+
+ pPList eFaces = E_faces(edgeDel);
+ void * temp3 = 0;
+ while ( pFace face = (pFace)PList_next(eFaces,&temp3) ) {
+
+ pEdge eDel, eTgt;
+
+ pPList fEdges = F_edges(face);
+ void * temp4 = 0;
+ while ( pEdge edge = (pEdge)PList_next(fEdges, &temp4) ) {
+ if ( edge != edgeDel ) {
+ if (E_inClosure(edge,(pEntity)vDel)) eDel = edge; // deleted edge
+ else eTgt = edge; // target edge
+ }
+ }
+ PList_delete(fEdges);
+
+ eOldToNew[eDel] = eTgt;
+
+ // Choose the classification of target edge
+ if( E_whatInType(eDel) < E_whatInType(eTgt) ) {
+ E_setWhatIn( eTgt, E_whatIn(eDel) );
+ }
+
+ // Choose the direction of target edge
+ if( E_vertex(eDel,0) == E_vertex(eTgt,0) ||
+ E_vertex(eDel,1) == E_vertex(eTgt,1) ) {
+ eDirs[eDel] = true;
+ }
+ else {
+ eDirs[eDel] = false;
+ }
+ }
+ PList_delete(eFaces);
+
+ // --- build the new mesh ---
+
+ pPList newRegions = PList_new();
+ pPList vDelRegions = V_regions(vDel);
+ void * temp5 = 0;
+ while ( pRegion region = (pRegion)PList_next(vDelRegions,&temp5) ) {
+
+ if( PList_inList(eRegions,(pEntity)region) ) continue;
+
+ // need to create a new region
+ pFace rFaces[4];
+
+ pFace fExt = R_vtOpFc(region,vDel);
+
+ for(int iF=0; iF<4; iF++) {
+
+ pFace face = R_face(region,iF);
+
+ if( face == fExt ) {
+ rFaces[iF] = face;
+ continue;
+ }
+
+ if ( fOldToNew.find(face) != fOldToNew.end() ) {
+ rFaces[iF] = fOldToNew.find(face)->second;
+ }
+ else {
+ // need to create a new face
+ pEdge fEdges[3];
+
+ for(int iE=0; iE<3; iE++ ) {
+
+ pEdge edge = F_edge(face,iE);
+
+ if( F_inClosure(fExt,(pEntity)edge) ) {
+ fEdges[iE] = edge;
+ continue;
+ }
+
+ if ( eOldToNew.find(edge) != eOldToNew.end() ) {
+ fEdges[iE] = eOldToNew.find(edge)->second;
+ }
+ else {
+ // need to create a new edge
+
+ pVertex eVertices[2];
+ for(int iV=0; iV<2; iV++) {
+ pVertex pV = E_vertex(edge,iV);
+ if( pV == vDel ) eVertices[iV] = vTgt;
+ else eVertices[iV] = pV;
+ }
+
+ // create the edge
+ pGEntity eGEntity = E_whatIn(edge);
+ fEdges[iE] = M_createE(mesh, eVertices[0], eVertices[1], eGEntity);
+ eOldToNew[edge] = fEdges[iE];
+ }
+ }
+
+ // create the face
+ pGEntity fGEntity = F_whatIn(face);
+ rFaces[iF] = M_createF(mesh, 3, fEdges, fGEntity);
+ fOldToNew[face] = rFaces[iF];
+ }
+ }
+
+ // create the region
+ pGEntity rGEntity = (pGEntity)R_whatIn(region);
+ pRegion newRegion = M_createR(mesh, 4, rFaces, rGEntity);
+ PList_append(newRegions, newRegion);
+ }
+
+ PList_delete(eRegions);
+
+ // --- call callback functions ---
+ CallBackManagerSgl::instance().callCallBacks(vDelRegions,
+ newRegions,
+ MAd_ECOLLAPSE,
+ (pEntity)vDel);
+ PList_delete(newRegions);
+
+ // --- delete old cavity ---
+ void * temp = 0;
+ while ( pRegion region = (pRegion)PList_next(vDelRegions,&temp) ) {
+ M_removeRegion(mesh,region);
+ }
+ PList_delete(vDelRegions);
+
+ pPList vFaces = V_faces(vDel);
+ temp = 0;
+ while ( pFace face = (pFace)PList_next(vFaces,&temp) ) {
+ M_removeFace(mesh,face);
+ }
+ PList_delete(vFaces);
+
+ pPList vEdges = V_edges(vDel);
+ temp = 0;
+ while ( pEdge edge = (pEdge)PList_next(vEdges,&temp) ) {
+ M_removeEdge(mesh,edge);
+ }
+ PList_delete(vEdges);
+
+ M_removeVertex(mesh,vDel);
+
+ */
+
+ // -------------------------------------------------------------------
+ void E_collapseOnGFace(pMesh mesh,
+ pEdge edgeDel,
+ pVertex vDel,
+ pVertex vTgt)
+ {
+ // --- list edges to be merged ---
+
+ std::map<pEdge,pEdge> eOldToNew; // deleted edge -> corresponding new (or target) edge
+ std::map<pEdge,bool> eDirs; // if direction of (deleted) edge has to be changed
+
+ pPList eFaces = E_faces(edgeDel);
+ void * temp1 = 0;
+ while ( pFace face = (pFace)PList_next(eFaces,&temp1) ) {
+
+ pEdge eDel, eTgt;
+
+ pPList fEdges = F_edges(face);
+ void * temp2 = 0;
+ while ( pEdge edge = (pEdge)PList_next(fEdges, &temp2) ) {
+ if ( edge != edgeDel ) {
+ if (E_inClosure(edge,(pEntity)vDel)) eDel = edge; // deleted edge
+ else eTgt = edge; // target edge
+ }
+ }
+ PList_delete(fEdges);
+
+ eOldToNew[eDel] = eTgt;
+
+ // Choose the classification of target edge
+ if( E_whatInType(eDel) < E_whatInType(eTgt) ) {
+ E_setWhatIn( eTgt, E_whatIn(eDel) );
+ }
+
+ // Choose the direction of target edge
+ if( E_vertex(eDel,0) == E_vertex(eTgt,0) ||
+ E_vertex(eDel,1) == E_vertex(eTgt,1) ) {
+ eDirs[eDel] = true;
+ }
+ else {
+ eDirs[eDel] = false;
+ }
+ }
+
+ // --- build the new mesh ---
+
+ pPList newFaces = PList_new();
+ pPList vDelFaces = V_faces(vDel);
+ void * temp3 = 0;
+ while ( pFace face = (pFace)PList_next(vDelFaces,&temp3) ) {
+
+ if( PList_inList(eFaces,(pEntity)face) ) continue;
+
+ // need to create a new face
+ pEdge fEdges[3];
+
+ pEdge eExt = F_vtOpEd(face,vDel);
+
+ for(int iE=0; iE<3; iE++ ) {
+
+ pEdge edge = F_edge(face,iE);
+
+ if( edge == eExt ) {
+ fEdges[iE] = edge;
+ continue;
+ }
+
+ if ( eOldToNew.find(edge) != eOldToNew.end() ) {
+ fEdges[iE] = eOldToNew.find(edge)->second;
+ }
+ else {
+ // need to create a new edge
+
+ pVertex eVertices[2];
+ for(int iV=0; iV<2; iV++) {
+ pVertex pV = E_vertex(edge,iV);
+ if( pV == vDel ) eVertices[iV] = vTgt;
+ else eVertices[iV] = pV;
+ }
+
+ // create the edge
+ pGEntity eGEntity = E_whatIn(edge);
+ fEdges[iE] = M_createE(mesh, eVertices[0], eVertices[1], eGEntity);
+ eOldToNew[edge] = fEdges[iE];
+ }
+ }
+
+ // create the face
+ pGEntity fGEntity = F_whatIn(face);
+ pFace newFace = M_createF(mesh, 3, fEdges, fGEntity);
+ PList_append(newFaces,newFace);
+ }
+
+ PList_delete(eFaces);
+
+ // --- call callback functions ---
+ CallBackManagerSgl::instance().callCallBacks(vDelFaces,
+ newFaces,
+ MAd_ECOLLAPSE,
+ (pEntity)vDel);
+ PList_delete(newFaces);
+
+ // --- delete old cavity ---
+ void * temp = 0;
+ while ( pFace face = (pFace)PList_next(vDelFaces,&temp) ) {
+ M_removeFace(mesh,face);
+ }
+ PList_delete(vDelFaces);
+
+ pPList vEdges = V_edges(vDel);
+ temp = 0;
+ while ( pEdge edge = (pEdge)PList_next(vEdges,&temp) ) {
+ M_removeEdge(mesh,edge);
+ }
+ PList_delete(vEdges);
+
+ M_removeVertex(mesh,vDel);
+ }
+
+
+ // -------------------------------------------------------------------
+ pVertex E_split(pMesh mesh, pEdge edge, double xyz[3], double t)
+ {
+ // --- build the vertex ---
+
+ pVertex newV = NULL; // the new vertex
+
+ pGEntity edgeGE = E_whatIn(edge); // its classification
+
+ double u[2][2];
+ u[0][0] = -2.; u[0][1] = -2.; u[1][0] = -2.; u[1][1] = -2.;
+ if ( E_params(edge,u) ) {
+ double uV[2];
+ if ( GEN_type(edgeGE) == 2 ) {
+ GF_centerOnGeodesic( (pGFace)edgeGE, t, u, uV );
+ }
+ else {
+ for (int iP=0; iP<2; iP++) uV[iP] = (1.-t) * u[0][iP] + t * u[1][iP];
+ }
+ newV = M_createVP(mesh, xyz[0], xyz[1], xyz[2], uV[0], uV[1], -1, edgeGE);
+ }
+ else {
+ newV = M_createV(mesh, xyz[0], xyz[1], xyz[2], -1, edgeGE);
+ }
+
+ // --- build the edges ---
+ pPList newEdges = PList_new();
+ pEdge e1 = M_createE(mesh, E_vertex(edge,0), newV, edgeGE);
+ PList_append(newEdges,e1);
+ pEdge e2 = M_createE(mesh, newV, E_vertex(edge,1), edgeGE);
+ PList_append(newEdges,e2);
+
+ // --- build the faces bordered by new edges ---
+ pPList newFaces = PList_new();
+ pPList eFaces = E_faces(edge);
+ void * temp = NULL;
+ while( pFace face = (pFace)PList_next(eFaces,&temp) ) {
+
+ pGEntity fGE = F_whatIn(face);
+ pEdge newE = M_createE(mesh, newV, F_edOpVt(face,edge), fGE);
+
+ int iEdge = 0;
+ for( iEdge=0; iEdge< F_numEdges(face); iEdge++) {
+ if( F_edge(face,iEdge) == edge ) break ;
+ }
+ pEdge fEdges[3];
+ fEdges[0] = edge ;
+ fEdges[1] = F_edge(face,(iEdge+1)%3);
+ fEdges[2] = F_edge(face,(iEdge+2)%3);
+
+ pFace newF1, newF2;
+ if( F_edgeDir(face,iEdge) ) {
+
+ pEdge newFEdges1[3] = {e1, newE, fEdges[2]};
+ newF1 = M_createF(mesh, 3, newFEdges1, fGE);
+ EN_attachDataP((pEntity)fEdges[2],"_EdgeSplitMarker_",(void *)newF1);
+
+ pEdge newFEdges2[3] = {e2, fEdges[1], newE};
+ newF2 = M_createF(mesh, 3, newFEdges2, fGE);
+ EN_attachDataP((pEntity)fEdges[1],"_EdgeSplitMarker_",(void *)newF2);
+ }
+ else {
+ pEdge newFEdges1[3] = {e1, fEdges[1], newE};
+ newF1 = M_createF(mesh, 3, newFEdges1, fGE);
+ EN_attachDataP((pEntity)fEdges[1],"_EdgeSplitMarker_",(void *)newF1);
+
+ pEdge newFEdges2[3] = {e2, newE, fEdges[2]};
+ newF2 = M_createF(mesh, 3, newFEdges2, fGE);
+ EN_attachDataP((pEntity)fEdges[2],"_EdgeSplitMarker_",(void *)newF2);
+ }
+ EN_attachDataP((pEntity)face,"_EdgeSplitMarker_",(void *)newE);
+ EN_attachDataP((pEntity)newF1,"_EdgeSplitMarker_",face);
+ EN_attachDataP((pEntity)newF2,"_EdgeSplitMarker_",face);
+
+ PList_append(newFaces,newF1);
+ PList_append(newFaces,newF2);
+ }
+
+ pPList delRegs = PList_new();
+ pPList eRegs = E_regions(edge);
+ if (eRegs) {
+
+ temp = NULL;
+ while( pRegion region = (pRegion)PList_next(eRegs, &temp) ) {
+
+ pGEntity rGE = (pGEntity)R_whatIn(region);
+
+ pFace extFaces[2];
+
+ // --- build the new face between the two new regions ---
+ pEdge fEdges[3];
+ for(int iF=0, eCount=0, fCount=0; iF<R_numFaces(region); iF++) {
+ pFace face = R_face(region,iF);
+ if( F_inClosure(face,(pEntity)edge) ) {
+ fEdges[eCount++] = (pEdge)EN_dataP((pEntity)face,"_EdgeSplitMarker_");
+ }
+ else {
+ extFaces[fCount++] = face;
+ }
+ }
+ pEdge oppE = R_gtOppEdg(region,edge);
+ fEdges[2] = oppE;
+ // if( E_vertex(fEdges[0],1) != E_vertex(fEdges[1],0) &&
+ // E_vertex(fEdges[0],1) != E_vertex(fEdges[1],1) ) {
+ // pEdge tmpE = fEdges[1] ;
+ // fEdges[1] = fEdges[2];
+ // fEdges[2] = tmpE;
+ // }
+ pFace newF = M_createF(mesh, 3, fEdges, rGE);
+
+ // -- build the regions ---
+ pFace rFaces[4];
+
+ rFaces[0] = extFaces[0] ;
+ rFaces[1] = newF;
+ int fIndex = 2;
+ for(int i=0; i<F_numEdges(extFaces[0]); i++) {
+ pEdge tmpE = F_edge(extFaces[0],i);
+ if( tmpE != oppE ) {
+ rFaces[fIndex] = (pFace)EN_dataP((pEntity)tmpE,"_EdgeSplitMarker_");
+ fIndex++;
+ }
+ }
+ M_createR(mesh, 4, rFaces, rGE);
+
+ rFaces[0] = extFaces[1] ;
+ rFaces[1] = newF;
+ fIndex = 2;
+ for( int i=0; i < F_numEdges(extFaces[1]); i++ ) {
+ pEdge tmpE = F_edge(extFaces[1],i);
+ if( tmpE != oppE ) {
+ rFaces[fIndex] = (pFace)EN_dataP((pEntity)tmpE,"_EdgeSplitMarker_");
+ fIndex++;
+ }
+ }
+ M_createR(mesh, 4, rFaces, rGE);
+
+ PList_append(delRegs,region);
+ }
+ }
+ PList_delete(eRegs);
+
+ pPList delEdge = PList_new();
+ PList_append(delEdge,edge);
+ CallBackManagerSgl::instance().callCallBacks(delEdge, newEdges,
+ MAd_ESPLIT, (pEntity)newV);
+ PList_delete(delEdge);
+ PList_delete(newEdges);
+
+ // --- remove regions ---
+ temp = NULL;
+ while( pRegion region = (pRegion)PList_next(delRegs,&temp) ) {
+ M_removeRegion(mesh, region);
+ }
+ PList_delete(delRegs);
+
+ // --- remove and clean faces ---
+ temp = NULL;
+ while( pFace face = (pFace)PList_next(eFaces,&temp) ) {
+
+ EN_removeData((pEntity)face,"_EdgeSplitMarker_");
+
+ for(int iE=0; iE<F_numEdges(face); iE++) {
+ pEdge iEdge = F_edge(face,iE);
+ if( iEdge != edge ) EN_removeData((pEntity)iEdge,"_EdgeSplitMarker_");
+ }
+
+ M_removeFace(mesh, face);
+ }
+ PList_delete(eFaces);
+
+ temp = NULL;
+ while( pFace face = (pFace)PList_next(newFaces,&temp) ) {
+ EN_removeData((pEntity)face,"_EdgeSplitMarker_");
+ }
+ PList_delete(newFaces);
+
+ // --- remove edge ---
+ M_removeEdge(mesh,edge);
+
+ return newV ;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/OperatorTools.h b/Adapt/operator/OperatorTools.h
new file mode 100644
index 0000000..1167260
--- /dev/null
+++ b/Adapt/operator/OperatorTools.h
@@ -0,0 +1,48 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_OPERATORTOOLS
+#define _H_OPERATORTOOLS
+
+#include "MSops.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+
+ bool V_setPosition(pVertex, double[3]);
+
+ // --- Related to edge collapse ---
+
+ void E_collapse(pMesh, // the mesh
+ pEdge, // the edge to be collapsed
+ pVertex, // the vertex to be deleted
+ pVertex // the target vertex
+ );
+
+ void E_collapseOnGFace(pMesh, // the mesh
+ pEdge, // the edge to be collapsed
+ pVertex, // the vertex to be deleted
+ pVertex // the target vertex
+ );
+
+ // --- Related to edge split ---
+
+ pVertex E_split(pMesh, pEdge, double[3], double t=0.5);
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
+
diff --git a/Adapt/operator/RegionRemoveOp.cc b/Adapt/operator/RegionRemoveOp.cc
new file mode 100644
index 0000000..d31503f
--- /dev/null
+++ b/Adapt/operator/RegionRemoveOp.cc
@@ -0,0 +1,184 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "RegionRemoveOp.h"
+#include "CallBackManager.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ bool regionRemoveOp::checkConstraints() const
+ {
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool regionRemoveOp::checkGeometry()
+ {
+ // deny if a vertex is classified on a geometrical edge or vertex
+ int nbClassVerts = 0;
+ pPList rVerts = R_vertices(region);
+ void * temp = NULL;
+ while ( pVertex vert = (pVertex) PList_next(rVerts,&temp) ) {
+ if ( EN_whatInType((pEntity)vert) < 2 ) nbClassVerts++;
+ }
+ PList_delete(rVerts);
+ if ( nbClassVerts != 0 ) return false;
+
+ // deny if an edge is classified on a geometrical edge
+ int nbClassEdges = 0;
+ pPList rEdges = R_edges(region);
+ void * temp2 = NULL;
+ while ( pEdge edge = (pEdge) PList_next(rEdges,&temp2) ) {
+ if ( EN_whatInType((pEntity)edge) < 2 ) nbClassEdges++;
+ }
+ PList_delete(rEdges);
+ if ( nbClassEdges != 0 ) return false;
+
+ int nbExternalFaces = 0;
+ for (int iF=0; iF < 4; iF++) {
+
+ pFace face = R_face(region,iF);
+
+ // see which faces will be deleted
+ if ( F_numRegions(face) == 1 ) {
+ nbExternalFaces++;
+ delFace[iF] = true;
+ }
+ else {
+ delFace[iF] = false;
+ }
+
+ // see on which geometric entity the new
+ // boundary faces will be classified
+ pGEntity pGE = EN_whatIn((pEntity)face);
+ if ( GEN_type(pGE) == 2 ) {
+ classifyFaces = true;
+ geoFace = pGE;
+ }
+ }
+ // ensure not to create a hole in a volume
+ if ( nbExternalFaces == 0 ) return false;
+
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ bool regionRemoveOp::evaluateShapes()
+ {
+ double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+ results->setWorstShape( worstShape );
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void regionRemoveOp::evaluateLengths() const
+ {
+ results->setMinLenSq(1.);
+ results->setMaxLenSq(1.);
+ }
+
+ // -------------------------------------------------------------------
+ void regionRemoveOp::apply()
+ {
+ // --- classify faces ---
+ if (classifyFaces) {
+ for (int iF=0; iF < 4; iF++) {
+ if ( delFace[iF] == false ) {
+ pFace face = R_face(region,iF);
+ F_setWhatIn(face,geoFace);
+ }
+ }
+ }
+
+ // --- list faces to delete ---
+ pPList delF = PList_new();
+ for (int iF=0; iF < 4; iF++) {
+ if ( delFace[iF] == true ) PList_append(delF,R_face(region,iF));
+ }
+
+ // --- list edges to delete ---
+ pPList delE = PList_new();
+ pPList rEdges = R_edges(region);
+ void * temp = NULL;
+ while ( pEdge edge = (pEdge) PList_next(rEdges,&temp) ) {
+ bool toDel = true;
+ pPList eFaces = E_faces(edge);
+ void * temp2 = NULL;
+ while ( pFace face = (pFace) PList_next(eFaces,&temp2) ) {
+ if ( !PList_inList(delF,face) ) { toDel = false; break; }
+ }
+ PList_delete(eFaces);
+ if (toDel) PList_append(delE,edge);
+ }
+ PList_delete(rEdges);
+
+ // --- list vertices to delete ---
+ pPList delV = PList_new();
+ pPList rVerts = R_vertices(region);
+ void * temp3 = NULL;
+ while ( pVertex vert = (pVertex) PList_next(rVerts,&temp3) ) {
+ bool toDel = true;
+ pPList vEdges = V_edges(vert);
+ void * temp4 = NULL;
+ while ( pEdge edge = (pEdge) PList_next(vEdges,&temp4) ) {
+ if ( !PList_inList(delE,edge) ) { toDel = false; break; }
+ }
+ if (toDel) PList_append(delV,vert);
+ }
+ PList_delete(rVerts);
+
+
+ // --- call callback functions ---
+ pPList emptyList;
+ pPList delEn = PList_new();
+ void * delTmp = NULL;
+ while ( pFace face = (pFace) PList_next(delF,&delTmp) ) PList_append(delEn,face);
+ delTmp = NULL;
+ while ( pEdge edge = (pEdge) PList_next(delE,&delTmp) ) PList_append(delEn,edge);
+ delTmp = NULL;
+ while ( pVertex vert = (pVertex) PList_next(delV,&delTmp) ) PList_append(delEn,vert);
+ CallBackManagerSgl::instance().callCallBacks(delEn,
+ emptyList,
+ MAd_RREMOVE,
+ region);
+ PList_delete(delEn);
+
+ // --- delete entities ---
+
+ M_removeRegion(mesh,region);
+
+ void * delTmp2 = NULL;
+ while ( pFace face = (pFace) PList_next(delF,&delTmp2) ) {
+ M_removeFace(mesh,face);
+ }
+
+ delTmp2 = NULL;
+ while ( pEdge edge = (pEdge) PList_next(delE,&delTmp2) ) {
+ M_removeEdge(mesh,edge);
+ }
+
+ delTmp2 = NULL;
+ while ( pVertex vertex = (pVertex) PList_next(delV,&delTmp2) ) {
+ M_removeVertex(mesh,vertex);
+ }
+
+ PList_delete(delF);
+ PList_delete(delE);
+ PList_delete(delV);
+
+ HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/RegionRemoveOp.h b/Adapt/operator/RegionRemoveOp.h
new file mode 100644
index 0000000..48ba6af
--- /dev/null
+++ b/Adapt/operator/RegionRemoveOp.h
@@ -0,0 +1,87 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_REGIONREMOVEOP
+#define _H_REGIONREMOVEOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class regionRemoveOp: public MAdOperatorBase
+ {
+ public:
+
+ regionRemoveOp(pMesh, DiscreteSF *);
+ regionRemoveOp(const regionRemoveOp &);
+ ~regionRemoveOp() {}
+
+ operationType type() const { return MAd_RREMOVE; }
+
+ void setRegion(pRegion);
+
+ void getCavity(pPList *) const;
+
+ void apply();
+
+ private:
+
+ bool checkConstraints() const;
+ bool checkGeometry();
+ bool evaluateShapes();
+ void evaluateLengths() const;
+
+ private:
+
+ pRegion region;
+
+ bool classifyFaces;
+ pGEntity geoFace;
+
+ bool delFace[4];
+ };
+
+ // -------------------------------------------------------------------
+ inline regionRemoveOp::regionRemoveOp(const regionRemoveOp & _rr):
+ MAdOperatorBase(_rr), region(_rr.region),
+ classifyFaces(_rr.classifyFaces), geoFace(_rr.geoFace)
+ {
+ for (int i=0; i<4; i++) delFace[i] = _rr.delFace[i];
+ }
+
+ // -------------------------------------------------------------------
+ inline regionRemoveOp::regionRemoveOp(pMesh _m, DiscreteSF * _sf):
+ MAdOperatorBase(_m,_sf), region(NULL),
+ classifyFaces(false), geoFace(NULL)
+ {
+ for (int i=0; i<4; i++) delFace[i] = false;
+ }
+
+ // -------------------------------------------------------------------
+ inline void regionRemoveOp::setRegion(pRegion _region)
+ {
+ region = _region;
+ }
+
+ // -------------------------------------------------------------------
+ inline void regionRemoveOp::getCavity(pPList * cavity) const
+ {
+ PList_append(*cavity,region);
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/SliverFaceHandler.cc b/Adapt/operator/SliverFaceHandler.cc
new file mode 100644
index 0000000..920c9a7
--- /dev/null
+++ b/Adapt/operator/SliverFaceHandler.cc
@@ -0,0 +1,275 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "SliverFaceHandler.h"
+#include "EdgeSwapOp.h"
+#include "EdgeCollapseOp.h"
+#include "FaceCollapseOp.h"
+#include "MeshParametersManager.h"
+#include "MAdOutput.h"
+
+// standard C/C++
+#include <set>
+using std::set;
+#include <sstream>
+using std::stringstream;
+using std::string;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void sliverFaceHandler::removeSliverFaces(int* nbSliverIn, int* nbSliverOut)
+ {
+ // --- list all slivers ---
+
+ set<pFace> slivers;
+ if (nbSliverIn) (*nbSliverIn) = 0;
+ FIter fIter = M_faceIter(mesh);
+ while( pFace face = FIter_next(fIter) ) {
+ if ( F_isSliver(face) ) {
+ slivers.insert(face);
+ if (nbSliverIn) (*nbSliverIn)++;
+ }
+ }
+ FIter_delete(fIter);
+
+ // --- iterate on slivers elimination attempts ---
+
+ int iter = 0;
+ int maxIter = 5;
+ bool eliminated = true;
+ *nbSliverOut = *nbSliverIn;
+ while ( ( eliminated ) &&
+ ( *nbSliverOut > 0 ) &&
+ ( iter < maxIter ) ) {
+
+ eliminated = false;
+
+ set<pFace> oldSlivers;
+
+ // --- process the slivers list ---
+ set<pFace>::iterator sIter = slivers.begin();
+ set<pFace>::iterator sLast = slivers.end();
+ for (; sIter != sLast; sIter++) {
+
+ pFace sliver = *sIter;
+
+ // --- check if the sliver still exists ---
+ if ( oldSlivers.find(sliver) != oldSlivers.end() ) continue;
+
+ // --- check if the sliver is still a sliver ---
+ if ( !F_isSliver(sliver) ) {
+ oldSlivers.insert(sliver);
+ continue;
+ }
+
+ // --- find an appropriate modification ---
+ pMAdOperator modif = NULL;
+ int result = findOperation(sliver,&modif);
+
+ if ( result <= 0 && reportFailures ) reportSliver(sliver);
+
+ if ( result >= 1 && modif ) {
+
+ // --- prepare to remove deleted faces from sliver list ---
+ pPList cavity;
+ modif->getCavity(&cavity);
+ void * tmp = 0;
+ while( pFace pf = (pFace)PList_next(cavity,&tmp) ) {
+ oldSlivers.insert(pf);
+ }
+ PList_delete(cavity);
+
+ // --- eliminate the sliver ---
+ modif->apply();
+ eliminated = true;
+ oldSlivers.insert(sliver);
+ }
+
+ if (modif) delete modif;
+ }
+
+ // --- count remaining and list slivers ---
+ slivers.clear();
+ if (nbSliverOut) (*nbSliverOut) = 0;
+ fIter = M_faceIter(mesh);
+ while( pFace face = FIter_next(fIter) ) {
+ if ( F_isSliver(face) ) {
+ slivers.insert(face);
+ if (nbSliverOut) (*nbSliverOut)++;
+ }
+ }
+ FIter_delete(fIter);
+
+ iter++;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ // Try to find a modification that eliminates the sliver triangle.
+ // Return:
+ // 0: no modification found
+ // 1: a modification is found but with a resulting sliver (with better shape)
+ // 2: a modification is found with no remaining sliver
+ int sliverFaceHandler::findOperation(pFace face,
+ pMAdOperator* modification)
+ {
+ MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+ *modification = NULL;
+
+ double bestShape = 0.;
+ mqm.getShape(face,0,&bestShape);
+
+ if ( bestShape >= mpm.getSliverTriBound() ) {
+ printf ("Warning: processing a face which is not a sliver in findOperation\n");
+ return 0;
+ }
+
+ // check edge swaps
+ // -----------------
+
+ edgeSwapOp eSwap(mesh,sizeField);
+// if( collapseOnBdry ) eSwap.setCheckVolume(0.,dATol);
+
+ for (int i=0; i<3; i++) {
+
+ eSwap.setSwapEdge(F_edge(face,i));
+
+ double worst;
+ if ( eSwap.evaluate(&worst) && worst > bestShape ) {
+ bestShape = worst;
+ if (*modification) delete *modification;
+ *modification = new edgeSwapOp(eSwap);
+ if (bestShape > mpm.getSliverTriBound()) return 2;
+ }
+ }
+
+ // check edge collapses
+ // ---------------------
+
+ edgeCollapseOp eCollapse(mesh,sizeField);
+ eCollapse.collapseOnBoundary(collapseOnBdry,dATol);
+
+ for(int i=0; i<3; i++) {
+
+ pEdge edge = F_edge(face,i);
+
+ for (int j=0; j<2; j++) {
+
+ eCollapse.setCollapseEdge(edge,E_vertex(edge,j),E_vertex(edge,(j+1)%2));
+
+ double worst;
+ if (eCollapse.evaluate(&worst) && worst > bestShape ) {
+ bestShape = worst;
+ if (*modification) delete *modification;
+ *modification = new edgeCollapseOp(eCollapse);
+ if (bestShape > mpm.getSliverTriBound()) return 2;
+ // if (bestShape > mpm.getSliverTriBound()) { printf("Applied edge collapse\n"); return 2;}
+ }
+ }
+ }
+
+ // check face collapse
+ // --------------------
+
+ if ( addNodes )
+ {
+ faceCollapseOp fCollapse(mesh,sizeField);
+ fCollapse.collapseOnBoundary(collapseOnBdry,dATol);
+
+ for(int iE=0; iE<3; iE++) {
+
+ pEdge edge = F_edge(face,iE);
+
+ for (int iDir=0; iDir<2; iDir++) {
+
+ fCollapse.reset(face,edge,(bool)iDir);
+
+ double worst;
+ if (fCollapse.evaluate(&worst) && worst > bestShape ) {
+ bestShape = worst;
+ if (*modification) delete *modification;
+ *modification = new faceCollapseOp(fCollapse);
+ if (bestShape > mpm.getSliverTriBound()) return 2;
+ // if (bestShape > mpm.getSliverTriBound()) { printf("Applied face collapse\n"); return 2;}
+ }
+ }
+ }
+ }
+
+ if( *modification ) return 1;
+
+ return 0;
+ }
+
+ // -------------------------------------------------------------------
+ bool sliverFaceHandler::F_isSliver(pFace face)
+ {
+ MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+ double shape;
+ mqm.getShape(face,0,&shape);
+
+ if( shape < mpm.getSliverTriBound() )
+ return true;
+
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ bool sliverFaceHandler::F_isSliver(pFace face, double * shape)
+ {
+ MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+ mqm.getShape(face,0,shape);
+
+ if( *shape < mpm.getSliverTriBound() )
+ return true;
+
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ void sliverFaceHandler::reportSliver(pFace face)
+ {
+ stringstream ss;
+ string idStr; ss << reportId; ss >> idStr;
+
+ string name = reportPrefix + "sliver" + idStr + ".pos";
+
+ pPList cavity = PList_new();
+
+ PList_append(cavity,face);
+
+ for (int iV=0; iV<F_numVertices(face); iV++) {
+
+ pVertex vertex = F_vertex(face, iV);
+
+ pPList vFaces = V_faces(vertex);
+ void * temp = 0;
+ while ( pFace pf = (pFace)PList_next(vFaces,&temp) ) {
+ PList_appUnique(cavity,pf);
+ }
+ PList_delete(vFaces);
+ }
+
+ printPosEntities(cavity,name.c_str(),OD_MEANRATIO,sizeField);
+
+ PList_delete(cavity);
+
+ reportId++;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/SliverFaceHandler.h b/Adapt/operator/SliverFaceHandler.h
new file mode 100644
index 0000000..53287a0
--- /dev/null
+++ b/Adapt/operator/SliverFaceHandler.h
@@ -0,0 +1,111 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_SLIVERFACEHANDLER
+#define _H_SLIVERFACEHANDLER
+
+#include "MAdOperatorBase.h"
+
+#include <string>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class sliverFaceHandler {
+
+ public:
+
+ sliverFaceHandler(pMesh, DiscreteSF *);
+ ~sliverFaceHandler() {}
+
+ public:
+
+ void removeSliverFaces(int * nbIn=NULL, int * nbOut=NULL);
+
+ void setSizeField(DiscreteSF *);
+
+ // whether we can use operations on boundaries
+ void collapseOnBoundary(bool, double);
+
+ // whether we can use operations that add nodes
+ void newVertexPermission(bool);
+ bool getNewVertexPermission() const { return addNodes; }
+
+ void enableReport(std::string);
+
+ private:
+
+ int findOperation(pFace, pMAdOperator *);
+
+ bool F_isSliver(pFace);
+ bool F_isSliver(pFace, double *);
+
+ void reportSliver(pFace);
+
+ private:
+
+ pMesh mesh;
+ DiscreteSF * sizeField;
+ MeshQualityManager& mqm;
+
+ bool collapseOnBdry;
+ double dATol;
+
+ bool addNodes; // whether or not we can use operators that add nodes
+ // (edge split)
+
+ bool reportFailures;
+ int reportId;
+ std::string reportPrefix;
+
+ };
+
+ // -------------------------------------------------------------------
+ inline sliverFaceHandler::sliverFaceHandler(pMesh m, DiscreteSF * sf):
+ mesh(m),sizeField(sf), mqm(MeshQualityManagerSgl::instance()),
+ collapseOnBdry(false), dATol(MAdTOL), addNodes(true),
+ reportFailures(false),reportId(0),reportPrefix("")
+ {}
+
+ // -------------------------------------------------------------------
+ inline void sliverFaceHandler::setSizeField(DiscreteSF * sf)
+ {
+ sizeField = sf;
+ }
+
+ // -------------------------------------------------------------------
+ inline void sliverFaceHandler::collapseOnBoundary(bool cob, double tolerance)
+ {
+ collapseOnBdry = cob;
+ dATol = tolerance;
+ }
+
+ // -------------------------------------------------------------------
+ inline void sliverFaceHandler::newVertexPermission(bool allow)
+ {
+ addNodes = allow;
+ }
+
+ // -------------------------------------------------------------------
+ inline void sliverFaceHandler::enableReport(std::string prefix)
+ {
+ reportFailures = true;
+ reportPrefix = prefix;
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
+
diff --git a/Adapt/operator/SliverRegionHandler.cc b/Adapt/operator/SliverRegionHandler.cc
new file mode 100644
index 0000000..ddac9d6
--- /dev/null
+++ b/Adapt/operator/SliverRegionHandler.cc
@@ -0,0 +1,1221 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "SliverRegionHandler.h"
+#include "EdgeSplitOp.h"
+#include "EdgeCollapseOp.h"
+#include "FaceCollapseOp.h"
+#include "DESCOp.h"
+#include "EdgeSwapOp.h"
+#include "FaceSwapOp.h"
+#include "VertexMoveOp.h"
+#include "MeshParametersManager.h"
+#include "MAdOutput.h"
+#include "MathUtils.h"
+
+#include <sstream>
+using std::stringstream;
+using std::set;
+using std::ostream;
+using std::string;
+using std::endl;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void sliverRegionHandler::removeSliverRegions(int* nbSliverIn, int* nbSliverOut)
+ {
+ // --- list all slivers ---
+
+ set<pRegion> slivers;
+ if (nbSliverIn) (*nbSliverIn) = 0;
+ RIter rIter = M_regionIter(mesh);
+ while( pRegion region = RIter_next(rIter) ) {
+ if ( R_isSliver(region) ) {
+ slivers.insert(region);
+ if (nbSliverIn) (*nbSliverIn)++;
+ }
+ }
+ RIter_delete(rIter);
+
+ // --- iterate on slivers elimination attempts ---
+
+ int iter = 0;
+ int maxIter = 5;
+ bool eliminated = true;
+ *nbSliverOut = *nbSliverIn;
+ while ( ( eliminated ) &&
+ ( *nbSliverOut > 0 ) &&
+ ( iter < maxIter ) ) {
+
+ eliminated = false;
+
+ set<pRegion> oldSlivers;
+
+ // --- process the slivers list ---
+ set<pRegion>::iterator sIter = slivers.begin();
+ set<pRegion>::iterator sLast = slivers.end();
+ for (; sIter != sLast; sIter++) {
+
+ pRegion sliver = *sIter;
+
+ // --- check if the sliver still exists ---
+ if ( oldSlivers.find(sliver) != oldSlivers.end() ) continue;
+
+ // --- check if the sliver is still a sliver ---
+ if ( !R_isSliver(sliver) ) {
+ oldSlivers.insert(sliver);
+ continue;
+ }
+
+ // --- find an appropriate modification ---
+ pMAdOperator modif = NULL;
+ int result = findOperation(sliver,&modif);
+
+ if ( testOperators ) testOperations(sliver);
+
+ if ( result <= 0 && reportFailures ) reportSliver(sliver);
+
+ if ( result >= 1 ) {
+
+ assert(modif);
+
+ // --- prepare to remove deleted regions from sliver list ---
+ pPList affReg;
+ modif->getCavity(&affReg);
+ void * tmp = 0;
+ while( pRegion pr = (pRegion)PList_next(affReg,&tmp) ) {
+ oldSlivers.insert(pr);
+ }
+ PList_delete(affReg);
+
+ // --- eliminate the sliver ---
+ modif->apply();
+ eliminated = true;
+ oldSlivers.insert(sliver);
+ }
+
+ if (modif) delete modif;
+ }
+
+ // --- count remaining and list slivers ---
+ slivers.clear();
+ if (nbSliverOut) (*nbSliverOut) = 0;
+ rIter = M_regionIter(mesh);
+ while( pRegion region = RIter_next(rIter) ) {
+ if ( R_isSliver(region) ) {
+ slivers.insert(region);
+ if (nbSliverOut) (*nbSliverOut)++;
+ }
+ }
+ RIter_delete(rIter);
+
+ iter++;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ // Try to find an operation that eliminates the sliver.
+ // Returns:
+ // 0: no modification found
+ // 1: a modification is found but with a resulting sliver (with better shape)
+ // 2: a modification is found with no remaining sliver
+ int sliverRegionHandler::findOperation(pRegion region,
+ pMAdOperator* operation)
+ {
+ MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+ *operation = NULL;
+
+ double bestShape = 0.;
+ mqm.getShape(region,&bestShape);
+
+ if ( bestShape >= mpm.getSliverTetBound() ) {
+ printf ("Warning: processing a tet which is not a sliver in handleSliverTet\n");
+ return 0;
+ }
+
+ edgeCollapseOp eCollOp (mesh,sizeField);
+ eCollOp.collapseOnBoundary(collapseOnBdry,dVTolClps);
+
+ faceCollapseOp fCollOp (mesh,sizeField);
+ fCollOp.collapseOnBoundary(collapseOnBdry,dVTolClps);
+
+ edgeSwapOp eSwapOp (mesh,sizeField);
+ eSwapOp.swapOnBoundary(swapOnBdry,dVTolSwap);
+
+ DESCOp descOp (mesh,sizeField);
+ edgeSplitOp eSplitOp(mesh,sizeField);
+ faceSwapOp fSwapOp (mesh,sizeField);
+ vertexMoveOp vMoveOp (mesh,sizeField,false);
+
+ pEntity keyEnts[4];
+ int sType = getSliverType(region, keyEnts);
+ if( sType == 0 ) return 0;
+
+ double worst;
+
+ // --- TYPE I slivers ---
+ if( sType == 1 )
+ {
+#ifdef MAKESTATS
+ numTypeI_In++;
+#endif
+
+ // check split
+ // ------------
+ if ( addNodes ) {
+ for(int i=0; i<2; i++) {
+#ifdef MAKESTATS
+ numSplitTested_I++;
+#endif
+ eSplitOp.setSplitEdge((pEdge)keyEnts[i]);
+
+ if( E_whatInType((pEdge)keyEnts[i]) != 3 ) continue;
+
+ // determine the position of the new vertex
+// double newPos[3];
+// E_cavityCenter( (pEdge)keyEnts[i], newPos );
+// double t = E_linearParams((pEdge)keyEnts[i],newPos);
+// if( t>1. || t<0. ) continue;
+// eSplitOp.setSplitPos(newPos);
+
+ worst = -1.;
+ if( eSplitOp.evaluate(&worst) && worst > bestShape &&
+ eSplitOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ eSplitOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ bestShape = worst;
+ if(*operation) delete *operation;
+ *operation = new edgeSplitOp(eSplitOp);
+#ifdef MAKESTATS
+ numSplitAvailable_I++;
+ if (bestShape < mpm.getSliverTetBound()) numSplitToSliver_I++;
+#endif
+ if (bestShape > mpm.getSliverTetBound()) break;
+ }
+ }
+ if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+ numSplitOperated_I++;
+#endif
+ return 2;
+ }
+ }
+
+ // check edge collapses
+ // ---------------------
+ for(int i=0; i<6; i++) {
+ pEdge edge = R_edge(region,i);
+ for (int j=0; j<2; j++) {
+#ifdef MAKESTATS
+ numEClpsTested_I++;
+#endif
+ eCollOp.setCollapseEdge(edge,E_vertex(edge,j),E_vertex(edge,1-j));
+
+ worst = -1.;
+ if ( eCollOp.evaluate(&worst) && worst > bestShape &&
+ eCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ eCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ bestShape = worst;
+ if (*operation) delete *operation;
+ *operation = new edgeCollapseOp(eCollOp);
+#ifdef MAKESTATS
+ numEClpsAvailable_I++;
+ if (worst < mpm.getSliverTetBound()) numEClpsToSliver_I++;
+#endif
+ if (bestShape > mpm.getSliverTetBound()) break;
+ }
+ }
+ if (bestShape > mpm.getSliverTetBound()) break;
+ }
+ if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+ numEClpsOperated_I++;
+#endif
+ return 2;
+ }
+
+ // check double edge split collapse
+ // ---------------------------------
+ if ( addNodes ) {
+ for(int i=0; i<2; i++) {
+#ifdef MAKESTATS
+ numDESCTested_I++;
+#endif
+ descOp.setDESC(region,(pEdge)keyEnts[i%2],(pEdge)keyEnts[(i+1)%2]);
+
+ worst = -1.;
+ if( descOp.evaluate(&worst) && worst > bestShape &&
+ descOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ descOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ bestShape = worst;
+ if(*operation) delete *operation;
+ *operation = new DESCOp(descOp);
+#ifdef MAKESTATS
+ numDESCAvailable_I++;
+ if (worst < mpm.getSliverTetBound()) numDESCToSliver_I++;
+#endif
+ }
+ if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+ numDESCOperated_I++;
+#endif
+ return 2;
+ }
+ }
+ }
+
+ // check face collapse
+ // --------------------
+ if ( addNodes ) {
+ for(int i=0; i<2; i++) {
+ for( int ClpsOnvt=1; ClpsOnvt>=0; ClpsOnvt-- ) {
+#ifdef MAKESTATS
+ numFClpsTested_I++;
+#endif
+ fCollOp.reset((pFace)keyEnts[i+2],(pEdge)keyEnts[i], ClpsOnvt);
+
+ worst = -1.;
+ if( fCollOp.evaluate(&worst) && worst > bestShape &&
+ fCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ fCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ bestShape = worst;
+ if (*operation) delete *operation;
+ *operation = new faceCollapseOp(fCollOp);
+#ifdef MAKESTATS
+ numFClpsAvailable_I++;
+ if (worst < mpm.getSliverTetBound()) {
+ numFClpsToSliver_I++;
+ }
+#endif
+ if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+ numFClpsOperated_I++;
+#endif
+ return 2;
+ }
+ }
+ }
+ }
+ }
+
+ // check edge swaps
+ // -----------------
+ for(int i=0; i<2; i++) {
+#ifdef MAKESTATS
+ numSwapTested_I++;
+#endif
+ eSwapOp.setSwapEdge((pEdge)keyEnts[i]);
+
+ worst = -1.;
+ if( eSwapOp.evaluate(&worst) && worst > bestShape &&
+ eSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ eSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ bestShape = worst;
+ if (*operation) delete *operation;
+ *operation = new edgeSwapOp(eSwapOp);
+#ifdef MAKESTATS
+ numSwapAvailable_I++;
+ if (worst < mpm.getSliverTetBound()) numSwapToSliver_I++;
+#endif
+ if (bestShape > mpm.getSliverTetBound()) break;
+ }
+ }
+ if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+ numSwapOperated_I++;
+#endif
+ return 2;
+ }
+
+ // check vertex move
+ // ------------------
+ pPList verts = R_vertices(region);
+ void * temp = NULL;
+ while ( pVertex pv = (pVertex)PList_next(verts,&temp) ) {
+#ifdef MAKESTATS
+ numVMoveTested_I++;
+#endif
+ if( V_whatInType(pv) != 3 ) continue;
+
+ vMoveOp.setPositionToOptimal(pv);
+
+ worst = -1.;
+ if( vMoveOp.evaluate(&worst) && worst > bestShape &&
+ vMoveOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ vMoveOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ bestShape = worst;
+ if(*operation) delete *operation;
+ *operation = new vertexMoveOp(vMoveOp);
+#ifdef MAKESTATS
+ numVMoveAvailable_I++;
+ if (bestShape < mpm.getSliverTetBound()) numVMoveToSliver_I++;
+#endif
+ }
+ }
+ PList_delete(verts);
+ if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+ numVMoveOperated_I++;
+#endif
+ return 2;
+ }
+
+
+#ifdef MAKESTATS
+ if( *operation ) {
+ switch ((*operation)->type()) {
+ case MAd_ECOLLAPSE: { numEClpsOperated_I++; break; }
+ case MAd_ESWAP: { numSwapOperated_I++; break; }
+ case MAd_FCOLLAPSE: { numFClpsOperated_I++; break; }
+ case MAd_DESPLTCLPS: { numDESCOperated_I++; break; }
+ case MAd_ESPLIT: { numSplitOperated_I++; break; }
+ case MAd_VERTEXMOVE: { numVMoveOperated_I++; break; }
+ default: throw;
+ }
+ }
+#endif
+
+ if( *operation ) return 1;
+
+#ifdef MAKESTATS
+ set<pRegion>::const_iterator sIter = sliversOut.find(region);
+ if (sIter == sliversOut.end() ) {
+ sliversOut.insert(region);
+ numTypeI_Out++;
+ }
+#endif
+ }
+
+ // --- TYPE II slivers ---
+ else
+ {
+#ifdef MAKESTATS
+ numTypeII_In++;
+#endif
+
+ // check edge collapses
+ // ---------------------
+ for(int i=0; i<6; i++) {
+#ifdef MAKESTATS
+ numEClpsTested_II++;
+#endif
+ pEdge edge = R_edge(region,i);
+ for (int j=0; j<2; j++) {
+ eCollOp.setCollapseEdge(edge,E_vertex(edge,j),E_vertex(edge,(j+1)%2));
+
+ worst = -1.;
+ if( eCollOp.evaluate(&worst) && worst > bestShape &&
+ eCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ eCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ bestShape = worst;
+ if (*operation) delete *operation;
+ *operation = new edgeCollapseOp(eCollOp);
+#ifdef MAKESTATS
+ numEClpsAvailable_II++;
+ if (worst < mpm.getSliverTetBound()) numEClpsToSliver_II++;
+#endif
+ if (bestShape > mpm.getSliverTetBound()) break;
+ }
+ }
+ if (bestShape > mpm.getSliverTetBound()) break;
+ }
+ if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+ numEClpsOperated_II++;
+#endif
+ return 2;
+ }
+
+ // check face collapse
+ // --------------------
+ if ( addNodes ) {
+ for( int ClpsOnvt=1; ClpsOnvt>=0; ClpsOnvt-- ) {
+#ifdef MAKESTATS
+ numFClpsTested_II++;
+#endif
+ fCollOp.reset((pFace)keyEnts[2],(pEdge)keyEnts[1], ClpsOnvt);
+
+ worst = -1.;
+ if( fCollOp.evaluate(&worst) && worst > bestShape &&
+ fCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ fCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ bestShape = worst;
+ if (*operation) delete *operation;
+ *operation = new faceCollapseOp(fCollOp);
+#ifdef MAKESTATS
+ numFClpsAvailable_II++;
+ if (bestShape < mpm.getSliverTetBound()) numFClpsToSliver_II++;
+#endif
+ }
+ if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+ numFClpsOperated_II++;
+#endif
+ return 2;
+ }
+ }
+ }
+
+ // check edge swaps
+ // -----------------
+ for(int i=0; i<3; i++) {
+#ifdef MAKESTATS
+ numSwapTested_II++;
+#endif
+ pEdge edge = F_edge((pFace)keyEnts[0],i);
+ eSwapOp.setSwapEdge(edge);
+
+ worst=-1.;
+ if( eSwapOp.evaluate(&worst) && worst > bestShape &&
+ eSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ eSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ bestShape = worst;
+ if (*operation) delete *operation;
+ *operation = new edgeSwapOp(eSwapOp);
+#ifdef MAKESTATS
+ numSwapAvailable_II++;
+ if (worst < mpm.getSliverTetBound()) numSwapToSliver_II++;
+#endif
+ if (bestShape > mpm.getSliverTetBound()) break;
+ }
+ }
+ if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+ numSwapOperated_II++;
+#endif
+ return 2;
+ }
+
+ // check face swap on the key face
+ // --------------------------------
+#ifdef MAKESTATS
+ numFSwapTested_II++;
+#endif
+ fSwapOp.setSwapFace((pFace)keyEnts[0]);
+
+ worst = -1.;
+ if( fSwapOp.evaluate(&worst) && worst > bestShape &&
+ fSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ fSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ bestShape = worst;
+ if(*operation) delete *operation;
+ *operation = new faceSwapOp(fSwapOp);
+#ifdef MAKESTATS
+ numFSwapAvailable_II++;
+ if (bestShape < mpm.getSliverTetBound()) numFSwapToSliver_II++;
+#endif
+ }
+ if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+ numFSwapOperated_II++;
+#endif
+ return 2;
+ }
+
+ // check vertex move
+ // ------------------
+ pPList verts = R_vertices(region);
+ void * temp = NULL;
+ while ( pVertex pv = (pVertex)PList_next(verts,&temp) ) {
+#ifdef MAKESTATS
+ numVMoveTested_II++;
+#endif
+ if( V_whatInType(pv) != 3 ) continue;
+
+ vMoveOp.setPositionToOptimal(pv);
+
+ worst = -1.;
+ if( vMoveOp.evaluate(&worst) && worst > bestShape &&
+ vMoveOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ vMoveOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ bestShape = worst;
+ if(*operation) delete *operation;
+ *operation = new vertexMoveOp(vMoveOp);
+#ifdef MAKESTATS
+ numVMoveAvailable_II++;
+ if (bestShape < mpm.getSliverTetBound()) numVMoveToSliver_II++;
+#endif
+ }
+ }
+ PList_delete(verts);
+ if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+ numVMoveOperated_II++;
+#endif
+ return 2;
+ }
+
+#ifdef MAKESTATS
+ if( *operation ) {
+ switch ((*operation)->type()) {
+ case MAd_ECOLLAPSE: { numEClpsOperated_II++; break; }
+ case MAd_ESWAP: { numSwapOperated_II++; break; }
+ case MAd_FSWAP: { numFSwapOperated_II++; break; }
+ case MAd_FCOLLAPSE: { numFClpsOperated_II++; break; }
+ case MAd_VERTEXMOVE: { numVMoveOperated_II++; break; }
+ default: throw;
+ }
+ }
+#endif
+
+ if( *operation ) return 1;
+
+#ifdef MAKESTATS
+ set<pRegion>::const_iterator sIter = sliversOut.find(region);
+ if (sIter == sliversOut.end() ) {
+ sliversOut.insert(region);
+ numTypeII_Out++;
+ }
+#endif
+ }
+
+ return 0;
+ }
+
+ // -------------------------------------------------------------------
+ bool sliverRegionHandler::R_isSliver(pRegion region, double* shape)
+ {
+ MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+ mqm.getShape(region,shape);
+
+ if( *shape < mpm.getSliverTetBound() ) return true;
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ bool sliverRegionHandler::R_isSliver(pRegion region)
+ {
+ MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+ double shape;
+ mqm.getShape(region,&shape);
+
+ if( shape < mpm.getSliverTetBound() ) return true;
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ // Gets the type of sliver and the related key entities.
+ // Returns 0 : failure
+ // 1 : type I
+ // 2 : type II
+ int sliverRegionHandler::getSliverType(const pRegion region,
+ pEntity keyEnts[4])
+ {
+ pFace base = R_face(region,0);
+ pVertex oppV = R_fcOpVt(region,base);
+
+ pEdge edges[6]; // the three ordered edges of the tet with base to be base
+ pVertex verts[3]; // the three ordered vertices of the face
+ double fxyz[3][3]; // coordinates of the three vertices of the face
+ double pxyz[3]; // coordinates of the opposite vertex
+ pFace faces[4]; // ordered faces of the tet
+ double area[4]; // areas of the faces
+
+ for(int i=0; i<3; i++) {
+ edges[i] = F_edge(base,i);
+ if(F_edgeDir(base,i)) verts[i] = E_vertex(edges[i],0);
+ else verts[i] = E_vertex(edges[i],1);
+ V_coord(verts[i],fxyz[i]);
+ }
+
+ faces[0] = base;
+ for(int i=0; i<4; i++) {
+ pFace face = R_face(region,i);
+ if( face == base ) continue;
+ if( F_inClosure(face,(pEntity)edges[0]) ) { faces[1]=face; continue; }
+ if( F_inClosure(face,(pEntity)edges[1]) ) { faces[2]=face; continue; }
+ if( F_inClosure(face,(pEntity)edges[2]) ) faces[3]=face;
+ }
+
+ for(int i=1; i<3; i++) {
+ for(int j=0; j<3; j++) {
+ pEdge edge = F_edge(faces[i],j);
+ if( edge == edges[i-1] ) continue;
+ if( E_inClosure(edge,(pEntity)verts[0]) ) { edges[3]=edge; continue; }
+ if( E_inClosure(edge,(pEntity)verts[1]) ) { edges[4]=edge; continue; }
+ if( E_inClosure(edge,(pEntity)verts[2]) ) edges[5]=edge;
+ }
+ }
+
+ V_coord(oppV,pxyz);
+ double proj[3];
+ int bit;
+ pointToTriangle(fxyz,pxyz,proj,&bit,area);
+
+ // 010=2 | 011=3 / 001=1
+ // | /
+ // ------------+--e2--+-----------
+ // v0| /v2
+ // | 7 /
+ // 110=6 e0 e1
+ // | /
+ // | / 101=5
+ // |/
+ // v1+
+ // /|
+ // / |
+ // 4
+
+
+ // determine the key entities
+ switch( bit ) {
+ case 1:{
+ int Emap[] = {0,4,3};
+ int Fmap[] = {0,2,3};
+ keyEnts[0] = (pEntity)faces[1];
+ int index = indexOfMin(area[0],area[2],area[3]);
+ keyEnts[1] = (pEntity)edges[Emap[index]];
+ keyEnts[2] = (pEntity)faces[Fmap[index]];
+ break;
+ }
+ case 2: {
+ int Emap[] = {1,4,5};
+ int Fmap[] = {0,1,3};
+ keyEnts[0] = (pEntity)faces[2];
+ int index = indexOfMin(area[0],area[1],area[3]);
+ keyEnts[1] = (pEntity)edges[Emap[index]];
+ keyEnts[2] = (pEntity)faces[Fmap[index]];
+ break;
+ }
+ case 3: {
+ keyEnts[0] = (pEntity)edges[2];
+ keyEnts[1] = (pEntity)edges[4];
+ keyEnts[2] = (pEntity)( (area[0]<area[3]) ? faces[0]:faces[3] );
+ keyEnts[3] = (pEntity)( (area[1]<area[2]) ? faces[1]:faces[2] );
+ break;
+ }
+ case 4: {
+ int Emap[] = {2,3,5};
+ int Fmap[] = {0,1,2};
+ keyEnts[0] = (pEntity)faces[3];
+ int index = indexOfMin(area[0],area[1],area[2]);
+ keyEnts[1] = (pEntity)edges[Emap[index]];
+ keyEnts[2] = (pEntity)faces[Fmap[index]];
+ break;
+ }
+ case 5: {
+ keyEnts[0] = (pEntity)edges[1];
+ keyEnts[1] = (pEntity)edges[3];
+ keyEnts[2] = (pEntity)( (area[0]<area[2]) ? faces[0]:faces[2] );
+ keyEnts[3] = (pEntity)( (area[1]<area[3]) ? faces[1]:faces[3] );
+ break;
+ }
+ case 6: {
+ keyEnts[0] = (pEntity)edges[0];
+ keyEnts[1] = (pEntity)edges[5];
+ keyEnts[2] = (pEntity)( (area[0]<area[1]) ? faces[0]:faces[1] );
+ keyEnts[3] = (pEntity)( (area[2]<area[3]) ? faces[2]:faces[3] );
+ break;
+ }
+ case 7: {
+ int Emap[] = {0,1,2};
+ int Fmap[] = {1,2,3};
+ keyEnts[0] = (pEntity)faces[0];
+ int index = indexOfMin(area[1],area[2],area[3]);
+ keyEnts[1] = (pEntity)edges[Emap[index]];
+ keyEnts[2] = (pEntity)faces[Fmap[index]];
+ break;
+ }
+ case 0:
+ case 8:
+ case 9:
+ case 10: {
+ break;
+ }
+ default:
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"not a valid value %d",bit);
+ }
+
+ if ( bit==0 || bit > 7 ) return 0;
+ if ( bit==3 || bit==5 || bit==6 ) return 1;
+ return 2;
+ }
+
+ // -------------------------------------------------------------------
+ void sliverRegionHandler::printStats(ostream& out) const {
+
+#ifdef MAKESTATS
+ out << "\n*** Statistics about the sliverRegionHandler ***\n\n";
+ out << "Slivers considered: " << numTypeI_In+numTypeII_In<<endl;
+ out << " - Type I: \t"<< numTypeI_In << " ( " << numTypeI_Out << " not resolved )\n";
+ out << " - Type II:\t"<< numTypeII_In << " ( " << numTypeII_Out << " not resolved )\n\n";
+
+ out << " \n--- Type I slivers ---\n\n";
+ out << "\t nbTestedOp\t nbAvailableOp \t nbOperated \t nbLeadToASliver\n";
+ out << "ESplit:\t\t"<<numSplitTested_I << "\t\t" << numSplitAvailable_I<< "\t\t" << numSplitOperated_I<< "\t\t" <<numSplitToSliver_I << "\n";
+ out << "EClps:\t\t"<< numEClpsTested_I << "\t\t" << numEClpsAvailable_I << "\t\t" << numEClpsOperated_I<< "\t\t" <<numEClpsToSliver_I << "\n";
+ out << "DESpltClps:\t"<<numDESCTested_I << "\t\t" << numDESCAvailable_I << "\t\t" <<numDESCOperated_I << "\t\t" <<numDESCToSliver_I << "\n";
+ out << "FClps:\t\t"<<numFClpsTested_I << "\t\t" << numFClpsAvailable_I<< "\t\t" << numFClpsOperated_I<< "\t\t" <<numFClpsToSliver_I << "\n";
+ out << "ESwap:\t\t"<< numSwapTested_I << "\t\t" << numSwapAvailable_I << "\t\t" << numSwapOperated_I<< "\t\t" <<numSwapToSliver_I << "\n";
+ out << "VMove:\t\t"<<numVMoveTested_I << "\t\t" << numVMoveAvailable_I<< "\t\t" << numVMoveOperated_I<< "\t\t" <<numVMoveToSliver_I << "\n";
+
+ out << " \n--- Type II slivers ---\n\n";
+ out << "\t nbTestedOp\t nbAvailableOp \t nbOperated \t nbLeadToASliver\n";
+ out << "EClps:\t\t"<<numEClpsTested_II << "\t\t" << numEClpsAvailable_II<< "\t\t" << numEClpsOperated_II<< "\t\t" <<numEClpsToSliver_II << "\n";
+ out << "FClps:\t\t"<<numFClpsTested_II << "\t\t" << numFClpsAvailable_II << "\t\t" <<numFClpsOperated_II << "\t\t" << numFClpsToSliver_II<< "\n";
+ out << "ESwap:\t\t"<<numSwapTested_II << "\t\t" << numSwapAvailable_II<< "\t\t" << numSwapOperated_II<< "\t\t" <<numSwapToSliver_II << "\n";
+ out << "FSwap:\t\t"<<numFSwapTested_II << "\t\t" << numFSwapAvailable_II << "\t\t" <<numFSwapOperated_II << "\t\t" << numFSwapToSliver_II<< "\n";
+ out << "VMove:\t\t"<<numVMoveTested_II << "\t\t" << numVMoveAvailable_II<< "\t\t" << numVMoveOperated_II<< "\t\t" <<numVMoveToSliver_II << "\n";
+
+ out << "\n\n";
+
+#else
+
+ cout << "Could not write slivers statistics because SliverRegionHandler was compiled without the flag 'MAKESTATS'\n";
+
+#endif
+
+ }
+
+
+ // -------------------------------------------------------------------
+ void sliverRegionHandler::testOperations(pRegion region)
+ {
+ if (!R_isSliver(region)) return;
+
+ bool solvedSlivGlob = false;
+ bool solvedGlob = false;
+
+ bool solvedSliv = false;
+ bool solved = false;
+
+ double bestShape = 0.;
+ mqm.getShape(region,&bestShape);
+
+ MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+ edgeCollapseOp eCollOp (mesh,sizeField);
+ eCollOp.collapseOnBoundary(collapseOnBdry,dVTolClps);
+
+ faceCollapseOp fCollOp (mesh,sizeField);
+ fCollOp.collapseOnBoundary(collapseOnBdry,dVTolClps);
+
+ edgeSwapOp eSwapOp (mesh,sizeField);
+ eSwapOp.swapOnBoundary(swapOnBdry,dVTolSwap);
+
+ DESCOp descOp(mesh,sizeField);
+ edgeSplitOp eSplitOp(mesh,sizeField);
+ faceSwapOp fSwapOp(mesh,sizeField);
+ vertexMoveOp vMoveOp(mesh,sizeField,false);
+
+ pEntity keyEnts[4];
+ int sType = getSliverType(region, keyEnts);
+ if( sType == 0 ) return;
+
+ double worst;
+
+ // --- TYPE I slivers ---
+ if( sType == 1 )
+ {
+ tested_I++;
+
+ // check split
+ // ------------
+ solvedSliv = false;
+ solved = false;
+ for(int i=0; i<2; i++) {
+
+ eSplitOp.setSplitEdge((pEdge)keyEnts[i]);
+
+ if( E_whatInType((pEdge)keyEnts[i]) != 3 ) continue;
+
+ // determine the position of the new vertex
+// double newPos[3];
+// E_cavityCenter( (pEdge)keyEnts[i], newPos );
+// double t = E_linearParams((pEdge)keyEnts[i],newPos);
+// if( t>1. || t<0. ) continue;
+// eSplitOp.setSplitPos(newPos);
+
+ worst = -1.;
+ if( eSplitOp.evaluate(&worst) && worst > bestShape &&
+ eSplitOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ eSplitOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ if (worst < mpm.getSliverTetBound()) {
+ solvedSliv = true;
+ }
+ else {
+ solved = true;
+ break;
+ }
+ }
+ }
+ if ( solved ) { solvedGlob=true; splitSolves_I++; }
+ else if ( solvedSliv ) { solvedSlivGlob=true; splitSolvesToSliver_I++; }
+
+ // check edge collapses
+ // ---------------------
+ solvedSliv = false;
+ solved = false;
+ for(int i=0; i<6; i++) {
+ pEdge edge = R_edge(region,i);
+ for (int j=0; j<2; j++) {
+ eCollOp.setCollapseEdge(edge,E_vertex(edge,j),E_vertex(edge,1-j));
+
+ worst = -1.;
+ if ( eCollOp.evaluate(&worst) && worst > bestShape &&
+ eCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ eCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ if (worst < mpm.getSliverTetBound()) {
+ solvedSliv = true;
+ }
+ else {
+ solved = true;
+ break;
+ }
+ }
+ }
+ if (worst > mpm.getSliverTetBound()) break;
+ }
+ if ( solved ) { solvedGlob=true; clpsSolves_I++; }
+ else if ( solvedSliv ) { solvedSlivGlob=true; clpsSolvesToSliver_I++; }
+
+ // check double edge split collapse
+ // ---------------------------------
+ solvedSliv = false;
+ solved = false;
+ for(int i=0; i<2; i++) {
+ descOp.setDESC(region,(pEdge)keyEnts[i%2],(pEdge)keyEnts[(i+1)%2]);
+
+ worst = -1.;
+ if( descOp.evaluate(&worst) && worst > bestShape &&
+ descOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ descOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ if (worst < mpm.getSliverTetBound()) {
+ solvedSliv = true;
+ }
+ else {
+ solved = true;
+ }
+ }
+ }
+ if ( solved ) { solvedGlob=true; descSolves_I++; }
+ else if ( solvedSliv ) { solvedSlivGlob=true; descSolvesToSliver_I++; }
+
+ // check face collapse
+ // --------------------
+ solvedSliv = false;
+ solved = false;
+ for(int i=0; i<2; i++) {
+ for( int ClpsOnvt=1; ClpsOnvt>=0; ClpsOnvt-- ) {
+ fCollOp.reset((pFace)keyEnts[i+2],(pEdge)keyEnts[i], ClpsOnvt);
+
+ worst = -1.;
+ if( fCollOp.evaluate(&worst) && worst > bestShape &&
+ fCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ fCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ if (worst < mpm.getSliverTetBound()) {
+ solvedSliv = true;
+ }
+ else {
+ solved = true;
+ break;
+ }
+ }
+ }
+ if( worst > mpm.getSliverTetBound() ) break;
+ }
+ if ( solved ) { solvedGlob=true; fclpsSolves_I++; }
+ else if ( solvedSliv ) { solvedSlivGlob=true; fclpsSolvesToSliver_I++; }
+
+ // check edge swaps (2 edges)
+ // ---------------------------
+ solvedSliv = false;
+ solved = false;
+ for(int i=0; i<2; i++) {
+ eSwapOp.setSwapEdge((pEdge)keyEnts[i]);
+
+ worst = -1.;
+ if( eSwapOp.evaluate(&worst) && worst > bestShape &&
+ eSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ eSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ if (worst < mpm.getSliverTetBound()) {
+ solvedSliv = true;
+ }
+ else {
+ solved = true;
+ break;
+ }
+ }
+ }
+ if ( solved ) { solvedGlob=true; swapSolves_I++; }
+ else if ( solvedSliv ) { solvedSlivGlob=true; swapSolvesToSliver_I++; }
+
+ // check vertex move
+ // ------------------
+ solvedSliv = false;
+ solved = false;
+ pPList verts = R_vertices(region);
+ void * temp = NULL;
+ while ( pVertex pv = (pVertex)PList_next(verts,&temp) ) {
+ if( V_whatInType(pv) != 3 ) continue;
+
+ vMoveOp.setPositionToOptimal(pv);
+
+ worst = -1.;
+ if( vMoveOp.evaluate(&worst) && worst > bestShape &&
+ vMoveOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ vMoveOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ if (worst < mpm.getSliverTetBound()) {
+ solvedSliv = true;
+ }
+ else {
+ solved = true;
+ break;
+ }
+ }
+ }
+ PList_delete(verts);
+ if ( solved ) { solvedGlob=true; nodeSolves_I++; }
+ else if ( solvedSliv ) { solvedSlivGlob=true; nodeSolvesToSliver_I++; }
+
+ if (!solvedGlob) {
+ set<pRegion>::const_iterator sIter = notSolved.find(region);
+ if (sIter == notSolved.end() ) {
+ notSolved.insert(region);
+ notSolved_I++;
+ if (solvedSlivGlob) solvedWithSliver_I++;
+ }
+ else {
+ notSolvedDuplicated_I++;
+ if (solvedSlivGlob) solvedWithSliverDuplicated_I++;
+ }
+ }
+
+ }
+
+ // --- TYPE II slivers ---
+ else
+ {
+ tested_II++;
+
+ // check edge collapses
+ // ---------------------
+ solvedSliv = false;
+ solved = false;
+ for(int i=0; i<6; i++) {
+ pEdge edge = R_edge(region,i);
+ for (int j=0; j<2; j++) {
+ eCollOp.setCollapseEdge(edge,E_vertex(edge,j),E_vertex(edge,(j+1)%2));
+
+ worst = -1.;
+ if ( eCollOp.evaluate(&worst) && worst > bestShape &&
+ eCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ eCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ if (worst < mpm.getSliverTetBound()) {
+ solvedSliv = true;
+ }
+ else {
+ solved = true;
+ break;
+ }
+ }
+ }
+ if (worst > mpm.getSliverTetBound()) break;
+ }
+ if ( solved ) { solvedGlob=true; clpsSolves_II++; }
+ else if ( solvedSliv ) { solvedSlivGlob=true; clpsSolvesToSliver_II++; }
+
+ // check face collapse
+ // --------------------
+
+ solvedSliv = false;
+ solved = false;
+ for( int ClpsOnvt=1; ClpsOnvt>=0; ClpsOnvt-- ) {
+ fCollOp.reset((pFace)keyEnts[2],(pEdge)keyEnts[1], ClpsOnvt);
+
+ worst = -1.;
+ if( fCollOp.evaluate(&worst) && worst > bestShape &&
+ fCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ fCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ if (worst < mpm.getSliverTetBound()) {
+ solvedSliv = true;
+ break;
+ }
+ else {
+ solved = true;
+ break;
+ }
+ }
+ }
+ if ( solved ) { solvedGlob=true; fclpsSolves_II++; }
+ else if ( solvedSliv ) { solvedSlivGlob=true; fclpsSolvesToSliver_II++; }
+
+ // check edge swaps
+ // -----------------
+ solvedSliv = false;
+ solved = false;
+ for(int i=0; i<3; i++) {
+ pEdge edge = F_edge((pFace)keyEnts[0],i);
+ eSwapOp.setSwapEdge(edge);
+
+ worst = -1.;
+ if( eSwapOp.evaluate(&worst) && worst > bestShape &&
+ eSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ eSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ if (worst < mpm.getSliverTetBound()) {
+ solvedSliv = true;
+ }
+ else {
+ solved = true;
+ break;
+ }
+ }
+ }
+ if ( solved ) { solvedGlob=true; swapSolves_II++; }
+ else if ( solvedSliv ) { solvedSlivGlob=true; swapSolvesToSliver_II++; }
+
+ // check face swap
+ // ----------------
+ solvedSliv = false;
+ solved = false;
+ fSwapOp.setSwapFace((pFace)keyEnts[0]);
+
+ worst = -1.;
+ if( fSwapOp.evaluate(&worst) && worst > bestShape &&
+ fSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ fSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ if (worst < mpm.getSliverTetBound()) solvedSliv = true;
+ else solved = true;
+ }
+ if ( solved ) { solvedGlob=true; fswapSolves_II++; }
+ else if ( solvedSliv ) { solvedSlivGlob=true; fswapSolvesToSliver_II++; }
+
+ // check vertex move
+ // ------------------
+ solvedSliv = false;
+ solved = false;
+ pPList verts = R_vertices(region);
+ void * temp = NULL;
+ while ( pVertex pv = (pVertex)PList_next(verts,&temp) ) {
+ if( V_whatInType(pv) != 3 ) continue;
+
+ vMoveOp.setPositionToOptimal(pv);
+
+ worst = -1.;
+ if( vMoveOp.evaluate(&worst) && worst > bestShape &&
+ vMoveOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+ vMoveOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+ if (worst < mpm.getSliverTetBound()) {
+ solvedSliv = true;
+ }
+ else {
+ solved = true;
+ break;
+ }
+ }
+ }
+ PList_delete(verts);
+ if ( solved ) { solvedGlob=true; nodeSolves_II++; }
+ else if ( solvedSliv ) { solvedSlivGlob=true; nodeSolvesToSliver_II++; }
+
+ if (!solvedGlob) {
+ set<pRegion>::const_iterator sIter = notSolved.find(region);
+ if (sIter == notSolved.end() ) {
+ notSolved.insert(region);
+ notSolved_II++;
+ if (solvedSlivGlob) solvedWithSliver_II++;
+ }
+ else {
+ notSolvedDuplicated_II++;
+ if (solvedSlivGlob) solvedWithSliverDuplicated_II++;
+ }
+ }
+ }
+
+ }
+
+ // -------------------------------------------------------------------
+ void sliverRegionHandler::printOperatorsTest(ostream& out) const
+ {
+ int testedUnique_I = tested_I-solvedWithSliverDuplicated_I-notSolvedDuplicated_I;
+ int solved_I = tested_I-solvedWithSliver_I-notSolved_I-solvedWithSliverDuplicated_I-notSolvedDuplicated_I;
+ int testedUnique_II = tested_II-solvedWithSliverDuplicated_II-notSolvedDuplicated_II;
+ int solved_II = tested_II-solvedWithSliver_II-notSolved_II-solvedWithSliverDuplicated_II-notSolvedDuplicated_II;
+
+ out << "\n*** SliverRegionHandler statistics (every operation is tested) ***\n\n";
+ out << "Slivers considered: " << testedUnique_I+testedUnique_II<<endl;
+ out << "\t Tested\t Tested dupl.\t Solved \t New sliver\t New sl. dupl.\t Not solved\t Not solved dupl.\n";
+ out << " - Type I: \t"<< testedUnique_I
+ << "\t\t" << tested_I-testedUnique_I
+ << "\t\t" << solved_I
+ << "\t\t" << solvedWithSliver_I
+ << "\t\t" << solvedWithSliverDuplicated_I
+ << "\t\t" << notSolved_I
+ << "\t\t" << notSolvedDuplicated_I
+ << "\n";
+ out << " - Type II: \t"<< testedUnique_II
+ << "\t\t" << tested_II-testedUnique_II
+ << "\t\t" << solved_II
+ << "\t\t" << solvedWithSliver_II
+ << "\t\t" << solvedWithSliverDuplicated_II
+ << "\t\t" << notSolved_II
+ << "\t\t" << notSolvedDuplicated_II
+ << "\n";
+
+ out << " \n--- Type I slivers ---\n\n";
+ out << "\t Solved\t Solved with a sliver\n";
+ out << "ESwap:\t\t"<< swapSolves_I << "\t\t" << swapSolvesToSliver_I << "\n";
+ out << "EClps:\t\t"<< clpsSolves_I << "\t\t" << clpsSolvesToSliver_I << "\n";
+ out << "FClps:\t\t"<< fclpsSolves_I << "\t\t" << fclpsSolvesToSliver_I << "\n";
+ out << "DESpltClps:\t"<< descSolves_I << "\t\t" << descSolvesToSliver_I << "\n";
+ out << "ESplt:\t\t"<< splitSolves_I << "\t\t" << splitSolvesToSliver_I << "\n";
+ out << "Reloc:\t\t"<< nodeSolves_I << "\t\t" << nodeSolvesToSliver_I << "\n";
+
+ out << " \n--- Type II slivers ---\n\n";
+ out << "\t Solved\t Solved with a sliver\n";
+ out << "ESwap:\t\t"<< swapSolves_II << "\t\t" << swapSolvesToSliver_II << "\n";
+ out << "FSwap:\t\t"<< fswapSolves_II << "\t\t" << fswapSolvesToSliver_II << "\n";
+ out << "EClps:\t\t"<< clpsSolves_II << "\t\t" << clpsSolvesToSliver_II << "\n";
+ out << "FClps:\t\t"<< fclpsSolves_II << "\t\t" << fclpsSolvesToSliver_II << "\n";
+ out << "Reloc:\t\t"<< nodeSolves_II << "\t\t" << nodeSolvesToSliver_II << "\n";
+
+ out << "\n\n";
+
+ }
+
+ // -------------------------------------------------------------------
+ void sliverRegionHandler::reportSliver(pRegion region)
+ {
+ stringstream ss;
+ string idStr; ss << reportId; ss >> idStr;
+
+ string name = reportPrefix + "sliver" + idStr + ".pos";
+
+ pPList cavity = PList_new();
+
+ PList_append(cavity,region);
+
+ for (int iV=0; iV<R_numVertices(region); iV++) {
+
+ pVertex vertex = R_vertex(region, iV);
+
+ pPList vRegs = V_regions(vertex);
+ void * temp = 0;
+ while ( pRegion pr = (pRegion)PList_next(vRegs,&temp) ) {
+ PList_appUnique(cavity,pr);
+ }
+ PList_delete(vRegs);
+ }
+
+ printPosEntities(cavity,name.c_str(),OD_MEANRATIO,sizeField);
+
+ PList_delete(cavity);
+
+ reportId++;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/SliverRegionHandler.h b/Adapt/operator/SliverRegionHandler.h
new file mode 100644
index 0000000..d2ace63
--- /dev/null
+++ b/Adapt/operator/SliverRegionHandler.h
@@ -0,0 +1,200 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_SLIVERREGIONHANDLER
+#define _H_SLIVERREGIONHANDLER
+
+#include "MAdOperatorBase.h"
+
+#include <set>
+#include <iostream>
+#include <string>
+
+#define MAKESTATS 1
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class sliverRegionHandler {
+
+ public:
+
+ sliverRegionHandler(pMesh, DiscreteSF *);
+ ~sliverRegionHandler() {}
+
+ public:
+
+ void removeSliverRegions(int * nbIn=NULL, int * nbOut=NULL);
+
+ void setSizeField(DiscreteSF *);
+
+ // whether we can use operations on boundaries
+ void collapseOnBoundary(bool, double);
+ void swapOnBoundary(bool, double);
+
+ // whether we can use operations that add nodes
+ void newVertexPermission(bool);
+ bool getNewVertexPermission() const { return addNodes; }
+
+ void enableReport(std::string);
+ void setTestAllOperators(bool);
+
+ private:
+
+ int findOperation(pRegion, pMAdOperator *);
+ bool R_isSliver(pRegion);
+ bool R_isSliver(pRegion, double *);
+
+ int getSliverType(const pRegion, pEntity[4]);
+
+ void reportSliver(pRegion);
+
+ private:
+
+ pMesh mesh;
+ DiscreteSF * sizeField;
+
+ MeshQualityManager& mqm;
+
+ bool collapseOnBdry; // whether or not we can collapse boundary edges
+ double dVTolClps;
+ bool swapOnBdry; // whether or not we can swap boundary edges
+ double dVTolSwap;
+
+ bool addNodes; // whether or not we can use operators that add nodes
+ // (edge split, face collapse, DESC)
+
+ bool reportFailures;
+ int reportId;
+ std::string reportPrefix;
+
+ bool testOperators;
+
+#ifdef MAKESTATS
+
+ private:
+
+ // statistics:
+
+ int numTypeI_In, numTypeI_Out, numTypeII_In, numTypeII_Out;
+ int numSwapTested_I, numSwapAvailable_I, numSwapOperated_I, numSwapToSliver_I;
+ int numEClpsTested_I, numEClpsAvailable_I, numEClpsOperated_I, numEClpsToSliver_I;
+ int numFClpsTested_I, numFClpsAvailable_I, numFClpsOperated_I, numFClpsToSliver_I;
+ int numDESCTested_I, numDESCAvailable_I, numDESCOperated_I, numDESCToSliver_I;
+ int numSplitTested_I, numSplitAvailable_I, numSplitOperated_I, numSplitToSliver_I;
+ int numVMoveTested_I, numVMoveAvailable_I, numVMoveOperated_I, numVMoveToSliver_I;
+
+ int numSwapTested_II, numSwapAvailable_II, numSwapOperated_II, numSwapToSliver_II;
+ int numEClpsTested_II, numEClpsAvailable_II, numEClpsOperated_II, numEClpsToSliver_II;
+ int numFSwapTested_II, numFSwapAvailable_II, numFSwapOperated_II, numFSwapToSliver_II;
+ int numFClpsTested_II, numFClpsAvailable_II, numFClpsOperated_II, numFClpsToSliver_II;
+ int numVMoveTested_II, numVMoveAvailable_II, numVMoveOperated_II, numVMoveToSliver_II;
+
+ // remaining slivers
+ std::set<pRegion> sliversOut;
+
+#endif
+
+ // test operators
+ std::set<pRegion> sliversIn;
+ int tested_I, tested_II, notSolved_I, notSolved_II, solvedWithSliver_I, solvedWithSliver_II;
+ int notSolvedDuplicated_I, notSolvedDuplicated_II, solvedWithSliverDuplicated_I, solvedWithSliverDuplicated_II;
+
+ int swapSolves_I,clpsSolves_I,fclpsSolves_I,descSolves_I,splitSolves_I,nodeSolves_I;
+ int swapSolvesToSliver_I,clpsSolvesToSliver_I,fclpsSolvesToSliver_I,descSolvesToSliver_I,splitSolvesToSliver_I,nodeSolvesToSliver_I;
+
+ int swapSolves_II, fswapSolves_II, clpsSolves_II, fclpsSolves_II, nodeSolves_II;
+ int swapSolvesToSliver_II, fswapSolvesToSliver_II, clpsSolvesToSliver_II, fclpsSolvesToSliver_II, nodeSolvesToSliver_II;
+
+ // remaining slivers
+ std::set<pRegion> notSolved;
+
+ public:
+
+ void testOperations(pRegion);
+
+ void printStats(std::ostream&) const;
+ void printOperatorsTest(std::ostream&) const;
+
+ };
+
+ // -------------------------------------------------------------------
+ inline sliverRegionHandler::sliverRegionHandler(pMesh m, DiscreteSF * sf):
+ mesh(m),sizeField(sf), mqm(MeshQualityManagerSgl::instance()),
+ collapseOnBdry(false),dVTolClps(MAdTOL),swapOnBdry(false),dVTolSwap(MAdTOL),
+ addNodes(true),
+ reportFailures(false),reportId(0),reportPrefix(""),testOperators(false)
+#ifdef MAKESTATS
+ , numTypeI_In(0), numTypeI_Out(0), numTypeII_In(0), numTypeII_Out(0),
+ numSwapTested_I(0), numSwapAvailable_I(0), numSwapOperated_I(0), numSwapToSliver_I(0),
+ numEClpsTested_I(0), numEClpsAvailable_I(0), numEClpsOperated_I(0), numEClpsToSliver_I(0),
+ numFClpsTested_I(0), numFClpsAvailable_I(0), numFClpsOperated_I(0), numFClpsToSliver_I(0),
+ numDESCTested_I(0), numDESCAvailable_I(0), numDESCOperated_I(0), numDESCToSliver_I(0),
+ numSplitTested_I(0), numSplitAvailable_I(0), numSplitOperated_I(0), numSplitToSliver_I(0),
+ numVMoveTested_I(0), numVMoveAvailable_I(0), numVMoveOperated_I(0), numVMoveToSliver_I(0),
+ numSwapTested_II(0), numSwapAvailable_II(0), numSwapOperated_II(0), numSwapToSliver_II(0),
+ numEClpsTested_II(0), numEClpsAvailable_II(0), numEClpsOperated_II(0), numEClpsToSliver_II(0),
+ numFSwapTested_II(0), numFSwapAvailable_II(0), numFSwapOperated_II(0), numFSwapToSliver_II(0),
+ numFClpsTested_II(0), numFClpsAvailable_II(0), numFClpsOperated_II(0), numFClpsToSliver_II(0),
+ numVMoveTested_II(0), numVMoveAvailable_II(0), numVMoveOperated_II(0), numVMoveToSliver_II(0),
+#endif
+ tested_I(0), tested_II(0), notSolved_I(0), notSolved_II(0), solvedWithSliver_I(0), solvedWithSliver_II(0),
+ notSolvedDuplicated_I(0), notSolvedDuplicated_II(0), solvedWithSliverDuplicated_I(0), solvedWithSliverDuplicated_II(0),
+ swapSolves_I(0),clpsSolves_I(0),fclpsSolves_I(0),descSolves_I(0),splitSolves_I(0),nodeSolves_I(0), swapSolvesToSliver_I(0),clpsSolvesToSliver_I(0),fclpsSolvesToSliver_I(0),descSolvesToSliver_I(0),splitSolvesToSliver_I(0),nodeSolvesToSliver_I(0),
+ swapSolves_II(0), fswapSolves_II(0), clpsSolves_II(0), fclpsSolves_II(0), nodeSolves_II(0), swapSolvesToSliver_II(0), fswapSolvesToSliver_II(0), clpsSolvesToSliver_II(0), fclpsSolvesToSliver_II(0), nodeSolvesToSliver_II(0)
+ {}
+
+ // -------------------------------------------------------------------
+ inline void sliverRegionHandler::setSizeField(DiscreteSF * sf)
+ {
+ sizeField = sf;
+ }
+
+ // -------------------------------------------------------------------
+ inline void sliverRegionHandler::collapseOnBoundary(bool cob, double tolerance)
+ {
+ collapseOnBdry = cob;
+ dVTolClps = tolerance;
+ }
+
+ // -------------------------------------------------------------------
+ inline void sliverRegionHandler::swapOnBoundary(bool sob, double tolerance)
+ {
+ swapOnBdry = sob;
+ dVTolSwap = tolerance;
+ }
+
+ // -------------------------------------------------------------------
+ inline void sliverRegionHandler::newVertexPermission(bool allow)
+ {
+ addNodes = allow;
+ }
+
+ // -------------------------------------------------------------------
+ inline void sliverRegionHandler::enableReport(std::string prefix)
+ {
+ reportFailures = true;
+ reportPrefix = prefix;
+ }
+
+ // -------------------------------------------------------------------
+ inline void sliverRegionHandler::setTestAllOperators(bool test)
+ {
+ testOperators = test;
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/VertexMoveOp.cc b/Adapt/operator/VertexMoveOp.cc
new file mode 100644
index 0000000..38492f0
--- /dev/null
+++ b/Adapt/operator/VertexMoveOp.cc
@@ -0,0 +1,437 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "VertexMoveOp.h"
+#include "OperatorTools.h"
+#include "MathUtils.h"
+
+#include <iostream>
+using std::cerr;
+#include <queue>
+using std::queue;
+using std::set;
+using std::multiset;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ vDisplacement::vDisplacement(const vDisplacement& _vDisp)
+ {
+ pv = _vDisp.pv;
+ for(int i=0; i<3; i++) dxyz[i] = _vDisp.dxyz[i];
+ }
+
+ // -------------------------------------------------------------------
+ vDisplacement::vDisplacement(pVertex v, double disp[3])
+ {
+ pv = v;
+ for(int i=0; i<3; i++) dxyz[i] = disp[i];
+ }
+
+ // -------------------------------------------------------------------
+ void vDisplacement::scale(double factor)
+ {
+ for(int i=0; i<3; i++) dxyz[i] = factor * dxyz[i];
+ }
+
+ // -------------------------------------------------------------------
+ bool vDisplacementLess::operator() (const vDisplacement& vd1,
+ const vDisplacement& vd2) const
+ {
+ if (vd1.pv == vd2.pv)
+ if (vd1.dxyz[0] == vd2.dxyz[0])
+ if (vd1.dxyz[1] == vd2.dxyz[1])
+ return (vd1.dxyz[2] < vd2.dxyz[2]);
+ else return (vd1.dxyz[1] < vd2.dxyz[1]);
+ else return (vd1.dxyz[0] < vd2.dxyz[0]);
+ else return (vd1.pv < vd2.pv);
+
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ bool vertexMoveOp::move(std::set<vDisplacement,vDisplacementLess>& _vDisps,
+ double factor)
+ {
+ resetDisplacements();
+ set<vDisplacement,vDisplacementLess>::const_iterator vDIt = _vDisps.begin();
+ set<vDisplacement,vDisplacementLess>::const_iterator vDEnd = _vDisps.end();
+ for (; vDIt != vDEnd; vDIt++) {
+ vDisplacement vDisp = *vDIt;
+ vDisp.scale(factor);
+ vDisps.insert(vDisp);
+ }
+ return operate();
+ }
+
+ // -------------------------------------------------------------------
+ bool vertexMoveOp::move(multiset<vDisplacement,vDisplacementLess>& _vDisps,
+ double factor)
+ {
+ resetDisplacements();
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt = _vDisps.begin();
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = _vDisps.end();
+ for (; vDIt != vDEnd; vDIt++) {
+ vDisplacement vDisp = *vDIt;
+ vDisp.scale(factor);
+ vDisps.insert(vDisp);
+ }
+ return operate();
+ }
+
+ // -------------------------------------------------------------------
+ bool vertexMoveOp::move(pVertex v, double disp[3])
+ {
+ return move( vDisplacement(v,disp) );
+ }
+
+ // -------------------------------------------------------------------
+ bool vertexMoveOp::move(vDisplacement vDisp)
+ {
+ resetDisplacements();
+ addVDisplacement(vDisp);
+ return operate();
+ }
+
+ // -------------------------------------------------------------------
+ bool vertexMoveOp::operate()
+ {
+ double shape;
+ if ( !evaluate(&shape) ) return false;
+ apply();
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void vertexMoveOp::addVDisplacement(pVertex v, double disp[3])
+ {
+ vDisplacement vDisp(v,disp);
+ addVDisplacement(vDisp);
+ }
+
+ // -------------------------------------------------------------------
+ void vertexMoveOp::addVDisplacement(vDisplacement vDisp)
+ {
+ vDisps.insert(vDisp);
+ }
+
+ // -------------------------------------------------------------------
+ void vertexMoveOp::resetDisplacements()
+ {
+ vDisps.clear();
+ }
+
+ // -------------------------------------------------------------------
+ void vertexMoveOp::setDisplacement(pVertex v, double disp[3])
+ {
+ resetDisplacements();
+ addVDisplacement(v,disp);
+ }
+
+ // -------------------------------------------------------------------
+ void vertexMoveOp::setPosition(pVertex v, double pos[3])
+ {
+ double xyz0[3], dxyz[3];
+ V_coord(v,xyz0);
+ diffVec(pos,xyz0,dxyz);
+ setDisplacement(v,dxyz);
+ }
+
+ // -------------------------------------------------------------------
+ void vertexMoveOp::setPositionToOptimal(pVertex v)
+ {
+ double opt[3];
+ if (computeOptimalLocation(v, opt)) setPosition(v, opt);
+ }
+
+ // -------------------------------------------------------------------
+ bool vertexMoveOp::computeOptimalLocation(pVertex vt, double opt[3]) const
+ {
+ if ( V_whatInType(vt) != dim ) return false;
+
+ bool flag = false;
+
+ // --- get original coordinates ---
+ double ori[3]; V_coord(vt,ori);
+
+ // --- get connected faces ---
+ std::set<pFace> fSet;
+ pPList faces = V_faces(vt);
+ void * temp = 0;
+ while ( pFace pf = (pFace) PList_next(faces,&temp) ) fSet.insert(pf);
+ PList_delete(faces);
+
+ // --- get original worst volume ratio ---
+ double oriWorstRatio = F_worstVolumeRatio(fSet);
+
+ // --- set first trial: the center of the cavity ---
+ V_cavityCenter(vt,opt);
+
+ int iter = 0;
+ while ( iter < 3 && dotProd(opt,ori) > MAdTOL ) {
+
+ // --- get worst vol ratio if we move to optimal ---
+ V_setPosition(vt,opt);
+ double optWorstRatio = F_worstVolumeRatio(fSet);
+
+ // --- if it does not improve volume ratio ---
+ // --- move it if increasing shape ---
+ if( fabs(oriWorstRatio-optWorstRatio) < OPTILOC_MIN_IMPROVE_RATIO ) {
+
+ V_setPosition(vt,ori);
+ double oriWorstShp;
+ mqm.V_worstShape(vt,&oriWorstShp);
+
+ V_setPosition(vt,opt);
+ double optWorstShp;
+ mqm.V_worstShape(vt,&optWorstShp);
+
+ if( (optWorstShp-oriWorstShp) > OPTILOC_MIN_IMPROVE_SHAPE ) {
+ flag = true; break;
+ }
+ }
+
+ // --- if it improves volume ratio ---
+ if( (oriWorstRatio-optWorstRatio) > OPTILOC_MIN_IMPROVE_RATIO &&
+ optWorstRatio != -1. ) {
+ flag = true; break;
+ }
+
+ // --- underrelax solution ---
+ for(int i=0; i<3; i++)
+ opt[i] = 0.5*(opt[i]+ori[i]);
+
+ iter++;
+ }
+
+ // --- put back the vertex at its original location ---
+ V_setPosition(vt,ori);
+
+ // --- no improvement found ---
+ if (!flag) V_coord(vt,opt);
+
+ return flag;
+ }
+
+ // -------------------------------------------------------------------
+ bool vertexMoveOp::checkConstraints() const
+ {
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt = vDisps.begin();
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+ for (; vDIt != vDEnd; vDIt++) {
+ vDisplacement vd = *vDIt;
+ if ( EN_constrained((pEntity)(vd.pv)) ) return false;
+ }
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool vertexMoveOp::checkGeometry()
+ {
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt = vDisps.begin();
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+ for (; vDIt != vDEnd; vDIt++) {
+ vDisplacement vd = *vDIt;
+ // check vertex is not on a boundary (if requested)
+ if (fixedBndry) if ( V_whatInType(vd.pv) < dim ) return false;
+ }
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool vertexMoveOp::evaluateShapes2D()
+ {
+ pPList faces;
+ getCavity(&faces);
+
+ double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+ void * temp = NULL;
+ while( pFace face = (pFace) PList_next(faces,&temp) ) {
+
+ double fCoords[3][3];
+ pMSize fSizes[3] = {NULL,NULL,NULL};
+
+ double fOriNor[3];
+ F_normal(face,fOriNor);
+
+ pPList fVerts = F_vertices(face,1);
+ void * temp2 = NULL;
+ int iNode = 0;
+ while ( pVertex pV = (pVertex)PList_next(fVerts,&temp2) ) {
+
+ V_coord(pV,fCoords[iNode]);
+
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt = vDisps.begin();
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+ for (; vDIt != vDEnd; vDIt++) {
+ if ( (*vDIt).pv == pV ) {
+ for (int iC=0; iC<3; iC++) fCoords[iNode][iC] += (*vDIt).dxyz[iC];
+ }
+ }
+
+ fSizes[iNode] = sizeField->findSize(pV);
+
+ iNode++;
+ }
+ PList_delete(fVerts);
+
+ // Check if the shape is acceptable and compare it to the worst shape
+ double shape = 0.;
+ if ( !mqm.getElementEvaluator()->XYZ_F_shape(fCoords, fSizes, fOriNor, &shape) ) {
+ PList_delete(faces);
+ return false;
+ }
+ else {
+ if ( shape < worstShape ) worstShape = shape;
+ }
+ }
+ PList_delete(faces);
+
+ results->setWorstShape(worstShape);
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool vertexMoveOp::evaluateShapes()
+ {
+ if (dim == 2) return evaluateShapes2D();
+
+ pPList regs;
+ getCavity(®s);
+
+ double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+ void * temp = NULL;
+ while( pRegion region = (pRegion) PList_next(regs,&temp) ) {
+
+ double rCoords[4][3];
+ pMSize rSizes[4] = {NULL,NULL,NULL,NULL};
+
+ pPList rVerts = R_vertices(region);
+ void * temp2 = NULL;
+ int iNode = 0;
+ while ( pVertex pV = (pVertex)PList_next(rVerts,&temp2) ) {
+
+ V_coord(pV,rCoords[iNode]);
+
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt = vDisps.begin();
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+ for (; vDIt != vDEnd; vDIt++) {
+ if ( (*vDIt).pv == pV ) {
+ for (int iC=0; iC<3; iC++) rCoords[iNode][iC] += (*vDIt).dxyz[iC];
+ }
+ }
+
+ rSizes[iNode] = sizeField->findSize(pV);
+
+ iNode++;
+ }
+ PList_delete(rVerts);
+
+ // Check if the shape is acceptable and compare it to the worst shape
+ double shape = 0.;
+ if ( !mqm.getElementEvaluator()->XYZ_R_shape(rCoords, rSizes, &shape) ) {
+ PList_delete(regs);
+ return false;
+ }
+ else {
+ if ( shape < worstShape ) worstShape = shape;
+ }
+ }
+ PList_delete(regs);
+
+ results->setWorstShape(worstShape);
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void vertexMoveOp::evaluateLengths() const
+ {
+ double minSq = MAdBIG;
+ double maxSq = 0.;
+
+ pPList edges;
+ getAffectedEdges(&edges);
+
+ void* tmp=0;
+ while ( pEdge pe = (pEdge)PList_next(edges,&tmp) ) {
+ double lSq = sizeField->SF_E_lengthSq(pe);
+ if ( lSq > maxSq ) maxSq = lSq;
+ if ( lSq < minSq ) minSq = lSq;
+ }
+
+ PList_delete(edges);
+
+ results->setMaxLenSq(maxSq);
+ results->setMinLenSq(minSq);
+ }
+
+ // -------------------------------------------------------------------
+ void vertexMoveOp::getAffectedEdges(pPList * edges) const
+ {
+ *edges = PList_new();
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt = vDisps.begin();
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+ for (; vDIt != vDEnd; vDIt++) {
+ pPList vEdges = V_edges(vDIt->pv);
+ (*edges) = PList_appPListUnique(*edges,vEdges);
+ PList_delete(vEdges);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void vertexMoveOp::getCavity(pPList * cavity) const
+ {
+ *cavity = PList_new();
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt = vDisps.begin();
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+ for (; vDIt != vDEnd; vDIt++) {
+ if ( dim == 3 ) {
+ pPList vRegs = V_regions(vDIt->pv);
+ (*cavity) = PList_appPListUnique(*cavity,vRegs);
+ PList_delete(vRegs);
+ }
+ else {
+ pPList vFaces = V_faces(vDIt->pv);
+ (*cavity) = PList_appPListUnique(*cavity,vFaces);
+ PList_delete(vFaces);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void vertexMoveOp::apply()
+ {
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt = vDisps.begin();
+ multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+ for (; vDIt != vDEnd; vDIt++) {
+ vDisplacement vd = *vDIt;
+
+ double target[3]; V_coord(vd.pv,target);
+ for (int i=0; i < 3; i++) target[i] += vd.dxyz[i];
+
+ if ( !V_setPosition(vd.pv,target) ) {
+ cerr << "Error: could not move vertex\n"; throw;
+ }
+ }
+ HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/VertexMoveOp.h b/Adapt/operator/VertexMoveOp.h
new file mode 100644
index 0000000..b4ebce7
--- /dev/null
+++ b/Adapt/operator/VertexMoveOp.h
@@ -0,0 +1,112 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_VERTEXMOVEOP
+#define _H_VERTEXMOVEOP
+
+#include "MAdOperatorBase.h"
+
+#include <set>
+
+#define OPTILOC_MIN_IMPROVE_RATIO 1.e-3
+#define OPTILOC_MIN_IMPROVE_SHAPE 1.e-3
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // GCTODO: rewrite it simpler
+ struct vDisplacement
+ {
+ vDisplacement(const vDisplacement&);
+ vDisplacement(pVertex, double[3]);
+ void scale(double);
+ pVertex pv;
+ double dxyz[3]; // displacement
+ };
+
+ struct vDisplacementLess
+ {
+ bool operator() (const vDisplacement&, const vDisplacement&) const;
+ };
+
+ // -------------------------------------------------------------------
+ class vertexMoveOp : public MAdOperatorBase
+ {
+ public:
+
+ vertexMoveOp(pMesh, DiscreteSF *, bool _fixBndry=true);
+ vertexMoveOp(const vertexMoveOp &);
+ ~vertexMoveOp() {}
+
+ operationType type() const { return MAd_VERTEXMOVE; }
+
+ void setFixedBndry(bool);
+
+ void resetDisplacements();
+ void addVDisplacement(pVertex, double[3]);
+ void addVDisplacement(vDisplacement);
+ void setDisplacement(pVertex, double[3]);
+ void setPosition(pVertex, double[3]);
+ void setPositionToOptimal(pVertex);
+
+ bool computeOptimalLocation(pVertex, double[3]) const;
+
+ void getAffectedEdges(pPList *) const;
+ void getCavity(pPList *) const;
+
+ void apply();
+ bool move (std::set<vDisplacement,vDisplacementLess>&, double factor=1.0);
+ bool move (std::multiset<vDisplacement,vDisplacementLess>&, double factor=1.0);
+ bool move (pVertex, double[3]);
+ bool move (vDisplacement);
+ bool operate ();
+
+ private:
+
+ bool checkConstraints() const;
+ bool checkGeometry();
+ bool evaluateShapes();
+ bool evaluateShapes2D();
+ void evaluateLengths() const;
+
+ private:
+
+ std::multiset<vDisplacement,vDisplacementLess> vDisps;
+ bool fixedBndry; // indicates if the boundary vertices can move
+ };
+
+ // -------------------------------------------------------------------
+ inline vertexMoveOp::vertexMoveOp(const vertexMoveOp & _vm):
+ MAdOperatorBase(_vm)
+ {
+ vDisps = _vm.vDisps;
+ fixedBndry = _vm.fixedBndry;
+ }
+
+ // -------------------------------------------------------------------
+ inline vertexMoveOp::vertexMoveOp(pMesh _m, DiscreteSF * _sf,
+ bool _fixBndry):
+ MAdOperatorBase(_m,_sf), fixedBndry(_fixBndry)
+ {}
+
+ // -------------------------------------------------------------------
+ inline void vertexMoveOp::setFixedBndry(bool fixed)
+ {
+ fixedBndry = fixed;
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/output/MAdOutput.cc b/Adapt/output/MAdOutput.cc
new file mode 100644
index 0000000..0c7d83c
--- /dev/null
+++ b/Adapt/output/MAdOutput.cc
@@ -0,0 +1,785 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdOutput.h"
+#include "MeanRatioEvaluator.h"
+#include "OrientedMeanRatioEvaluator.h"
+#include "MAdMessage.h"
+#include "MathUtils.h"
+#include "LocalSizeField.h"
+#include "MAdResourceManager.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+#include <vector>
+using std::vector;
+using std::string;
+using std::set;
+
+namespace MAd {
+
+ // ----------------------------------------------------------------------
+ enum dataType {
+ SCALAR,
+ VECTORIAL
+ };
+
+ dataType getOutputDataType(MAdOutputData t) {
+ switch (t) {
+ case OD_CONSTANT:
+ case OD_MEANRATIO:
+ case OD_SIZEFIELD_MEAN:
+ case OD_SIZEFIELD_MIN:
+ case OD_SIZEFIELD_MAX:
+ case OD_DIMENSION:
+ case OD_ITERORDER:
+ case OD_CURVATURE_DIV:
+ case OD_CURVATURE_MAX:
+ case OD_CURVATURE_MIN:
+ { return SCALAR; break; }
+ case OD_CURVATURE_MAX_VEC:
+ case OD_CURVATURE_MIN_VEC:
+ case OD_ANISO_SF_AXIS0:
+ case OD_ANISO_SF_AXIS1:
+ case OD_ANISO_SF_AXIS2:
+ { return VECTORIAL; break; }
+ }
+ throw;
+ };
+
+ std::string getOutputName( MAdOutputData type ) {
+ switch (type) {
+ case OD_CONSTANT: return "constant field";
+ case OD_MEANRATIO: return "mean ratio";
+ case OD_ORIENTEDMEANRATIO: return "oriented mean ratio";
+ case OD_SIZEFIELD_MEAN: return "mean size (among the 3 directions) in the size field";
+ case OD_SIZEFIELD_MIN: return "minimum size (among the 3 directions) in the size field";
+ case OD_SIZEFIELD_MAX: return "maximum size (among the 3 directions) in the size field";
+ case OD_DIMENSION: return "element dimension";
+ case OD_ITERORDER: return "element id regarding place in iterator";
+ case OD_CURVATURE_DIV: return "divergence of the curvature";
+ case OD_CURVATURE_MAX: return "surface maximum curvature (scalar field)";
+ case OD_CURVATURE_MIN: return "surface minimum curvature (scalar field)";
+ case OD_CURVATURE_MAX_VEC: return "surface maximum curvature (vectorial field)";
+ case OD_CURVATURE_MIN_VEC: return "surface minimum curvature (vectorial field)";
+ case OD_ANISO_SF_AXIS0: return "anisotropic size field along first direction";
+ case OD_ANISO_SF_AXIS1: return "anisotropic size field along second direction";
+ case OD_ANISO_SF_AXIS2: return "anisotropic size field along third direction";
+ }
+ return "unknown output type";
+ };
+
+ // ----------------------------------------------------------------------
+ double* getData(MAdOutputData type, const pEntity pe, const pSField sf=NULL, int id=0)
+ {
+ int dim = EN_type(pe);
+ double * result;
+
+ switch (type) {
+
+ case OD_DIMENSION: {
+ result = new double[4];
+ for (int i=0; i<4; i++) result[i] = (double)dim;
+ return result;
+ }
+
+ case OD_CONSTANT: {
+ result = new double[4];
+ for (int i=0; i<4; i++) result[i] = 1.;
+ return result;
+ }
+
+ case OD_MEANRATIO: {
+ if ( !sf ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "No size field given to compute mean ratio");
+ }
+ if ( sf->getType() != DISCRETESFIELD ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Discrete size field required for quality evaluation");
+ }
+ meanRatioEvaluator evalu((DiscreteSF*)sf);
+ double tmp;
+ switch (dim) {
+ case 3:
+ result = new double[4];
+ evalu.R_shape((pRegion)pe,&tmp);
+ for (int i=0; i<4; i++) result[i] = tmp;
+ return result;
+ case 2:
+ result = new double[3];
+ evalu.F_shape((pFace)pe,0,&tmp);
+ for (int i=0; i<3; i++) result[i] = tmp;
+ return result;
+ default:
+ cerr << "Error in outputs: getData on an element if dimension inferior to 2\n";
+ throw;
+ }
+ }
+
+ case OD_ORIENTEDMEANRATIO: {
+ if ( !sf ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "No size field given to compute mean ratio");
+ }
+ if ( sf->getType() != DISCRETESFIELD ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Discrete size field required for quality evaluation");
+ }
+ orientedMeanRatioEvaluator evalu((DiscreteSF*)sf);
+ double tmp;
+ switch (dim) {
+ case 3:
+ result = new double[4];
+ evalu.R_shape((pRegion)pe,&tmp);
+ for (int i=0; i<4; i++) result[i] = tmp;
+ return result;
+ case 2:
+ result = new double[3];
+ evalu.F_shape((pFace)pe,0,&tmp);
+ for (int i=0; i<3; i++) result[i] = tmp;
+ return result;
+ default:
+ cerr << "Error in outputs: getData on an element if dimension inferior to 2\n";
+ throw;
+ }
+ }
+
+ case OD_ITERORDER: {
+ result = new double[4];
+ for (int i=0; i<4; i++) result[i] = (double)id;
+ return result;
+ }
+
+ case OD_SIZEFIELD_MEAN:
+ case OD_SIZEFIELD_MIN:
+ case OD_SIZEFIELD_MAX: {
+ if ( !sf ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "No size field given");
+ }
+ void * temp;
+ pPList verts;
+ int k;
+ pVertex pv;
+ pMSize size;
+ double h;
+ switch (dim) {
+ case 3:
+ result = new double[4];
+ verts = R_vertices((pRegion)pe);
+ temp = 0 ; k=0;
+ while ( ( pv = (pVertex)PList_next(verts,&temp) ) )
+ {
+ size = sf->getSize(pv);
+ if ( type == OD_SIZEFIELD_MEAN ) h = size->getMeanLength();
+ if ( type == OD_SIZEFIELD_MIN ) h = size->getMinLength();
+ if ( type == OD_SIZEFIELD_MAX ) h = size->getMaxLength();
+ if (size) delete size;
+ result[k] = h;
+ k++;
+ }
+ PList_delete(verts);
+ return result;
+ case 2:
+ result = new double[3];
+ verts = F_vertices( (pFace)pe, 1);
+ temp = 0 ; k=0;
+ while ( ( pv = (pVertex)PList_next(verts,&temp) ) )
+ {
+ size = sf->getSize(pv);
+ if ( type == OD_SIZEFIELD_MEAN ) h = size->getMeanLength();
+ if ( type == OD_SIZEFIELD_MIN ) h = size->getMinLength();
+ if ( type == OD_SIZEFIELD_MAX ) h = size->getMaxLength();
+ if (size) delete size;
+ result[k] = h;
+ k++;
+ }
+ PList_delete(verts);
+ return result;
+ default:
+ cerr << "Error in outputs: getData on an element if dimension inferior to 2\n";
+ throw;
+ }
+ }
+
+ case OD_CURVATURE_DIV: {
+ if ( dim < 3 )
+ {
+#ifdef _HAVE_GMSH_
+ result = new double[4];
+ pGEntity pge = EN_whatIn(pe);
+ if ( GEN_type(pge) != 2 ) {
+ for (int i=0; i<4; i++) result[i] = -1.;
+ return result;
+ }
+ double u[4][2];
+ F_params((pFace)pe,u);
+ for (int iV=0; iV<F_numVertices((pFace)pe); iV++)
+ {
+ result[iV] = GF_curvatureDiv((pGFace)pge, u[iV], 1.e6);
+ }
+ return result;
+#else
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Gmsh required for divergence of surface curvature");
+#endif
+ }
+ else
+ {
+ if ( !sf || ( sf->getType() != LOCALSFIELD ) ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "A local size field is required to output divergence of the curvature on elements");
+ }
+ result = new double[4];
+ LocalSizeField * sf_cast = (LocalSizeField *) sf;
+ pRegion pr = (pRegion) pe;
+ for (int iV=0; iV<4; iV++)
+ {
+ if ( sf_cast->getCurvature(R_vertex(pr,iV), &(result[iV])) ) {}
+ else result[iV] = -1.;
+ }
+ return result;
+ }
+ return NULL;
+ }
+
+ case OD_CURVATURE_MAX: {
+#ifdef _HAVE_GMSH_
+ if ( dim != 2 ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Cannot output curvatures on other entities than faces");
+ }
+ result = new double[4];
+ pGEntity pge = EN_whatIn(pe);
+ if ( GEN_type(pge) != 2 ) {
+ for (int i=0; i<4; i++) result[i] = -1.;
+ return result;
+ }
+ double u[4][2];
+ F_params((pFace)pe,u);
+ for (int iV=0; iV<F_numVertices((pFace)pe); iV++)
+ {
+ double dirMax[3], dirMin[3], curvMax, curvMin;
+ GF_curvatures((pGFace)pge, u[iV],
+ dirMax, dirMin, &curvMax, &curvMin, 1.e6);
+ result[iV] = curvMax;
+ }
+ return result;
+#else
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gmsh required for curvature");
+#endif
+ }
+
+ case OD_CURVATURE_MIN: {
+#ifdef _HAVE_GMSH_
+ if ( dim != 2 ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Cannot output curvatures on other entities than faces");
+ }
+ result = new double[4];
+ pGEntity pge = EN_whatIn(pe);
+ if ( GEN_type(pge) != 2 ) {
+ for (int i=0; i<4; i++) result[i] = -1.;
+ return result;
+ }
+ double u[4][2];
+ F_params((pFace)pe,u);
+ for (int iV=0; iV<F_numVertices((pFace)pe); iV++)
+ {
+ double dirMax[3], dirMin[3], curvMax, curvMin;
+ GF_curvatures((pGFace)pge, u[iV],
+ dirMax, dirMin, &curvMax, &curvMin, 1.e6);
+ result[iV] = curvMin;
+ }
+ return result;
+#else
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gmsh required for curvature");
+#endif
+ }
+
+ case OD_CURVATURE_MAX_VEC: {
+#ifdef _HAVE_GMSH_
+ if ( dim != 2 ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Cannot output curvatures on other entities than faces");
+ }
+ result = new double[9];
+ pGEntity pge = EN_whatIn(pe);
+ if ( GEN_type(pge) != 2 ) {
+ for (int i=0; i<9; i++) result[i] = -1.;
+ return result;
+ }
+ double u[3][2];
+ F_params((pFace)pe,u);
+ for (int iV=0; iV<3; iV++)
+ {
+ double dirMax[3], dirMin[3], curvMax, curvMin;
+ GF_curvatures((pGFace)pge, u[iV],
+ dirMax, dirMin, &curvMax, &curvMin, 1.e6);
+ normalizeVec(dirMax,dirMax);
+ for (int iC=0; iC<3; iC++) result[3*iV+iC] = dirMax[iC] * curvMax;
+ }
+ return result;
+#else
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gmsh required for curvature");
+#endif
+ }
+
+ case OD_CURVATURE_MIN_VEC: {
+#ifdef _HAVE_GMSH_
+ if ( dim != 2 ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Cannot output curvatures on other entities than faces");
+ }
+ result = new double[9];
+ pGEntity pge = EN_whatIn(pe);
+ if ( GEN_type(pge) != 2 ) {
+ for (int i=0; i<9; i++) result[i] = -1.;
+ return result;
+ }
+ double u[3][2];
+ F_params((pFace)pe,u);
+ for (int iV=0; iV<3; iV++)
+ {
+ double dirMax[3], dirMin[3], curvMax, curvMin;
+ GF_curvatures((pGFace)pge, u[iV],
+ dirMax, dirMin, &curvMax, &curvMin, 1.e6);
+ normalizeVec(dirMin,dirMin);
+ for (int iC=0; iC<3; iC++) result[3*iV+iC] = dirMin[iC] * curvMin;
+ }
+ return result;
+#else
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gmsh required for curvature");
+#endif
+ }
+
+ case OD_ANISO_SF_AXIS0:
+ case OD_ANISO_SF_AXIS1:
+ case OD_ANISO_SF_AXIS2:
+ {
+ if ( !sf ) MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size field given");
+
+ void * temp;
+ pPList verts;
+ int k;
+ pVertex pv;
+ switch (dim) {
+ case 3:
+ result = new double[12];
+ verts = R_vertices((pRegion)pe);
+ temp = 0 ; k=0;
+ while ( ( pv = (pVertex)PList_next(verts,&temp) ) )
+ {
+ pMSize size = sf->getSize(pv);
+ double h, dir[3];
+ if ( type == OD_ANISO_SF_AXIS0 ) h = size->direction(0,dir);
+ if ( type == OD_ANISO_SF_AXIS1 ) h = size->direction(1,dir);
+ if ( type == OD_ANISO_SF_AXIS2 ) h = size->direction(2,dir);
+ if (size) delete size;
+ for (int iC=0; iC<3; iC++) result[3*k+iC] = h * dir[iC];
+ k++;
+ }
+ PList_delete(verts);
+ return result;
+ case 2:
+ result = new double[9];
+ verts = F_vertices( (pFace)pe, 1);
+ temp = 0 ; k=0;
+ while ( ( pv = (pVertex)PList_next(verts,&temp) ) )
+ {
+ pMSize size = sf->getSize(pv);
+ double h, dir[3];
+ if ( type == OD_ANISO_SF_AXIS0 ) h = size->direction(0,dir);
+ if ( type == OD_ANISO_SF_AXIS1 ) h = size->direction(1,dir);
+ if ( type == OD_ANISO_SF_AXIS2 ) h = size->direction(2,dir);
+ if (size) delete size;
+ for (int iC=0; iC<3; iC++) result[3*k+iC] = h * dir[iC];
+ k++;
+ }
+ PList_delete(verts);
+ return result;
+ default:
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Dimension < 2: %d",dim);
+ }
+ }
+
+ default:
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Data type not handled in switch");
+ }
+ return 0;
+ }
+
+ // ----------------------------------------------------------------------
+ void writeFaces (const pMesh m, const pSField sf, FILE *f, MAdOutputData type)
+ {
+ int count = 0;
+ FIter fit = M_faceIter(m);
+ while (pFace pf = FIter_next(fit))
+ {
+ double xyz[3][3];
+ F_coordP1(pf, xyz);
+ double* data = getData(type,(pEntity)pf,sf,count);
+ if ( getOutputDataType(type) == SCALAR ) {
+ fprintf (f,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ xyz[2][0],xyz[2][1],xyz[2][2],
+ data[0],data[1],data[2]);
+ }
+ if ( getOutputDataType(type) == VECTORIAL ) {
+ fprintf (f,"VT(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g,%g,%g,%g,%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ xyz[2][0],xyz[2][1],xyz[2][2],
+ data[0],data[1],data[2],
+ data[3],data[4],data[5],
+ data[6],data[7],data[8]);
+ }
+ delete [] data;
+ count++;
+ }
+ FIter_delete(fit);
+ }
+
+ // ----------------------------------------------------------------------
+ void writeRegions (const pMesh m, const pSField sf, FILE *f, MAdOutputData type)
+ {
+ int count = 0;
+ RIter rit = M_regionIter(m);
+ while (pRegion pr = RIter_next(rit))
+ {
+ double xyz[4][3];
+ R_coordP1(pr, xyz);
+ double* data = getData(type,(pEntity)pr,sf,count);
+ if ( getOutputDataType(type) == SCALAR ) {
+ fprintf (f,"SS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ xyz[2][0],xyz[2][1],xyz[2][2],
+ xyz[3][0],xyz[3][1],xyz[3][2],
+ data[0],data[1],data[2],data[3]);
+ }
+ if ( getOutputDataType(type) == VECTORIAL ) {
+ fprintf (f,"VS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ xyz[2][0],xyz[2][1],xyz[2][2],
+ xyz[3][0],xyz[3][1],xyz[3][2],
+ data[0],data[1],data[2],data[3],
+ data[4],data[5],data[6],data[7],
+ data[8],data[9],data[10],data[11]);
+ }
+ delete [] data;
+ count++;
+ }
+ RIter_delete(rit);
+ }
+
+ // ----------------------------------------------------------------------
+ void MAdGmshOutput (const pMesh m, const pSField sf, const char *fn, MAdOutputData type)
+ {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+ double t0 = tm.getTime();
+
+ if ( sf ) MAdMsgSgl::instance().info(-1,__FILE__,
+ "Generating output \'%s\' on file \'%s\' with size field \'%s\'",
+ getOutputName(type).c_str(), fn, sf->getName().c_str());
+ else MAdMsgSgl::instance().info(-1,__FILE__,
+ "Generating output \'%s\' on file \'%s\'",
+ getOutputName(type).c_str(), fn);
+
+ FILE *f = fopen (fn, "w");
+ if ( !f ) {
+ cerr << "Error: could not open file " << fn << endl; throw;
+ }
+
+ fprintf (f,"View\" mesh \" {\n");
+
+ if (M_dim(m)==2) writeFaces(m,sf,f,type);
+ else writeRegions(m,sf,f,type);
+
+ fprintf (f,"};\n");
+ fclose (f);
+
+ MAdMsgSgl::instance().info(-1,__FILE__,"Output generated in %f seconds",
+ tm.getTime()-t0);
+ }
+
+ // ----------------------------------------------------------------------
+ void MAdAttachedNodalDataOutput(const pMesh m, const char *fn, pMeshDataId id)
+ {
+ FILE *f = fopen (fn, "w");
+ if ( !f ) {
+ cerr << "Error: could not open file " << fn << endl; throw;
+ }
+
+ fprintf (f,"View\" mesh \" {\n");
+
+ if (M_dim(m)==2) {
+
+ FIter fit = M_faceIter(m);
+ while (pFace pf = FIter_next(fit))
+ {
+ // get the coordinates
+ double xyz[3][3];
+ F_coordP1(pf, xyz);
+
+ // get the data at nodes
+ double data[3];
+ pPList verts = F_vertices(pf,1);
+ void* tmp = 0;
+ int i = 0;
+ while ( pEntity pv = PList_next(verts,&tmp) ) {
+ if ( EN_getDataDbl((pEntity)pv,id,&(data[i])) ) {}
+ else data[i] = -10.;
+ i++;
+ }
+ PList_delete(verts);
+
+ // write an element
+ fprintf (f,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ xyz[2][0],xyz[2][1],xyz[2][2],
+ data[0],data[1],data[2]);
+ }
+ FIter_delete(fit);
+ }
+ else {
+
+ RIter rit = M_regionIter(m);
+ while (pRegion pr = RIter_next(rit))
+ {
+ // get the coordinates
+ double xyz[4][3];
+ R_coordP1(pr, xyz);
+
+ // get the data at nodes
+ double data[4];
+ pPList verts = R_vertices(pr);
+ void* tmp = 0;
+ int i = 0;
+ while ( pEntity pv = PList_next(verts,&tmp) ) {
+ if ( EN_getDataDbl(pv,id,&(data[i])) ) {}
+ else data[i] = -10.;
+ i++;
+ }
+ PList_delete(verts);
+
+ // write an element
+ fprintf (f,"SS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ xyz[2][0],xyz[2][1],xyz[2][2],
+ xyz[3][0],xyz[3][1],xyz[3][2],
+ data[0],data[1],data[2],data[3]);
+ }
+ RIter_delete(rit);
+
+ }
+
+ fprintf (f,"};\n");
+ fclose (f);
+ }
+
+ // ----------------------------------------------------------------------
+ void MAdAttachedNodalDataVecOutput(const pMesh m, const char *fn, pMeshDataId id)
+ {
+ FILE *f = fopen (fn, "w");
+ if ( !f ) {
+ cerr << "Error: could not open file " << fn << endl; throw;
+ }
+
+ fprintf (f,"View\" mesh \" {\n");
+
+ if (M_dim(m)==2) {
+
+ FIter fit = M_faceIter(m);
+ while (pFace pf = FIter_next(fit))
+ {
+ // get the coordinates
+ double xyz[3][3];
+ F_coordP1(pf, xyz);
+
+ // get the data at nodes
+ double data[3][3];
+ pPList verts = F_vertices(pf,1);
+ void* tmp = 0;
+ int i = 0;
+ while ( pEntity pv = PList_next(verts,&tmp) ) {
+ void * tmpDat = NULL;
+ if ( EN_getDataPtr((pEntity)pv,id,&tmpDat) )
+ {
+ // vector<double> * vec = (vector<double>*) tmpDat;
+ // for (int j=0; j<3; j++) data[i][j] = (*vec)[j];
+ for (int j=0; j<3; j++) data[i][j] = ((double*)tmpDat)[j];
+ }
+ else
+ {
+ for (int j=0; j<3; j++) data[i][j] = -10.;
+ }
+ i++;
+ }
+ PList_delete(verts);
+
+ // write an element
+ fprintf (f,"VT(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g,%g,%g,%g,%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ xyz[2][0],xyz[2][1],xyz[2][2],
+ data[0][0],data[0][1],data[0][2],
+ data[1][0],data[1][1],data[1][2],
+ data[2][0],data[2][1],data[2][2]);
+ }
+ FIter_delete(fit);
+ }
+ else {
+
+ RIter rit = M_regionIter(m);
+ while (pRegion pr = RIter_next(rit))
+ {
+ // get the coordinates
+ double xyz[4][3];
+ R_coordP1(pr, xyz);
+
+ // get the data at nodes
+ double data[4][3];
+ pPList verts = R_vertices(pr);
+ void* tmp = 0;
+ int i = 0;
+ while ( pEntity pv = PList_next(verts,&tmp) ) {
+ void * tmpDat = NULL;
+ if ( EN_getDataPtr((pEntity)pv,id,&tmpDat) )
+ {
+ // vector<double> * vec = (vector<double>*) tmpDat;
+ // for (int j=0; j<3; j++) data[i][j] = (*vec)[j];
+ for (int j=0; j<3; j++) data[i][j] = ((double*)tmpDat)[j];
+ }
+ else
+ {
+ for (int j=0; j<3; j++) data[i][j] = -10.;
+ }
+ i++;
+ }
+ PList_delete(verts);
+
+ // write an element
+ fprintf (f,"VS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ xyz[2][0],xyz[2][1],xyz[2][2],
+ xyz[3][0],xyz[3][1],xyz[3][2],
+ data[0][0],data[0][1],data[0][2],
+ data[1][0],data[1][1],data[1][2],
+ data[2][0],data[2][1],data[2][2],
+ data[3][0],data[3][1],data[3][2]);
+ }
+ RIter_delete(rit);
+
+ }
+
+ fprintf (f,"};\n");
+ fclose (f);
+ }
+
+ // -------------------------------------------------------------------
+ void printPosRegions(const set<pRegion> regs, string fn, MAdOutputData type,
+ const pSField sf, int id)
+ {
+ FILE *f = fopen (fn.c_str(), "w");
+ fprintf (f,"View\" mesh \" {\n");
+
+ set<pRegion>::const_iterator rIter = regs.begin();
+ for (; rIter != regs.end(); rIter++) {
+ double* data = getData(type,*rIter,sf);
+ double xyz[4][3];
+ R_coordP1(*rIter, xyz);
+ fprintf (f,"SS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ xyz[2][0],xyz[2][1],xyz[2][2],
+ xyz[3][0],xyz[3][1],xyz[3][2],
+ data[0],data[1],data[2],data[3]);
+ delete [] data;
+ }
+
+ fprintf (f,"};\n");
+ fclose (f);
+ }
+
+ // -------------------------------------------------------------------
+ void printPosEntities(const pPList ents, string fn, MAdOutputData type,
+ const pSField sf, int id)
+ {
+ FILE *f = fopen (fn.c_str(), "w");
+ fprintf (f,"View\" mesh \" {\n");
+
+ void *iter=0;
+ while( pEntity ent = PList_next(ents,&iter) ) {
+ double* data = getData(type,ent,sf);
+ switch ( EN_type(ent) ) {
+ case 0:
+ {
+ double xyz[3];
+ V_coord((pVertex)ent, xyz);
+ fprintf (f,"SP(%g,%g,%g) {%g};\n",
+ xyz[0],xyz[1],xyz[2],
+ data[0]);
+ break;
+ }
+ case 1:
+ {
+ double xyz[2][3];
+ E_coordP1((pEdge)ent, xyz);
+ fprintf (f,"SL(%g,%g,%g,%g,%g,%g) {%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ data[0],data[1]);
+ break;
+ }
+ case 2:
+ {
+ double xyz[3][3];
+ F_coordP1((pFace)ent, xyz);
+ fprintf (f,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ xyz[2][0],xyz[2][1],xyz[2][2],
+ data[0],data[1],data[2]);
+ break;
+ }
+ case 3:
+ {
+ double xyz[4][3];
+ R_coordP1((pRegion)ent, xyz);
+ fprintf (f,"SS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g};\n",
+ xyz[0][0],xyz[0][1],xyz[0][2],
+ xyz[1][0],xyz[1][1],xyz[1][2],
+ xyz[2][0],xyz[2][1],xyz[2][2],
+ xyz[3][0],xyz[3][1],xyz[3][2],
+ data[0],data[1],data[2],data[3]);
+ break;
+ }
+ }
+ delete [] data;
+ }
+
+ fprintf (f,"};\n");
+ fclose (f);
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/output/MAdOutput.h b/Adapt/output/MAdOutput.h
new file mode 100644
index 0000000..1246af5
--- /dev/null
+++ b/Adapt/output/MAdOutput.h
@@ -0,0 +1,65 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADOUTPUT
+#define _H_MADOUTPUT
+
+#include "SizeFieldBase.h"
+#include "MSops.h"
+
+#include <string>
+#include <set>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ typedef enum MAdOutputData {
+ OD_CONSTANT = 0,
+ OD_MEANRATIO = 1,
+ OD_ORIENTEDMEANRATIO = 2,
+ OD_SIZEFIELD_MEAN = 3,
+ OD_SIZEFIELD_MIN = 4,
+ OD_SIZEFIELD_MAX = 5,
+ OD_DIMENSION = 6,
+ OD_ITERORDER = 7,
+ OD_CURVATURE_DIV = 8,
+ OD_CURVATURE_MAX = 9,
+ OD_CURVATURE_MIN = 10,
+ OD_CURVATURE_MAX_VEC = 11,
+ OD_CURVATURE_MIN_VEC = 12,
+ OD_ANISO_SF_AXIS0 = 13,
+ OD_ANISO_SF_AXIS1 = 14,
+ OD_ANISO_SF_AXIS2 = 15
+ } MAdOutputData;
+
+ // -------------------------------------------------------------------
+
+ void MAdGmshOutput(const pMesh m, const pSField sf,
+ const char *fn, MAdOutputData type);
+
+ void MAdAttachedNodalDataOutput (const pMesh m, const char *fn,
+ pMeshDataId id);
+ void MAdAttachedNodalDataVecOutput(const pMesh m, const char *fn,
+ pMeshDataId id);
+
+ void printPosEntities(const pPList ents, std::string fn, MAdOutputData type,
+ const pSField sf=NULL, int id=0);
+
+ void printPosRegions(const std::set<pRegion>, std::string fn, MAdOutputData type,
+ const pSField sf=NULL, int id=0);
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/quality/ElementEvaluatorBase.h b/Adapt/quality/ElementEvaluatorBase.h
new file mode 100644
index 0000000..75c7329
--- /dev/null
+++ b/Adapt/quality/ElementEvaluatorBase.h
@@ -0,0 +1,67 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ELEMENTEVALUATORBASE
+#define _H_ELEMENTEVALUATORBASE
+
+#include "DiscreteSF.h"
+#include "MeshDataBaseInterface.h"
+
+#include <string>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ enum evaluationType {
+ UNKNOWNEVALTYPE,
+ MEANRATIO,
+ ORIENTEDMEANRATIO
+ };
+
+ // -------------------------------------------------------------------
+ class elementEvaluatorBase {
+
+ public:
+
+ elementEvaluatorBase(const DiscreteSF * f): sizeField(f) { setDefaultAcptValue(); }
+ virtual ~elementEvaluatorBase() {};
+
+ void setSizeField(const DiscreteSF * sf) {sizeField = sf;}
+
+ virtual int R_shape(const pRegion r, double * result) const = 0;
+ virtual int F_shape(const pFace f, const double normal[3], double * result) const = 0;
+ virtual int XYZ_R_shape(const double[4][3], const pMSize[4], double * result) const = 0;
+ virtual int XYZ_F_shape(const double[3][3], const pMSize[3], const double normal[3], double * result) const = 0;
+
+ virtual inline double worstShapeEver() const {return 0.;}
+ virtual inline double bestShapeEver() const {return 1.;}
+ virtual inline double whatsWorst(double shp1, double shp2) const {return std::min(shp1,shp2);}
+
+ virtual evaluationType getType () const = 0;
+ virtual std::string getName () const = 0;
+
+ double getAcceptableValue() { return acptValue; }
+ void setAcptValue(double t) { acptValue = t; }
+ void setDefaultAcptValue() { acptValue = 1.0e-10; }
+
+ protected:
+
+ const DiscreteSF * sizeField;
+ double acptValue;
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/quality/ElementStatistics.h b/Adapt/quality/ElementStatistics.h
new file mode 100644
index 0000000..39798f1
--- /dev/null
+++ b/Adapt/quality/ElementStatistics.h
@@ -0,0 +1,71 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ELEMENTSTATISTICS
+#define _H_ELEMENTSTATISTICS
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class ElementStatistics {
+
+ public:
+
+ ElementStatistics();
+ ElementStatistics(const ElementStatistics &);
+ ~ElementStatistics() {};
+
+ // interface to set information
+ void reset();
+ void setWorstShape(double v) { worstShape = v; }
+ void setMaxLenSq(double v) { maxLenSq = v; }
+ void setMinLenSq(double v) { minLenSq = v; }
+
+ // interface to get information
+ double getWorstShape() const { return worstShape; }
+ double getMaxLenSq() const { return maxLenSq; }
+ double getMinLenSq() const { return minLenSq; }
+
+ private:
+
+ double worstShape;
+ double minLenSq, maxLenSq;
+ };
+
+ // -------------------------------------------------------------------
+ inline ElementStatistics::ElementStatistics()
+ {
+ reset();
+ }
+
+ // -------------------------------------------------------------------
+ inline ElementStatistics::ElementStatistics(const ElementStatistics & eq)
+ {
+ worstShape = eq.worstShape;
+ minLenSq = eq.minLenSq;
+ maxLenSq = eq.maxLenSq;
+ }
+
+ // -------------------------------------------------------------------
+ inline void ElementStatistics::reset()
+ {
+ worstShape = MAdBIG;
+ minLenSq = MAdBIG;
+ maxLenSq = 0.0;
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/quality/MeanRatioEvaluator.cc b/Adapt/quality/MeanRatioEvaluator.cc
new file mode 100644
index 0000000..d41e5d7
--- /dev/null
+++ b/Adapt/quality/MeanRatioEvaluator.cc
@@ -0,0 +1,169 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MeanRatioEvaluator.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::string;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ meanRatioEvaluator::meanRatioEvaluator(const DiscreteSF * f):
+ elementEvaluatorBase(f)
+ {}
+
+ // -------------------------------------------------------------------
+ int meanRatioEvaluator::F_shape(const pFace face, const double normal[3],
+ double * shape) const
+ {
+ double fxyz[3][3];
+ pMSize pS[3];
+
+ void *iter=0;
+ int i = 0;
+ pPList fvts=F_vertices(face,1);
+ while( pVertex vt=(pVertex)PList_next(fvts,&iter) ) {
+ pS[i]=sizeField->findSize(vt);
+ V_coord(vt,fxyz[i++]);
+ }
+ PList_delete(fvts);
+
+ return XYZ_F_shape(fxyz,pS,normal,shape);
+ }
+
+ // -------------------------------------------------------------------
+ int meanRatioEvaluator::XYZ_F_shape(const double xyz[3][3], const pMSize pS[3],
+ const double nor[3], double * shape) const
+ {
+ if( sizeField->getType() == NULLSFIELD ) {
+ if( ! XYZ_F_shape(xyz,pS[0],nor,shape) )
+ { *shape=0; return 0; }
+ return 1;
+ }
+
+ // use central size to compute shape
+ pMSize pSZ = MS_interpolate(pS[0], pS[1], pS[2], 0.33, 0.33);
+ int res = XYZ_F_shape(xyz, pSZ, nor, shape);
+ if ( pSZ ) delete pSZ;
+ return res;
+
+// // compute shapes using sizes at every vertex and retain the worst one
+// double shp[3];
+// for(int i=0; i<3; i++) {
+// if( ! XYZ_F_shape(xyz, pS[i], nor, &shp[i]) )
+// { *shape = 0.; return 0; }
+// }
+// *shape = std::min(std::min(shp[0],shp[1]),shp[2]);
+// return 1;
+ }
+
+ // -------------------------------------------------------------------
+ int meanRatioEvaluator::XYZ_F_shape(const double xyz[3][3], const pMSize pS,
+ const double nor[3], double * shape) const
+ {
+ double aSq,sumSq;
+
+ aSq = sizeField->SF_XYZ_areaSq(xyz,pS,nor);
+
+ if( aSq <= 0. ) { *shape = 0.; return 0; }
+
+ sumSq = sizeField->SF_XYZ_lengthSq(xyz[1],xyz[0],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[2],xyz[0],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[1],xyz[2],pS);
+
+ *shape = 48.*aSq/(sumSq*sumSq);
+
+ if(*shape < acptValue) return 0;
+ else if (*shape > (1.+MAdTOL) ) *shape = 1.;
+
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+ int meanRatioEvaluator::R_shape(const pRegion rgn, double * shape) const
+ {
+ double rxyz[4][3];
+ pMSize pS[4];
+
+ void *iter=0;
+ int i=0;
+ pPList verts=R_vertices(rgn);
+ while( pVertex vt=(pVertex)PList_next(verts,&iter) ) {
+ pS[i]=sizeField->findSize(vt);
+ V_coord(vt,rxyz[i++]);
+ }
+ PList_delete(verts);
+
+ return XYZ_R_shape(rxyz,pS,shape);
+ }
+
+ // -------------------------------------------------------------------
+ int meanRatioEvaluator::XYZ_R_shape(const double xyz[4][3], const pMSize pS[4],
+ double * shape) const
+ {
+ if( sizeField->getType() == NULLSFIELD ) {
+ if( ! XYZ_R_shape(xyz,pS[0],shape) )
+ { *shape=0.; return 0; }
+ return 1;
+ }
+
+ // use central size
+ pMSize pSZ = MS_interpolate(pS[0], pS[1], pS[2], pS[3], 0.25, 0.25, 0.25);
+
+ // use minimal size
+// pMSize pSZ;
+// double hmin = MAdBIG;
+// for(int i=0; i<4; i++) {
+// if( pS[i] ) {
+// double s = pS[i]->minSize();
+// if( s < hmin ) { hmin = s; pSZ = pS[i]; }
+// }
+// }
+// assert( hmin != MAdBIG );
+
+ int res = XYZ_R_shape(xyz,pSZ,shape);
+ if ( pSZ ) delete pSZ;
+ return res;
+ }
+
+ // -------------------------------------------------------------------
+ int meanRatioEvaluator::XYZ_R_shape(const double xyz[4][3], const pMSize pS,
+ double * shape) const
+ {
+ double vol,sumSq;
+
+ vol = sizeField->SF_XYZ_volume(xyz,pS);
+
+ if ( vol < 0. ) { *shape = 0.; return 0; }
+
+ sumSq = sizeField->SF_XYZ_lengthSq(xyz[1],xyz[0],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[2],xyz[0],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[0],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[1],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[2],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[1],xyz[2],pS);
+
+ *shape = 15552.*vol*vol/(sumSq*sumSq*sumSq);
+
+ if(*shape < acptValue) return 0;
+ else if (*shape > (1.+MAdTOL) ) *shape = 1.;
+
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/quality/MeanRatioEvaluator.h b/Adapt/quality/MeanRatioEvaluator.h
new file mode 100644
index 0000000..018242c
--- /dev/null
+++ b/Adapt/quality/MeanRatioEvaluator.h
@@ -0,0 +1,66 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MEANRATIOEVALUATOR
+#define _H_MEANRATIOEVALUATOR
+
+#include "ElementEvaluatorBase.h"
+
+/* -------------------------------------------------------------------
+
+Computes the cubic of the mean ratio of any element of the mesh (tri or tet)
+The mean ratio is expressed as:
+
+For tetrahedrons:
+
+eta = 12 * ( ( 3*Volume ) ^ (2/3) ) / ( sum(edgeLength^2) )
+
+or equivalently:
+
+eta ^ 3 = 15552 * (Volume) ^ 2 / ( sum(edgeLength^2) ) ^ 3
+
+For triangles:
+
+eta ^ 2 = 48 * ( Area ^ 2 ) / ( sum(edgeLength^2) ) ^ 2
+
+This ensures ratios ranging from 0 (flat element) to 1 (equilateral)
+
+------------------------------------------------------------------- */
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class meanRatioEvaluator : public elementEvaluatorBase
+ {
+ public:
+ meanRatioEvaluator(const DiscreteSF * f);
+ virtual ~meanRatioEvaluator() {}
+
+ virtual int F_shape(const pFace pf, const double normal[3], double * result) const;
+ virtual int R_shape(const pRegion pr, double * result) const;
+ virtual int XYZ_F_shape(const double[3][3], const pMSize[3], const double normal[3], double * result) const;
+ virtual int XYZ_R_shape(const double[4][3], const pMSize[4], double * result) const;
+
+ virtual evaluationType getType () const {return MEANRATIO;}
+ virtual std::string getName () const {return "Mean ratio";}
+
+ protected:
+ virtual int XYZ_F_shape(const double[3][3], const pMSize pS, const double normal[3], double * result) const;
+ virtual int XYZ_R_shape(const double[4][3], const pMSize pS, double * result) const;
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/quality/MeshQualityManager.cc b/Adapt/quality/MeshQualityManager.cc
new file mode 100644
index 0000000..03acff6
--- /dev/null
+++ b/Adapt/quality/MeshQualityManager.cc
@@ -0,0 +1,678 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MeshQualityManager.h"
+#include "MeanRatioEvaluator.h"
+#include "OrientedMeanRatioEvaluator.h"
+#include "CallBackManager.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::ostream;
+#include <iomanip>
+#include <math.h>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void QualityDeletingCBFunctionMove (pVertex pv, double *, void *)
+ {
+ MeshQualityManagerSgl::instance().clearNeighbourShapes(pv);
+ }
+
+ // -------------------------------------------------------------------
+ void QualityDeletingCBFunction (pPList before, pPList after, void *,
+ operationType type , pEntity ppp)
+ {
+ switch (type) {
+ case MAd_ESPLIT: {
+ // In the edge split case, we have to delete the shapes associated to the old elements
+
+ // find the old edge
+ void *tmp=0;
+ pEntity pE = PList_next(before,&tmp);
+
+ // clear all shapes in the neighbour of the edge
+ MeshQualityManagerSgl::instance().clearNeighbourShapes((pEdge) pE);
+
+ break;
+ }
+ case MAd_ECOLLAPSE: {
+ // In the edge collapse case, we have to delete the shapes attached to the neighbour elements of the deleted node.
+ // clear all shapes in the neighbour of the deleted node
+ MeshQualityManagerSgl::instance().clearNeighbourShapes((pVertex) ppp);
+
+ break;
+ }
+ case MAd_FSWAP:{
+ // In the face swap case, we have to delete the shapes associated to the old elements
+ void * temp = NULL;
+ while ( pEntity ent = PList_next(before,&temp) ) {
+ MeshQualityManagerSgl::instance().clearShape(ent);
+ }
+ break;
+ }
+ case MAd_ESWAP: {
+ // In the edge swap case, we have to delete the shapes associated to the old elements
+ void * temp = NULL;
+ while ( pEntity ent = PList_next(before,&temp) ) {
+ MeshQualityManagerSgl::instance().clearShape(ent);
+ }
+ break;
+ }
+ case MAd_RREMOVE: {
+ // delete the shape associated to the deleted region
+ MeshQualityManagerSgl::instance().clearShape(ppp);
+ break;
+ }
+ default: {
+ printf("Error in MeshQualityManager: Callback function not implemented for mesh modification %d",
+ type);
+ throw;
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::initialize(pMesh m, DiscreteSF * sf, evaluationType type)
+ {
+ mesh = m;
+ sizeField = sf;
+
+ dim = M_dim(mesh);
+ shapeId = MD_newMeshDataId("");
+
+ switch(type) {
+ case MEANRATIO: {
+ if(!evaluator) {
+ evaluator = new meanRatioEvaluator(sizeField);
+ }
+ break;
+ }
+ default: {
+ cerr << "Error: unknown evaluation type when initializing the mesh quality manager\n";
+ throw;
+ }
+ }
+
+ CallBackManagerSgl::instance().registerCallBack(QualityDeletingCBFunction,NULL);
+ CallBackManagerSgl::instance().registerCallBackMove(QualityDeletingCBFunctionMove,NULL);
+
+ if(!histogram) {
+ histogram = new int[10];
+ }
+ if(!histogramAvg) {
+ histogramAvg = new double[10];
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::setMesh(pMesh m)
+ {
+ mesh = m;
+ dim = M_dim(mesh);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::finalize()
+ {
+ clearAllShapes();
+ MD_deleteMeshDataId(shapeId);
+ if (evaluator) {
+ delete evaluator;
+ evaluator=NULL;
+ }
+ if (histogram) {
+ delete [] histogram;
+ histogram=NULL;
+ }
+ if (histogramAvg) {
+ delete [] histogramAvg;
+ histogramAvg=NULL;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::evaluateAllShapes() const
+ {
+ if (!mesh) {
+ cout << "Warning: Could not evaluate shapes in the element evaluator: no mesh specified\n";
+ return;
+ }
+
+ if ( dim == 3 ) {
+ RIter rit = M_regionIter(mesh);
+ while ( pRegion pr = RIter_next(rit) ) {
+ double tmp;
+ if ( !getAttachedShape((pEntity)pr,&tmp) ) {
+ double shape;
+ evaluator->R_shape(pr,&shape);
+ attachShape((pEntity)pr, shape);
+ }
+ }
+ RIter_delete(rit);
+ }
+ else {
+ FIter fit = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fit) ) {
+ double tmp;
+ if ( !getAttachedShape((pEntity)pf,&tmp) ) {
+ double shape;
+ evaluator->F_shape(pf,0,&shape);
+ attachShape((pEntity)pf, shape);
+ }
+ }
+ FIter_delete(fit);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::evaluateAndReplaceAllShapes() const
+ {
+ if (!mesh) {
+ cout << "Warning: Could not evaluate shapes in the element evaluator: no mesh specified\n";
+ return;
+ }
+
+ if ( dim == 3 ) {
+ RIter rit = M_regionIter(mesh);
+ while ( pRegion pr = RIter_next(rit) ) {
+ double shape;
+ evaluator->R_shape(pr,&shape);
+ attachShape((pEntity)pr, shape);
+ }
+ RIter_delete(rit);
+ }
+ else {
+ FIter fit = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fit) ) {
+ double shape;
+ evaluator->F_shape(pf,0,&shape);
+ attachShape((pEntity)pf, shape);
+ }
+ FIter_delete(fit);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ int MeshQualityManager::getShape(pFace pf, double normal[3], double * result) const
+ {
+ return evaluator->F_shape(pf,normal,result);
+ }
+
+ // -------------------------------------------------------------------
+ int MeshQualityManager::getShape(pRegion pr, double * result) const
+ {
+ // return evaluator->R_shape(pr,result);
+ if ( !getAttachedShape((pEntity)pr, result) ) {
+ int flag = evaluator->R_shape(pr,result);
+ attachShape((pEntity)pr,*result);
+ return flag;
+ }
+
+ if ( *result < evaluator->getAcceptableValue() ) return 0;
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::clearAllShapes() const
+ {
+ if (!mesh) {
+ cout << "Warning: Could not clear shapes in the element evaluator: no mesh specified\n";
+ return;
+ }
+
+ if ( dim == 3 ) {
+ RIter rit = M_regionIter(mesh);
+ while ( pRegion pr = RIter_next(rit) ) {
+ clearShape((pEntity)pr);
+ }
+ RIter_delete(rit);
+ }
+ else {
+ FIter fit = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fit) ) {
+ clearShape((pEntity)pf);
+ }
+ FIter_delete(fit);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::clearShape(pEntity pe) const
+ {
+ EN_deleteData(pe, shapeId);
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::clearNeighbourShapes(pVertex pv) const
+ {
+ if ( dim==3 ) {
+ pPList regs = V_regions(pv);
+ void* temp=0;
+ while ( pEntity region = PList_next(regs,&temp) ) {
+ clearShape( region );
+ }
+ PList_delete(regs);
+ }
+ else {
+ pPList faces = V_faces(pv);
+ void* temp=0;
+ while ( pEntity face = PList_next(faces,&temp) ) {
+ clearShape( face );
+ }
+ PList_delete(faces);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::clearNeighbourShapes(pEdge pe) const
+ {
+ if ( dim==3 ) {
+ pPList regs = E_regions(pe);
+ void* temp=0;
+ while ( pEntity region = PList_next(regs,&temp) ) {
+ clearShape( region );
+ }
+ PList_delete(regs);
+ }
+ else {
+ pPList faces = E_faces(pe);
+ void* temp=0;
+ while ( pEntity face = PList_next(faces,&temp) ) {
+ clearShape( face );
+ }
+ PList_delete(faces);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ int MeshQualityManager::V_worstShape(pVertex vt, double* result) const
+ {
+ pRegion region;
+ pPList rlist = V_regions(vt);
+ double worst = evaluator->bestShapeEver();
+ double shape_1;
+
+ double mtol = evaluator->getAcceptableValue();
+ void *temp=0;
+
+ if( PList_size(rlist)==0 ) {
+ // 2D case
+ pPList flist = V_faces(vt);
+ pFace face;
+ while( ( face = (pFace)PList_next(flist,&temp) ) ) {
+ getShape(face,0,&shape_1);
+ if( shape_1 <= mtol ) {
+ PList_delete(flist);
+ *result = shape_1;
+ return 0;
+ }
+ if(shape_1 < worst)
+ worst = shape_1;
+ }
+ PList_delete(flist);
+ }
+ else {
+ // 3D case
+ while( ( region = (pRegion)PList_next(rlist,&temp) ) ) {
+ getShape(region,&shape_1);
+ if( shape_1 <= mtol ) {
+ PList_delete(rlist);
+ *result = shape_1;
+ return 0;
+ }
+ if(shape_1 < worst)
+ worst = shape_1;
+ }
+ }
+
+ PList_delete(rlist);
+ *result = worst;
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+
+ int MeshQualityManager::E_worstShape(pEdge e, double* result) const {
+
+ double worst = evaluator->bestShapeEver();
+ double shape_1;
+ double mtol = evaluator->getAcceptableValue();
+
+ // 2D case
+ if( E_numRegions(e)==0 ) {
+ pFace face;
+ for( int i=0; i<E_numFaces(e); i++ ) {
+ face=E_face(e,i);
+ if (!getShape(face,0,&shape_1) || shape_1 <= mtol ) {
+ *result = 0.0; return 0;
+ }
+ if( shape_1 < worst) worst = shape_1;
+ }
+ }
+ // 3D case
+ else {
+ pPList rlist = E_regions(e);
+ pRegion region; void *temp=0;
+ while( ( region=(pRegion)PList_next(rlist,&temp) ) ) {
+ if ( !getShape(region,&shape_1) || shape_1 <= mtol ) {
+ PList_delete(rlist); *result = 0.0; return 0;
+ }
+ if( shape_1 < worst) worst = shape_1;
+ }
+ PList_delete(rlist);
+ }
+
+ *result = worst;
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+
+ int MeshQualityManager::F_worstShape(pFace f, double* result) const {
+
+ double worst = evaluator->bestShapeEver();
+ double shape_1;
+ double mtol = evaluator->getAcceptableValue();
+
+ pPList rlist = F_regions(f);
+ pRegion region; void *temp=0;
+ while( ( region=(pRegion)PList_next(rlist,&temp) ) ) {
+ if ( !getShape(region,&shape_1) || shape_1 <= mtol ) {
+ PList_delete(rlist); *result = 0.0; return 0;
+ }
+ if( shape_1 < worst) worst = shape_1;
+ }
+ PList_delete(rlist);
+
+ *result = worst;
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+ int MeshQualityManager::FList_worstShape(pPList faces, double * result) const
+ {
+ double worst = evaluator->bestShapeEver();
+
+ void* tmp=0;
+ while( pEntity pe = PList_next(faces,&tmp) ) {
+
+ if ( EN_type(pe) != 2 ) {
+ cerr << "Error: Received an entity of dimension " << EN_type(pe) << " in FList_worstShape\n";
+ throw;
+ }
+
+ double shape;
+ if ( !getShape( (pFace)pe, 0, &shape) ) {
+ *result = 0;
+ return 0;
+ }
+ else {
+ worst = evaluator->whatsWorst(shape, worst);
+ }
+ }
+
+ *result = worst;
+
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+ int MeshQualityManager::RList_worstShape(pPList regions, double * result) const
+ {
+ double worst = evaluator->bestShapeEver();
+
+ void* tmp=0;
+ while( pEntity pe = PList_next(regions,&tmp) ) {
+
+ if ( EN_type(pe) != 3 ) {
+ cerr << "Error: Received an entity of dimension " << EN_type(pe) << " in RList_worstShape\n";
+ throw;
+ }
+
+ double shape;
+ if ( !getShape( (pRegion)pe, &shape) ) {
+ *result = 0.;
+ return 0;
+ }
+ else {
+ worst = evaluator->whatsWorst(shape, worst);
+ }
+ }
+
+ *result = worst;
+
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::attachShape(pEntity pe, double shape) const
+ {
+ EN_modifyDataDbl(pe, shapeId, shape);
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshQualityManager::getAttachedShape(const pEntity pe, double* result) const
+ {
+ if ( !EN_getDataDbl(pe, shapeId, result) ) return false;
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool MeshQualityManager::checkAttachedShapes() const
+ {
+ bool ok = true;
+
+ int noData = 0;
+ int dataOK = 0;
+ int wrongData = 0;
+
+ if (dim == 3) {
+ RIter rit = M_regionIter(mesh);
+ while ( pRegion pr = RIter_next(rit) ) {
+ double attachedShape;
+ if ( !getAttachedShape((pEntity)pr,&attachedShape) ) noData++;
+ else {
+ double shape;
+ evaluator->R_shape(pr,&shape);
+ if ( fabs(shape - attachedShape) <= 1.e-12 ) dataOK++;
+ else {
+ cout<<"Warning: wrong shape found: attached: "<<attachedShape<<", real: "<<shape<<endl;
+ wrongData++;
+ ok = false;
+ }
+ }
+ }
+ RIter_delete(rit);
+ }
+ else {
+ FIter fit = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fit) ) {
+ double attachedShape;
+ if ( !getAttachedShape((pEntity)pf,&attachedShape) ) noData++;
+ else {
+ double shape;
+ evaluator->F_shape(pf,0,&shape);
+ if ( fabs(shape - attachedShape) <= 1.e-12 ) dataOK++;
+ else {
+ cout<<"Warning: wrong shape found: attached: "<<attachedShape<<", real: "<<shape<<endl;
+ wrongData++;
+ ok = false;
+ }
+ }
+ }
+ FIter_delete(fit);
+ }
+
+ cout << "\nAttached shapes report:\n\n";
+ cout << "Elements checked: "<<noData+dataOK+wrongData<<endl;
+ cout << "Elements with no attached shape: "<<noData<<endl;
+ cout << "Elements with a correct shape: "<<dataOK<<endl;
+ cout << "Elements with a wrong shape: "<<wrongData<<endl;
+ cout<<endl;
+
+ return ok;
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::evaluateSizes()
+ {
+ minAbsoluteSize = MAdBIG;
+ maxAbsoluteSize = 0.;
+ sizesSum = 0.;
+
+ switch( dim )
+ {
+ case 3: {
+ RIter rit = M_regionIter(mesh);
+ while ( pRegion r = RIter_next(rit) )
+ {
+ double vol = R_volume(r);
+ minAbsoluteSize = std::min(minAbsoluteSize,vol);
+ maxAbsoluteSize = std::max(maxAbsoluteSize,vol);
+ sizesSum += vol;
+ }
+ RIter_delete(rit);
+ break;
+ }
+ case 2: {
+ FIter fit = M_faceIter(mesh);
+ while ( pFace f = FIter_next(fit) )
+ {
+ double area = F_area(f,0);
+ minAbsoluteSize = std::min(minAbsoluteSize,area);
+ maxAbsoluteSize = std::max(maxAbsoluteSize,area);
+ sizesSum += area;
+ }
+ FIter_delete(fit);
+ break;
+ }
+ default: {
+ cerr << "Dimension " << dim << " not handled by meshEvaluator\n";
+ throw;
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::evaluateShapes()
+ {
+ worstShape = evaluator->bestShapeEver();
+ meanShape = 0.;
+ for (int i=0; i<10; i++) histogram[i]=0;
+ notAcpt = 0;
+
+ switch( dim )
+ {
+ case 3: {
+ nbElem = M_numRegions(mesh);
+ RIter rit = M_regionIter(mesh);
+ while ( pRegion r = RIter_next(rit) )
+ {
+ double shape;
+ if ( !getShape(r,&shape) ) notAcpt++;
+ else if (shape < 0.) {cerr << "Error: element with negative quality\n"; throw;}
+ else {
+ if (shape >= 1.) { shape = 1.-MAdTOL; }
+ unsigned int qualityLevel = (unsigned int)floor(shape*10.);
+ if ( qualityLevel == 10 ) qualityLevel = 9;
+ histogram[qualityLevel]++;
+ }
+ meanShape += shape;
+ worstShape = evaluator->whatsWorst(worstShape,shape);
+ }
+ RIter_delete(rit);
+ break;
+ }
+ case 2: {
+ nbElem = M_numFaces(mesh);
+ FIter fit = M_faceIter(mesh);
+ while ( pFace f = FIter_next(fit) ) {
+ double shape;
+ if ( !getShape(f,0,&shape)) histogram[0]++;
+ else if (shape < 0.) {cerr << "Error: element with negative quality\n"; throw;}
+ else if (shape > 1.) { shape = 1.; }
+ else {
+ unsigned int qualityLevel = (unsigned int)floor(shape*10);
+ histogram[qualityLevel]++;
+ }
+ meanShape += shape;
+ worstShape = evaluator->whatsWorst(worstShape,shape);
+ }
+ FIter_delete(fit);
+ break;
+ }
+ default: {
+ cerr << "Dimension " << dim << " not handled by meshEvaluator\n";
+ throw;
+ }
+ }
+
+ meanShape /= nbElem;
+ for (int i=0; i<10; i++) histogramAvg[i] = (double)histogram[i] / nbElem;
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::evaluateStatistics()
+ {
+ evaluateSizes();
+ evaluateShapes();
+ }
+
+ // -------------------------------------------------------------------
+ void MeshQualityManager::printStatistics(ostream& out) const
+ {
+ out << "\n ---------- Mesh quality report ----------\n\n";
+ out << "Criterion: " << evaluator->getName() << "\n\n";
+ out << " Average element quality\t"<<std::setprecision(4)<<meanShape<<"\n";
+ out << " Worst element quality\t\t"<<std::setprecision(4)<<worstShape<<"\n";
+ out << " Non acceptable elements\t"<< notAcpt << " \n";
+ out << std::setprecision(2) << std::setw(0);
+ out << std::fixed;
+
+ out << "\n --- Histogram ---\n\n";
+
+ for (int i = 0; i < 10; i++) {
+ out <<std::setprecision(1)
+ << " " << ((double)i)/10. << " < Q < " << ((double)(i+1))/10. << " : "
+ <<std::setprecision(2)<<std::setw(5)
+ << (histogramAvg[i])*100. <<" % "<<std::setw(7)<< histogram[i]<<" elements\n";
+ }
+ out<<endl;
+
+ out << std::setprecision(6) << std::setw(0); // return to default values
+ out.unsetf(std::ios::floatfield); // return to default values
+
+ out<<" Smallest ";
+ if (dim == 3) out <<"volume ";
+ else out<<"area ";
+ out <<"(absolute space)\t"<< minAbsoluteSize << "\n";
+ out<<" Biggest ";
+ if (dim == 3) out <<"volume ";
+ else out<<"area ";
+ out <<"(absolute space)\t"<< maxAbsoluteSize << "\n";
+ out<<" Total ";
+ if (dim == 3) out <<"volume ";
+ else out<<"area ";
+ out <<" (absolute space)\t"<< sizesSum << "\n\n";
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
diff --git a/Adapt/quality/MeshQualityManager.h b/Adapt/quality/MeshQualityManager.h
new file mode 100644
index 0000000..d7cb5fc
--- /dev/null
+++ b/Adapt/quality/MeshQualityManager.h
@@ -0,0 +1,139 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MESHQUALITYMANAGER
+#define _H_MESHQUALITYMANAGER
+
+#include "SizeFieldBase.h"
+#include "ElementEvaluatorBase.h"
+#include "MeshDataBaseInterface.h"
+#include "MAdSingleton.h"
+
+#include <iostream>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class MeshQualityManager {
+
+ public:
+
+ MeshQualityManager():evaluator(NULL), histogram(NULL), histogramAvg(NULL){};
+ ~MeshQualityManager() {};
+
+ void initialize(pMesh m, DiscreteSF * sf, evaluationType type);
+ void setMesh(pMesh m);
+ void finalize();
+
+ // -------------------------------------------------------------------
+
+ public:
+
+ const pMeshDataId getShapeId() const { return shapeId; }
+ const elementEvaluatorBase * getElementEvaluator() const { return evaluator; }
+
+ // evaluate missing shapes
+ void evaluateAllShapes() const;
+
+ // evaluate all shapes, replace existing ones
+ void evaluateAndReplaceAllShapes() const;
+
+ // compute and return the shape of the face (no storage for faces)
+ // return 0 if the face is not acceptable, 1 otherwise
+ int getShape(pFace pf, double normal[3], double * result) const;
+
+ // get the shape of the region, compute and store the shape if missing
+ // return 0 if the region is not acceptable, 1 otherwise
+ int getShape(pRegion pr, double * result) const;
+
+ // delete all shapes
+ void clearAllShapes() const;
+
+ // delete the shape of this entity
+ void clearShape(pEntity pe) const;
+
+ // delete all shapes of the elements neighbouring the entity
+ void clearNeighbourShapes(pVertex pv) const;
+ void clearNeighbourShapes(pEdge pe) const;
+
+ // evaluate the worst shape of all elements surrounding one or several entities
+ int V_worstShape(pVertex v, double* result) const;
+ int E_worstShape(pEdge e, double* result) const;
+ int F_worstShape(pFace f, double* result) const;
+
+ // evaluate the worst shape in a list of elements
+ int FList_worstShape(pPList faces, double * result) const;
+ int RList_worstShape(pPList regions, double * result) const;
+
+ // check that the attached shapes are still correct (debugging function)
+ bool checkAttachedShapes() const;
+
+ private:
+
+ // attach a computed shape to the entity
+ void attachShape(pEntity pe, double shape) const;
+
+ // get the shape of an entity if it exists, return false otherwise
+ bool getAttachedShape(const pEntity pe, double* result) const;
+
+ public:
+
+ // Evaluate statistics about elements sizes
+ void evaluateSizes();
+
+ // Evaluate statistics about elements shapes
+ void evaluateShapes();
+
+ // Evaluate all statistics
+ void evaluateStatistics();
+
+ // get statistics ( evaluate it first )
+ double getMeanShape() const { return meanShape; }
+ double getWorstShape() const { return worstShape; }
+ double getMinSize() const { return minAbsoluteSize; }
+ double getMaxSize() const { return maxAbsoluteSize; }
+ void printStatistics(std::ostream& out) const;
+
+ // -------------------------------------------------------------------
+
+ private:
+
+ pMesh mesh;
+ int dim;
+ DiscreteSF * sizeField;
+
+ elementEvaluatorBase* evaluator;
+
+ pMeshDataId shapeId;
+
+ // --- statistics ---
+ // ------------------
+ int nbElem;
+ double worstShape;
+ double meanShape;
+ double minAbsoluteSize; // Area or volume of the smallest element in usual space (no metric)
+ double maxAbsoluteSize; // Area or volume of the biggest element in usual space (no metric)
+ double sizesSum;
+ int notAcpt; // number of non acceptable elements
+ int* histogram; // counters of elements with different qualities
+ double* histogramAvg; // proportion of elements with different qualities
+
+ };
+
+ // -------------------------------------------------------------------
+
+ typedef MAdSingleton<MeshQualityManager> MeshQualityManagerSgl;
+
+}
+
+#endif
diff --git a/Adapt/quality/OrientedMeanRatioEvaluator.cc b/Adapt/quality/OrientedMeanRatioEvaluator.cc
new file mode 100644
index 0000000..0e09bf6
--- /dev/null
+++ b/Adapt/quality/OrientedMeanRatioEvaluator.cc
@@ -0,0 +1,123 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "OrientedMeanRatioEvaluator.h"
+#include "AnisoMeshSize.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::string;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ orientedMeanRatioEvaluator::orientedMeanRatioEvaluator(const DiscreteSF * f):
+ meanRatioEvaluator(f)
+ {}
+
+ // -------------------------------------------------------------------
+ int orientedMeanRatioEvaluator::XYZ_F_shape(const double xyz[3][3], const pMSize pS,
+ const double nor[3], double * shape) const
+ {
+ double aSq,sumSq;
+
+ aSq = sizeField->SF_XYZ_areaSq(xyz,pS,nor);
+
+ if( aSq <= 0. ) { *shape = 0.; return 0; }
+
+ sumSq = sizeField->SF_XYZ_lengthSq(xyz[1],xyz[0],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[2],xyz[0],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[1],xyz[2],pS);
+
+ *shape = 48.*aSq/(sumSq*sumSq);
+
+ if ( pS->getType() == ANISOTROPIC )
+ {
+ double tmp[3]; diffVec(xyz[1],xyz[0],tmp);
+ double cosa = fabs( ((AnisoMeshSize*)pS)->angleWithDir0(tmp) );
+ *shape *= ( fabs( cosa - 0.5 ) + 0.5 );
+ diffVec(xyz[2],xyz[0],tmp);
+ cosa = fabs( ((AnisoMeshSize*)pS)->angleWithDir0(tmp) );
+ *shape *= ( fabs( cosa - 0.5 ) + 0.5 );
+ diffVec(xyz[2],xyz[1],tmp);
+ cosa = fabs( ((AnisoMeshSize*)pS)->angleWithDir0(tmp) );
+ *shape *= ( fabs( cosa - 0.5 ) + 0.5 );
+ }
+
+ if(*shape < acptValue) return 0;
+ else if (*shape > (1.+MAdTOL) ) *shape = 1.;
+
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+ int orientedMeanRatioEvaluator::XYZ_R_shape(const double xyz[4][3], const pMSize pS,
+ double * shape) const
+ {
+ double vol,sumSq;
+
+ vol = sizeField->SF_XYZ_volume(xyz,pS);
+
+ if ( vol < 0. ) { *shape = 0.; return 0; }
+
+ sumSq = sizeField->SF_XYZ_lengthSq(xyz[1],xyz[0],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[2],xyz[0],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[0],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[1],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[2],pS);
+ sumSq += sizeField->SF_XYZ_lengthSq(xyz[1],xyz[2],pS);
+
+ *shape = 15552.*vol*vol/(sumSq*sumSq*sumSq);
+
+ if ( pS->getType() == ANISOTROPIC )
+ {
+ double dir0[3]; pS->direction(0,dir0); normalizeVec(dir0,dir0);
+ double orientFactor = 1.;
+
+ double tmp[3]; diffVec(xyz[1],xyz[0],tmp); normalizeVec(tmp,tmp);
+ double cosa = fabs( dotProd(dir0,tmp) );
+ orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+
+ diffVec(xyz[2],xyz[0],tmp); normalizeVec(tmp,tmp);
+ cosa = fabs( dotProd(dir0,tmp) );
+ orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+
+ diffVec(xyz[3],xyz[0],tmp); normalizeVec(tmp,tmp);
+ cosa = fabs( dotProd(dir0,tmp) );
+ orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+
+ diffVec(xyz[2],xyz[1],tmp); normalizeVec(tmp,tmp);
+ cosa = fabs( dotProd(dir0,tmp) );
+ orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+
+ diffVec(xyz[3],xyz[1],tmp); normalizeVec(tmp,tmp);
+ cosa = fabs( dotProd(dir0,tmp) );
+ orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+
+ diffVec(xyz[3],xyz[2],tmp); normalizeVec(tmp,tmp);
+ cosa = fabs( dotProd(dir0,tmp) );
+ orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+
+ *shape *= orientFactor;
+ }
+
+ if(*shape < acptValue) return 0;
+ else if (*shape > (1.+MAdTOL) ) *shape = 1.;
+
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/quality/OrientedMeanRatioEvaluator.h b/Adapt/quality/OrientedMeanRatioEvaluator.h
new file mode 100644
index 0000000..c7d4cbb
--- /dev/null
+++ b/Adapt/quality/OrientedMeanRatioEvaluator.h
@@ -0,0 +1,68 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ORIENTEDMEANRATIOEVALUATOR
+#define _H_ORIENTEDMEANRATIOEVALUATOR
+
+#include "MeanRatioEvaluator.h"
+
+/* -------------------------------------------------------------------
+
+Computes the cubic of the mean ratio of any element of the
+mesh (tri or tet) penalised (for every edge 'e') by a factor
+
+ | |cos(alpha_e)| - 0.5 | + 0.5
+
+where 'alpha_e' is the angle of 'e' with the direction of the minimal
+size. This is equivalent to the mean ratio for isotropic sizes.
+
+The mean ratio is expressed as:
+
+For tetrahedrons:
+
+ eta = 12 * ( ( 3*Volume ) ^ (2/3) ) / ( sum(edgeLength^2) )
+
+or equivalently:
+
+ eta ^ 3 = 15552 * (Volume) ^ 2 / ( sum(edgeLength^2) ) ^ 3
+
+For triangles:
+
+ eta ^ 2 = 48 * ( Area ^ 2 ) / ( sum(edgeLength^2) ) ^ 2
+
+This ensures ratios ranging from 0 (flat element) to 1 (equilateral)
+
+------------------------------------------------------------------- */
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class orientedMeanRatioEvaluator : public meanRatioEvaluator
+ {
+ public:
+ orientedMeanRatioEvaluator(const DiscreteSF * f);
+ virtual ~orientedMeanRatioEvaluator() {}
+
+ virtual evaluationType getType () const {return ORIENTEDMEANRATIO;}
+ virtual std::string getName () const {return "Oriented mean ratio";}
+
+ protected:
+ virtual int XYZ_F_shape(const double[3][3], const pMSize pS, const double normal[3], double * result) const;
+ virtual int XYZ_R_shape(const double[4][3], const pMSize pS, double * result) const;
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/repositioning/GeoMatcher.cc b/Adapt/repositioning/GeoMatcher.cc
new file mode 100644
index 0000000..81dab88
--- /dev/null
+++ b/Adapt/repositioning/GeoMatcher.cc
@@ -0,0 +1,153 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "GeoMatcher.h"
+#include "CallBackManager.h"
+#include "MathUtils.h"
+#include "ModelInterface.h"
+#include "MAdMessage.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void GeoMatcherCBFunction (pPList before, pPList after, void * data,
+ operationType type , pEntity ppp)
+ {
+#ifdef _HAVE_GMSH_
+ geoMatcher * gm = (geoMatcher *)(data);
+
+ switch (type) {
+ case MAd_ESPLIT: {
+
+ if ( gm->relocationsComputed() ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Applying an edge split during a geometry snapping procedure");
+ }
+
+ // if new point is on a line or surface, you need to find its
+ // projection on the geometrical entity and impose its new
+ // location as a Dirichlet BC in the elastic model
+
+ pGEntity pGE = V_whatIn( (pVertex)ppp );
+ int dimBnd = GEN_type(pGE);
+ if ( dimBnd < 3 ) {
+
+ double xyz[3]; // current position of the new point
+ V_coord( (pVertex)ppp, xyz );
+// printVec(xyz,"Original location");
+
+ double u,v;
+ if ( !V_params((pVertex)ppp,&u,&v) ) {
+ V_info((pVertex)ppp);
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Not a parametric point");
+ }
+
+ double tgt[3]; // the target location
+ switch (dimBnd) {
+ case 2: { // on a surface
+ GF_xyz((pGFace)pGE, u, v, tgt);
+ break;
+ }
+ case 1: { // on a line
+ GE_xyz((pGEdge)pGE, u, tgt);
+ break;
+ }
+ default: {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Unexpected geometric entity dimension for a new vertex: %d",
+ dimBnd);
+ }
+ }
+// printVec(tgt,"Target location");
+
+ // compute the difference with the current position
+ double dx[3];
+ diffVec(tgt,xyz,dx);
+// printVec(dx,"DISPLACEMENT");
+
+ // impose the motion as a Dirichlet BC in the elastic model
+ smallVector dxVec(3);
+ for (int i=0; i<3; i++) dxVec(i) = dx[i];
+ gm->addDirichlet( (pVertex)ppp, dxVec );
+ }
+ break;
+ }
+ case MAd_ECOLLAPSE: {
+ gm->delDirichlet( (pVertex)ppp );
+ gm->delRelocation( (pVertex)ppp );
+ break;
+ }
+ case MAd_FSWAP:
+ case MAd_ESWAP: {
+ break;
+ }
+ case MAd_RREMOVE: {
+ throw; // some nodes could become parametric: to be checked
+ void * temp = NULL;
+ while ( pEntity pE = PList_next(before,&temp) ) {
+ if ( EN_type(pE) == 0 ) {
+ gm->delDirichlet( (pVertex)pE );
+ }
+ }
+ break;
+ }
+ default: {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Callback function not implemented for mesh modification %d",
+ type);
+ }
+ }
+#endif
+ }
+
+ // -------------------------------------------------------------------
+ geoMatcher::geoMatcher(pMesh _mesh):
+ MAdElasticityOp(_mesh)
+ {
+ CallBackManagerSgl::instance().registerCallBack(GeoMatcherCBFunction,this);
+ }
+
+ // -------------------------------------------------------------------
+ geoMatcher::geoMatcher(const geoMatcher& gm):
+ MAdElasticityOp(gm)
+ {
+ CallBackManagerSgl::instance().registerCallBack(GeoMatcherCBFunction,this);
+ }
+
+ // -------------------------------------------------------------------
+ geoMatcher::~geoMatcher()
+ {
+ CallBackManagerSgl::instance().unregisterCallBack(GeoMatcherCBFunction,this);
+ }
+
+ // -------------------------------------------------------------------
+ void geoMatcher::printFailures(std::ostream& out) const
+ {
+ if ( failures.size() ) {
+ out << "No failure reported in the GeoMatcher\n";
+ }
+ else {
+ out << failures.size() << " failures reported in the GeoMatcher:\n\n";
+ int i = 0;
+ std::list<double>::const_iterator it = failures.begin();
+ for (; it != failures.end(); it++)
+ {
+ out << i << " ratio: " << *it << "\n";
+ i++;
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/repositioning/GeoMatcher.h b/Adapt/repositioning/GeoMatcher.h
new file mode 100644
index 0000000..9533d69
--- /dev/null
+++ b/Adapt/repositioning/GeoMatcher.h
@@ -0,0 +1,45 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_GEOMATCHER
+#define _H_GEOMATCHER
+
+#include "MAdElasticityOp.h"
+#include <list>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class geoMatcher: public MAdElasticityOp
+ {
+
+ public:
+
+ geoMatcher(pMesh);
+ geoMatcher(const geoMatcher&);
+ ~geoMatcher();
+
+ void reportFailure(double ratio) { failures.push_back(ratio); }
+ void printFailures(std::ostream&) const;
+
+ private:
+
+ std::list<double> failures;
+
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/repositioning/LaplaceSmoothingOp.cc b/Adapt/repositioning/LaplaceSmoothingOp.cc
new file mode 100644
index 0000000..872c794
--- /dev/null
+++ b/Adapt/repositioning/LaplaceSmoothingOp.cc
@@ -0,0 +1,75 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "LaplaceSmoothingOp.h"
+#include "VertexMoveOp.h"
+#include "MeshParametersManager.h"
+#include "MathUtils.h"
+
+#include <vector>
+using std::vector;
+#include <math.h>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ LaplaceSmoothingOp::LaplaceSmoothingOp(pMesh m, DiscreteSF * sf):
+ nodesRepositioningOp(m,sf)
+ {}
+
+ // -------------------------------------------------------------------
+ int LaplaceSmoothingOp::run(double * L2Norm)
+ {
+ return run(OPTIMAL,L2Norm);
+ }
+
+ // -------------------------------------------------------------------
+ int LaplaceSmoothingOp::run(LaplSmooType type, double * L2Norm)
+ {
+ *L2Norm = 0.0;
+
+ vertexMoveOp * vMove = new vertexMoveOp(mesh,sizeField,true);
+
+ VIter vit = M_vertexIter(mesh);
+ while( pVertex pv = VIter_next(vit) ) {
+
+ if ( V_whatInType(pv) != dim ) continue;
+
+ double ori[3];
+ V_coord(pv,ori);
+
+ double opt[3];
+ if ( type == OPTIMAL ) {
+ if (vMove->computeOptimalLocation(pv, opt)) vMove->setPosition(pv, opt);
+ } else {
+ V_cavityCenter(pv,opt);
+ vMove->setPosition(pv, opt);
+ }
+
+ double worst;
+ if( vMove->evaluate(&worst) ) {
+ vMove->apply();
+ double disp[3];
+ diffVec(ori,opt,disp);
+ *L2Norm += dotProd(disp,disp);
+ }
+
+ vMove->resetDisplacements();
+ }
+
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
diff --git a/Adapt/repositioning/LaplaceSmoothingOp.h b/Adapt/repositioning/LaplaceSmoothingOp.h
new file mode 100644
index 0000000..ce4804d
--- /dev/null
+++ b/Adapt/repositioning/LaplaceSmoothingOp.h
@@ -0,0 +1,46 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LAPLACESMOOTHINGOP
+#define _H_LAPLACESMOOTHINGOP
+
+#include "NodesRepositioningOp.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ enum LaplSmooType {
+ FAST,
+ OPTIMAL
+ };
+
+ // -------------------------------------------------------------------
+ class LaplaceSmoothingOp : public nodesRepositioningOp {
+
+ public:
+
+ LaplaceSmoothingOp(pMesh m, DiscreteSF * sf);
+ ~LaplaceSmoothingOp() {}
+
+ public:
+
+ virtual int run(double * L2Norm);
+ virtual int run(LaplSmooType type, double * L2Norm);
+
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/repositioning/MAdElasticityOp.cc b/Adapt/repositioning/MAdElasticityOp.cc
new file mode 100644
index 0000000..44f291d
--- /dev/null
+++ b/Adapt/repositioning/MAdElasticityOp.cc
@@ -0,0 +1,954 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdElasticityOp.h"
+#include "MAdResourceManager.h"
+#include "OperatorTools.h"
+#include "MathUtils.h"
+#include "MAdOutput.h"
+#include "CallBackManager.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::make_pair;
+using std::map;
+using std::set;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void ElasticityOpCBFunction (pPList before, pPList after, void * data,
+ operationType type , pEntity ppp)
+ {
+ MAdElasticityOp * elast = (MAdElasticityOp *)(data);
+ if ( !(elast->relocationsComputed()) ) return;
+
+ switch (type) {
+ case MAd_ESPLIT: {
+
+ // find the old edge
+ void * temp = NULL;
+ pEntity pE = PList_next(before,&temp);
+
+ // take the interpolated displacements between the extremities
+ // of the edge for the new vertex
+ elast->addVertexOnEdge( (pVertex)ppp, (pEdge)pE );
+
+ break;
+ }
+ case MAd_ECOLLAPSE: {
+ elast->removeVertex( (pVertex)ppp );
+ break;
+ }
+ case MAd_FSWAP:
+ case MAd_ESWAP: {
+ break;
+ }
+ case MAd_RREMOVE: {
+ void * temp = NULL;
+ while ( pEntity pE = PList_next(before,&temp) ) {
+ if ( EN_type(pE) == 0 ) {
+ elast->removeVertex( (pVertex)pE );
+ }
+ }
+ break;
+ }
+ default: {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Callback function not implemented for mesh modification %d",
+ type);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ MAdElasticityOp::MAdElasticityOp(pMesh m):
+ mesh(m), E(1.), nu(0.45), chi(1.0), computed(false),
+ cavityEqualMesh(false), cavityThickness(3)
+ {
+ dim = M_dim(mesh);
+ CallBackManagerSgl::instance().registerCallBack(ElasticityOpCBFunction,this);
+ }
+
+ // -------------------------------------------------------------------
+ MAdElasticityOp::MAdElasticityOp(const MAdElasticityOp& eop):
+ mesh(eop.mesh), dim(eop.dim),
+ E(eop.E), nu(eop.nu), chi(eop.chi),
+ computed(eop.computed),
+ cavityEqualMesh(eop.cavityEqualMesh),
+ cavityThickness(eop.cavityThickness)
+ {
+ localIds = eop.localIds;
+ dirichlet = eop.dirichlet;
+ CallBackManagerSgl::instance().registerCallBack(ElasticityOpCBFunction,this);
+ }
+
+ // -------------------------------------------------------------------
+ MAdElasticityOp::~MAdElasticityOp()
+ {
+ CallBackManagerSgl::instance().unregisterCallBack(ElasticityOpCBFunction,this);
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::setMaterials(double _E, double _nu)
+ {
+ E = _E; nu = _nu;
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::setStiffnessAlterationCoef(double _chi)
+ {
+ chi = _chi;
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::clear()
+ {
+ localIds.clear();
+ cavity.clear();
+ dirichlet.clear();
+ relocations.clear();
+ computed = false;
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::buildCavity()
+ {
+ computed = false;
+
+ if ( cavityEqualMesh ) return;
+
+ int nVertInit = dirichlet.size();
+
+ cavity.clear();
+
+ if ( cavityThickness < 1 ) return;
+
+ set<pVertex> innerNodes; // nodes inside the cavity and dirichlet
+ set<pRegion> prevLayer;
+
+ // --- first layer ---
+ pRegion pr;
+ pVertex pv;
+ map<pVertex,smallVector>::const_iterator dIter = dirichlet.begin();
+ for (; dIter != dirichlet.end(); dIter++) {
+ pv = (*dIter).first;
+ pPList vRegs = V_regions(pv);
+ void * temp = NULL;
+ while ( ( pr = (pRegion)PList_next(vRegs,&temp) ) ) {
+ cavity.insert(pr);
+ prevLayer.insert(pr);
+ }
+ PList_delete(vRegs);
+ innerNodes.insert(pv);
+ }
+
+ // --- next layers ---
+ for (int iL=1; iL < cavityThickness; iL++) {
+ set<pRegion> curLayer;
+ set<pRegion>::const_iterator rIter = prevLayer.begin();
+ for (; rIter != prevLayer.end(); rIter++ ) {
+ pPList rVerts = R_vertices(*rIter);
+ void * temp = NULL;
+ while ( ( pv = (pVertex)PList_next(rVerts,&temp) ) ) {
+ if ( innerNodes.find(pv) == innerNodes.end() ) {
+ pPList vRegs = V_regions(pv);
+ void * temp = NULL;
+ while ( ( pr = (pRegion)PList_next(vRegs,&temp) ) ) {
+ if ( cavity.find(pr) == cavity.end() ) {
+ cavity.insert(pr);
+ curLayer.insert(pr);
+ }
+ }
+ PList_delete(vRegs);
+ innerNodes.insert(pv);
+ }
+ }
+ PList_delete(rVerts);
+ }
+ prevLayer.clear();
+ prevLayer.insert(curLayer.begin(),curLayer.end());
+ curLayer.clear();
+ }
+
+ printf("Built a cavity with %d elements, dirichlet size: %d\n",cavity.size(),dirichlet.size());
+
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::setHomogDirichletBC()
+ {
+ dirichlet.clear();
+ setDirichletBC();
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::setDirichletBC()
+ {
+ computed = false;
+ smallVector zero(3); zero.set_all(0.);
+
+ set<pVertex> verts;
+ collectBCVertices(&verts);
+
+ set<pVertex>::const_iterator vIter = verts.begin();
+ set<pVertex>::const_iterator vLast = verts.end();
+ for (; vIter != vLast; vIter++) {
+ addDirichlet(*vIter,zero);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::collectBCVertices(set<pVertex> * bcVerts)
+ {
+ if ( cavityEqualMesh )
+ {
+ FIter fit = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fit) ) {
+ if ( EN_whatInType((pEntity)pf) == 2 ) {
+ pPList fV = F_vertices(pf,1);
+ void* tmp=0;
+ while ( pVertex pv = (pVertex)PList_next(fV,&tmp) ) {
+ (*bcVerts).insert(pv);
+ }
+ PList_delete(fV);
+ }
+ }
+ FIter_delete(fit);
+ }
+ else
+ {
+ set<pRegion>::const_iterator cavIter = cavity.begin();
+ for (; cavIter != cavity.end(); cavIter++) {
+ pPList rFaces = R_faces(*cavIter);
+ void * temp = NULL;
+ pFace pf;
+ while ( ( pf = (pFace)PList_next(rFaces,&temp) ) ) {
+ pRegion otherR = F_otherRegion(pf,*cavIter);
+ if ( !otherR || cavity.find(otherR) == cavity.end() ) {
+ pPList fVerts = F_vertices(pf,1);
+ void * temp2 = NULL;
+ pVertex pv;
+ while ( ( pv = (pVertex)PList_next(fVerts,&temp2) ) ) {
+ (*bcVerts).insert(pv);
+ }
+ PList_delete(fVerts);
+ }
+ }
+ PList_delete(rFaces);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::addDirichlet(pVertex pv, smallVector& dxyz)
+ {
+ map<pVertex,smallVector>::iterator dIter = dirichlet.find(pv);
+ if ( dIter != dirichlet.end() ) {
+ smallVector dxyz1 = (*dIter).second;
+ dxyz1.add(dxyz);
+ dirichlet.erase(dIter);
+ dirichlet.insert(make_pair(pv,dxyz1));
+ }
+ else {
+ dirichlet.insert(make_pair(pv,dxyz));
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::delDirichlet(pVertex pv)
+ {
+ map<pVertex,smallVector>::iterator dIter = dirichlet.find(pv);
+ if ( dIter != dirichlet.end() ) {
+ dirichlet.erase(dIter);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::delRelocation(pVertex pv)
+ {
+ map<pVertex,smallVector>::iterator dIter = relocations.find(pv);
+ if ( dIter != relocations.end() ) {
+ relocations.erase(dIter);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ // Generates table of vertex pointers to local ids and returns number
+ // of vertices in the cavity.
+ int MAdElasticityOp::generateVertexIds()
+ {
+ computed = false;
+ localIds.clear();
+
+ int id = 0;
+
+ if (cavityEqualMesh) {
+ VIter vit = M_vertexIter(mesh);
+ while ( pVertex pv = VIter_next(vit) ) {
+ localIds[pv] = id;
+ id++;
+ }
+ VIter_delete(vit);
+ }
+ else {
+ set<pVertex> verts;
+ set<pRegion>::const_iterator cavIter = cavity.begin();
+ for (; cavIter != cavity.end(); cavIter++) {
+ pPList rVerts = R_vertices(*cavIter);
+ void * temp = NULL;
+ while ( pVertex pv = (pVertex)PList_next(rVerts,&temp) ) {
+ if ( verts.find(pv) == verts.end() ) {
+ localIds[pv] = id;
+ id++;
+ verts.insert(pv);
+ }
+ }
+ PList_delete(rVerts);
+ }
+ }
+ return id;
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::addToMatrix(const pRegion pr,
+ int nbVert,
+ MAdLinearSystemDef * lsys)
+ {
+ int rNodes = R_numVertices(pr);
+ int locSyze = rNodes*dim;
+
+ smallMatrix locK(locSyze,locSyze);
+ element3DMatrix(pr, locK);
+
+ pPList vertsI = R_vertices(pr);
+ pPList vertsJ = R_vertices(pr);
+ void* tmpI = 0;
+ int i = 0;
+ while ( pVertex pvI = (pVertex)PList_next(vertsI,&tmpI) ) {
+
+ int locIdI = localIds[pvI];
+
+ void* tmpJ = 0;
+ int j = 0;
+ while ( pVertex pvJ = (pVertex)PList_next(vertsJ,&tmpJ) ) {
+
+ int locIdJ = localIds[pvJ];
+
+ for (int k=0; k<dim; k++) {
+ for (int l=0; l<dim; l++) {
+ lsys->addToMatrix(nbVert*k + locIdI, nbVert*l+locIdJ, locK(k*rNodes+i,l*rNodes+j));
+ }
+ }
+ j++;
+ }
+ i++;
+ }
+ PList_delete(vertsI);
+ PList_delete(vertsJ);
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::allocateMatrix(int nbVert, MAdLinearSystemDef * lsys)
+ {
+ if (cavityEqualMesh) {
+ VIter vit2 = M_vertexIter(mesh);
+ while ( pVertex pv2 = VIter_next(vit2) ) {
+ int locId = localIds[pv2];
+ int nbNeighbors = V_numEdges(pv2);
+ for (int iDir=0; iDir<3; iDir++) {
+ int row = nbVert*iDir + locId;
+ lsys->set_nnz(row,(nbNeighbors+1)*3);// A node is coupled with all its neighbors, and don't forget himself
+ }
+ }
+ VIter_delete(vit2);
+ }
+ else {
+ map<pVertex,set<pVertex> > conn;
+ set<pRegion>::const_iterator cIter = cavity.begin();
+ for (; cIter != cavity.end(); cIter++) {
+ pPList rEdges = R_edges(*cIter);
+ void * temp = NULL;
+ pEdge edge;
+ pVertex v0, v1;
+ while ( ( edge = (pEdge)PList_next(rEdges,&temp)) ) {
+ v0 = E_vertex(edge,0);
+ v1 = E_vertex(edge,1);
+ conn[v0].insert(v1);
+ conn[v1].insert(v0);
+ }
+ PList_delete(rEdges);
+ }
+
+ pVertex pv;
+ map<pVertex,set<pVertex> >::const_iterator conIter = conn.begin();
+ for (; conIter != conn.end(); conIter++) {
+ pv = conIter->first;
+ int locId = localIds[pv];
+ int nbNeighbors = conIter->second.size();
+ for (int iDir=0; iDir<3; iDir++) {
+ int row = nbVert*iDir + locId;
+ lsys->set_nnz(row,(nbNeighbors+1)*3);// A node is coupled with all its neighbors, and don't forget himself
+ }
+ }
+ }
+
+ lsys->allocate_matrix();
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::addVertexOnEdge(pVertex pv, pEdge pe)
+ {
+ if ( computed == true )
+ {
+ double t = E_linearParams(pe,pv);
+
+ smallVector dx0, dx1;
+ for (int i=0; i<2; i++)
+ {
+ pVertex vi = E_vertex(pe,i);
+ std::map<pVertex,smallVector >::iterator iter = relocations.find(pv);
+ if ( iter != relocations.end() ) {
+ if (i==0) dx0 = (*iter).second;
+ else dx1 = (*iter).second;
+ }
+ else return;
+ }
+ smallVector newDx(3);
+ for (int i=0; i<3; i++) newDx(i) = (1.-t) * dx0(i) + t * dx1(i);
+ relocations[pv] = newDx;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::removeVertex(pVertex pv)
+ {
+ if ( computed == true )
+ {
+ std::map<pVertex,smallVector >::iterator iter = relocations.find(pv);
+ if ( iter != relocations.end() ) {
+ relocations.erase(iter);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::setVertexResult(int nbVert, pVertex pv,
+ const MAdLinearSystemDef * lsys)
+ {
+ // get the vertex id
+ map<pVertex,int>::const_iterator itId = localIds.find(pv);
+ int id = (*itId).second;
+
+ // get the dx
+ smallVector dX(3);
+ for (int iDir=0; iDir<3; iDir++) {
+ int row = nbVert*iDir + id;
+ dX(iDir) = lsys->getFromSolution(row);
+ }
+
+ relocations[pv] = dX;
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::setResults(int nbVert,
+ const MAdLinearSystemDef * lsys)
+ {
+ relocations.clear();
+
+ if (cavityEqualMesh) {
+ pVertex pv;
+ VIter vit = M_vertexIter(mesh);
+ while ( ( pv = VIter_next(vit) ) ) {
+ setVertexResult(nbVert,pv,lsys);
+ }
+ VIter_delete(vit);
+ }
+ else {
+ set<pVertex> vertices;
+ set<pRegion>::const_iterator cIter = cavity.begin();
+ for (; cIter != cavity.end(); cIter++) {
+ pPList rVerts = R_vertices(*cIter);
+ void * temp = NULL;
+ pVertex pv;
+ while ( ( pv = (pVertex)PList_next(rVerts,&temp) ) ) {
+ vertices.insert(pv);
+ }
+ PList_delete(rVerts);
+ }
+
+ set<pVertex>::const_iterator vIter = vertices.begin();
+ for (; vIter != vertices.end(); vIter++) {
+ setVertexResult(nbVert,*vIter,lsys);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::printRelocations(std::ostream& out) const
+ {
+ out << "Printing relocation: "<<relocations.size()<<" vertices relocated\n";
+ std::map<pVertex,smallVector>::const_iterator iter = relocations.begin();
+ for(; iter != relocations.end(); iter++)
+ {
+ pVertex pv = (*iter).first;
+ int id = EN_id(pv);
+ pGEntity ge = V_whatIn(pv);
+ int gdim = GEN_type(ge);
+ int gtag = GEN_tag(ge);
+ smallVector dX = (*iter).second;
+ out <<"Vertex "<<pv<<" with id "<<id<<" and class ("<<gdim<<","<<gtag<<"): "<<dX(0)<<" "<<dX(1)<<" "<<dX(2)<<"\n";
+ }
+
+ out << "Printed relocation: "<<relocations.size()<<" vertices relocated\n";
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::printDirichlet(std::ostream& out) const
+ {
+ out << "Printing dirichlet BCs: "<<dirichlet.size()<<" vertices\n";
+ std::map<pVertex,smallVector>::const_iterator iter = dirichlet.begin();
+ for(; iter != dirichlet.end(); iter++)
+ {
+ pVertex pv = (*iter).first;
+ int id = EN_id(pv);
+ pGEntity ge = V_whatIn(pv);
+ int gdim = GEN_type(ge);
+ int gtag = GEN_tag(ge);
+ smallVector dX = (*iter).second;
+ out <<"Vertex "<<pv<<" with id "<<id<<" and class ("<<gdim<<","<<gtag<<"): "<<dX(0)<<" "<<dX(1)<<" "<<dX(2)<<"\n";
+ }
+
+ out << "Printed dirichlet BCs: "<<dirichlet.size()<<" vertices\n";
+ }
+
+ // -------------------------------------------------------------------
+ int MAdElasticityOp::compute()
+ {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+
+ relocations.clear();
+
+ // --------------------------------------------
+ // If there is no element in the cavity, just
+ // prescribed node relocations (dirichlet) ...
+ // --------------------------------------------
+ if ( !cavityEqualMesh && cavity.empty() ) {
+ MAdMsgSgl::instance().info(__LINE__,__FILE__,
+ "Empty cavity for elastic computation");
+ relocations = dirichlet;
+ }
+
+ // --------------------------------------------------
+ // ... if an elastic computation has to be performed
+ // --------------------------------------------------
+ else {
+
+ if ( dim != 3 ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Elasticity model only implemented for dimension 3, current dimension is %d",
+ dim);
+ }
+
+ MeshQualityManagerSgl::instance().evaluateSizes(); // required for detJ0
+
+ MAdResourceManagerSgl::instance().printMemoryUsage("Before elastic system allocation");
+
+ // --- produce the mapping pVertex -> localId ---
+ int nbVert = generateVertexIds();
+
+ // --- create the linear system ---
+ double t_sys0 = tm.getTime();
+ int sysSize = dim * nbVert;
+ MAdLinearSystemDef * lsys = new MAdLinearSystemDef();
+ lsys->allocate(sysSize);
+
+ lsys->setSolver(CG);
+ lsys->setFillIn(4);
+ lsys->setEps(1.e-12);
+
+ lsys->setPrec(1.e-12); // for gmm only
+ lsys->setNoisy(1); // for gmm only
+
+ // --- allocate the matrix ---
+ allocateMatrix(nbVert,lsys); // for PETSc only
+
+ lsys->zeroMatrix();
+ lsys->zeroRightHandSide();
+
+ double dt_sys = tm.getTime() - t_sys0;
+ MAdMsgSgl::instance().info(-1,__FILE__,
+ "Created the system in %f seconds",dt_sys);
+ MAdResourceManagerSgl::instance().printMemoryUsage("Elastic system allocated");
+
+ // --- assemble the matrix ---
+ double t_ass0 = tm.getTime();
+ if (cavityEqualMesh) {
+ RIter rit = M_regionIter(mesh);
+ while ( pRegion pr = RIter_next(rit) ) addToMatrix(pr,nbVert,lsys);
+ RIter_delete(rit);
+ }
+ else {
+ set<pRegion>::const_iterator cavIter = cavity.begin();
+ for (; cavIter != cavity.end(); cavIter++) addToMatrix(*cavIter,nbVert,lsys);
+ }
+ double dt_ass = tm.getTime() - t_ass0;
+ MAdMsgSgl::instance().info(-1,__FILE__,
+ "Assembled the matrix in %f seconds",dt_ass);
+ MAdResourceManagerSgl::instance().printMemoryUsage("Matrix assembled");
+
+ // --- apply bc (ugly but it works hum) ---
+ double t_bc0 = tm.getTime();
+ map<pVertex,smallVector>::iterator dIter = dirichlet.begin();
+ map<pVertex,smallVector>::iterator dLast = dirichlet.end();
+ for (; dIter != dLast; dIter++) {
+
+ pVertex pv = (*dIter).first;
+ smallVector dxyz = (*dIter).second;
+
+ // get the vertex id
+ map<pVertex,int>::const_iterator itId = localIds.find(pv);
+ int id = (*itId).second;
+
+ for (int iDir=0; iDir<3; iDir++) {
+ int row = nbVert*iDir + id;
+ const double BIG = /*lsys->getFromMatrix(row,row) * */1.e12;
+ lsys->addToMatrix(row,row,BIG);
+ lsys->addToRightHandSide(row,BIG * dxyz(iDir));
+ }
+
+ }
+ double dt_bc = tm.getTime() - t_bc0;
+ MAdMsgSgl::instance().info(-1,__FILE__,
+ "Applied boundary conditions in %f seconds",dt_bc);
+ MAdResourceManagerSgl::instance().printMemoryUsage("BC applied");
+
+ // --- reorder matrix ---
+ lsys->reorder();
+ MAdResourceManagerSgl::instance().printMemoryUsage("Matrix reordered");
+
+ // --- solve the system ---
+ double t_slv0 = tm.getTime();
+ int converged = lsys->systemSolve();
+ double dt_slv = tm.getTime() - t_slv0;
+ MAdMsgSgl::instance().info(-1,__FILE__,
+ "Solved the elastic system (convergence flag: %d) in %f seconds",
+ converged,dt_slv);
+ MAdResourceManagerSgl::instance().printMemoryUsage("System solved");
+
+
+ // --- fill relocations with the results ---
+ setResults(nbVert,lsys);
+
+ localIds.clear();
+ delete lsys;
+ }
+
+ dirichlet.clear();
+ cavity.clear();
+
+ computed = true;
+
+ return 1;
+ }
+
+
+ // -------------------------------------------------------------------
+ bool MAdElasticityOp::checkArea(const pFace pf, double ratio)
+ {
+ bool inCavity = false;
+
+ double fxyz[3][3];
+ F_coordP1(pf,fxyz);
+ double oriNorm[3];
+ XYZ_F_normal(fxyz,oriNorm);
+
+ pPList fVerts = F_vertices(pf,1);
+ void * temp = NULL;
+ int i = 0;
+ pVertex pv;
+ while ( ( pv = (pVertex)PList_next(fVerts,&temp) ) ) {
+ std::map<pVertex,smallVector>::const_iterator iter = relocations.find(pv);
+ if ( iter != relocations.end() ) {
+ inCavity = true;
+ for (int j=0; j<3; j++) fxyz[i][j] += ratio * (*iter).second(j);
+ }
+ i++;
+ }
+ PList_delete(fVerts);
+
+ // Do the check only if one of the nodes moved
+ if ( inCavity ) {
+ double tgtNorm[3];
+ XYZ_F_normal(fxyz,tgtNorm);
+ double prod = oriNorm[0] * tgtNorm[0] + oriNorm[1] * tgtNorm[1] + oriNorm[2] * tgtNorm[2];
+ if ( prod <= 0. ) return false;
+ }
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ // Cannot use 'cavity': it is hard to maintain if mesh modifications
+ // occur during advancement so it is cleared in 'compute()'.
+ bool MAdElasticityOp::checkAreas(double ratio)
+ {
+ pFace pf;
+ FIter fit = M_faceIter(mesh);
+ while ( ( pf = FIter_next(fit) ) ) {
+ if ( !checkArea(pf,ratio) ) {
+ FIter_delete(fit);
+ return false;
+ }
+ }
+ FIter_delete(fit);
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool MAdElasticityOp::checkVolume(const pRegion pr, double ratio)
+ {
+ bool inCavity = false;
+
+ double rxyz[4][3];
+ R_coordP1(pr,rxyz);
+
+ pPList rVerts = R_vertices(pr);
+ void * temp = NULL;
+ int i = 0;
+ pVertex pv;
+ while ( ( pv = (pVertex)PList_next(rVerts,&temp) ) ) {
+ std::map<pVertex,smallVector>::const_iterator iter = relocations.find(pv);
+ if ( iter != relocations.end() ) {
+ inCavity = true;
+ for (int j=0; j<3; j++) rxyz[i][j] += ratio * (*iter).second(j);
+ }
+ i++;
+ }
+ PList_delete(rVerts);
+
+ // Do the check only if one of the nodes moved
+ if ( inCavity && R_XYZ_volume(rxyz) <= MAdTOL ) return false;
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ // Cannot use 'cavity': it is hard to maintain if mesh modifications
+ // occur during advancement so it is cleared in 'compute()'.
+ bool MAdElasticityOp::checkVolumes(double ratio)
+ {
+ pRegion pr;
+ RIter rit = M_regionIter(mesh);
+ while ( ( pr = RIter_next(rit) ) ) {
+ if ( !checkVolume(pr,ratio) ) {
+ RIter_delete(rit);
+ return false;
+ }
+ }
+ RIter_delete(rit);
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::relocate(double ratio)
+ {
+ pVertex pv;
+ double xyz[3];
+
+ std::map<pVertex,smallVector>::const_iterator iter = relocations.begin();
+ for(; iter != relocations.end(); iter++)
+ {
+ pv = (*iter).first;
+ V_coord(pv,xyz);
+
+ smallVector dX = (*iter).second;
+
+ xyz[0] += ratio * dX(0);
+ xyz[1] += ratio * dX(1);
+ xyz[2] += ratio * dX(2);
+ if ( !V_setPosition(pv,xyz) ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Could not relocate a node");
+
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ // Advances the relocation as far as possible
+ // Returns:
+ // - 0: no relocation possible
+ // - 1: advanced but not to the final position
+ // - 2: reached the full prescribed relocation
+ int MAdElasticityOp::advance(double * ratio, double tolerance)
+ {
+ if ( *ratio >= 1.-tolerance ) {
+ *ratio = 1.;
+ return 2;
+ }
+
+ int achieved = 0; // the result returned
+
+ int subIter = 0;
+ const int nbMaxIter = 6;
+
+ double margin = 1. - *ratio; // in [0;1] : the rest of the motion to be performed
+ double curRatio = 1.; // in [0;1] : the part of the margin that will be tested next
+ double delta = 0.5; // in [0;1] : the increment/decrement of ratio at next iteration
+ double best = -1.; // in [0;1] : the best current ratio with positive volumes
+
+ while ( subIter < nbMaxIter )
+ {
+ double totalAdvancement = curRatio * margin + *ratio;
+ bool check;
+ if ( dim == 3 ) check = checkVolumes( curRatio * margin );
+ else check = checkAreas ( curRatio * margin );
+ if ( !check ) {
+ curRatio -= delta;
+ }
+ else {
+ best = curRatio;
+ if ( totalAdvancement + tolerance >= 1. ) { achieved = 2; break; }
+ else { achieved = 1; curRatio += delta; }
+ }
+
+ subIter++;
+ delta *= 0.5;
+// printf("Ratio: %f, margin: %f, achieved: %d, subIter: %d, best: %f, curRatio: %f, delta: %f\n",
+// *ratio, margin, achieved, subIter, best, curRatio, delta);
+ }
+
+ double moveRatio = 0.;
+ if ( achieved == 2 ) {
+ moveRatio = ( 1. - *ratio );
+ relocate(moveRatio);
+ *ratio = 1.;
+ }
+ else if ( achieved == 1 ) {
+ moveRatio = best * margin;
+ relocate(moveRatio);
+ *ratio += moveRatio;
+ }
+
+ return achieved;
+ }
+
+ // -------------------------------------------------------------------
+ // Force the relocation even if it leads to negative volumes
+ void MAdElasticityOp::forceRelocation()
+ {
+ relocate(1.);
+ }
+
+ // -------------------------------------------------------------------
+ void MAdElasticityOp::element3DMatrix(pRegion pr, smallMatrix& m) const
+ {
+ int nbNodes = 4;
+ double xyz[4][3];
+ R_coordP1(pr,xyz);
+
+ 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} };
+
+ smallMatrix H (6,6);
+ for (int i=0;i<6;i++)
+ for (int j=0;j<6;j++)
+ H(i,j) = C[i][j];
+
+ smallMatrix B (6,3*nbNodes);
+ smallMatrix BTH (3*nbNodes,6);
+ smallMatrix BT (3*nbNodes,6);
+
+ const double gradShpFct[4][3] =
+ { {-1., -1., -1.},
+ { 1., 0., 0.},
+ { 0., 1., 0.},
+ { 0., 0., 1.} };
+
+ double jac [3][3];
+ jac[0][0] = jac[0][1] = jac[0][2] = 0.;
+ jac[1][0] = jac[1][1] = jac[1][2] = 0.;
+ jac[2][0] = jac[2][1] = jac[2][2] = 0.;
+ for(int i = 0; i < nbNodes; i++) {
+ jac[0][0] += xyz[i][0] * gradShpFct[i][0]; jac[0][1] += xyz[i][1] * gradShpFct[i][0]; jac[0][2] += xyz[i][2] * gradShpFct[i][0];
+ jac[1][0] += xyz[i][0] * gradShpFct[i][1]; jac[1][1] += xyz[i][1] * gradShpFct[i][1]; jac[1][2] += xyz[i][2] * gradShpFct[i][1];
+ jac[2][0] += xyz[i][0] * gradShpFct[i][2]; jac[2][1] += xyz[i][1] * gradShpFct[i][2]; jac[2][2] += xyz[i][2] * gradShpFct[i][2];
+ }
+ const double detJ = fabs(jac[0][0] * jac[1][1] * jac[2][2] + jac[0][2] * jac[1][0] * jac[2][1] +
+ jac[0][1] * jac[1][2] * jac[2][0] - jac[0][2] * jac[1][1] * jac[2][0] -
+ jac[0][0] * jac[1][2] * jac[2][1] - jac[0][1] * jac[1][0] * jac[2][2]);
+
+ double invjac [3][3];
+ inverseMat (jac, invjac) ;
+
+ double Grads[4][3];
+
+ B.set_all(0.0);
+ BT.set_all(0.0);
+
+ for (int j=0;j<nbNodes;j++){
+
+ Grads[j][0] = invjac[0][0] * gradShpFct[j][0] + invjac[0][1] * gradShpFct[j][1] + invjac[0][2] * gradShpFct[j][2];
+ Grads[j][1] = invjac[1][0] * gradShpFct[j][0] + invjac[1][1] * gradShpFct[j][1] + invjac[1][2] * gradShpFct[j][2];
+ Grads[j][2] = invjac[2][0] * gradShpFct[j][0] + invjac[2][1] * gradShpFct[j][1] + invjac[2][2] * gradShpFct[j][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.set_all(0.0);
+ m.blas_dgemm (BTH,B,detJ,1.0);
+
+ // --- Selective element stiffening ---
+ // reference:
+ // Stein, Tezduyar, Benney "Mesh Moving Techniques for FSI with Large Displacement", ASME, 2003.
+
+ double detJ0 = MeshQualityManagerSgl::instance().getMaxSize();
+ if ( detJ0 <= 0. ) detJ0 = 1.;
+
+ double scaleFactor = pow( detJ0 / detJ, chi);
+ if ( scaleFactor > 1.e12 || scaleFactor < 1.e-12 ) {
+ cout <<"Warning in MAdElasticity: scale factor for element stiffness is "<<scaleFactor<<endl;
+ }
+
+ m.scale ( scaleFactor );
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/repositioning/MAdElasticityOp.h b/Adapt/repositioning/MAdElasticityOp.h
new file mode 100644
index 0000000..d82aafc
--- /dev/null
+++ b/Adapt/repositioning/MAdElasticityOp.h
@@ -0,0 +1,149 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADELASTICITYOP
+#define _H_MADELASTICITYOP
+
+#include "MAdMatrix.h"
+#include "VertexMoveOp.h"
+#include "MAdLinearSystem.h"
+
+#include <map>
+#include <set>
+
+/*
+ This operator uses an analogy with an elastic medium in order to compute
+ the displacements of the vertices resulting from a prescribed displacement
+ of the boundaries.
+
+ The steps to make a computation are the following:
+
+ 1. Choose a set of nodal displacements by calling 'addDirichlet'
+ --> build part of 'dirichlet'
+ 2. Build a cavity around the nodes for which you prescribed a displacement
+ --> build 'cavity'
+ 3. Impose homogenous Dirichlet boudnary conditions to the boundaries
+ of the cavity with 'setDirichletBC()' (except the nodes with a
+ prescribed displacement)
+ --> finish building 'dirichlet'
+ 4. Compute the displacements with 'compute'
+ --> build 'relocations'
+ --> clear 'cavity' and 'dirichlet'
+ --> 'computed' set to 'true'
+ 5. Apply a part of the displacement to the mesh with 'advance'
+ (as much as you can)
+ 6. Once nodes are fully relocated, call 'clear'
+ --> clear all
+ --> computed set to 'false'
+*/
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class MAdElasticityOp {
+
+ public:
+
+ MAdElasticityOp(pMesh m);
+ MAdElasticityOp(const MAdElasticityOp&);
+ virtual ~MAdElasticityOp();
+
+ public:
+
+ void clear();
+
+ int meshDim() const { return dim; }
+
+ void setMaterials(double _E, double _nu);
+ void setStiffnessAlterationCoef(double _chi);
+
+ void setCavityEqualMesh(bool _m, int thickness)
+ {
+ cavityEqualMesh = _m;
+ cavityThickness = thickness;
+ }
+
+ void buildCavity();
+
+ void setDirichletBC();
+ void setHomogDirichletBC();
+ void addDirichlet(pVertex pv, smallVector& dxyz);
+ void delDirichlet(pVertex pv);
+
+ int compute();
+ bool relocationsComputed() const { return computed; }
+ void delRelocation(pVertex pv);
+
+ // Advances the relocation as far as possible
+ // Returns:
+ // - 0: no relocation possible
+ // - 1: advanced but not to the final position
+ // - 2: reached the full prescribed relocation
+ int advance(double * ratio, double tolerance=MAdTOL);
+ void forceRelocation();
+
+ void removeVertex(pVertex);
+ void addVertexOnEdge(pVertex, pEdge);
+
+ // debugging functions
+ void printRelocations(std::ostream& out) const;
+ void printDirichlet(std::ostream& out) const;
+
+ private:
+
+ int generateVertexIds();
+ void collectBCVertices(std::set<pVertex> * bcVerts);
+
+ void element3DMatrix (pRegion pr, smallMatrix& m) const;
+ void addToMatrix(const pRegion, int, MAdLinearSystemDef *);
+ void allocateMatrix(int, MAdLinearSystemDef *);
+
+ void setVertexResult(int, pVertex, const MAdLinearSystemDef *);
+ void setResults(int, const MAdLinearSystemDef *);
+
+ bool checkArea(const pFace, double ratio);
+ bool checkAreas(double ratio);
+ bool checkVolume(const pRegion, double ratio);
+ bool checkVolumes(double ratio);
+ void relocate(double ratio);
+
+ private:
+
+ pMesh mesh;
+ int dim;
+
+ double E, nu;
+
+ // exponent of the alteration of stiffness based on elements size:
+ // chi=0 => no alteration
+ // chi increases => smaller elements stiffer
+ double chi;
+
+ bool computed;
+
+ std::map<pVertex,int> localIds;
+
+ bool cavityEqualMesh;
+ int cavityThickness;
+ std::set<pRegion> cavity;
+
+ std::map<pVertex,smallVector > dirichlet;
+ std::map<pVertex,smallVector > relocations;
+
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/repositioning/MobileObject.cc b/Adapt/repositioning/MobileObject.cc
new file mode 100644
index 0000000..aa731ea
--- /dev/null
+++ b/Adapt/repositioning/MobileObject.cc
@@ -0,0 +1,496 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MobileObject.h"
+#include "NodalDataManager.h"
+
+#include <iostream>
+using std::cerr;
+using std::cout;
+using std::endl;
+#include <string.h>
+using std::set;
+//using std::multiset;
+using std::list;
+using std::pair;
+using std::vector;
+using std::string;
+
+namespace MAd {
+
+ // ----------------------------------------------------------------------
+ mobileObject::mobileObject(const pMesh m, string _name):
+ mesh(m),name(_name),prescribeType(""),DxParsed(NULL),
+ velType(NOFORMULATION),VParsed(NULL)//, Cxyz(NULL), Vxyz(NULL)
+ {
+#ifdef PARALLEL
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Mobile objects not supported in parallel");
+#endif
+ }
+
+ // ----------------------------------------------------------------------
+ mobileObject::~mobileObject()
+ {
+ if (DxParsed) { delete DxParsed; DxParsed = NULL; }
+ if (VParsed) { delete VParsed; VParsed = NULL; }
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObject::setDxKinematics(vector<string> _str)
+ {
+ if ( strcmp(prescribeType.c_str(),"") ) {
+ cerr << "Error: imposing a position on an object with another imposed movement: "<<prescribeType<<"\n";
+ throw;
+ }
+ prescribeType = "Displacement";
+
+ if (DxParsed) delete DxParsed;
+ DxParsed = new MAdStringFieldEvaluator(_str);
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObject::setVKinematics(velocityFormulation type, double V[3],
+ double C[3], vector<string> _str)
+ {
+ if ( strcmp(prescribeType.c_str(),"") ) {
+ cerr << "Error: imposing a velocity on an object with another imposed movement: "<<prescribeType<<"\n";
+ throw;
+ }
+ prescribeType = "Velocity";
+
+ velType = type;
+ if ( V ) {
+ for (int i=0; i<3; i++) Vxyz[i] = V[i];
+ }
+ if ( C ) {
+ for (int i=0; i<3; i++) Cxyz[i] = C[i];
+ }
+ if (type == PARSED) VParsed = new MAdStringFieldEvaluator(_str);
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObject::addLocalSField(LocalSizeField* lsf)
+ {
+ sizes.insert(lsf);
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObject::addGEntity(int type, int tag)
+ {
+ geomEntities.push_back(std::make_pair(type,tag));
+ addVerticesOnGEntity(type,tag);
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObject::reAddVertices()
+ {
+ vertices.clear();
+ list<pair<int,int> >::const_iterator it = geomEntities.begin();
+ list<pair<int,int> >::const_iterator itEnd = geomEntities.end();
+ for (; it != itEnd; it++) addVerticesOnGEntity(it->first, it->second);
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObject::addVerticesOnGEntity(int type, int tag)
+ {
+ switch (type) {
+ case 0:
+ {
+ VIter vit = M_vertexIter(mesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ pGEntity pg = EN_whatIn((pEntity)pv);
+ int pgType = EN_whatInType( (pEntity) pv );
+ if(pg)
+ if (GEN_tag(pg) == tag && pgType == 0)
+ {
+ vertices.insert(pv);
+ }
+ }
+ VIter_delete(vit);
+ break;
+ }
+ case 1:
+ {
+ EIter eit = M_edgeIter(mesh);
+ while (pEdge pe = EIter_next(eit))
+ {
+ pGEntity pg = EN_whatIn((pEntity)pe);
+ int pgType = EN_whatInType( (pEntity) pe );
+ if(pg)
+ if (GEN_tag(pg) == tag && pgType == 1)
+ {
+ vertices.insert(E_vertex (pe,0));
+ vertices.insert(E_vertex (pe,1));
+ }
+ }
+ EIter_delete(eit);
+ }
+ case 2:
+ {
+ FIter fit = M_faceIter(mesh);
+ while (pFace pf = FIter_next(fit))
+ {
+ pGEntity pg = EN_whatIn((pEntity)pf);
+ int pgType = EN_whatInType( (pEntity) pf );
+ if(pg)
+ if (GEN_tag(pg) == tag && pgType == 2)
+ {
+ vertices.insert(F_vertex (pf,0));
+ vertices.insert(F_vertex (pf,1));
+ vertices.insert(F_vertex (pf,2));
+ }
+ }
+ FIter_delete(fit);
+ }
+ case 3:
+ {
+ RIter rit = M_regionIter(mesh);
+ while (pRegion pr = RIter_next(rit))
+ {
+ pGEntity pg = EN_whatIn((pEntity)pr);
+ int pgType = EN_whatInType( (pEntity) pr );
+ if(pg)
+ if (GEN_tag(pg) == tag && pgType == 3)
+ {
+ vertices.insert(R_vertex (pr,0));
+ vertices.insert(R_vertex (pr,1));
+ vertices.insert(R_vertex (pr,2));
+ vertices.insert(R_vertex (pr,3));
+ }
+ }
+ RIter_delete(rit);
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObject::computePrescribedDisplacement (double t, double dt)
+ {
+ if ( !(NodalDataManagerSgl::instance().isCoordinates()) ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Allocate initial coordinates before making any move (use AdaptInterface::storeInitialCoordinates())");
+ }
+
+ prescribedDisplacement.clear();
+ reAddVertices();
+
+ if ( !strcmp(prescribeType.c_str(),"Velocity") )
+ {
+ double V[3]; V[0]=0.; V[1]=0.; V[2]=0.;
+ if (velType == RANDOM_TRANSLATION)
+ randomVelocity(V);
+ set<pVertex> :: iterator itV = vertices.begin();
+ set<pVertex> :: iterator itVEnd = vertices.end();
+ for ( ; itV != itVEnd ; ++itV)
+ {
+ double dx[3];
+ double xyz[3]; V_coord (*itV,xyz);
+ if ( velType != RANDOM_TRANSLATION)
+ velocityFunction(xyz,t,V);
+ dx[0] = V[0] * dt;
+ dx[1] = V[1] * dt;
+ dx[2] = V[2] * dt;
+
+ vDisplacement disp(*itV,dx);
+ prescribedDisplacement.insert(disp);
+ }
+ }
+
+ else if ( !strcmp(prescribeType.c_str(),"Displacement") )
+ {
+ set<pVertex> :: iterator itV = vertices.begin();
+ set<pVertex> :: iterator itVEnd = vertices.end();
+ for ( ; itV != itVEnd ; ++itV)
+ {
+ // get initial position
+ vector<double> xyz0;
+ NodalDataManagerSgl::instance().getStoredCoordinates(*itV,xyz0);
+
+ // get prescribed displacement (relative to and evaluated on initial position)
+ double dx0[3];
+ DxParsed->eval(xyz0,t,dx0);
+
+ // get current position
+ double xyz[3]; V_coord (*itV,xyz);
+
+ // get new position
+ double xyznew[3];
+ for (int i=0; i<3; i++) xyznew[i] = xyz0[i] + dx0[i];
+
+ // compute the displacement
+ double dx[3];
+ dx[0] = xyznew[0] - xyz[0];
+ dx[1] = xyznew[1] - xyz[1];
+ dx[2] = xyznew[2] - xyz[2];
+
+ vDisplacement disp(*itV,dx);
+ prescribedDisplacement.insert(disp);
+ }
+ }
+
+ else {
+ cerr<< "Error: no kinematics specified for this object\n";
+ throw;
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObject::describe (std::ostream& out) const
+ {
+ out << "Object \'" << name.c_str() << "\' carries "
+ << vertices.size() << " nodes with xyz velocity:\n"
+ << " * Vx: "<<Vxyz[0]<<"\n"
+ << " * Vy: "<<Vxyz[1]<<"\n"
+ << " * Vz: "<<Vxyz[2]<<"\n"
+ << " and analytical velocity formulation "<<velType<<"\n\n";
+ }
+
+ // ----------------------------------------------------------------------
+ // generates velocities between -1 and 1
+ void mobileObject::randomVelocity(double* V)
+ {
+ V[0] = ( ( (double)rand() / ((double)(RAND_MAX)+(double)(1)) ) - 0.5 ) * 2.;
+ V[1] = ( ( (double)rand() / ((double)(RAND_MAX)+(double)(1)) ) - 0.5 ) * 2.;
+ V[2] = ( ( (double)rand() / ((double)(RAND_MAX)+(double)(1)) ) - 0.5 ) * 2.;
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObject::velocityFunction(double* xyz, double t, double* V)
+ {
+ double x = xyz[0];
+ double y = xyz[1];
+ double z = xyz[2];
+
+ switch (velType)
+ {
+ case NOFORMULATION:
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Velocity formulation: NOFORMULATION");
+ }
+ case PARSED:
+ {
+ VParsed->eval(xyz,t,V);
+ break;
+ }
+ case TRANSLATION:
+ {
+ V[0] = Vxyz[0]; V[1] = Vxyz[1]; V[2] = Vxyz[2];
+ break;
+ }
+ case FULLRANDOM:
+ {
+ randomVelocity(V);
+ break;
+ }
+ case RANDOM_TRANSLATION:
+ {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "VelocityFunction with tag RANDOM_TRANSLATION should not be used");
+ randomVelocity(V);
+ break;
+ }
+ case ISOMETRY: // expansion
+ {
+ V[0] = Vxyz[0] * ( x - Cxyz[0] );
+ V[1] = Vxyz[1] * ( y - Cxyz[1] );
+ V[2] = Vxyz[2] * ( z - Cxyz[2] );
+ break;
+ }
+ case ROTATION: // rotation
+ {
+ double velYZ = Vxyz[0];
+ double velZX = Vxyz[1];
+ double velXY = Vxyz[2];
+ double rYZ = sqrt ( (y - Cxyz[1])*(y - Cxyz[1]) + (z - Cxyz[2])*(z - Cxyz[2]) );
+ double rZX = sqrt ( (x - Cxyz[0])*(x - Cxyz[0]) + (z - Cxyz[2])*(z - Cxyz[2]) );
+ double rXY = sqrt ( (x - Cxyz[0])*(x - Cxyz[0]) + (y - Cxyz[1])*(y - Cxyz[1]) );
+ double angleYZ = atan2((y - Cxyz[1]), (z - Cxyz[2]));
+ double angleZX = atan2((z - Cxyz[2]), (x - Cxyz[0]));
+ double angleXY = atan2((x - Cxyz[0]), (y - Cxyz[1]));
+ V[0] = 0 - velZX * rZX * sin(angleZX) + velXY * rXY * cos(angleXY) ;
+ V[1] = 0 + velYZ * rYZ * cos(angleYZ) - velXY * rXY * sin(angleXY) ;
+ V[2] = 0 - velYZ * rYZ * sin(angleYZ) + velZX * rZX * cos(angleZX) ;
+ break;
+ }
+ case SHEAR_YZ: // shear plane YZ
+ {
+ V[0] = Vxyz[0] * ( x - Cxyz[0] );
+ V[1] = Vxyz[1] * ( x - Cxyz[0] );
+ V[2] = Vxyz[2] * ( x - Cxyz[0] );
+ break;
+ }
+ case SHEAR_ZX: // shear plane ZX
+ {
+ V[0] = Vxyz[0] * ( y - Cxyz[1] );
+ V[1] = Vxyz[1] * ( y - Cxyz[1] );
+ V[2] = Vxyz[2] * ( y - Cxyz[1] );
+ break;
+ }
+ case SHEAR_XY: // shear plane XY
+ {
+ V[0] = Vxyz[0] * ( z - Cxyz[2] );
+ V[1] = Vxyz[1] * ( z - Cxyz[2] );
+ V[2] = Vxyz[2] * ( z - Cxyz[2] );
+ break;
+ }
+ case BENCH2: // bench 2
+ {
+ double Xmax0 = 10.;
+ double X = Xmax0 + Vxyz[0] * t;
+ V[0] = Vxyz[0] * x / X;
+ V[1] = 0.0;
+ V[2] = 0.0;
+ break;
+ }
+ case CROSS_EXPANSION_WITH_ROTATION: // cross expantion with rotation
+ {
+ double cx = 0.45;
+ double cy = 0.35 ;
+ double r = sqrt ((x - cx)*(x - cx) + (y - cy)*(y - cy));
+ double tt = atan2((x - cx), (y - cy));
+ V[0] = 0 + 4*r * cos(tt) + sin(tt) * .3;
+ V[1] = 0 - 4*r * sin(tt) + cos(tt) * .3;
+ V[2] = 0;
+ break;
+ }
+ default:
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Unknowm velocity formulation %d",velType);
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // ----------------------- MOBILE OBJECTS SET ---------------------------
+ // ----------------------------------------------------------------------
+ mobileObjectSet::mobileObjectSet(): elasticOp(NULL)
+ {
+ }
+
+ // ----------------------------------------------------------------------
+ mobileObjectSet::~mobileObjectSet()
+ {
+ clear();
+ if (elasticOp) delete elasticOp;
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObjectSet::clear()
+ {
+ mobSet.clear();
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObjectSet::insert(mobileObject* mob)
+ {
+ mobSet.insert(mob);
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObjectSet::describe(std::ostream& out) const
+ {
+ out << "\n--- Mobile objects set description ---\n\n";
+ set<mobileObject*>::const_iterator groupIt = mobSet.begin();
+ set<mobileObject*>::const_iterator groupItEnd = mobSet.end();
+ for ( ; groupIt != groupItEnd ; ++groupIt) {
+ (*groupIt)->describe(out);
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObjectSet::computePrescribedDisplacement (double t, double dt)
+ {
+ prescribedDisplacement.clear();
+
+ set<mobileObject*>::const_iterator groupIt = mobSet.begin();
+ set<mobileObject*>::const_iterator groupItEnd = mobSet.end();
+ for ( ; groupIt != groupItEnd ; ++groupIt) {
+
+ // compute the forced displacement for each object
+ (*groupIt)->computePrescribedDisplacement (t,dt);
+
+ // gather all displacements
+ set<vDisplacement,vDisplacementLess> objDisp = (*groupIt)->getPrescribedDisplacement();
+ set<vDisplacement,vDisplacementLess>::const_iterator itObjDx = objDisp.begin();
+ for(; itObjDx != objDisp.end(); itObjDx++) {
+ vDisplacement vdisp(*itObjDx);
+ prescribedDisplacement.insert(vdisp);
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ int mobileObjectSet::partlyMove(vertexMoveOp& vMoveOp, double t, double dt, double * part)
+ {
+ computePrescribedDisplacement(t, dt);
+
+ int ok = 0;
+ const int maxNumReduct = 8;
+ const double reductFactor = 0.5;
+ *part = 1.0;
+ cout<<"Attempts to move vertices: [ ";
+ for (int i=0; i < maxNumReduct; i++) {
+ cout <<"* ";
+ if (!vMoveOp.move(prescribedDisplacement,*part)) *part *= reductFactor;
+ else { ok = 1; break;}
+ }
+ cout << "]\n";
+ return ok;
+ }
+
+ // ----------------------------------------------------------------------
+ void mobileObjectSet::setupElasticRepositioning(pMesh mesh, double t, double dt,
+ double chi, bool meshIsCavity,
+ int cavityThickness)
+ {
+ if ( mobSet.empty() ) return;
+
+ // setup the elastic operator
+ if (elasticOp) { delete elasticOp; elasticOp = NULL; }
+ elasticOp = new MAdElasticityOp(mesh);
+ if ( chi >= 0. ) elasticOp->setStiffnessAlterationCoef(chi);
+ elasticOp->setCavityEqualMesh(meshIsCavity,cavityThickness);
+
+ // prescribe bcs
+ computePrescribedDisplacement(t, dt);
+ set<vDisplacement,vDisplacementLess>::const_iterator dIter = prescribedDisplacement.begin();
+ set<vDisplacement,vDisplacementLess>::const_iterator dLast = prescribedDisplacement.end();
+ for (; dIter != dLast; dIter++) {
+ pVertex vert = (*dIter).pv;
+ smallVector disp(3);
+ for (int i=0; i<3; i++) disp(i) = (*dIter).dxyz[i];
+ elasticOp->addDirichlet(vert,disp);
+ }
+
+ elasticOp->buildCavity();
+ elasticOp->setDirichletBC();
+
+ // compute elastic repositioning
+ elasticOp->compute();
+ }
+
+ // ----------------------------------------------------------------------
+ int mobileObjectSet::reposition(double * ratio)
+ {
+ if ( mobSet.empty() ) return true;
+ int flag = elasticOp->advance(ratio);
+ if ( flag == 2 ) elasticOp->clear();
+ return flag;
+ }
+
+ // ----------------------------------------------------------------------
+
+}
diff --git a/Adapt/repositioning/MobileObject.h b/Adapt/repositioning/MobileObject.h
new file mode 100644
index 0000000..8621260
--- /dev/null
+++ b/Adapt/repositioning/MobileObject.h
@@ -0,0 +1,149 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MOBILEOBJECT
+#define _H_MOBILEOBJECT
+
+#include "VertexMoveOp.h"
+#include "MAdStringFieldEvaluator.h"
+#include "LocalSizeField.h"
+#include "MSops.h"
+#include "MAdElasticityOp.h"
+
+#include <set>
+#include <list>
+#include <utility>
+#include <vector>
+#include <string>
+
+namespace MAd {
+
+ // ----------------------------------------------------------------------
+ enum velocityFormulation {
+ NOFORMULATION,
+ PARSED,
+ TRANSLATION,
+ FULLRANDOM,
+ RANDOM_TRANSLATION,
+ ISOMETRY,
+ ROTATION,
+ SHEAR_YZ,
+ SHEAR_ZX,
+ SHEAR_XY,
+ BENCH2,
+ CROSS_EXPANSION_WITH_ROTATION
+ };
+
+ // ----------------------------------------------------------------------
+ class mobileObject {
+
+ public:
+
+ mobileObject(const pMesh m,std::string _name="");
+ mobileObject(const mobileObject & mob);
+ ~mobileObject();
+
+ void setName(std::string nm) {name = nm;}
+ void setDxKinematics(std::vector<std::string> _Vstr);
+ void setVKinematics(velocityFormulation type, double V[3],
+ double C[3], std::vector<std::string> _Vstr);
+ void addLocalSField(LocalSizeField* lsf);
+ void addGEntity(int type, int tag);
+ void reAddVertices();
+
+ void computePrescribedDisplacement (double t, double dt);
+
+ void describe (std::ostream& out=std::cout) const;
+ const std::set<pVertex> getVertices() const {return vertices;}
+ std::set<vDisplacement,vDisplacementLess> getPrescribedDisplacement () const {return prescribedDisplacement;}
+ std::set<LocalSizeField* > getSizes() const { return sizes; }
+
+ private:
+
+ void addVerticesOnGEntity(int type, int tag);
+ void clearDisplacement();
+
+ void randomVelocity(double* V);
+ void velocityFunction(double xyz[3], double t, double* V);
+
+ private:
+
+ const pMesh mesh;
+ std::string name;
+ std::list<std::pair<int,int> > geomEntities; // list of (type,tag)
+ std::set<pVertex> vertices;
+
+ // Parameters describing the kinematics
+ std::string prescribeType;
+ // for position ...
+ MAdStringFieldEvaluator* DxParsed; // displacement relative to and evaluated on initial position
+ // ... or velocity
+ velocityFormulation velType;
+ double Cxyz[3], Vxyz[3];
+ MAdStringFieldEvaluator* VParsed; // velocity evaluated on current position
+
+ // // Parameters describing the size around
+ std::set<LocalSizeField* > sizes;
+
+ std::set<vDisplacement,vDisplacementLess> prescribedDisplacement;
+ };
+
+ // ----------------------------------------------------------------------
+ class mobileObjectSet {
+
+ public:
+
+ mobileObjectSet();
+ ~mobileObjectSet();
+
+ // larger possible motion by trials without volume nodes repositioning
+ int partlyMove(vertexMoveOp& vMoveOp, double t, double dt, double * part);
+
+ // move objects and reposition volume nodes. Needs the elastic operator.
+ void setupElasticRepositioning(pMesh mesh, double t, double dt,double chi=-1,
+ bool meshIsCavity=true, int cavityThickness=3);
+
+ // Advances the relocation as far as possible
+ // Returns:
+ // - 0: no relocation possible
+ // - 1: advanced but not to the final position
+ // - 2: reached the full prescribed relocation
+ int reposition(double * ratio);
+
+ // empty or fill the set
+ void clear();
+ void insert(mobileObject*);
+
+ std::set<vDisplacement,vDisplacementLess> getPrescribedDisplacement () const {return prescribedDisplacement;}
+ std::set<mobileObject*> getObjects() const {return mobSet;}
+
+ void describe(std::ostream& out=std::cout) const;
+
+ private:
+
+ // compute the objects displacement in a time interval
+ void computePrescribedDisplacement (double t, double dt) ;
+
+ private:
+
+ std::set<mobileObject*> mobSet;
+ std::set<vDisplacement,vDisplacementLess> prescribedDisplacement;
+
+ MAdElasticityOp * elasticOp;
+ };
+
+ // ----------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/repositioning/NodesRepositioningOp.h b/Adapt/repositioning/NodesRepositioningOp.h
new file mode 100644
index 0000000..ef5daf4
--- /dev/null
+++ b/Adapt/repositioning/NodesRepositioningOp.h
@@ -0,0 +1,59 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_NODESREPOSITIONINGOP
+#define _H_NODESREPOSITIONINGOP
+
+#include "DiscreteSF.h"
+#include "MeshQualityManager.h"
+#include "MeshDataBaseInterface.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ enum repositionType {
+ LAPLACE_FAST,
+ LAPLACE_OPTIMAL
+ };
+
+ // -------------------------------------------------------------------
+ class nodesRepositioningOp {
+
+ public:
+
+ nodesRepositioningOp(pMesh m, DiscreteSF * sf):
+ mesh(m), sizeField(sf), mqm(MeshQualityManagerSgl::instance())
+ {
+ dim = 3;
+ if ( M_numRegions(mesh) == 0 ) dim = 2;
+ }
+ virtual ~nodesRepositioningOp() {}
+
+ public:
+
+ virtual int run(double * L2Norm)=0;
+
+ protected:
+
+ pMesh mesh;
+ int dim;
+ DiscreteSF * sizeField;
+ MeshQualityManager& mqm;
+
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/sizeField/AnalyticalSField.cc b/Adapt/sizeField/AnalyticalSField.cc
new file mode 100644
index 0000000..28f5b4a
--- /dev/null
+++ b/Adapt/sizeField/AnalyticalSField.cc
@@ -0,0 +1,382 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "AnalyticalSField.h"
+#include "MAdTimeManager.h"
+#include "IsoMeshSize.h"
+#include "AnisoMeshSize.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // Constructors / destructors
+ // -------------------------------------------------------------------
+ AnalyticalSField::AnalyticalSField():
+ SizeFieldBase(), sFct(NULL), isotropic(true), evaluator(NULL)
+ {
+ setSize("1.");
+ }
+
+ // -------------------------------------------------------------------
+ AnalyticalSField::AnalyticalSField(std::string h):
+ SizeFieldBase(), sFct(NULL), isotropic(true), evaluator(NULL)
+ {
+ setSize(h);
+ }
+
+ // -------------------------------------------------------------------
+ AnalyticalSField::AnalyticalSField(std::vector<std::string> _h,
+ std::vector<std::string> _e0,
+ std::vector<std::string> _e1,
+ std::vector<std::string> _e2):
+ SizeFieldBase(), sFct(NULL), isotropic(false), evaluator(NULL)
+ {
+ setSize(_h,_e0,_e1,_e2);
+ }
+
+ // -------------------------------------------------------------------
+ AnalyticalSField::AnalyticalSField(sizeFunction f):
+ SizeFieldBase(), sFct(f), isotropic(false),
+ evaluator(NULL)
+ {}
+
+ // -------------------------------------------------------------------
+ AnalyticalSField::~AnalyticalSField()
+ {
+ if (evaluator) delete evaluator;
+ }
+
+ // -------------------------------------------------------------------
+ void AnalyticalSField::describe() const {
+
+ cout << "\nDescribing analytical size field: \n\n";
+
+ cout << " Orientation: \t";
+ if (isotropic) cout << "Isotropic\n\n";
+ else cout << "Anisotropic\n\n";
+
+ cout << " Representation:\t";
+ if (sFct) cout << "Size Function\n\n";
+ else {
+ if (isotropic) {
+ cout << "String:\n";
+ cout << " Size: " << h0 << "\n\n";
+ }
+ else {
+ cout << "Strings:\n";
+
+ cout << " - Sizes:\n";
+ cout << " * " << h0 << "\n";
+ cout << " * " << h1 << "\n";
+ cout << " * " << h2 << "\n";
+
+ cout << " - Vectors:\n";
+ cout << " * " << e0[0] <<"\t" << e0[1] <<"\t" << e0[2] <<"\n";
+ cout << " * " << e1[0] <<"\t" << e1[1] <<"\t" << e1[2] <<"\n";
+ cout << " * " << e2[0] <<"\t" << e2[1] <<"\t" << e2[2] <<"\n";
+
+ cout << "\n";
+ }
+ }
+
+ }
+
+ // -------------------------------------------------------------------
+ // Size imposition
+ // -------------------------------------------------------------------
+ void AnalyticalSField::setSize(const std::string h)
+ {
+ if (sFct) throw;
+
+ isotropic = true;
+
+ h0 = h;
+ h1 = h;
+ h2 = h;
+ e0.resize(3);
+ e1.resize(3);
+ e2.resize(3);
+ e0[0] = "1."; e0[1] = "0."; e0[2] = "0.";
+ e1[0] = "0."; e1[1] = "1."; e1[2] = "0.";
+ e2[0] = "0."; e2[1] = "0."; e2[2] = "1.";
+
+ if(evaluator) delete evaluator;
+ evaluator = new MAdStringFieldEvaluator(1,h.c_str());
+ }
+
+ // -------------------------------------------------------------------
+ void AnalyticalSField::setSize(std::vector<std::string> _h,
+ std::vector<std::string> _e0,
+ std::vector<std::string> _e1,
+ std::vector<std::string> _e2)
+ {
+ if (sFct) throw;
+
+ isotropic = false;
+
+ h0 = _h[0];
+ h1 = _h[1];
+ h2 = _h[2];
+ e0 = _e0;
+ e1 = _e1;
+ e2 = _e2;
+
+ if(evaluator) delete evaluator;
+ evaluator = new MAdStringFieldEvaluator(12,
+ h0.c_str(), h1.c_str(), h2.c_str(),
+ e0[0].c_str(), e0[1].c_str(), e0[2].c_str(),
+ e1[0].c_str(), e1[1].c_str(), e1[2].c_str(),
+ e2[0].c_str(), e2[1].c_str(), e2[2].c_str());
+ }
+
+ // -------------------------------------------------------------------
+ void AnalyticalSField::setSize(sizeFunction f)
+ {
+ if (evaluator) throw;
+ sFct = f;
+ }
+
+ // -------------------------------------------------------------------
+ // Evaluate a local size
+ // -------------------------------------------------------------------
+ pMSize AnalyticalSField::eval(const double xyz[3]) const
+ {
+ double time = MAdTimeManagerSgl::instance().getTime();
+
+ if(sFct) return (*sFct)(xyz,time);
+
+ else {
+ if (isotropic) {
+ double h;
+ evaluator->eval(xyz,time,&h);
+ return new IsoMeshSize(h);
+ }
+ else {
+ double vals[12];
+ evaluator->eval(xyz,time,vals);
+ double h[3] = {vals[0], vals[1], vals[2]};
+ double e[3][3] = { {vals[3], vals[4], vals[5]},
+ {vals[6], vals[7], vals[8]},
+ {vals[9], vals[10], vals[11]} };
+ return new AnisoMeshSize(e,h);
+ }
+ }
+ return NULL;
+ }
+
+ // -------------------------------------------------------------------
+ pMSize AnalyticalSField::getSize(const pVertex pv) const
+ {
+ double xyz[3];
+ V_coord(pv,xyz);
+ return eval(xyz);
+ }
+
+ // -------------------------------------------------------------------
+ pMSize AnalyticalSField::getSizeOnEntity(const pEntity,
+ const double xyz[3]) const
+ {
+ return eval(xyz);
+ }
+
+ // -------------------------------------------------------------------
+ // Length squared computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double AnalyticalSField::SF_VV_lengthSq(const pVertex pV0,
+ const pVertex pV1) const
+ {
+ double xyz[2][3];
+ V_coord(pV0,xyz[0]);
+ V_coord(pV1,xyz[1]);
+
+ pMSize pS[2];
+ pS[0] = getSize(pV0);
+ pS[1] = getSize(pV1);
+
+ double lSq = SF_XYZ_lengthSq(xyz[0],xyz[1],pS[0],pS[1]);
+
+ if ( pS[0] ) delete pS[0];
+ if ( pS[1] ) delete pS[1];
+
+ return lSq;
+ }
+
+ // -------------------------------------------------------------------
+ double AnalyticalSField::SF_XYZ_lengthSq(const double xyz0[3],
+ const double xyz1[3],
+ const pMSize pS0,
+ const pMSize pS1) const
+ {
+ if( pS0 )
+ {
+ double e[3];
+ diffVec(xyz0,xyz1,e);
+ double lenSq0 = pS0->normSq(e);
+ if ( pS1 )
+ {
+ double lenSq1 = pS1->normSq(e);
+ return sqrt(lenSq0*lenSq1);
+ }
+ else return lenSq0;
+ }
+ else {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+ }
+ return 0.;
+ }
+
+ // -------------------------------------------------------------------
+ // Area squared computation
+ // -------------------------------------------------------------------
+
+ double AnalyticalSField::SF_F_areaSq(const pFace face) const
+ {
+ double area = 0.;
+
+ double xyz[3][3];
+ F_coordP1(face,xyz);
+
+ void * temp = 0;
+ pPList fVerts = F_vertices(face,1);
+ while( pVertex pV = (pVertex)PList_next(fVerts,&temp) )
+ {
+ pMSize pS = getSize(pV);
+ area += SF_XYZ_areaSq(xyz,pS,0);
+ if (pS) delete pS;
+ }
+ PList_delete(fVerts);
+
+ area /= F_numVertices(face);
+
+ return area;
+ }
+
+ // -------------------------------------------------------------------
+ double AnalyticalSField::SF_XYZ_areaSq(const double fxyz[3][3],
+ const pMSize pS,
+ const double norDir[3]) const
+ {
+ if( !pS ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+ }
+
+ // get the two first edges
+ double e01[3],e02[3];
+ diffVec(fxyz[1],fxyz[0],e01);
+ diffVec(fxyz[2],fxyz[0],e02);
+
+ double nor[3];
+ crossProd(e01,e02,nor);
+
+ double l1SqInv = 1. / pS->lengthSqInDir(e01);
+ double l2SqInv = 1. / pS->lengthSqInDir(e02);
+
+ if( norDir && dotProd(norDir,nor) < MAdTOL ) return 0.;
+
+ double areaSq = 0.25 * dotProd(nor,nor) * l1SqInv * l2SqInv;
+ if( areaSq < MAdTOL ) return 0.;
+
+ return areaSq;
+ }
+
+ // -------------------------------------------------------------------
+ // Volume computation
+ // -------------------------------------------------------------------
+
+ double AnalyticalSField::SF_R_volume(const pRegion region) const
+ {
+ double vol = 0.;
+
+ double xyz[4][3];
+ R_coordP1(region,xyz);
+
+ pPList rVerts = R_vertices(region);
+ void * temp = 0;
+ while( pVertex pV = (pVertex)PList_next(rVerts,&temp) )
+ {
+ pMSize pS = getSize(pV);
+ vol += SF_XYZ_volume(xyz,pS);
+ if (pS) delete pS;
+ }
+ PList_delete(rVerts);
+
+ vol /= R_numVertices(region);
+
+ return vol;
+ }
+
+ // -------------------------------------------------------------------
+ double AnalyticalSField::SF_XYZ_volume(const double xyz[4][3],
+ const pMSize pS) const
+ {
+ if( !pS ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+ }
+
+ double physVol = R_XYZ_volume(xyz);
+
+ return ( physVol / (pS->size(0)*pS->size(1)*pS->size(2)) );
+ }
+
+ // -------------------------------------------------------------------
+ // Center of edge computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double AnalyticalSField::SF_E_center(const pEdge edge, double center[3],
+ double * reducSq, pMSize * cSize) const
+ {
+ return SF_VV_center(E_vertex(edge,0),E_vertex(edge,1),center,reducSq,cSize);
+ }
+
+ // -------------------------------------------------------------------
+ double AnalyticalSField::SF_VV_center(const pVertex v0, const pVertex v1,
+ double center[3], double * reducSq,
+ pMSize * cSize) const
+ {
+ double xyz[2][3];
+ V_coord(v0,xyz[0]);
+ V_coord(v1,xyz[1]);
+
+ pMSize pS[2];
+ pS[0] = getSize(v0);
+ pS[1] = getSize(v1);
+
+ double cParam = SF_XYZ_center(xyz,pS,center,reducSq,cSize);
+
+ if ( pS[0] ) delete pS[0];
+ if ( pS[1] ) delete pS[1];
+
+ return cParam;
+ }
+
+ // -------------------------------------------------------------------
+ void AnalyticalSField::scale(double fact)
+ {
+ printf("Not implemented (AnalyticalSField::scale)\n");
+ throw;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/AnalyticalSField.h b/Adapt/sizeField/AnalyticalSField.h
new file mode 100644
index 0000000..8fb179f
--- /dev/null
+++ b/Adapt/sizeField/AnalyticalSField.h
@@ -0,0 +1,94 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ANALYTICALSFIELD
+#define _H_ANALYTICALSFIELD
+
+#include "SizeFieldBase.h"
+#include "MAdStringFieldEvaluator.h"
+
+#include <vector>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ typedef pMSize (*sizeFunction)(const double[3],double);
+
+ // -------------------------------------------------------------------
+ class AnalyticalSField: public SizeFieldBase
+ {
+ public:
+
+ AnalyticalSField();
+ AnalyticalSField(std::string);
+ AnalyticalSField(std::vector<std::string>,std::vector<std::string>,
+ std::vector<std::string>,std::vector<std::string>);
+ AnalyticalSField(sizeFunction);
+ ~AnalyticalSField();
+
+ public:
+
+ sFieldType getType() const { return ANALYTICALSFIELD; }
+ void describe() const;
+
+ void scale(double);
+
+ // set the size
+ void setSize(sizeFunction);
+ void setSize(const std::string);
+ void setSize(std::vector<std::string>,std::vector<std::string>,
+ std::vector<std::string>,std::vector<std::string>);
+
+ // get the size at a location (allocate space!)
+ pMSize getSize(const pVertex) const;
+ pMSize getSizeOnEntity(const pEntity, const double[3]) const;
+
+ // edge length (squared)
+ double SF_VV_lengthSq(const pVertex, const pVertex) const;
+ double SF_XYZ_lengthSq(const double[3], const double[3],
+ const pMSize, const pMSize=NULL) const;
+
+ // face area (squared)
+ double SF_F_areaSq(const pFace) const;
+ double SF_XYZ_areaSq(const double[3][3], const pMSize,
+ const double[3]) const;
+
+ // region volume
+ double SF_R_volume(const pRegion) const;
+ double SF_XYZ_volume(const double[4][3], const pMSize) const;
+
+ // center and its associated size
+ double SF_E_center(const pEdge, double[3], double * reducSq, pMSize *) const;
+ double SF_VV_center(const pVertex, const pVertex,
+ double[3], double * reducSq, pMSize *) const;
+
+ private:
+
+ // description of the sizes if we use functions
+ sizeFunction sFct;
+
+ // description of the sizes if we use strings
+ bool isotropic;
+ std::string h0, h1, h2;
+ std::vector<std::string> e0, e1, e2;
+ MAdStringFieldEvaluator * evaluator;
+
+ private:
+
+ pMSize eval(const double[3]) const;
+ };
+
+}
+
+// -------------------------------------------------------------------
+#endif
diff --git a/Adapt/sizeField/AnisoMeshSize.cc b/Adapt/sizeField/AnisoMeshSize.cc
new file mode 100644
index 0000000..f494fc9
--- /dev/null
+++ b/Adapt/sizeField/AnisoMeshSize.cc
@@ -0,0 +1,280 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "AnisoMeshSize.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+#include "MAdDefines.h"
+#include "MeshParametersManager.h"
+
+#include <iostream>
+using std::string;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ AnisoMeshSize::AnisoMeshSize(double dirs[3][3], double _h[3]):
+ MeshSizeBase()
+ {
+ if( _h[0] <= 0. || _h[1] <= 0. || _h[2] <= 0. ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Negative size(s): %f %f %f",
+ _h[0], _h[1], _h[2]);
+ }
+
+ double t1[3], t2[3], t3[3];
+ double l1,l2,l3;
+
+ // sort the sizes from lowest to highest and fill first direction (GCRemark: not useful)
+ int hMin = indexOfMin(_h[0], _h[1], _h[2]);
+ l1 = 1. / (_h[hMin] * _h[hMin]);
+ double normInv = 1. / sqrt ( dirs[hMin][0] * dirs[hMin][0] +
+ dirs[hMin][1] * dirs[hMin][1] +
+ dirs[hMin][2] * dirs[hMin][2] );
+ for (int i=0; i<3; i++) t1[i] = dirs[hMin][i] * normInv;
+
+ hMin++;
+ if( _h[(hMin+1)%3] > _h[(hMin)%3] )
+ {
+ l2 = 1. / (_h[hMin%3] * _h[hMin%3]);
+ l3 = 1. / (_h[(hMin+1)%3] * _h[(hMin+1)%3]);
+ hMin = hMin%3;
+ }
+ else
+ {
+ l2 = 1. / (_h[(hMin+1)%3] * _h[(hMin+1)%3]);
+ l3 = 1. / (_h[hMin%3] * _h[hMin%3]);
+ hMin = (hMin+1)%3;
+ }
+
+ // project dir 1 so that it is perpendicular to dir 0
+ double cosa = dotProd(t1,dirs[hMin]);
+ double vec[3];
+ for( int i=0; i<3; i++ ) vec[i] = dirs[hMin][i] - cosa * t1[i];
+ normInv = 1. / sqrt ( vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2] );
+ for (int i=0; i<3; i++) t2[i] = vec[i] * normInv;
+
+ // find last dir as the direction orthogonal to the two previous ones
+ crossProd(t1,t2,t3);
+
+ // build the metric
+ M = MAdMetric(l1,l2,l3,t1,t2,t3);
+ }
+
+ // -------------------------------------------------------------------
+ AnisoMeshSize::AnisoMeshSize(double dir[3], double hDir, double hTg):
+ MeshSizeBase()
+ {
+ if( hDir <= 0. || hTg <= 0. ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Negative size(s): %f %f",
+ hDir, hTg);
+ }
+
+ double e[3][3];
+ double len[3];
+
+ // see if 'dir' is the direction of the minimal length
+ int iDir = 0;
+ if ( hDir > hTg ) iDir = 2;
+
+ // set the 'dir' direction and its length
+ normalizeVec(dir,e[iDir]);
+ len[iDir] = 1. / ( hDir * hDir );
+
+ // set other sizes in the right order
+ len[(iDir+1)%3] = 1. / ( hTg * hTg );
+ len[(iDir+2)%3] = len[(iDir+1)%3];
+
+ // find a perpendicular direction to dir
+ double dummy[3];
+ dummy[0] = 2. * ( e[iDir][0] + 1.3654364 );
+ dummy[1] = 3. * ( e[iDir][1] + 3.1368136 );
+ dummy[2] = 5. * ( e[iDir][2] + 7.3683686 );
+ normalizeVec(dummy,dummy);
+ double cosa = dotProd(e[iDir],dummy);
+ for( int i=0; i<3; i++ ) dummy[i] -= cosa * e[iDir][i];
+ normalizeVec(dummy,e[(iDir+1)%3]);
+
+ // find last dir as the direction orthogonal to the two previous ones
+ crossProd(e[iDir],e[(iDir+1)%3],e[(iDir+2)%3]);
+
+ // build the metric
+ M = MAdMetric(len[0],len[1],len[2],e[0],e[1],e[2]);
+ }
+
+ // -------------------------------------------------------------------
+ AnisoMeshSize::AnisoMeshSize(double h):
+ MeshSizeBase()
+ {
+ M = MAdMetric( 1./(h*h) );
+ }
+
+ // -------------------------------------------------------------------
+ AnisoMeshSize::AnisoMeshSize(const AnisoMeshSize &pm):
+ MeshSizeBase()
+ {
+ M = pm.M;
+ }
+
+ // -------------------------------------------------------------------
+ MeshSizeType AnisoMeshSize::getType() const
+ {
+ return ANISOTROPIC;
+ }
+
+ // -------------------------------------------------------------------
+ void AnisoMeshSize::intersect(const pMSize pMS1, const pMSize pMS2)
+ {
+ M = intersection(pMS1->getMetric(),pMS2->getMetric());
+ }
+
+ // -------------------------------------------------------------------
+ void AnisoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1,
+ double param)
+ {
+ M = interpolation(pMS0->getMetric(),pMS1->getMetric(),param);
+ }
+
+ // -------------------------------------------------------------------
+ void AnisoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1,
+ const pMSize pMS2, double u, double v)
+ {
+ M = interpolation(pMS0->getMetric(), pMS1->getMetric(),
+ pMS2->getMetric(), u, v);
+ }
+
+ // -------------------------------------------------------------------
+ void AnisoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1,
+ const pMSize pMS2, const pMSize pMS3,
+ double u, double v, double w)
+ {
+ M = interpolation(pMS0->getMetric(), pMS1->getMetric(),
+ pMS2->getMetric(), pMS3->getMetric(),
+ u, v, w);
+ }
+
+ // -------------------------------------------------------------------
+ double AnisoMeshSize::size(int i) const
+ {
+ doubleMatrix V = doubleMatrix(3,3);
+ doubleVector S = doubleVector(3);
+ M.eig(V,S,true);
+ double s = 1. / sqrt( S(i) );
+ if ( std::isnan(s) ) return MeshParametersManagerSgl::instance().getBigLength();
+ return s;
+ }
+
+ // -------------------------------------------------------------------
+ void AnisoMeshSize::sizes(double _h[3]) const
+ {
+ doubleMatrix V = doubleMatrix(3,3);
+ doubleVector S = doubleVector(3);
+ M.eig(V,S,true);
+ for (int i=0; i<3; i++) {
+ _h[i] = ( 1. / sqrt( S(i) ) );
+ if ( std::isnan(_h[i]) ) _h[i] = MeshParametersManagerSgl::instance().getBigLength();
+ }
+ }
+
+ // -------------------------------------------------------------------
+ double AnisoMeshSize::direction(int i, double dir[3]) const
+ {
+ doubleMatrix V = doubleMatrix(3,3);
+ doubleVector S = doubleVector(3);
+ M.eig(V,S,true); // each column of V is a direction, S gives corresponding 1/h^2
+ for (int iC=0; iC<3; iC++) dir[iC] = V(iC,i);
+ double s = 1. / sqrt( S(i) );
+ if ( std::isnan(s) ) return MeshParametersManagerSgl::instance().getBigLength();
+ return s;
+ }
+
+ // -------------------------------------------------------------------
+ void AnisoMeshSize::scale(int dir, double factor)
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Not implemented");
+ }
+
+ // -------------------------------------------------------------------
+ void AnisoMeshSize::scale(double factor)
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Not implemented");
+ }
+
+ // -------------------------------------------------------------------
+ double AnisoMeshSize::getMeanLength() const
+ {
+ doubleMatrix V = doubleMatrix(3,3);
+ doubleVector S = doubleVector(3);
+ M.eig(V,S,false);
+ double mean = 0.;
+ for (int i=0; i<3; i++) mean += 1. / sqrt( S(i) );
+ return ( MAdTHIRD * mean );
+ }
+
+ // -------------------------------------------------------------------
+ double AnisoMeshSize::getMinLength() const
+ {
+ doubleMatrix V = doubleMatrix(3,3);
+ doubleVector S = doubleVector(3);
+ M.eig(V,S,false);
+ int i = indexOfMax(S(0),S(1),S(2));
+ return ( 1. / sqrt( S(i) ) );
+ }
+
+ // -------------------------------------------------------------------
+ double AnisoMeshSize::getMaxLength() const
+ {
+ doubleMatrix V = doubleMatrix(3,3);
+ doubleVector S = doubleVector(3);
+ M.eig(V,S,false);
+ int i = indexOfMin(S(0),S(1),S(2));
+ return ( 1. / sqrt( S(i) ) );
+ }
+
+ // -------------------------------------------------------------------
+ // get the square of the norm in the metric
+ double AnisoMeshSize::normSq(const double vec[3]) const
+ {
+ return dot(vec,M,vec);
+ }
+
+ // -------------------------------------------------------------------
+ // get the square of desired edge length along 'vec'
+ double AnisoMeshSize::lengthSqInDir(const double vec[3]) const
+ {
+ double tmp[3];
+ normalizeVec(vec,tmp);
+ return ( 1. / dot(tmp,M,tmp) );
+ }
+
+ // -------------------------------------------------------------------
+ // get the cosine of the angle with the direction of the minimal size
+ double AnisoMeshSize::angleWithDir0(const double dir[3]) const
+ {
+ double tmp[3];
+ normalizeVec(dir,tmp);
+ double dir0[3];
+ direction(0,dir0);
+ normalizeVec(dir0,dir0);
+ return dotProd(tmp,dir0);
+ }
+
+ // -------------------------------------------------------------------
+ void AnisoMeshSize::print(string name) const
+ {
+ std::cout<<"Printing AnisoMeshSize \'"<<name<<"\' ("<<this<<")\n";
+ M.print("Mesh size metric");
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/AnisoMeshSize.h b/Adapt/sizeField/AnisoMeshSize.h
new file mode 100644
index 0000000..b212a10
--- /dev/null
+++ b/Adapt/sizeField/AnisoMeshSize.h
@@ -0,0 +1,79 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ANISOMESHSIZE
+#define _H_ANISOMESHSIZE
+
+#include "MeshSizeBase.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // This class stores an anisotropic mesh size (prescribed edge length)
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ class AnisoMeshSize : public MeshSizeBase {
+
+ public:
+
+ AnisoMeshSize(double e[3][3], double _h[3]);
+ AnisoMeshSize(double e[3], double hDir, double hTg);
+ AnisoMeshSize(double h=1.);
+ AnisoMeshSize(const AnisoMeshSize &);
+ ~AnisoMeshSize() {};
+
+ public:
+
+ MeshSizeType getType() const;
+ MAdMetric getMetric() const { return M; }
+
+ void intersect(const pMSize pMS0, const pMSize pMS1);
+
+ void interpolate(const pMSize, const pMSize, double);
+ void interpolate(const pMSize, const pMSize, const pMSize,
+ double, double);
+ void interpolate(const pMSize, const pMSize, const pMSize, const pMSize,
+ double, double, double);
+
+ double direction(int i, double dir[3]) const;
+ double size(int i=0) const;
+ void sizes(double _h[3]) const;
+
+ // get the square of the norm in the metric
+ double normSq(const double vec[3]) const;
+
+ double lengthSqInDir(const double dir[3]) const ;
+
+ // get the cosine of the angle with the direction of the minimal size
+ double angleWithDir0(const double dir[3]) const;
+
+ double getMeanLength() const;
+ double getMinLength() const;
+ double getMaxLength() const;
+
+ void scale(int, double);
+ void scale(double);
+
+ void print(std::string name="") const;
+
+ private:
+
+ MAdMetric M;
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/sizeField/DiscreteSF.cc b/Adapt/sizeField/DiscreteSF.cc
new file mode 100644
index 0000000..420f3b4
--- /dev/null
+++ b/Adapt/sizeField/DiscreteSF.cc
@@ -0,0 +1,80 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "DiscreteSF.h"
+#include "IsoMeshSize.h"
+#include "AnisoMeshSize.h"
+
+using namespace MAd;
+
+// -------------------------------------------------------------------
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ DiscreteSF::DiscreteSF(pMesh m, std::string name): SizeFieldBase(name)
+ {
+ mesh = m;
+ dim = M_dim(mesh);
+
+ pMSizeFieldId = MD_newMeshDataId("");
+ }
+
+ // -------------------------------------------------------------------
+ DiscreteSF::~DiscreteSF()
+ {
+ MD_deleteMeshDataId(pMSizeFieldId);
+ }
+
+ // -------------------------------------------------------------------
+ void DiscreteSF::deleteSize(pEntity entity)
+ {
+ void * temp;
+ if( EN_getDataPtr(entity,pMSizeFieldId,&temp) ) {
+ EN_deleteData(entity,pMSizeFieldId);
+ delete (pMSize)temp;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void DiscreteSF::setSize(pEntity ent,
+ double dirs[3][3],
+ double h[3])
+ {
+ pMSize pS = new AnisoMeshSize(dirs,h);
+ setSize(ent,pS);
+ }
+
+
+ // -------------------------------------------------------------------
+ void DiscreteSF::setSize(pEntity ent, double h)
+ {
+ pMSize pS = new IsoMeshSize(h);
+ setSize(ent,pS);
+ }
+
+ // -------------------------------------------------------------------
+ void DiscreteSF::setSize(pEntity pEnt, pMSize pS)
+ {
+ void * temp;
+ if( EN_getDataPtr(pEnt,pMSizeFieldId,&temp) ) {
+ delete (pMSize)temp;
+ EN_modifyDataPtr(pEnt,pMSizeFieldId,pS);
+ }
+ else {
+ EN_attachDataPtr(pEnt,pMSizeFieldId,pS);
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/DiscreteSF.h b/Adapt/sizeField/DiscreteSF.h
new file mode 100644
index 0000000..1a839c9
--- /dev/null
+++ b/Adapt/sizeField/DiscreteSF.h
@@ -0,0 +1,103 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_DISCRETESF
+#define _H_DISCRETESF
+
+#include "SizeFieldBase.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ enum DiscreteSFType {
+ UNKNOWN_DSFTYPE,
+ VERTEX_P1_DSFTYPE
+ };
+
+ // -------------------------------------------------------------------
+ class DiscreteSF : public SizeFieldBase
+ {
+ public:
+
+ DiscreteSF(pMesh, std::string name="");
+ ~DiscreteSF();
+
+ sFieldType getType() const { return DISCRETESFIELD; }
+ virtual DiscreteSFType discretization() const = 0;
+ pMesh getMesh() { return mesh; }
+
+ // delete sizes
+ virtual void cleanUp() = 0;
+ void deleteSize(pEntity);
+
+ // Intersect with another size field
+ virtual void intersect(const pSField) = 0;
+
+ // smooth the size field
+ virtual void smooth(double) = 0;
+
+ // set a size at all vertices
+ virtual void setCurrentSize() = 0;
+ virtual void setCurvatureSize(bool aniso,
+ double alpha=2., // prescribe 2*PI*alpha edges around a circle
+ double hMin=1.e-4) = 0; // minimal size
+ virtual void setAllVSizes(pMSize) = 0;
+ virtual void setAllVSizes(double[3][3], double[3]) = 0;
+ virtual void setAllVSizes(double) = 0;
+ virtual void scale(double) = 0;
+
+ // set the size at a vertex
+ void setSize(pEntity, double[3][3], double[3]);
+ void setSize(pEntity, pMSize);
+ void setSize(pEntity, double);
+
+ // get the size at a location (allocate space!)
+ virtual pMSize getSize(const pVertex) const = 0;
+ virtual pMSize getSizeOnEntity(const pEntity, const double[3]) const = 0;
+
+ // get the size at a vertex (do not allocate space)
+ virtual const pMSize findSize(const pVertex) const = 0;
+ virtual pMSize findSize(const pVertex) = 0;
+
+ // edge length (squared)
+ virtual double SF_VV_lengthSq(const pVertex, const pVertex) const = 0;
+ virtual double SF_XYZ_lengthSq(const double[3], const double[3],
+ const pMSize, const pMSize=NULL) const = 0;
+
+ // face area (squared)
+ virtual double SF_F_areaSq(const pFace) const = 0;
+ virtual double SF_XYZ_areaSq(const double[3][3], const pMSize,
+ const double[3]) const = 0;
+
+ // region volume
+ virtual double SF_R_volume(const pRegion) const = 0;
+ virtual double SF_XYZ_volume(const double[4][3], const pMSize) const = 0;
+
+ // center and its associated size
+ virtual double SF_E_center(const pEdge, double[3], double *reducSq, pMSize *) const = 0;
+ virtual double SF_VV_center(const pVertex, const pVertex,
+ double[3], double *reducSq, pMSize *) const = 0;
+
+ protected:
+
+ pMesh mesh;
+ int dim;
+ pMeshDataId pMSizeFieldId;
+
+ };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
diff --git a/Adapt/sizeField/IsoMeshSize.cc b/Adapt/sizeField/IsoMeshSize.cc
new file mode 100644
index 0000000..0ee6c99
--- /dev/null
+++ b/Adapt/sizeField/IsoMeshSize.cc
@@ -0,0 +1,176 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "IsoMeshSize.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+
+#include <stdio.h>
+#include <iostream>
+#include <stdlib.h>
+using std::string;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ IsoMeshSize::IsoMeshSize(double _h):
+ MeshSizeBase()
+ {
+ h = _h;
+ }
+
+ // -------------------------------------------------------------------
+ IsoMeshSize::IsoMeshSize(const IsoMeshSize &pm):
+ MeshSizeBase()
+ {
+ h = pm.size();
+ }
+
+ // -------------------------------------------------------------------
+ MeshSizeType IsoMeshSize::getType() const
+ {
+ return ISOTROPIC;
+ }
+
+ // -------------------------------------------------------------------
+ void IsoMeshSize::intersect(const pMSize pMS0, const pMSize pMS1)
+ {
+ if ( pMS0->getType() != ISOTROPIC ||
+ pMS1->getType() != ISOTROPIC ) {
+ printf("Error: intersecting anisotropic sizes in isotropic mesh size\n");
+ exit(1);
+ }
+
+ double h0 = ((IsoMeshSize*)pMS0)->size();
+ double h1 = ((IsoMeshSize*)pMS1)->size();
+ h = std::min(h0,h1);
+ }
+
+ // -------------------------------------------------------------------
+ void IsoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1,
+ double param)
+ {
+ if ( pMS0->getType() != ISOTROPIC ||
+ pMS1->getType() != ISOTROPIC ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Anisotropic size(s)");
+ }
+
+ double h0 = ((IsoMeshSize*)pMS0)->size();
+ double h1 = ((IsoMeshSize*)pMS1)->size();
+ h = h0 + param * ( h1 - h0 );
+ }
+
+ // -------------------------------------------------------------------
+ void IsoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1,
+ const pMSize pMS2, double u, double v)
+ {
+ if ( pMS0->getType() != ISOTROPIC ||
+ pMS1->getType() != ISOTROPIC ||
+ pMS2->getType() != ISOTROPIC ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Anisotropic size(s)");
+ }
+
+ double h0 = ((IsoMeshSize*)pMS0)->size();
+ double h1 = ((IsoMeshSize*)pMS1)->size();
+ double h2 = ((IsoMeshSize*)pMS2)->size();
+ h = (1.-u-v) * h0 + u * h1 + v * h2;
+ }
+
+ // -------------------------------------------------------------------
+ void IsoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1,
+ const pMSize pMS2, const pMSize pMS3,
+ double u, double v, double w)
+ {
+ if ( pMS0->getType() != ISOTROPIC ||
+ pMS1->getType() != ISOTROPIC ||
+ pMS2->getType() != ISOTROPIC ||
+ pMS3->getType() != ISOTROPIC ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Anisotropic size(s)");
+ }
+
+ double h0 = ((IsoMeshSize*)pMS0)->size();
+ double h1 = ((IsoMeshSize*)pMS1)->size();
+ double h2 = ((IsoMeshSize*)pMS2)->size();
+ double h3 = ((IsoMeshSize*)pMS3)->size();
+ h = (1.-u-v-w) * h0 + u * h1 + v * h2 + w * h3;
+ }
+
+ // -------------------------------------------------------------------
+ double IsoMeshSize::direction(int i, double dir[3]) const
+ {
+ for (int c=0; c<3; c++) dir[c] = 0.;
+ dir[i] = 1.;
+ return h;
+ }
+
+ // -------------------------------------------------------------------
+ double IsoMeshSize::size(int i) const {
+ return h;
+ }
+
+ // -------------------------------------------------------------------
+ void IsoMeshSize::sizes(double _h[3]) const {
+ _h[0] = _h[1] = _h[2] = h;
+ }
+
+ // -------------------------------------------------------------------
+ double IsoMeshSize::getMeanLength() const
+ {
+ return h;
+ }
+
+ // -------------------------------------------------------------------
+ double IsoMeshSize::getMinLength() const
+ {
+ return h;
+ }
+
+ // -------------------------------------------------------------------
+ double IsoMeshSize::getMaxLength() const
+ {
+ return h;
+ }
+
+ // -------------------------------------------------------------------
+ void IsoMeshSize::setSize(double _h)
+ {
+ h = _h;
+ }
+
+ // -------------------------------------------------------------------
+ void IsoMeshSize::scale(double factor)
+ {
+ h *= factor;
+ }
+
+ // -------------------------------------------------------------------
+ double IsoMeshSize::normSq(const double vec[3]) const
+ {
+ return ( dotProd(vec,vec) / (h*h) );
+ }
+
+ // -------------------------------------------------------------------
+ double IsoMeshSize::lengthSqInDir(const double vec[3]) const
+ {
+ return h*h;
+ }
+
+ // -------------------------------------------------------------------
+ void IsoMeshSize::print(string name) const
+ {
+ std::cout<<"Printing IsoMeshSize \'"<<name<<"\' ("<<this<<")\n";
+ std::cout<<" h:\t"<<h<<"\n";
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/IsoMeshSize.h b/Adapt/sizeField/IsoMeshSize.h
new file mode 100644
index 0000000..9ac8216
--- /dev/null
+++ b/Adapt/sizeField/IsoMeshSize.h
@@ -0,0 +1,74 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ISOMESHSIZE
+#define _H_ISOMESHSIZE
+
+#include "MeshSizeBase.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // This class stores an isotropic mesh size (prescribed edge length)
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ class IsoMeshSize : public MeshSizeBase {
+
+ public:
+
+ IsoMeshSize(double _h=-1.);
+ IsoMeshSize(const IsoMeshSize &);
+ ~IsoMeshSize() {};
+
+ public:
+
+ MeshSizeType getType() const;
+ MAdMetric getMetric() const { return MAdMetric(1./(h*h)); }
+
+ void intersect(const pMSize pMS0, const pMSize pMS1);
+ void intersect(const pMSize pMS);
+
+ void interpolate(const pMSize, const pMSize, double);
+ void interpolate(const pMSize, const pMSize, const pMSize,
+ double, double);
+ void interpolate(const pMSize, const pMSize, const pMSize, const pMSize,
+ double, double, double);
+
+ double direction(int i, double dir[3]) const;
+ double size(int i=0) const;
+ void sizes(double _h[3]) const;
+ double normSq(const double vec[3]) const;
+ double lengthSqInDir(const double dir[3]) const ;
+
+ double getMeanLength() const;
+ double getMinLength() const;
+ double getMaxLength() const;
+
+ void setSize(double);
+
+ void scale(int, double);
+ void scale(double);
+
+ void print(std::string name="") const;
+
+ private:
+
+ double h;
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/sizeField/LocalSizeField.cc b/Adapt/sizeField/LocalSizeField.cc
new file mode 100644
index 0000000..584288f
--- /dev/null
+++ b/Adapt/sizeField/LocalSizeField.cc
@@ -0,0 +1,542 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "LocalSizeField.h"
+#include "IsoMeshSize.h"
+#include "AnisoMeshSize.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+#include "MeshParametersManager.h"
+#include "MAdTimeManager.h"
+#include "MAdResourceManager.h"
+
+#include <iostream>
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::set;
+using std::string;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ LocalSizeField::LocalSizeField(pMesh m, string name, bool _distToFaces):
+ SizeFieldBase(name), mesh(m), geoDim(-1),
+ isotropic(true), radius(-1.), sizeN(""), sizeT(""),
+ sEvalN(NULL), sEvalT(NULL),
+ distToFaces(_distToFaces), dFct(mesh, distToFaces),
+ limit(false), tgSizeLimitCoef(MAdBIG), maxCurv(MAdBIG)
+ {
+#ifdef PARALLEL
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Local size fields not supported in parallel");
+#endif
+ }
+
+ // -------------------------------------------------------------------
+ LocalSizeField::LocalSizeField(const LocalSizeField& _lsf): dFct(NULL,false)
+ {
+ throw;
+ }
+
+ // -------------------------------------------------------------------
+ LocalSizeField::~LocalSizeField()
+ {
+ if ( sEvalN ) delete sEvalN;
+ if ( sEvalT ) delete sEvalT;
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ void LocalSizeField::addGeometricEntity(int type, int tag)
+ {
+ // check that the new entity has the same dimension as the previous ones
+ if ( geoDim < 0 ) geoDim = type;
+ else if ( geoDim != type ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Trying to insert a geo entity with dim %d while another entity with dim %d was previously inserted",
+ type, geoDim);
+ }
+
+ geomEntities.insert( GM_entityByTag(M_model(mesh),type,tag) );
+ }
+
+ // -------------------------------------------------------------------
+ void LocalSizeField::setIsoSize(double _radius, string _sizeN)
+ {
+ isotropic = true;
+ radius = _radius;
+ sizeN = _sizeN;
+ sizeT = "";
+ if( sEvalN ) delete sEvalN;
+ sEvalN = new MAdStringFieldEvaluator(1,sizeN.c_str());
+ }
+
+ // -------------------------------------------------------------------
+ void LocalSizeField::setAnisoSize(double _radius, string _sizeN,
+ string _sizeT)
+ {
+ isotropic = false;
+ radius = _radius;
+ sizeN = _sizeN;
+ sizeT = _sizeT;
+ if( sEvalN ) delete sEvalN;
+ if( sEvalT ) delete sEvalT;
+ sEvalN = new MAdStringFieldEvaluator(1,sizeN.c_str());
+ sEvalT = new MAdStringFieldEvaluator(1,sizeT.c_str());
+ }
+
+ // -------------------------------------------------------------------
+ void LocalSizeField::setCurvatureLimiter(double onTgSize, double _maxCurv)
+ {
+ limit = true;
+ tgSizeLimitCoef = onTgSize;
+ maxCurv = _maxCurv;
+ }
+
+ // -------------------------------------------------------------------
+ pMSize LocalSizeField::getSize(const pVertex pv) const
+ {
+ // get the distance
+ double dist = dFct.getDistance(pv);
+
+ double dxyz[3] = {0., 0., 0.}; dxyz[0] = dist;
+
+ // get the time
+ double time = MAdTimeManagerSgl::instance().getTime();
+
+ // get the sizes for this distance at this time
+ double sizeN_d, sizeT_d;
+ sEvalN->eval(dxyz,time,&sizeN_d);
+ if ( !isotropic ) sEvalT->eval(dxyz,time,&sizeT_d);
+
+ pMSize theSize;
+
+ if (dist >= radius) {
+ theSize = new IsoMeshSize (MeshParametersManagerSgl::instance().getBigLength());
+ }
+ else {
+ if ( isotropic ) {
+ theSize = new IsoMeshSize( sizeN_d );
+ }
+ else {
+ double nor[3];
+ if ( !dFct.getGradient(pv,nor) ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gradient not available for vertex %p",pv);
+ }
+
+ if ( fabs(nor[0]) <= MAdTOL && fabs(nor[1]) <= MAdTOL && fabs(nor[2]) <= MAdTOL ) {
+ theSize = new IsoMeshSize( sizeN_d );
+ }
+ else {
+ if ( limit )
+ {
+ double curvR;
+ if ( !dFct.getCurvature(pv,&curvR) ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Curvature not available for vertex %p",pv);
+ }
+ if ( curvR > MAdTOL ) {
+ curvR = std::min(curvR,maxCurv);
+ curvR = 1. / curvR;
+ // limit the tangent size regarding the curvature radius of the wall
+ sizeT_d = std::min(sizeT_d, tgSizeLimitCoef * curvR);
+ sizeT_d = std::max(sizeT_d,sizeN_d);
+ }
+ }
+
+ theSize = new AnisoMeshSize( nor, sizeN_d, sizeT_d );
+ }
+ }
+ }
+ return theSize;
+ }
+
+ // -------------------------------------------------------------------
+ pMSize LocalSizeField::getSizeOnEntity(const pEntity pe,
+ const double xyz[3]) const
+ {
+ // get the distance
+ double dist = dFct.computeDistance(xyz);
+
+ double dxyz[3] = {0., 0., 0.}; dxyz[0] = dist;
+
+ // get the time
+ double time = MAdTimeManagerSgl::instance().getTime();
+
+ // get the sizes for this distance at this time
+ double sizeN_d, sizeT_d;
+ sEvalN->eval(dxyz,time,&sizeN_d);
+ if ( !isotropic ) sEvalT->eval(dxyz,time,&sizeT_d);
+
+ pMSize theSize;
+
+ if (dist > radius) {
+ theSize = new IsoMeshSize (MeshParametersManagerSgl::instance().getBigLength());
+ }
+ else {
+ if ( isotropic ) {
+ theSize = new IsoMeshSize( sizeN_d );
+ }
+ else {
+ double nor[3];
+ if ( !dFct.getGradientOnEntity(pe,xyz,nor) ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gradient not available for entity %p",pe);
+ }
+
+ if ( fabs(nor[0]) <= MAdTOL && fabs(nor[1]) <= MAdTOL && fabs(nor[2]) <= MAdTOL ) {
+ theSize = new IsoMeshSize( sizeN_d );
+ }
+ else {
+ if ( limit )
+ {
+ double curvR;
+ if ( !dFct.getCurvatureOnEntity(pe,xyz,&curvR) ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Curvature not available for entity %p",pe);
+ }
+ if ( curvR > MAdTOL ) {
+ curvR = std::min(curvR,maxCurv);
+ curvR = 1. / curvR;
+ // limit the tangent size regarding the curvature radius of the wall
+ sizeT_d = std::min(sizeT_d, tgSizeLimitCoef * curvR);
+ sizeT_d = std::max(sizeT_d,sizeN_d);
+ }
+ }
+
+ theSize = new AnisoMeshSize( nor, sizeN_d, sizeT_d );
+ }
+ }
+ }
+ return theSize;
+ }
+
+ // -------------------------------------------------------------------
+ // Length squared computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double LocalSizeField::SF_VV_lengthSq(const pVertex pV0, const pVertex pV1) const
+ {
+ double xyz[2][3];
+ V_coord(pV0,xyz[0]);
+ V_coord(pV1,xyz[1]);
+
+ pMSize pS[2];
+ pS[0] = getSize(pV0);
+ pS[1] = getSize(pV1);
+
+ double lSq = SF_XYZ_lengthSq(xyz[0],xyz[1],pS[0],pS[1]);
+
+ if ( pS[0] ) delete pS[0];
+ if ( pS[1] ) delete pS[1];
+
+ return lSq;
+ }
+
+ // -------------------------------------------------------------------
+ double LocalSizeField::SF_XYZ_lengthSq(const double xyz0[3],
+ const double xyz1[3],
+ const pMSize pS0,
+ const pMSize pS1) const
+ {
+ if( pS0 )
+ {
+ double e[3];
+ diffVec(xyz0,xyz1,e);
+ double lenSq0 = pS0->normSq(e);
+ if ( pS1 )
+ {
+ double lenSq1 = pS1->normSq(e);
+ return sqrt(lenSq0*lenSq1);
+ }
+ else return lenSq0;
+ }
+ else {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+ }
+ return 0.;
+ }
+
+ // -------------------------------------------------------------------
+ // Area squared computation
+ // -------------------------------------------------------------------
+
+ double LocalSizeField::SF_F_areaSq(const pFace face) const
+ {
+ double area = 0.;
+
+ double xyz[3][3];
+ F_coordP1(face,xyz);
+
+ void * temp = 0;
+ pPList fVerts = F_vertices(face,1);
+ while( pVertex pV = (pVertex)PList_next(fVerts,&temp) )
+ {
+ pMSize pS = getSize(pV);
+ area += SF_XYZ_areaSq(xyz,pS,0);
+ if (pS) delete pS;
+ }
+ PList_delete(fVerts);
+
+ area /= F_numVertices(face);
+
+ return area;
+ }
+
+ // -------------------------------------------------------------------
+ double LocalSizeField::SF_XYZ_areaSq(const double fxyz[3][3],
+ const pMSize pS,
+ const double norDir[3]) const
+ {
+ if( !pS ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+ }
+
+ // get the two first edges
+ double e01[3],e02[3];
+ diffVec(fxyz[1],fxyz[0],e01);
+ diffVec(fxyz[2],fxyz[0],e02);
+
+ double nor[3];
+ crossProd(e01,e02,nor);
+
+ double l1SqInv = 1. / pS->lengthSqInDir(e01);
+ double l2SqInv = 1. / pS->lengthSqInDir(e02);
+
+ if( norDir && dotProd(norDir,nor) < MAdTOL ) return 0.;
+
+ double areaSq = 0.25 * dotProd(nor,nor) * l1SqInv * l2SqInv;
+ if( areaSq < MAdTOL ) return 0.;
+
+ return areaSq;
+ }
+
+ // -------------------------------------------------------------------
+ // Volume computation
+ // -------------------------------------------------------------------
+
+ double LocalSizeField::SF_R_volume(const pRegion region) const
+ {
+ double vol = 0.;
+
+ double xyz[4][3];
+ R_coordP1(region,xyz);
+
+ pPList rVerts = R_vertices(region);
+ void * temp = 0;
+ while( pVertex pV = (pVertex)PList_next(rVerts,&temp) )
+ {
+ pMSize pS = getSize(pV);
+ vol += SF_XYZ_volume(xyz,pS);
+ if (pS) delete pS;
+ }
+ PList_delete(rVerts);
+
+ vol /= R_numVertices(region);
+
+ return vol;
+ }
+
+ // -------------------------------------------------------------------
+ double LocalSizeField::SF_XYZ_volume(const double xyz[4][3], const pMSize pS) const
+ {
+ if( !pS ) {
+ printf("Error in LocalSizeField::volume: no size given\n");
+ throw;
+ }
+
+ double physVol = R_XYZ_volume(xyz);
+
+ return ( physVol / (pS->size(0)*pS->size(1)*pS->size(2)) );
+ }
+
+ // -------------------------------------------------------------------
+ // Center of edge computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double LocalSizeField::SF_E_center(const pEdge edge, double center[3],
+ double * reducSq, pMSize * cSize) const
+ {
+ return SF_VV_center(E_vertex(edge,0),E_vertex(edge,1),center,reducSq,cSize);
+ }
+
+ // -------------------------------------------------------------------
+ double LocalSizeField::SF_VV_center(const pVertex v0, const pVertex v1,
+ double center[3], double * reducSq,
+ pMSize * cSize) const
+ {
+ double xyz[2][3];
+ V_coord(v0,xyz[0]);
+ V_coord(v1,xyz[1]);
+
+ pMSize pS[2];
+ pS[0] = getSize(v0);
+ pS[1] = getSize(v1);
+
+ double cParam = SF_XYZ_center(xyz,pS,center,reducSq,cSize);
+
+ if ( pS[0] ) delete pS[0];
+ if ( pS[1] ) delete pS[1];
+
+ return cParam;
+ }
+
+ // -------------------------------------------------------------------
+ bool LocalSizeField::getCurvature(const pVertex pv, double *c) const
+ {
+ return dFct.getCurvature(pv,c);
+ }
+
+ // ----------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ void LocalSizeField::scale(double fact)
+ {
+ printf("Not implemented (LocalSizeField::scale)\n");
+ throw;
+ }
+
+ // ----------------------------------------------------------------------
+ // ----------------------------------------------------------------------
+ void LocalSizeField::updateTree()
+ {
+ MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+ double t0 = tm.getTime();
+
+ set<pVertex> vertices;
+ set<pEntity> entities;
+ collectEntities(&vertices, &entities);
+ dFct.computeTree(vertices,entities);
+
+ printf("Computed tree in %f sec\n",tm.getTime()-t0);
+
+ if ( !isotropic )
+ {
+ // curvatures are not implemented in 2D
+ if ( M_dim(mesh) < 3 ) dFct.computeGradientAtVertices();
+ else {
+
+ double t1 = tm.getTime();
+ dFct.computeAllDistAndGrad();
+ printf("Computed dist and grad in %f sec\n",tm.getTime()-t1);
+
+ double t2 = tm.getTime();
+
+ // gather all regions with a vertex in the scope of the size field
+ set<pRegion> allR;
+ pPList vRegs; void *temp=NULL;
+ VIter vit = M_vertexIter(mesh);
+ while (pVertex pv = VIter_next(vit)) {
+ if ( dFct.getDistance(pv) <= radius ) {
+ vRegs = V_regions(pv);
+ for (int i=0; i< PList_size(vRegs); i++) allR.insert((pRegion)PList_item(vRegs,i));
+ PList_delete(vRegs);
+ }
+ }
+ VIter_delete(vit);
+
+ //dFct.computeGradientAndCurvature(allR);
+ if ( limit ) {
+ dFct.computeCurvature(allR);
+ dFct.smoothCurvature(1);
+ }
+ printf("Computed curvatures in %f sec\n",tm.getTime()-t2);
+
+// #warning "debug: output curvatures in volume"
+// double t3 = tm.getTime();
+// dFct.outputDistance("dist.pos");
+// if ( limit ) dFct.outputCurvature("curv.pos");
+// dFct.outputGradAtVertices("grad.pos");
+// printf("Outputs in %f sec\n",tm.getTime()-t3);
+// exit(0);
+ }
+ }
+
+ printf("Updated tree in %f sec\n",tm.getTime()-t0);
+ }
+
+ // ----------------------------------------------------------------------
+ void LocalSizeField::collectEntities(set<pVertex> * verts,
+ set<pEntity> * ents) const
+ {
+ verts->clear();
+ ents->clear();
+
+ set<pGEntity>::const_iterator it = geomEntities.begin();
+ set<pGEntity>::const_iterator itEnd = geomEntities.end();
+ for (; it != itEnd; it++)
+ {
+ switch ( GEN_type(*it) ) {
+ case 0:
+ {
+ VIter vit = M_vertexIter(mesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ if ( EN_whatIn((pEntity)pv) == *it ) {
+ ents->insert(pv);
+ verts->insert(pv);
+ }
+ }
+ VIter_delete(vit);
+ break;
+ }
+ case 1:
+ {
+ EIter eit = M_edgeIter(mesh);
+ while (pEdge pe = EIter_next(eit))
+ {
+ if ( EN_whatIn((pEntity)pe) == *it )
+ {
+ ents->insert(pe);
+ verts->insert(E_vertex (pe,0));
+ verts->insert(E_vertex (pe,1));
+ }
+ }
+ EIter_delete(eit);
+ }
+ case 2:
+ {
+ FIter fit = M_faceIter(mesh);
+ while (pFace pf = FIter_next(fit))
+ {
+ if ( EN_whatIn((pEntity)pf) == *it )
+ {
+ ents->insert(pf);
+ verts->insert(F_vertex (pf,0));
+ verts->insert(F_vertex (pf,1));
+ verts->insert(F_vertex (pf,2));
+ }
+ }
+ FIter_delete(fit);
+ }
+ case 3:
+ {
+ RIter rit = M_regionIter(mesh);
+ while (pRegion pr = RIter_next(rit))
+ {
+ if ( EN_whatIn((pEntity)pr) == *it )
+ {
+ ents->insert(pr);
+ verts->insert(R_vertex (pr,0));
+ verts->insert(R_vertex (pr,1));
+ verts->insert(R_vertex (pr,2));
+ verts->insert(R_vertex (pr,3));
+ }
+ }
+ RIter_delete(rit);
+ }
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/LocalSizeField.h b/Adapt/sizeField/LocalSizeField.h
new file mode 100644
index 0000000..a6f3162
--- /dev/null
+++ b/Adapt/sizeField/LocalSizeField.h
@@ -0,0 +1,121 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LOCALSIZEFIELD
+#define _H_LOCALSIZEFIELD
+
+#include "SizeFieldBase.h"
+#include "DistanceFunction.h"
+#include "MAdStringFieldEvaluator.h"
+
+#include <set>
+#include <utility>
+#include <string>
+
+// -------------------------------------------------------------------
+/*
+ This class stores a size field around an object.
+ * The object is defined by a set of geometrical entities.
+ * The size field is defined by a radius and strings giving the
+ size in function of the distance to the object.
+ * Returns:
+ - If the distance is superior to the radius, the class
+ returns a huge size.
+ - Otherwise, it can return one of these sizes:
+ - an isotropic size (evaluated from 'sizeN')
+ - an anisotropic size with a main axis in the normal
+ direction to the object and a corresponding value ('sizeN'),
+ and two axis in the tangent directions with another value
+ ('sizeT').
+*/
+// -------------------------------------------------------------------
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class LocalSizeField : public SizeFieldBase {
+
+ public:
+
+ LocalSizeField(pMesh m, std::string name="", bool _distToFaces=false);
+ LocalSizeField(const LocalSizeField& _lsf);
+ ~LocalSizeField();
+
+ sFieldType getType() const { return LOCALSFIELD; }
+
+ void scale(double);
+
+ void addGeometricEntity(int type, int tag);
+ void updateTree();
+
+ void setIsoSize(double _radius, std::string _sizeN);
+ void setAnisoSize(double _radius, std::string _sizeN, std::string _sizeT);
+ void setCurvatureLimiter(double onTgSize, double _maxCurv=MAdBIG);
+
+ // get the size at a location (allocate space!)
+ pMSize getSize(const pVertex) const;
+ pMSize getSizeOnEntity(const pEntity, const double[3]) const;
+
+ // edge length (squared)
+ double SF_VV_lengthSq(const pVertex, const pVertex) const;
+ double SF_XYZ_lengthSq(const double[3], const double[3],
+ const pMSize, const pMSize=NULL) const;
+
+ // face area (squared)
+ double SF_F_areaSq(const pFace) const;
+ double SF_XYZ_areaSq(const double[3][3], const pMSize,
+ const double[3]) const;
+
+ // region volume
+ double SF_R_volume(const pRegion) const;
+ double SF_XYZ_volume(const double[4][3], const pMSize) const;
+
+ // center and its associated size
+ double SF_E_center(const pEdge, double[3], double * reducSq, pMSize *) const;
+ double SF_VV_center(const pVertex, const pVertex,
+ double[3], double * reducSq, pMSize *) const;
+
+ // divergence of the curvature
+ bool getCurvature(const pVertex pv, double *c) const;
+
+ private:
+
+ void collectEntities(std::set<pVertex> * verts,
+ std::set<pEntity> * ents) const;
+
+ private:
+
+ pMesh mesh;
+
+ std::set<pGEntity> geomEntities;
+ int geoDim;
+
+ bool isotropic;
+ double radius;
+ std::string sizeN, sizeT;
+ MAdStringFieldEvaluator * sEvalN, * sEvalT;
+
+ bool distToFaces; // true: distance computed to the faces of the wall (exact)
+ // false: distance computed to the vertices of the wall
+ distanceFunction dFct; // tool to compute distance and its derivatives
+
+ // limiters based on curvature
+ bool limit;
+ double tgSizeLimitCoef;
+ double maxCurv;
+ };
+
+}
+
+// -------------------------------------------------------------------
+#endif
diff --git a/Adapt/sizeField/MeshSizeBase.cc b/Adapt/sizeField/MeshSizeBase.cc
new file mode 100644
index 0000000..904dec9
--- /dev/null
+++ b/Adapt/sizeField/MeshSizeBase.cc
@@ -0,0 +1,104 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MeshSizeBase.h"
+#include "IsoMeshSize.h"
+#include "AnisoMeshSize.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ pMSize MS_copy(const pMSize pMS)
+ {
+ MeshSizeType type = pMS->getType();
+ switch (type) {
+ case ISOTROPIC:
+ return new IsoMeshSize((IsoMeshSize&)(*pMS));
+ break;
+ case ANISOTROPIC:
+ return new AnisoMeshSize((AnisoMeshSize&)(*pMS));
+ break;
+ default:
+ throw;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ pMSize MS_intersect(const pMSize pMS0, const pMSize pMS1)
+ {
+ pMSize newS;
+ if ( pMS0->getType() == ISOTROPIC &&
+ pMS1->getType() == ISOTROPIC ) {
+ newS = new IsoMeshSize();
+ }
+ else {
+ newS = new AnisoMeshSize();
+ }
+ newS->intersect(pMS0,pMS1);
+
+ return newS;
+ }
+
+ // -------------------------------------------------------------------
+ pMSize MS_interpolate(const pMSize pMS0, const pMSize pMS1, double param)
+ {
+ pMSize newS;
+ if ( pMS0->getType() == ISOTROPIC &&
+ pMS1->getType() == ISOTROPIC ) {
+ newS = new IsoMeshSize();
+ }
+ else {
+ newS = new AnisoMeshSize();
+ }
+ newS->interpolate(pMS0,pMS1,param);
+ return newS;
+ }
+
+ // -------------------------------------------------------------------
+ pMSize MS_interpolate(const pMSize pMS0, const pMSize pMS1,
+ const pMSize pMS2, double u, double v)
+ {
+ pMSize newS;
+ if ( pMS0->getType() == ISOTROPIC &&
+ pMS1->getType() == ISOTROPIC &&
+ pMS2->getType() == ISOTROPIC ) {
+ newS = new IsoMeshSize();
+ }
+ else {
+ newS = new AnisoMeshSize();
+ }
+ newS->interpolate(pMS0,pMS1,pMS2,u,v);
+ return newS;
+ }
+
+ // -------------------------------------------------------------------
+ pMSize MS_interpolate(const pMSize pMS0, const pMSize pMS1,
+ const pMSize pMS2, const pMSize pMS3,
+ double u, double v, double w)
+ {
+ pMSize newS;
+ if ( pMS0->getType() == ISOTROPIC &&
+ pMS1->getType() == ISOTROPIC &&
+ pMS2->getType() == ISOTROPIC &&
+ pMS3->getType() == ISOTROPIC ) {
+ newS = new IsoMeshSize();
+ }
+ else {
+ newS = new AnisoMeshSize();
+ }
+ newS->interpolate(pMS0,pMS1,pMS2,pMS3,u,v,w);
+ return newS;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/MeshSizeBase.h b/Adapt/sizeField/MeshSizeBase.h
new file mode 100644
index 0000000..a6d3c68
--- /dev/null
+++ b/Adapt/sizeField/MeshSizeBase.h
@@ -0,0 +1,105 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MESHSIZEBASE
+#define _H_MESHSIZEBASE
+
+#include "MAdMetric.h"
+
+#include <string>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ enum MeshSizeType {
+ ISOTROPIC,
+ ANISOTROPIC
+ };
+
+ // -------------------------------------------------------------------
+ typedef class MeshSizeBase * pMSize;
+
+ // -------------------------------------------------------------------
+ pMSize MS_copy(const pMSize pMS);
+ pMSize MS_intersect(const pMSize pMS0, const pMSize pMS1);
+ // interpolate on an edge
+ pMSize MS_interpolate(const pMSize, const pMSize, double);
+ // interpolate on a triangle
+ pMSize MS_interpolate(const pMSize, const pMSize, const pMSize,
+ double, double);
+ // interpolate on a tetrahedron
+ pMSize MS_interpolate(const pMSize, const pMSize, const pMSize, const pMSize,
+ double, double, double);
+
+ // -------------------------------------------------------------------
+ // This class stores a mesh size (prescribed edge length)
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ class MeshSizeBase
+ {
+ public:
+
+ MeshSizeBase() {};
+ virtual ~MeshSizeBase() {};
+
+ public:
+
+ virtual MeshSizeType getType() const = 0;
+ virtual MAdMetric getMetric() const = 0;
+
+ // this becomes the minimum size between two sizes
+ virtual void intersect(const pMSize pMS0, const pMSize pMS1) = 0;
+
+ // this becomes the interpolation between two sizes
+ virtual void interpolate(const pMSize, const pMSize, double) = 0;
+ // this becomes the interpolation between three sizes
+ virtual void interpolate(const pMSize, const pMSize, const pMSize,
+ double, double) = 0;
+ // this becomes the interpolation between four sizes
+ virtual void interpolate(const pMSize, const pMSize, const pMSize, const pMSize,
+ double, double, double) = 0;
+
+ // get a principle direction (eigenvectors of the metric)
+ virtual double direction(int i, double dir[3]) const = 0;
+
+ // get the desired size in a principle direction (eigenvalues)
+ virtual double size(int i=0) const = 0;
+
+ // get the desired size in the 3 directions (eigenvalues)
+ virtual void sizes(double _h[3]) const = 0;
+
+ // get the square norm of the vector in the metric
+ virtual double normSq(const double vec[3]) const = 0;
+
+ // get the desired size in the given direction
+ virtual double lengthSqInDir(const double dir[3]) const = 0;
+
+ // get the mean, min, max sizes
+ virtual double getMeanLength() const = 0;
+ virtual double getMinLength() const = 0;
+ virtual double getMaxLength() const = 0;
+
+ // scale the size
+ virtual void scale(double) = 0;
+
+ // print info
+ virtual void print(std::string name="") const = 0;
+
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/sizeField/NullSField.cc b/Adapt/sizeField/NullSField.cc
new file mode 100644
index 0000000..3bd1d8b
--- /dev/null
+++ b/Adapt/sizeField/NullSField.cc
@@ -0,0 +1,107 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "NullSField.h"
+#include "MathUtils.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // Length squared computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double NullSField::SF_VV_lengthSq(const pVertex v0, const pVertex v1) const
+ {
+ double xyz[2][3];
+ V_coord(v0,xyz[0]);
+ V_coord(v1,xyz[1]);
+
+ return SF_XYZ_lengthSq(xyz[0],xyz[1],NULL,NULL);
+ }
+
+ // -------------------------------------------------------------------
+ double NullSField::SF_XYZ_lengthSq(const double xyz0[3], const double xyz1[3],
+ const pMSize, const pMSize) const
+ {
+ double vec[3];
+ diffVec(xyz0,xyz1,vec);
+
+ return dotProd(vec,vec);
+ }
+
+ // -------------------------------------------------------------------
+ // Area squared computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double NullSField::SF_F_areaSq(const pFace face) const
+ {
+ double xyz[3][3];
+ F_coordP1(face,xyz);
+
+ return SF_XYZ_areaSq(xyz,NULL,NULL);
+ }
+
+ // -------------------------------------------------------------------
+ double NullSField::SF_XYZ_areaSq(const double xyz[3][3], const pMSize,
+ const double norDir[3]) const
+ {
+ return XYZ_F_areaSq(xyz,norDir);
+ }
+
+ // -------------------------------------------------------------------
+ // Volume computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double NullSField::SF_R_volume(const pRegion r) const
+ {
+ return R_volume(r);
+ }
+
+ // -------------------------------------------------------------------
+ double NullSField::SF_XYZ_volume(const double xyz[4][3],
+ const pMSize) const
+ {
+ return R_XYZ_volume(xyz);
+ }
+
+ // -------------------------------------------------------------------
+ // Center of edge computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double NullSField::SF_E_center(const pEdge edge,
+ double center[3], double * reducSq,
+ pMSize *) const
+ {
+ return SF_VV_center(E_vertex(edge,0),E_vertex(edge,1),center,reducSq,NULL);
+ }
+
+ // -------------------------------------------------------------------
+ double NullSField::SF_VV_center(const pVertex v0, const pVertex v1,
+ double center[3], double * reducSq,
+ pMSize *) const
+ {
+ double xyz[2][3];
+ V_coord(v0,xyz[0]);
+ V_coord(v1,xyz[1]);
+
+ for(int i=0; i<3; i++) center[i] = 0.5*(xyz[0][i]+xyz[1][i]);
+ *reducSq = 0.5;
+ return 0.5;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/NullSField.h b/Adapt/sizeField/NullSField.h
new file mode 100644
index 0000000..ff1e9b3
--- /dev/null
+++ b/Adapt/sizeField/NullSField.h
@@ -0,0 +1,66 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_NULLSFIELD
+#define _H_NULLSFIELD
+
+#include "SizeFieldBase.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class NullSField : public SizeFieldBase
+ {
+ public:
+
+ NullSField(): SizeFieldBase() {}
+ ~NullSField() {}
+
+ sFieldType getType() const { return NULLSFIELD; }
+
+ // edge length (squared)
+ double SF_VV_lengthSq(const pVertex, const pVertex) const;
+ double SF_XYZ_lengthSq(const double[3], const double[3],
+ const pMSize, const pMSize=NULL) const;
+
+ // face area (squared)
+ double SF_F_areaSq(const pFace) const;
+ double SF_XYZ_areaSq(const double[3][3], const pMSize,
+ const double[3]) const;
+
+ // region volume
+ double SF_R_volume(const pRegion) const;
+ double SF_XYZ_volume(const double[4][3], const pMSize) const;
+
+ // center and its associated size
+ double SF_E_center(const pEdge, double[3], double * reducSq, pMSize *) const;
+ double SF_VV_center(const pVertex, const pVertex,
+ double[3], double * reducSq, pMSize *) const;
+
+ public: // functions that have no sense here...
+
+ void scale(double) {return;}
+
+ void setSize(pEntity, pMSize) {return;}
+ void setSize(pEntity, double) {return;}
+ void deleteSize(pEntity) {return;}
+
+ pMSize getSize(const pVertex) const {return NULL;}
+ pMSize getSizeOnEntity(const pEntity, const double[3]) const {return NULL;};
+ };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
diff --git a/Adapt/sizeField/PWLinearSField.cc b/Adapt/sizeField/PWLinearSField.cc
new file mode 100644
index 0000000..ecce2fd
--- /dev/null
+++ b/Adapt/sizeField/PWLinearSField.cc
@@ -0,0 +1,590 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "PWLinearSField.h"
+#include "CallBackManager.h"
+#include "IsoMeshSize.h"
+#include "AnisoMeshSize.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+#include "MeshParametersManager.h"
+
+#include <stdio.h>
+#include <math.h>
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+#include <queue>
+
+using namespace MAd;
+
+// -------------------------------------------------------------------
+void PWLinearSFCBFunction (pPList before, pPList after, void * data,
+ operationType type , pEntity ppp)
+{
+ PWLSField * pwl = (PWLSField *)(data);
+
+ switch (type) {
+ case MAd_ESPLIT: {
+
+ double xyz[3];
+ V_coord((pVertex)ppp,xyz);
+
+ // find the old edge
+ void *tmp=0;
+ pEntity pE = PList_next(before,&tmp);
+
+ // interpolate size at new location
+ pMSize newSize = pwl->getSizeOnEntity(pE,xyz);
+
+ pwl->setSize(ppp,newSize);
+ break;
+ }
+ case MAd_ECOLLAPSE: {
+ pwl->deleteSize(ppp);
+ break;
+ }
+ case MAd_FSWAP:
+ case MAd_ESWAP: {
+ break;
+ }
+ case MAd_RREMOVE: {
+ void * temp = NULL;
+ while ( pEntity pE = PList_next(before,&temp) ) {
+ if ( EN_type(pE) == 0 ) {
+ pwl->deleteSize( (pVertex)pE );
+ }
+ }
+ break;
+ }
+ default: {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Not implemented for mesh modification %d",
+ type);
+ }
+ }
+}
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ PWLSField::PWLSField(pMesh m, std::string name): DiscreteSF(m, name)
+ {
+ CallBackManagerSgl::instance().registerCallBack(PWLinearSFCBFunction,this);
+ }
+
+ // -------------------------------------------------------------------
+ PWLSField::~PWLSField()
+ {
+ cleanUp();
+ CallBackManagerSgl::instance().unregisterCallBack(PWLinearSFCBFunction,this);
+ }
+
+ // -------------------------------------------------------------------
+ void PWLSField::cleanUp()
+ {
+ VIter iter = M_vertexIter(mesh);
+ while( pVertex pV = VIter_next(iter) ) deleteSize((pEntity)pV);
+ VIter_delete(iter);
+ }
+
+ // -------------------------------------------------------------------
+ void PWLSField::intersect(const pSField extField)
+ {
+ VIter iter = M_vertexIter(mesh);
+ while( pVertex pV = VIter_next(iter) )
+ {
+ // get the size for the extern size field
+ pMSize extS = extField->getSize(pV);
+ if (!extS) continue;
+
+ // get the size for this size field
+ pMSize intS = this->findSize(pV);
+ if (!intS) {
+ setSize((pEntity)pV,extS);
+ }
+ else {
+ pMSize newS = MS_intersect(intS,extS);
+ delete extS;
+ setSize(pV,newS);
+ }
+ }
+ VIter_delete(iter);
+ }
+
+ // -------------------------------------------------------------------
+ // Smooth the size field by limiting the size gradient along an edge
+ // to maxGrad
+ void PWLSField::smooth(double maxGrad)
+ {
+ // edges still to be checked
+ std::queue<pEdge> toCheck;
+
+ // check every edge at least once
+ EIter eIt = M_edgeIter(mesh);
+ while( pEdge edge = EIter_next(eIt) ) toCheck.push(edge);
+ EIter_delete(eIt);
+
+ while ( !toCheck.empty() ) {
+
+ std::set<pEdge> toAdd;
+
+ // check the content of toCheck
+ while ( !toCheck.empty() ) {
+ smoothOnEdge(toCheck.front(),maxGrad,&toAdd);
+ toCheck.pop();
+ }
+
+ // move content of toAdd to toCheck
+ std::set<pEdge>::const_iterator eIter = toAdd.begin();
+ for (; eIter != toAdd.end(); eIter++ ) toCheck.push(*eIter);
+ toAdd.clear();
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void PWLSField::smoothOnEdge(const pEdge edge, double maxGrad,
+ std::set<pEdge>* toAdd)
+ {
+ pVertex pV[2];
+ pMSize pMS[2];
+ double h[2];
+ for (int iV=0; iV<2; iV++) {
+ pV[iV] = E_vertex(edge,iV);
+ pMS[iV] = findSize(pV[iV]);
+ if ( pMS[iV]->getType() != ISOTROPIC ) {
+ printf("Error: PWLSField::smoothOnEdge not implemented for anisotropic sizes\n");
+ exit(1);
+ }
+ h[iV] = ( (IsoMeshSize*)(pMS[iV]) )->size();
+ }
+
+ double physLength = E_length(edge);
+
+ double grad = fabs( h[1] - h[0] ) / physLength;
+ if ( grad > maxGrad ) {
+
+ int toScale = 1;
+ if ( h[0] > h[1] ) toScale = 0;
+
+ double maxSize = maxGrad * physLength + h[1-toScale];
+ ( (IsoMeshSize*)(pMS[toScale]) )->setSize(maxSize-MAdTOL);
+
+ for( int iE=0; iE<V_numEdges(pV[toScale]); iE++ ) {
+ pEdge newEdge = V_edge(pV[toScale],iE);
+ if ( newEdge == edge ) continue;
+ toAdd->insert(newEdge);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void PWLSField::setCurrentSize()
+ {
+ VIter vi = M_vertexIter(mesh);
+ while ( pVertex vert = VIter_next(vi) ) {
+ double lenSq = V_meanEdgeLenSq(vert);
+ pMSize pSV = new IsoMeshSize(sqrt(lenSq));
+ setSize((pEntity)vert,pSV);
+ }
+ VIter_delete(vi);
+ }
+
+ // -------------------------------------------------------------------
+ void PWLSField::setCurvatureSize(bool aniso, double alpha, double hMin)
+ {
+ if ( !(mesh->isParametric()) ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Curvature not available without a geometry (mesh is not parametric");
+ }
+
+#ifdef _HAVE_GMSH_
+ double bigLen = MeshParametersManagerSgl::instance().getBigLength();
+ double curvMaxBound = 10. / hMin;
+ pVertex vert;
+ VIter vi = M_vertexIter(mesh);
+ while ( ( vert = VIter_next(vi) ) )
+ {
+ pGEntity pge = V_whatIn(vert);
+ int gdim = GEN_type(pge);
+ pMSize pSV;
+ if ( aniso && gdim==2 )
+ {
+ double u[2];
+ V_params(vert,&(u[0]),&(u[1]));
+ double dir[3][3], curv[3];
+ GF_curvatures((pGFace)pge, u, dir[0], dir[1], &(curv[0]), &(curv[1]), curvMaxBound);
+ crossProd(dir[0],dir[1],dir[2]);
+ curv[2] = -1.;
+
+ double h[3] = { -1., -1., -1. };
+ for (int iD=0; iD<3; iD++) {
+ if ( curv[iD] <= MAdTOL ) h[iD] = bigLen;
+ else {
+ h[iD] = 1. / ( curv[iD] * alpha );
+ h[iD] = std::min(std::max(h[iD],hMin),bigLen);
+ }
+ }
+
+ pSV = new AnisoMeshSize(dir,h);
+ }
+ else
+ {
+ double curv = -1.;
+ switch(gdim) {
+ case 3: break;
+ case 2: {
+ double u[2];
+ V_params(vert,&(u[0]),&(u[1]));
+ curv = GF_curvatureDiv((pGFace)pge, u, curvMaxBound);
+ break;
+ }
+ case 1: {
+ double u, tmp;
+ V_params(vert,&u,&tmp);
+ curv = GE_curvature((pGEdge)pge, u, curvMaxBound);
+ break;
+ }
+ case 0: {
+ curv = -1.;
+ std::list<pGEdge> gEdges = GV_edges((pGVertex)pge);
+ std::list<pGEdge>::const_iterator eIter = gEdges.begin();
+ for (; eIter != gEdges.end(); eIter++) {
+ pGEdge pGEd = *eIter;
+ double u;
+ GV_reparamOnEdge((pGVertex)pge, pGEd, &u);
+ double tmpcurv = GE_curvature(pGEd, u, curvMaxBound);
+ if ( tmpcurv > curv ) curv = tmpcurv;
+ }
+ break;
+ }
+ }
+
+ double h = -1.;
+ if ( curv <= MAdTOL ) h = bigLen;
+ else {
+ h = 1. / ( curv * alpha );
+ h = std::min(std::max(h,hMin),bigLen);
+ }
+ pSV = new IsoMeshSize(h);
+ }
+ setSize((pEntity)vert,pSV);
+ }
+ VIter_delete(vi);
+#else
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Curvature not available without Gmsh");
+#endif
+ }
+
+ // -------------------------------------------------------------------
+ void PWLSField::setAllVSizes(pMSize pS)
+ {
+ VIter vi = M_vertexIter(mesh);
+ while ( pVertex vert = VIter_next(vi) ) {
+ pMSize pSCopy = MS_copy(pS);
+ setSize((pEntity)vert,pSCopy);
+ }
+ VIter_delete(vi);
+ }
+
+ // -------------------------------------------------------------------
+ void PWLSField::setAllVSizes(double dirs[3][3], // three unit vectors
+ double h[3])
+ {
+ pMSize pS = new AnisoMeshSize(dirs,h);
+ setAllVSizes(pS);
+ }
+
+ // -------------------------------------------------------------------
+ void PWLSField::setAllVSizes(double h)
+ {
+ pMSize pS = new IsoMeshSize(h);
+ setAllVSizes(pS);
+ }
+
+ // -------------------------------------------------------------------
+ void PWLSField::scale(double fact)
+ {
+ VIter vIter = M_vertexIter(mesh);
+ while( pVertex pV = VIter_next(vIter) )
+ {
+ pMSize pS = findSize(pV);
+ pS->scale(fact);
+ }
+ VIter_delete(vIter);
+ }
+
+ // -------------------------------------------------------------------
+ // Length squared computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double PWLSField::SF_VV_lengthSq(const pVertex v0, const pVertex v1) const
+ {
+ double xyz[2][3];
+ V_coord(v0,xyz[0]);
+ V_coord(v1,xyz[1]);
+
+ pMSize pS[2];
+ pS[0] = findSize(v0);
+ pS[1] = findSize(v1);
+
+ return SF_XYZ_lengthSq(xyz[0],xyz[1],pS[0],pS[1]);
+ }
+
+ // -------------------------------------------------------------------
+ double PWLSField::SF_XYZ_lengthSq(const double xyz0[3], const double xyz1[3],
+ const pMSize pS0, const pMSize pS1) const
+ {
+ if( pS0 )
+ {
+ double e[3];
+ diffVec(xyz0,xyz1,e);
+ double lenSq0 = pS0->normSq(e);
+ if ( pS1 )
+ {
+ double lenSq1 = pS1->normSq(e);
+ return sqrt(lenSq0*lenSq1);
+ }
+ else return lenSq0;
+ }
+ else {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+ }
+ return 0.;
+ }
+
+ // -------------------------------------------------------------------
+ // Area squared computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double PWLSField::SF_F_areaSq(const pFace face) const
+ {
+ double area = 0.;
+
+ double xyz[3][3];
+ F_coordP1(face,xyz);
+
+ void * temp = 0;
+ pPList fVerts = F_vertices(face,1);
+ while( pVertex pV = (pVertex)PList_next(fVerts,&temp) )
+ {
+ pMSize pS = findSize(pV);
+ area += SF_XYZ_areaSq(xyz,pS,0);
+ }
+ PList_delete(fVerts);
+
+ area /= F_numVertices(face);
+
+ return area;
+ }
+
+ // -------------------------------------------------------------------
+ double PWLSField::SF_XYZ_areaSq(const double fxyz[3][3], const pMSize pS,
+ const double norDir[3]) const
+ {
+ if( !pS ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+ }
+
+ // get the two first edges
+ double e01[3],e02[3];
+ diffVec(fxyz[1],fxyz[0],e01);
+ diffVec(fxyz[2],fxyz[0],e02);
+
+ double nor[3];
+ crossProd(e01,e02,nor);
+
+ double l1SqInv = 1. / pS->lengthSqInDir(e01);
+ double l2SqInv = 1. / pS->lengthSqInDir(e02);
+
+ if( norDir && dotProd(norDir,nor) < MAdTOL ) return 0.;
+
+ double areaSq = 0.25 * dotProd(nor,nor) * l1SqInv * l2SqInv;
+ if( areaSq < MAdTOL ) return 0.;
+
+ return areaSq;
+ }
+
+ // -------------------------------------------------------------------
+ // Volume computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double PWLSField::SF_R_volume(const pRegion region) const
+ {
+ double vol = 0.;
+
+ double xyz[4][3];
+ R_coordP1(region,xyz);
+
+ pPList rVerts = R_vertices(region);
+ void * temp = 0;
+ while( pVertex pV = (pVertex)PList_next(rVerts,&temp) )
+ {
+ pMSize pS = findSize(pV);
+ vol += SF_XYZ_volume(xyz,pS);
+ }
+ PList_delete(rVerts);
+
+ vol /= R_numVertices(region);
+
+ return vol;
+ }
+
+ // -------------------------------------------------------------------
+ double PWLSField::SF_XYZ_volume(const double xyz[4][3], const pMSize pS) const
+ {
+ if( !pS ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+ }
+
+ double physVol = R_XYZ_volume(xyz);
+ double h[3];
+ pS->sizes(h);
+ return ( physVol / ( h[0] * h[1] * h[2]) );
+ }
+
+ // -------------------------------------------------------------------
+ // Center of edge computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double PWLSField::SF_E_center(const pEdge edge, double center[3],
+ double * reducSq, pMSize * cSize) const
+ {
+ return SF_VV_center(E_vertex(edge,0),E_vertex(edge,1),center,reducSq,cSize);
+ }
+
+ // -------------------------------------------------------------------
+ double PWLSField::SF_VV_center(const pVertex v0, const pVertex v1,
+ double center[3], double * reducSq,
+ pMSize * cSize) const
+ {
+ double xyz[2][3];
+ V_coord(v0,xyz[0]);
+ V_coord(v1,xyz[1]);
+
+ pMSize pS[2];
+ pS[0] = findSize(v0);
+ pS[1] = findSize(v1);
+
+ return SF_XYZ_center(xyz,pS,center,reducSq,cSize);
+ }
+
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ const pMSize PWLSField::findSize(const pVertex pV) const
+ {
+ void * size;
+ if( EN_getDataPtr( (pEntity)pV, pMSizeFieldId, &size) ) return (pMSize)size;
+ return NULL;
+ }
+
+ // -------------------------------------------------------------------
+ pMSize PWLSField::findSize(const pVertex pV)
+ {
+ void * size;
+ if( EN_getDataPtr( (pEntity)pV, pMSizeFieldId, &size) ) return (pMSize)size;
+ return NULL;
+ }
+
+ // -------------------------------------------------------------------
+ pMSize PWLSField::getSize(const pVertex pV) const
+ {
+ void * temp;
+ if( EN_getDataPtr((pEntity)pV,pMSizeFieldId,&temp) ) {
+ return MS_copy((pMSize)temp);
+ }
+ return NULL;
+ }
+
+ // -------------------------------------------------------------------
+ pMSize PWLSField::getSizeOnEntity(const pEntity entity,
+ const double xyz[3]) const
+ {
+ int type = EN_type(entity);
+ switch(type) {
+ case 0: return getSize((pVertex)entity);
+ case 1: return getSizeOnEdge((pEdge)entity,xyz);
+ case 2: return getSizeOnFace((pFace)entity,xyz);
+ case 3: return getSizeOnRegion((pRegion)entity,xyz);
+ }
+ return NULL;
+ }
+
+ // -------------------------------------------------------------------
+ pMSize PWLSField::getSizeOnEdge(const pEdge edge,
+ const double xyz[3]) const
+ {
+ double u = E_linearParams(edge,xyz);
+ return getSizeOnEdgeParam(edge,u);
+ }
+
+ // -------------------------------------------------------------------
+ pMSize PWLSField::getSizeOnEdgeParam(const pEdge pE,
+ const double u) const
+ {
+ pMSize pS0 = findSize( E_vertex(pE,0) );
+ pMSize pS1 = findSize( E_vertex(pE,1) );
+
+ return MS_interpolate( pS0, pS1, u );
+ }
+
+ // -------------------------------------------------------------------
+ pMSize PWLSField::getSizeOnFace(const pFace face,
+ const double xyz[3]) const
+ {
+ double u[2];
+ F_linearParams(face,xyz,u);
+ return getSizeOnFaceParam(face,u);
+ }
+
+ // -------------------------------------------------------------------
+ pMSize PWLSField::getSizeOnFaceParam(const pFace face,
+ const double u[2]) const
+ {
+ pMSize pS0 = findSize( F_vertex(face,0) );
+ pMSize pS1 = findSize( F_vertex(face,1) );
+ pMSize pS2 = findSize( F_vertex(face,2) );
+
+ return MS_interpolate( pS0, pS1, pS2, u[0], u[1] );
+ }
+
+ // -------------------------------------------------------------------
+ pMSize PWLSField::getSizeOnRegion(const pRegion region,
+ const double xyz[3]) const
+ {
+ double u[3];
+ R_linearParams(region, xyz, u);
+ return getSizeOnRegionParam(region, u);
+ }
+
+ // -------------------------------------------------------------------
+ pMSize PWLSField::getSizeOnRegionParam(const pRegion region,
+ const double u[3]) const
+ {
+ pMSize pS0 = findSize( R_vertex(region,0) );
+ pMSize pS1 = findSize( R_vertex(region,1) );
+ pMSize pS2 = findSize( R_vertex(region,2) );
+ pMSize pS3 = findSize( R_vertex(region,3) );
+
+ return MS_interpolate( pS0, pS1, pS2, pS3, u[0], u[1], u[2] );
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/PWLinearSField.h b/Adapt/sizeField/PWLinearSField.h
new file mode 100644
index 0000000..d254cc1
--- /dev/null
+++ b/Adapt/sizeField/PWLinearSField.h
@@ -0,0 +1,96 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_PWLINEARSFIELD
+#define _H_PWLINEARSFIELD
+
+#include "DiscreteSF.h"
+
+#include <set>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class PWLSField : public DiscreteSF
+ {
+ public:
+
+ PWLSField(pMesh, std::string name="");
+ ~PWLSField();
+
+ DiscreteSFType discretization() const { return VERTEX_P1_DSFTYPE; }
+
+ // delete sizes
+ void cleanUp();
+
+ // Intersect with another size field
+ void intersect(const pSField);
+
+ // smooth the size field
+ void smooth(double);
+
+ // set a size at all vertices
+ void setCurrentSize();
+ void setCurvatureSize(bool aniso,
+ double alpha=2., // prescribe 2*PI*alpha edges around a circle
+ double hMin=1.e-4); // minimal size
+ void setAllVSizes(pMSize);
+ void setAllVSizes(double[3][3], double[3]);
+ void setAllVSizes(double);
+ void scale(double);
+
+ // get the size at a location (allocate space!)
+ pMSize getSize(const pVertex) const;
+ pMSize getSizeOnEntity(const pEntity, const double[3]) const;
+
+ // get the size at a vertex (do not allocate space)
+ const pMSize findSize(const pVertex) const;
+ pMSize findSize(const pVertex);
+
+ // edge length (squared)
+ double SF_VV_lengthSq(const pVertex, const pVertex) const;
+ double SF_XYZ_lengthSq(const double[3], const double[3],
+ const pMSize, const pMSize=NULL) const;
+
+ // face area (squared)
+ double SF_F_areaSq(const pFace) const;
+ double SF_XYZ_areaSq(const double[3][3], const pMSize,
+ const double[3]) const;
+
+ // region volume
+ double SF_R_volume(const pRegion) const;
+ double SF_XYZ_volume(const double[4][3], const pMSize) const;
+
+ // center and its associated size
+ double SF_E_center(const pEdge, double[3], double * reducSq, pMSize *) const;
+ double SF_VV_center(const pVertex, const pVertex,
+ double[3], double * reducSq, pMSize *) const;
+
+ protected:
+
+ pMSize getSizeOnEdge(const pEdge, const double[3]) const;
+ pMSize getSizeOnEdgeParam(const pEdge, const double) const;
+ pMSize getSizeOnFace(const pFace, const double[3]) const;
+ pMSize getSizeOnFaceParam(const pFace, const double[2]) const;
+ pMSize getSizeOnRegion(const pRegion, const double[3]) const;
+ pMSize getSizeOnRegionParam(const pRegion, const double[3]) const;
+
+ void smoothOnEdge(const pEdge, double, std::set<pEdge>*);
+
+ };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
diff --git a/Adapt/sizeField/SizeFieldBase.cc b/Adapt/sizeField/SizeFieldBase.cc
new file mode 100644
index 0000000..b8b7dc8
--- /dev/null
+++ b/Adapt/sizeField/SizeFieldBase.cc
@@ -0,0 +1,90 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "SizeFieldBase.h"
+#include "MAdOutput.h"
+#include "MathUtils.h"
+
+using std::string;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // Length squared computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double SizeFieldBase::SF_E_lengthSq(const pEdge edge) const
+ {
+ return SF_VV_lengthSq(E_vertex(edge,0),E_vertex(edge,1));
+ }
+
+ // -------------------------------------------------------------------
+ // Center of edge computation
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ double SizeFieldBase::SF_XYZ_center(const double xyz[2][3], const pMSize pS[2],
+ double center[3], double * reducSq,
+ pMSize * cSize) const
+ {
+ if( !pS[0] || !pS[1] ) {
+ printf("Error in SizeFieldBase::SF_XYZ_center: one of the sizes is NULL\n");
+ throw;
+ }
+
+ double vec[3];
+ diffVec(xyz[1],xyz[0],vec);
+
+ double lenSq[2];
+ lenSq[0] = pS[0]->lengthSqInDir(vec);
+ lenSq[1] = pS[1]->lengthSqInDir(vec);
+ double lenRatSqrt = pow(lenSq[1]/lenSq[0],0.25);
+
+ double cParam = 1. / ( 1. + lenRatSqrt );
+ *reducSq = 1. / ( 1./lenRatSqrt + lenRatSqrt + 2 );
+
+// double len[2];
+// len[0] = sqrt(pS[0]->lengthSqInDir(vec));
+// len[1] = sqrt(pS[1]->lengthSqInDir(vec));
+
+// double cParam = len[0] / ( len[0] + len[1] );
+
+ for (int i=0; i<3; i++) {
+ center[i] = cParam * xyz[1][i] + (1-cParam) * xyz[0][i];
+ }
+
+ *cSize = MS_interpolate(pS[0],pS[1],cParam);
+
+ return cParam;
+ }
+
+ // -------------------------------------------------------------------
+ void SizeFieldBase::printPosIsotropic(const pMesh mesh, const string name)
+ {
+ MAdGmshOutput(mesh, this, name.c_str(), OD_SIZEFIELD_MEAN);
+ }
+
+ // -------------------------------------------------------------------
+ void SizeFieldBase::printPosAnisotropic(const pMesh mesh, const string baseName)
+ {
+ string name0 = baseName + "0.pos";
+ MAdGmshOutput(mesh, this, name0.c_str(), OD_ANISO_SF_AXIS0);
+ string name1 = baseName + "1.pos";
+ MAdGmshOutput(mesh, this, name1.c_str(), OD_ANISO_SF_AXIS1);
+ string name2 = baseName + "2.pos";
+ MAdGmshOutput(mesh, this, name2.c_str(), OD_ANISO_SF_AXIS2);
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/SizeFieldBase.h b/Adapt/sizeField/SizeFieldBase.h
new file mode 100644
index 0000000..74aab5f
--- /dev/null
+++ b/Adapt/sizeField/SizeFieldBase.h
@@ -0,0 +1,101 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_SIZEFIELDBASE
+#define _H_SIZEFIELDBASE
+
+#include "MeshSizeBase.h"
+#include "MSops.h"
+#include "MAdDefines.h"
+
+#include <string>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ enum sFieldType {
+ UNKNOWNSFIELDTYPE,
+ NULLSFIELD,
+ DISCRETESFIELD,
+ ANALYTICALSFIELD,
+ LOCALSFIELD
+ };
+
+ // -------------------------------------------------------------------
+ typedef class SizeFieldBase * pSField;
+
+ // -------------------------------------------------------------------
+ class SizeFieldBase
+ {
+ public:
+
+ SizeFieldBase(std::string _name=""): name(_name) {};
+ virtual ~SizeFieldBase() {};
+
+ public:
+
+ virtual sFieldType getType() const = 0 ;
+ std::string getName() const { return name; }
+
+ virtual void scale(double) = 0;
+
+ public:
+
+ // edge length (squared)
+ virtual double SF_E_lengthSq(const pEdge) const;
+ virtual double SF_VV_lengthSq(const pVertex,const pVertex) const = 0;
+ virtual double SF_XYZ_lengthSq(const double[3], const double[3],
+ const pMSize, const pMSize=NULL) const = 0;
+
+ // face area (squared)
+ virtual double SF_F_areaSq(const pFace) const = 0;
+ virtual double SF_XYZ_areaSq(const double[3][3], const pMSize,
+ const double[3]) const = 0;
+
+ // region volume
+ virtual double SF_R_volume(const pRegion) const = 0;
+ virtual double SF_XYZ_volume(const double[4][3], const pMSize) const = 0;
+
+ // center and its associated size
+ virtual double SF_E_center(const pEdge, double[3], double * reducSq, pMSize *) const = 0;
+ virtual double SF_VV_center(const pVertex, const pVertex,
+ double[3], double * reducSq, pMSize *) const = 0;
+ virtual double SF_XYZ_center(const double[2][3], const pMSize[2],
+ double[3], double * reducSq, pMSize *) const;
+
+ public:
+
+ // get the size at a location
+ // --- Memory is allocated ! ---
+ virtual pMSize getSize(const pVertex) const = 0;
+ virtual pMSize getSizeOnEntity(const pEntity,
+ const double[3]) const = 0;
+
+ public:
+
+ // visualisation of the isotropic size in a .pos file
+ void printPosIsotropic (const pMesh mesh, const std::string name);
+ // visualisation of the anisotropic size in a .pos file
+ void printPosAnisotropic(const pMesh mesh, const std::string baseName);
+
+ private:
+
+ std::string name;
+
+ };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
diff --git a/Adapt/sizeField/SizeFieldManager.cc b/Adapt/sizeField/SizeFieldManager.cc
new file mode 100644
index 0000000..d69a5c9
--- /dev/null
+++ b/Adapt/sizeField/SizeFieldManager.cc
@@ -0,0 +1,175 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "SizeFieldManager.h"
+#include "NullSField.h"
+#include "MAdTimeManager.h"
+#include "MeshQualityManager.h"
+#include "MAdMessage.h"
+
+#include <iostream>
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::set;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ SizeFieldManager::SizeFieldManager(pMesh m, pSField psf):
+ localTime(-1.),smooth(false),maxGradient(1.)
+ {
+ if (!m) return;
+ mesh = m;
+
+ mainSF = new PWLSField(mesh,"Main size field");
+
+ localTime = MAdTimeManagerSgl::instance().getTime();
+
+ if (!psf) MAdMsgSgl::instance().warning(__LINE__,__FILE__,"No size field registered");
+
+ else {
+
+ mainSF->intersect(psf);
+
+ sFieldType type = psf->getType();
+ switch (type) {
+ case NULLSFIELD: {
+ break;
+ }
+ case DISCRETESFIELD: {
+ assert ( ((DiscreteSF*)psf)->discretization() == VERTEX_P1_DSFTYPE );
+ PWLSField* linsf = static_cast<PWLSField*>(psf);
+ addPWLinearSF( linsf );
+ break;
+ }
+ case ANALYTICALSFIELD: {
+ AnalyticalSField* asf = static_cast<AnalyticalSField*>(psf);
+ addAnalyticalSF( asf );
+ break;
+ }
+ case LOCALSFIELD: {
+ LocalSizeField* locsf = static_cast<LocalSizeField*>(psf);
+ addLocalSF( locsf );
+ break;
+ }
+ default: {
+ cerr <<"Error: unknown size field type "<<type<<"\n"; throw;
+ }
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ SizeFieldManager::~SizeFieldManager() {
+
+ if (mainSF) delete mainSF;
+ linears.clear();
+ analyticals.clear();
+ locals.clear();
+ }
+
+ // -------------------------------------------------------------------
+ void SizeFieldManager::setMesh(pMesh m)
+ {
+ mesh = m;
+ mainSF = new PWLSField(mesh);
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,"No size field registered");
+ }
+
+ // -------------------------------------------------------------------
+ void SizeFieldManager::intersect(const pSField sf) {
+ mainSF->intersect(sf);
+ }
+
+ // -------------------------------------------------------------------
+ void SizeFieldManager::addSizeField(pSField sf) {
+
+ mainSF->intersect(sf);
+
+ sFieldType type = sf->getType();
+ switch (type) {
+ case NULLSFIELD: {
+ break;
+ }
+ case DISCRETESFIELD: {
+ assert ( ((DiscreteSF*)sf)->discretization() == VERTEX_P1_DSFTYPE );
+ PWLSField* linsf = static_cast<PWLSField*>(sf);
+ addPWLinearSF( linsf );
+ break;
+ }
+ case ANALYTICALSFIELD: {
+ AnalyticalSField* asf = static_cast<AnalyticalSField*>(sf);
+ addAnalyticalSF( asf );
+ break;
+ }
+ case LOCALSFIELD: {
+ LocalSizeField* locsf = static_cast<LocalSizeField*>(sf);
+ addLocalSF( locsf );
+ break;
+ }
+ default: {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Unknown size field type %d",type);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void SizeFieldManager::addPWLinearSF(PWLSField* sf) {
+ linears.insert(sf);
+ }
+
+ // -------------------------------------------------------------------
+ void SizeFieldManager::addAnalyticalSF(AnalyticalSField* sf) {
+ analyticals.insert(sf);
+ }
+
+ // -------------------------------------------------------------------
+ void SizeFieldManager::addLocalSF(LocalSizeField* sf) {
+ locals.insert(sf);
+ }
+
+ // -------------------------------------------------------------------
+ void SizeFieldManager::update()
+ {
+ MeshQualityManagerSgl::instance().clearAllShapes(); // not useful in isotropic case (be careful about the hypothesis)
+
+ mainSF->cleanUp();
+
+ set<PWLSField*>::const_iterator linIter = linears.begin();
+ set<PWLSField*>::const_iterator linLast = linears.end();
+ for (; linIter != linLast; linIter++) {
+ mainSF->intersect(*linIter);
+ }
+
+ set<AnalyticalSField*>::const_iterator aIter = analyticals.begin();
+ set<AnalyticalSField*>::const_iterator aLast = analyticals.end();
+ for (; aIter != aLast; aIter++) {
+ mainSF->intersect(*aIter);
+ }
+
+ set<LocalSizeField*>::iterator locIter = locals.begin();
+ set<LocalSizeField*>::iterator locLast = locals.end();
+ for (; locIter != locLast; locIter++) {
+ (*locIter)->updateTree();
+ mainSF->intersect(*locIter);
+ }
+
+ if ( smooth ) mainSF->smooth(maxGradient);
+
+ localTime = MAdTimeManagerSgl::instance().getTime();
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/SizeFieldManager.h b/Adapt/sizeField/SizeFieldManager.h
new file mode 100644
index 0000000..99207fc
--- /dev/null
+++ b/Adapt/sizeField/SizeFieldManager.h
@@ -0,0 +1,85 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_SIZEFIELDMANAGER
+#define _H_SIZEFIELDMANAGER
+
+#include "SizeFieldBase.h"
+#include "PWLinearSField.h"
+#include "LocalSizeField.h"
+#include "AnalyticalSField.h"
+
+#include <set>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // This class lists, intersects and updates all size fields
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+
+ class SizeFieldManager {
+
+ public:
+
+ SizeFieldManager(pMesh m, pSField psf=NULL);
+ ~SizeFieldManager();
+
+ public:
+
+ void setMesh(pMesh m);
+ void setSmoothing(bool enable, double maxGrad)
+ {
+ smooth = enable;
+ maxGradient = maxGrad;
+ }
+
+ void intersect(const pSField sf);
+
+ void addSizeField(pSField sf);
+
+ void update();
+
+ DiscreteSF* getSizeField() { return mainSF; }
+ const DiscreteSF* getSizeField() const { return mainSF; }
+
+ std::set<LocalSizeField *> getLocalSizeFields() const { return locals; }
+
+ private:
+
+ void addPWLinearSF(PWLSField * sf);
+ void addAnalyticalSF(AnalyticalSField * sf);
+ void addLocalSF(LocalSizeField * sf);
+
+ private:
+
+ DiscreteSF* mainSF;
+
+ std::set<PWLSField *> linears;
+ std::set<AnalyticalSField *> analyticals;
+ std::set<LocalSizeField *> locals;
+
+ pMesh mesh;
+
+ double localTime;
+
+ bool smooth;
+ double maxGradient;
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/utils/CallBackManager.cc b/Adapt/utils/CallBackManager.cc
new file mode 100644
index 0000000..e69b8da
--- /dev/null
+++ b/Adapt/utils/CallBackManager.cc
@@ -0,0 +1,100 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "CallBackManager.h"
+
+using std::list;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void CallBackManager::initialize()
+ {
+ }
+
+ // -------------------------------------------------------------------
+ void CallBackManager::finalize()
+ {
+ CB.clear();
+ CBMove.clear();
+ }
+
+ // -------------------------------------------------------------------
+ void CallBackManager::registerCallBack(CBFunction CBFct,
+ void* userData)
+ {
+ CBStructure cb;
+ cb.function = CBFct;
+ cb.data = userData;
+ CB.push_back(cb);
+ }
+
+ // -------------------------------------------------------------------
+ void CallBackManager::registerCallBackMove(CBFunc_move CB_move,
+ void* userData_move)
+ {
+ CBStructureMove cbm;
+ cbm.function = CB_move;
+ cbm.data = userData_move;
+ CBMove.push_back(cbm);
+ }
+
+ // -------------------------------------------------------------------
+ void CallBackManager::unregisterCallBack(CBFunction CBFct,
+ void* userData)
+ {
+ CBStructure cb;
+ cb.function = CBFct;
+ cb.data = userData;
+ CB.remove(cb);
+ }
+
+ // -------------------------------------------------------------------
+ void CallBackManager::unregisterCallBackMove(CBFunc_move CB_move,
+ void* userData_move)
+ {
+ CBStructureMove cbm;
+ cbm.function = CB_move;
+ cbm.data = userData_move;
+ CBMove.remove(cbm);
+ }
+
+ // -------------------------------------------------------------------
+ void CallBackManager::callCallBacks(pPList before, pPList after,
+ operationType type , pEntity ppp)
+ {
+ list<CBStructure>::const_iterator cbIter = CB.begin();
+ list<CBStructure>::const_iterator cbLast = CB.end();
+
+ for (; cbIter != cbLast; cbIter++) {
+ CBFunction f = (*cbIter).function;
+ void * userData = (*cbIter).data;
+ f(before,after,userData,type,ppp);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void CallBackManager::callCallBackMoves(pVertex pv, double * xyz)
+ {
+ list<CBStructureMove>::const_iterator cbIterM = CBMove.begin();
+ list<CBStructureMove>::const_iterator cbLastM = CBMove.end();
+
+ for (; cbIterM != cbLastM; cbIterM++) {
+ CBFunc_move fM = (*cbIterM).function;
+ void * userDataM = (*cbIterM).data;
+ fM(pv,xyz,userDataM);
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/utils/CallBackManager.h b/Adapt/utils/CallBackManager.h
new file mode 100644
index 0000000..2adb42a
--- /dev/null
+++ b/Adapt/utils/CallBackManager.h
@@ -0,0 +1,89 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_CALLBACKMANAGER
+#define _H_CALLBACKMANAGER
+
+#include "MAdOperatorBase.h"
+
+#include "MAdSingleton.h"
+
+#include "MSops.h"
+#include <list>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // callback functions
+ typedef void (*CBFunction)(pPList, pPList,
+ void *, operationType, pEntity);
+ typedef void (*CBFunc_move)(pVertex, double *, void *);
+
+ // -------------------------------------------------------------------
+ struct CBStructure {
+
+ CBFunction function;
+ void* data;
+
+ bool operator== (CBStructure cb) const {
+ if ( function==cb.function && data==cb.data) return true;
+ return false;
+ }
+ };
+
+ // -------------------------------------------------------------------
+ struct CBStructureMove {
+ CBFunc_move function;
+ void* data;
+
+ bool operator== (CBStructureMove cbm) const {
+ if ( function==cbm.function && data==cbm.data) return true;
+ return false;
+ }
+ };
+
+ // -------------------------------------------------------------------
+ class CallBackManager {
+
+ public:
+
+ CallBackManager() {};
+ ~CallBackManager() {};
+
+ void initialize();
+ void finalize();
+
+ void registerCallBack(CBFunction CB, void* userData);
+ void registerCallBackMove(CBFunc_move CB_move, void* userData_move);
+
+ void unregisterCallBack(CBFunction CB, void* userData);
+ void unregisterCallBackMove(CBFunc_move CB_move, void* userData_move);
+
+ void callCallBacks(pPList before, pPList after,
+ operationType type , pEntity ppp);
+ void callCallBackMoves(pVertex, double *);
+
+ private:
+
+ std::list<CBStructure> CB;
+ std::list<CBStructureMove> CBMove;
+
+ };
+
+ // -------------------------------------------------------------------
+
+ typedef MAdSingleton<CallBackManager> CallBackManagerSgl;
+
+}
+
+#endif
diff --git a/Adapt/utils/DistanceFunction.cc b/Adapt/utils/DistanceFunction.cc
new file mode 100644
index 0000000..16b5f65
--- /dev/null
+++ b/Adapt/utils/DistanceFunction.cc
@@ -0,0 +1,1193 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "DistanceFunction.h"
+#include "MAdOutput.h"
+#include "CallBackManager.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void DistFct_CBMoveFct(pVertex pv, double * target, void * data)
+ {
+ // When a vertex is moved, the distance is cleared because it
+ // can be recalculated on-the-fly when needed.
+ // The gradients and curvatures are not cleared because they
+ // can be needed elsewhere and cannot be recalculated on-the-fly.
+
+ distanceFunction * dFct = (distanceFunction *) data;
+ dFct->clearDistance(pv);
+ }
+
+ // -------------------------------------------------------------------
+ void DistFct_CBFct(pPList before, pPList after, void * data,
+ operationType type , pEntity ppp)
+ {
+ distanceFunction * dFct = (distanceFunction *) data;
+
+ switch (type) {
+ case MAd_ESPLIT: {
+ // In the edge split case, we have to interpolate the data at the new node
+
+ double grads[2][3], curv[2];
+
+ // find the old edge
+ void * tmp = 0;
+ pEdge pe = (pEdge)PList_next(before,&tmp);
+ double t = E_linearParams(pe,(pVertex)ppp);
+
+ // interpolate distance gradient
+ if ( dFct->getGradient( E_vertex((pEdge)pe, 0), grads[0] ) &&
+ dFct->getGradient( E_vertex((pEdge)pe, 1), grads[1] ) )
+ {
+ double * newGrad = new double[3];
+ for (int i=0; i<3; i++) newGrad[i] = (1.-t) * grads[0][i] + t * grads[1][i];
+
+ // attach it
+ dFct->attachGradient((pVertex)ppp, newGrad);
+ }
+
+ // interpolate curvature
+ if ( dFct->getCurvature( E_vertex((pEdge)pe, 0), &(curv[0]) ) &&
+ dFct->getCurvature( E_vertex((pEdge)pe, 1), &(curv[1]) ) )
+ {
+ double newCurv = (1.-t) * curv[0] + t * curv[1];
+ dFct->attachCurvature((pVertex)ppp, newCurv);
+ }
+
+ break;
+ }
+ case MAd_ECOLLAPSE: {
+ // In the edge collapse case, we have to delete the datas attached to the deleted node
+ dFct->clearVertexData((pVertex)ppp);
+ break;
+ }
+ case MAd_ESWAP:
+ case MAd_FSWAP: {
+ // nothing to be done (no modification at nodes)
+ break;
+ }
+ case MAd_RREMOVE: {
+ void * temp = NULL;
+ while ( pEntity pE = PList_next(before,&temp) ) {
+ if ( EN_type(pE) == 0 ) {
+ dFct->clearVertexData((pVertex)pE);
+ }
+ }
+ break;
+ }
+ case MAd_UNKNOWNOPERATION:
+ case MAd_VERTEXMOVE:
+ case MAd_FCOLLAPSE:
+ case MAd_DESPLTCLPS:
+ default: {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Not implemented for mesh modification %d", type);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ distanceFunction::distanceFunction(pMesh m, bool _distToEntities):
+ mesh(m), distToEntities(_distToEntities), nVert(0), nEnt(0),
+ nVE(-1), xyzV(NULL), entToV(NULL)
+ {
+ distId = MD_newMeshDataId();
+ vGradId = MD_newMeshDataId();
+ rGradId = MD_newMeshDataId();
+ vCurvId = MD_newMeshDataId();
+
+ kdSearch = new SearchTool();
+
+ CallBackManagerSgl::instance().registerCallBackMove(DistFct_CBMoveFct,this);
+ CallBackManagerSgl::instance().registerCallBack(DistFct_CBFct,this);
+ }
+
+ // -------------------------------------------------------------------
+ distanceFunction::~distanceFunction()
+ {
+ clearDistances();
+ MD_deleteMeshDataId(distId);
+
+ clearGradientAtVertices();
+ MD_deleteMeshDataId(vGradId);
+
+ clearGradientInElements();
+ MD_deleteMeshDataId(rGradId);
+
+ clearCurvature();
+ MD_deleteMeshDataId(vCurvId);
+
+ if (xyzV) delete [] xyzV;
+ if (entToV) delete [] entToV;
+ if (kdSearch) delete kdSearch;
+
+ CallBackManagerSgl::instance().unregisterCallBackMove(DistFct_CBMoveFct,this);
+ CallBackManagerSgl::instance().unregisterCallBack(DistFct_CBFct,this);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::computeTree(const std::set<pVertex>& verts,
+ const std::set<pEntity>& ents)
+ {
+ // Build search tree and vertices coordinates
+
+ kdSearch->reset();
+
+ nVert = verts.size();
+ kdSearch->allocatePoints(nVert);
+
+ if ( xyzV ) delete [] xyzV;
+ xyzV = new double[3*nVert];
+
+ pvToSearchId.clear();
+ vToEnt.clear();
+
+ std::set<pVertex> :: const_iterator itV = verts.begin();
+ std::set<pVertex> :: const_iterator itVEnd = verts.end();
+ int k = 0;
+ for ( ; itV != itVEnd ; ++itV)
+ {
+ double coord[3]; V_coord(*itV,coord);
+ kdSearch->addPoint(k,coord);
+
+ pvToSearchId[*itV] = k;
+ for (int i=0; i<3; i++) xyzV[k*3+i] = coord[i];
+
+ k++;
+ }
+
+ kdSearch->allocateTree(nVert);
+
+ // Build wall entities topology
+
+ if ( distToEntities ) {
+ nEnt = ents.size();
+ if ( nEnt > 0 )
+ {
+ // allocate entities
+ nVE = EN_numVertices(*(ents.begin()));
+ if ( nVE > 3 ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Distance to entities with more than 3 vertices not implemented");
+ }
+ if (entToV) delete [] entToV;
+ entToV = new int[nVE*nEnt];
+
+ // fill it
+ int m = 0;
+ std::set<pEntity>::const_iterator itE = ents.begin();
+ for (; itE != ents.end(); itE++) {
+ pPList eVerts = EN_vertices(*itE);
+ for (int i=0; i<nVE; i++) {
+ int vId = pvToSearchId[(pVertex)PList_item(eVerts,i)];
+ entToV[nVE*m+i] = vId;
+ vToEnt.insert(std::make_pair(vId,m));
+ }
+ PList_delete(eVerts);
+
+ // ensure faces normals are outgoing
+ if ( EN_type(*itE) == 2 && M_dim(mesh) == 3 ) {
+ if ( F_numRegions((pFace)*itE) != 1 ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Faces with %d region(s), normals will not be outgoing",
+ F_numRegions((pFace)*itE));
+ }
+ else {
+ pRegion pr = F_region((pFace)*itE,0);
+ if ( R_dirUsingFace(pr,(pFace)*itE) != 1 ) {
+ int tmp = entToV[nVE*m+1];
+ entToV[nVE*m+1] = entToV[nVE*m+2];
+ entToV[nVE*m+2] = tmp;
+ }
+ }
+ }
+
+ m++;
+ }
+ }
+ else {
+ if (entToV) delete [] entToV;
+ entToV = NULL;
+ }
+ }
+
+ // Clear everything else
+
+ clearDistances();
+ clearGradientAtVertices();
+ clearGradientInElements();
+ clearCurvature();
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::computeAllDistances() const
+ {
+ pVertex pv;
+ VIter vit = M_vertexIter(mesh);
+ while ( ( pv = VIter_next(vit) ) )
+ {
+ computeDistance(pv);
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ double distanceFunction::getDistance(const pVertex pv) const
+ {
+ double dist;
+ if ( EN_getDataDbl((pEntity)pv,distId,&dist) ) return dist;
+ return computeDistance(pv);
+ }
+
+ // -------------------------------------------------------------------
+ double distanceFunction::computeDistance(const pVertex pv) const
+ {
+ double xyz[3]; V_coord(pv,xyz);
+ double dist = computeDistance(xyz);
+ EN_attachDataDbl((pEntity)pv,distId,dist);
+ return dist;
+ }
+
+ // -------------------------------------------------------------------
+ double distanceFunction::computeDistance(const double xyz[3]) const
+ {
+ return sqrt(computeDistSq(xyz));
+ }
+
+ // -------------------------------------------------------------------
+ double distanceFunction::computeDistSq(const double xyz[3]) const
+ {
+ if ( !distToEntities || nEnt == 0 ) return kdSearch->computeDistanceSq(xyz);
+
+ double minD = MAdBIG;
+
+ // --- compute distance to every entity and take minimum ---
+
+ double xyzE[3][3]; // 1 line = coordinates of 1 vertex
+ double vec[3];
+
+ //GC note: could be improved
+
+ // --- compute distance to entities neighboring closest point and take minimum ---
+ int closestId;
+ kdSearch->computeDistanceSq(xyz, &closestId);
+ std::multimap<int,int>::const_iterator bfIt = vToEnt.find(closestId);
+ assert ( bfIt != vToEnt.end() );
+ while ( bfIt != vToEnt.end() && bfIt->first == closestId )
+ {
+ int iE = (*bfIt).second;
+// for (int iE=0; iE<nEnt; iE++)
+// {
+ double dist;
+
+ for(int iV=0; iV<nVE; iV++) {
+ for(int iC=0; iC<3; iC++) xyzE[iV][iC] = xyzV[entToV[iE*nVE+iV]*3+iC];
+ }
+
+ if ( nVE == 3 ) {
+ dist = distToTriangleSq(xyzE,xyz,vec);
+ }
+ else {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Distance to a set of edge not implemented yet");
+ }
+
+ minD = std::min(minD,dist);
+
+ bfIt++;
+ }
+
+ return minD;
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::computeAllDistAndGrad() const
+ {
+ double testVec[3];
+ double xyzE[3][3]; // 1 line = coordinates of 1 vertex
+ pVertex pv;
+ VIter vit = M_vertexIter(mesh);
+ while ( ( pv = VIter_next(vit) ) )
+ {
+ double dist;
+ double * grad = new double[3];
+
+ double xyz[3];
+ V_coord(pv,xyz);
+
+ if ( !distToEntities || nEnt == 0 )
+ {
+ int closestId;
+ kdSearch->computeDistanceSq(xyz, &closestId);
+ double xyzW[3];
+ for (int iC=0; iC<3; iC++) xyzW[iC] = xyzV[3*closestId+iC];
+ diffVec(xyz,xyzW,grad);
+ dist = sqrt( dotProd(grad,grad) );
+ if ( dist <= MAdTOL ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Zero vector found for a distance gradient");
+ }
+ else {
+ normalizeVec(grad,grad);
+ }
+ }
+ else
+ {
+ double minD = MAdBIG;
+
+ //GC note: could be improved
+
+ // --- compute distance to entities neighboring closest point and take minimum ---
+ int closestId;
+ kdSearch->computeDistanceSq(xyz, &closestId);
+ std::multimap<int,int>::const_iterator bfIt = vToEnt.find(closestId);
+ assert ( bfIt != vToEnt.end() );
+ while ( bfIt != vToEnt.end() && bfIt->first == closestId )
+ {
+ int iE = (*bfIt).second;
+ // // --- compute distance to every entity and take minimum ---
+ // for (int iE=0; iE<nEnt; iE++)
+ // {
+ double distSq;
+
+ for(int iV=0; iV<nVE; iV++) {
+ for(int iC=0; iC<3; iC++) xyzE[iV][iC] = xyzV[entToV[iE*nVE+iV]*3+iC];
+ }
+
+ if ( nVE == 3 ) {
+ distSq = distToTriangleSq(xyzE,xyz,testVec);
+ }
+ else {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Distance to a set of edge not implemented yet");
+ }
+
+ if ( distSq < minD ) {
+ minD = distSq;
+ for (int i=0; i<3; i++) grad[i] = testVec[i];
+ }
+ minD = std::min(minD,distSq);
+
+ bfIt++;
+ }
+
+ dist = sqrt(minD);
+
+ // if the point is lying on the iso-zero, take the mean of the
+ // normals of the neighboring elements. The normals are supposed
+ // to be outgoing.
+ if ( minD < MAdTOL )
+ {
+ if (nVE != 3) throw;
+ grad[0] = 0.; grad[1] = 0.; grad[2] = 0.;
+ int locId = pvToSearchId.find(pv)->second;
+ std::multimap<int,int>::const_iterator bfIt = vToEnt.find(locId);
+ assert ( bfIt != vToEnt.end() );
+ while ( bfIt != vToEnt.end() && bfIt->first == locId )
+ {
+ int entId = bfIt->second;
+ for(int iV=0; iV<nVE; iV++) {
+ for(int iC=0; iC<3; iC++) xyzE[iV][iC] = xyzV[entToV[entId*nVE+iV]*3+iC];
+ }
+
+ double nor[3];
+ XYZ_F_normal(xyzE,nor);
+ normalizeVec(nor,nor);
+
+ // give more weight to the closest information
+ double cen[3], xyzToC[3];
+ meanRow33(xyzE,cen);
+ diffVec(cen,xyz,xyzToC);
+ double invDistToCenSq = 1. / dotProd(xyzToC,xyzToC);
+
+ for (int i=0; i<3; i++) grad[i] -= nor[i] * invDistToCenSq;
+
+ bfIt++;
+ }
+
+ normalizeVec(grad,grad);
+ }
+ else
+ {
+ double invD = 1./dist;
+ for (int i=0; i<3; i++) grad[i] *= invD;
+ }
+ }
+// #warning "hacked gradients"
+// for (int i=0; i<3; i++) grad[i] = xyz[i];
+// normalizeVec(grad,grad);
+
+ EN_attachDataDbl((pEntity)pv,distId,dist);
+ void * del;
+ if ( EN_getDataPtr((pEntity)pv,vGradId,&del) && del ) delete [] (double*)del;
+ EN_attachDataPtr((pEntity)pv,vGradId,grad);
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::clearDistance(const pVertex pv) const
+ {
+ EN_deleteData((pEntity)pv,distId);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::clearDistances() const
+ {
+ pVertex pv;
+ VIter vit = M_vertexIter(mesh);
+ while ( ( pv = VIter_next(vit) ) )
+ {
+ EN_deleteData((pEntity)pv,distId);
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::computeGradientInElements() const
+ {
+ double gsf[4][3] = {
+ {-1., -1., -1.},
+ { 1., 0., 0.},
+ { 0., 1., 0.},
+ { 0., 0., 1.},
+ };
+
+ pRegion pr;
+ RIter rit = M_regionIter(mesh);
+ while ( ( pr = RIter_next(rit) ) )
+ {
+ pPList rVerts = R_vertices(pr);
+ double dist[4];
+ void * temp = NULL;
+ pVertex pv;
+ int i = 0;
+ while ( ( pv = (pVertex)PList_next(rVerts,&temp) ) )
+ {
+ dist[i] = getDistance(pv);
+ i++;
+ }
+ PList_delete(rVerts);
+
+ double ijac[3][3], detj;
+ detj = R_invJacobian(pr,ijac);
+
+ void * del;
+ if ( EN_getDataPtr((pEntity)pr,rGradId,&del) && del ) delete [] (double*)del;
+ double * grad = new double[3];
+ for ( int iC=0; iC<3; iC++)
+ {
+ grad[iC] = 0.;
+ for (int iSF=0; iSF<4; iSF++) {
+ grad[iC] += dist[iSF] * ( gsf[iSF][0] * ijac[0][iC] +
+ gsf[iSF][1] * ijac[1][iC] +
+ gsf[iSF][2] * ijac[2][iC] );
+ }
+ }
+
+ EN_attachDataPtr((pEntity)pr,rGradId,grad);
+ }
+ RIter_delete(rit);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::clearGradientInElements() const
+ {
+ pRegion pr;
+ RIter rit = M_regionIter(mesh);
+ while ( ( pr = RIter_next(rit) ) )
+ {
+ EN_deleteData((pEntity)pr,rGradId);
+ }
+ RIter_delete(rit);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::computeGradientAtVertices()
+ {
+ computeGradientInElements();
+
+ pVertex pv;
+ VIter vit = M_vertexIter(mesh);
+ while ( ( pv = VIter_next(vit) ) )
+ {
+ void * del;
+ if ( EN_getDataPtr((pEntity)pv,vGradId,&del) && del ) delete [] (double*)del;
+ double * grad = new double[3];
+ for (int i=0; i<3; i++) grad[i] = 0.;
+
+ pPList vRegs = V_regions(pv);
+ void * temp = NULL;
+ void * rGrad = NULL;
+ pRegion pr;
+ while ( pr = (pRegion)PList_next(vRegs,&temp) )
+ {
+ if ( !EN_getDataPtr((pEntity)pr,rGradId,&rGrad) ) throw;
+ grad[0] += ((double*)rGrad)[0];
+ grad[1] += ((double*)rGrad)[1];
+ grad[2] += ((double*)rGrad)[2];
+ }
+
+ int nRegs = PList_size(vRegs);
+ PList_delete(vRegs);
+ double invNRegs = 1. / (double)nRegs;
+ for (int i=0; i<3; i++) grad[i] *= invNRegs;
+
+ EN_attachDataPtr((pEntity)pv,vGradId,grad);
+ }
+ VIter_delete(vit);
+
+ clearGradientInElements();
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::clearGradientAtVertices()
+ {
+ pVertex pv;
+ void *tmp;
+ VIter vit = M_vertexIter(mesh);
+ while ( ( pv = VIter_next(vit) ) )
+ {
+ if ( EN_getDataPtr((pEntity)pv,vGradId, &tmp) ) {
+ EN_deleteData((pEntity)pv,vGradId);
+ }
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ bool distanceFunction::getGradient(const pVertex pv, double grad[3]) const
+ {
+ void * tmp;
+ if ( !EN_getDataPtr((pEntity)pv,vGradId,&tmp) ) return false;
+ for (int i=0; i<3; i++) grad[i] = ((double*) tmp)[i];
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool distanceFunction::getCurvatureOnEntity(const pEntity entity,
+ const double xyz[3],
+ double *curv) const
+ {
+ int type = EN_type(entity);
+ switch(type) {
+ case 0: return getCurvature((pVertex)entity,curv);
+ case 1: {
+ double u = E_linearParams((pEdge)entity,xyz);
+ double c[2];
+ if ( !getCurvature(E_vertex((pEdge)entity,0), &(c[0])) ||
+ !getCurvature(E_vertex((pEdge)entity,1), &(c[1])) ) return false;
+ *curv = (1.-u) * c[0] + u * c[1];
+ return true;
+ }
+ case 2: {
+ double u[2];
+ F_linearParams((pFace)entity,xyz,u);
+ double c[3];
+ if ( !getCurvature(F_vertex((pFace)entity,0), &(c[0])) ||
+ !getCurvature(F_vertex((pFace)entity,1), &(c[1])) ||
+ !getCurvature(F_vertex((pFace)entity,2), &(c[2])) ) return false;
+
+ *curv = (1.-u[0]-u[1]) * c[0] + u[0] * c[1] + u[1] * c[2];
+ return true;
+ }
+ case 3: {
+ double u[3];
+ R_linearParams((pRegion)entity, xyz, u);
+ double c[4];
+ if ( !getCurvature(R_vertex((pRegion)entity,0), &(c[0])) ||
+ !getCurvature(R_vertex((pRegion)entity,1), &(c[1])) ||
+ !getCurvature(R_vertex((pRegion)entity,2), &(c[2])) ||
+ !getCurvature(R_vertex((pRegion)entity,3), &(c[3])) ) return false;
+
+ *curv = (1.-u[0]-u[1]-u[2]) * c[0] + u[0] * c[1] + u[1] * c[2] + u[2] * c[3];
+ return true;
+ }
+ default: throw;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ bool distanceFunction::getGradientOnEntity(const pEntity entity,
+ const double xyz[3],
+ double grad[3]) const
+ {
+ int type = EN_type(entity);
+ switch(type) {
+ case 0: return getGradient((pVertex)entity,grad);
+ case 1: return getGradientOnEdge((pEdge)entity,xyz,grad);
+ case 2: return getGradientOnFace((pFace)entity,xyz,grad);
+ case 3: return getGradientOnRegion((pRegion)entity,xyz,grad);
+ default: throw;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ bool distanceFunction::getGradientOnEdge(const pEdge edge,
+ const double xyz[3],
+ double grad[3]) const
+ {
+ double u = E_linearParams(edge,xyz);
+ return getGradientOnEdgeParam(edge,u,grad);
+ }
+
+ // -------------------------------------------------------------------
+ bool distanceFunction::getGradientOnEdgeParam(const pEdge pE,
+ const double u,
+ double grad[3]) const
+ {
+ double g0[3], g1[3];
+ if ( !getGradient(E_vertex(pE,0), g0) ||
+ !getGradient(E_vertex(pE,1), g1) ) return false;
+
+ for (int i=0; i<3; i++) grad[i] = (1.-u) * g0[i] + u * g1[i];
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool distanceFunction::getGradientOnFace(const pFace face,
+ const double xyz[3],
+ double grad[3]) const
+ {
+ double u[2];
+ F_linearParams(face,xyz,u);
+ return getGradientOnFaceParam(face,u,grad);
+ }
+
+ // -------------------------------------------------------------------
+ bool distanceFunction::getGradientOnFaceParam(const pFace face,
+ const double u[2],
+ double grad[3]) const
+ {
+ double g0[3], g1[3], g2[3];
+ if ( !getGradient(F_vertex(face,0), g0) ||
+ !getGradient(F_vertex(face,1), g1) ||
+ !getGradient(F_vertex(face,2), g2) ) return false;
+
+ for (int i=0; i<3; i++) grad[i] = (1.-u[0]-u[1]) * g0[i] + u[0] * g1[i] + u[1] * g2[i];
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ bool distanceFunction::getGradientOnRegion(const pRegion region,
+ const double xyz[3],
+ double grad[3]) const
+ {
+ double u[3];
+ R_linearParams(region, xyz, u);
+ return getGradientOnRegionParam(region, u, grad);
+ }
+
+ // -------------------------------------------------------------------
+ bool distanceFunction::getGradientOnRegionParam(const pRegion region,
+ const double u[3],
+ double grad[3]) const
+ {
+ double g0[3], g1[3], g2[3], g3[3];
+ if ( !getGradient(R_vertex(region,0), g0) ||
+ !getGradient(R_vertex(region,1), g1) ||
+ !getGradient(R_vertex(region,2), g2) ||
+ !getGradient(R_vertex(region,3), g3) ) return false;
+
+ for (int i=0; i<3; i++) {
+ grad[i] = (1.-u[0]-u[1]-u[2]) * g0[i] + u[0] * g1[i] + u[1] * g2[i] + u[2] * g3[i];
+ }
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::attachGradient(pVertex pv, double grad[3]) const
+ {
+ EN_attachDataPtr((pEntity)pv,vGradId,grad);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::outputDistance(const char * fn) const
+ {
+ MAdAttachedNodalDataOutput(mesh, fn, distId);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::outputGradAtVertices(const char * fn) const
+ {
+ MAdAttachedNodalDataVecOutput(mesh, fn, vGradId);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::clearVertexData(pVertex pv) const
+ {
+ EN_deleteData((pEntity)pv, vGradId);
+ EN_deleteData((pEntity)pv, distId);
+ EN_deleteData((pEntity)pv, vCurvId);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::computeCurvature(const std::set<pRegion>& regs)
+ {
+ int nR = regs.size(); // number of regions involved
+ int r2v[nR*4]; // regions vertices
+ std::map<pFace,pRegion> bFaces; // boundary faces (to 'regs') and
+ // the corresponding region
+ std::map<pVertex,int> v2i; // vertex pointers to local ids
+
+ // --- fill v2i and r2v ---
+
+ pVertex pv;
+ pRegion pr;
+ pFace pf;
+ std::map<pVertex,int>::iterator v2iIt;
+ int vId=0, rId=0;
+ std::set<pRegion>::const_iterator rIt = regs.begin();
+ for (; rIt != regs.end(); rIt++) {
+ // vertices
+ for (int i=0; i<4; i++) {
+ pv = R_vertex(*rIt,i);
+ v2iIt = v2i.find(pv);
+ if ( v2iIt == v2i.end() ) {
+ v2i[pv] = vId;
+ r2v[rId*4+i] = vId;
+ vId++;
+ }
+ else {
+ r2v[rId*4+i] = (*v2iIt).second;
+ }
+ }
+ // boundary faces
+ for (int i=0; i<4; i++) {
+ pf = R_face(*rIt,i);
+ pr = F_otherRegion(pf,*rIt);
+ if ( !pr || regs.find( pr ) == regs.end() ) {
+ bFaces[pf] = *rIt;
+ }
+ }
+ rId++;
+ }
+
+ // --- make the reverse mapping of v2i: i2v ---
+
+ int nV = v2i.size(); // number of vertices involved
+ pVertex i2v[nV]; // local ids to vertex pointers
+
+ std::map<pVertex,int>::const_iterator v2iIter = v2i.begin();
+ for(; v2iIter != v2i.end(); v2iIter++) i2v[v2iIter->second] = v2iIter->first;
+
+ // --- compute right hand side and mass matrix ---
+
+ double dPhidXi[4][3] = {
+ {-1., -1., -1.}, {1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.}
+ };
+
+ double over12 = 1./12.;
+ double over24 = 1./24.;
+
+ double rhs[nV], MLump[nV];
+ for (int i=0; i<nV; i++) {
+ rhs[i] = 0.;
+ MLump[i] = 0.;
+ }
+
+ void * tmpP;
+ double vGrad[4][3];
+ double ijac[3][3], detJ, dPhiDx[4][3];
+ int iR = 0;
+ for ( rIt = regs.begin(); rIt != regs.end(); rIt++ )
+ {
+ // get inverse Jacobian and determinant
+ detJ = R_invJacobian(*rIt,ijac);
+
+ // --- shape functions gradients and distance gradients ---
+ for (int iSF=0; iSF<4; iSF++)
+ {
+ int iId = r2v[iR*4+iSF];
+ assert ( EN_getDataPtr( (pEntity) ( i2v[iId] ), vGradId, &tmpP) );
+ for ( int iC=0; iC<3; iC++) {
+ dPhiDx[iSF][iC] = ( dPhidXi[iSF][0] * ijac[0][iC] +
+ dPhidXi[iSF][1] * ijac[1][iC] +
+ dPhidXi[iSF][2] * ijac[2][iC] );
+ vGrad[iSF][iC] = ((double*)tmpP)[iC];
+ }
+ }
+
+ // --- rhs and mass matrix ---
+ int iId, jSF;
+ for (int iSF=0; iSF<4; iSF++) {
+ iId = r2v[iR*4+iSF];
+ for (jSF=0; jSF<4; jSF++) {
+ rhs[iId] -= over24 * detJ * dotProd( dPhiDx[iSF], vGrad[jSF] );
+ }
+ MLump[iId] += over24 * detJ;
+ }
+
+ // --- boundary term ---
+
+ double nor[3], term, detJ;
+ pPList fVerts;
+ for (int iF=0; iF<4; iF++ )
+ {
+ pf = R_face(*rIt, iF);
+ if ( bFaces.find(pf) != bFaces.end() )
+ {
+ // we will need the outgoing normal...
+ // ... and the ordered vertices ...
+ F_normal(pf,nor);
+ normalizeVec(nor,nor);
+ if ( R_dirUsingFace(*rIt,pf) ) fVerts = F_vertices(pf, 1);
+ else {
+ fVerts = F_vertices(pf, 0);
+ for(int i=0; i<3; i++) nor[i] = -1.*nor[i];
+ }
+
+ // ... the jacobian of the face ...
+ detJ = 2. * F_area(pf);
+
+ // ... the gradient of distance at vertices.
+ for (int iVF=0; iVF<3; iVF++) {
+ pv = (pVertex)PList_item(fVerts,iVF);
+ EN_getDataPtr( (pEntity)pv, vGradId, &tmpP);
+ for(int i=0; i<3; i++) vGrad[iVF][i] = ((double*)tmpP)[i];
+ }
+
+ // compute the term
+ for (int iVF=0; iVF<3; iVF++) {
+ pv = (pVertex)PList_item(fVerts,iVF);
+ int iId = v2i.find(pv)->second;
+ for (int jVF=0; jVF<3; jVF++) {
+ if ( iVF == jVF ) {
+ rhs[iId] += over12 * detJ * dotProd( nor, vGrad[jVF] );
+ }
+ else {
+ rhs[iId] += over24 * detJ * dotProd( nor, vGrad[jVF] );
+ }
+ }
+ }
+ PList_delete(fVerts);
+ }
+ }
+
+ iR++;
+ }
+
+
+ // --- solve the system to find curvatures ---
+ for (int iV=0; iV<nV; iV++)
+ {
+ EN_attachDataDbl((pEntity)(i2v[iV]),vCurvId, fabs( rhs[iV] / MLump[iV] ));
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::computeGradientAndCurvature(const std::set<pRegion>& regs)
+ {
+ int nR = regs.size(); // number of regions involved
+ int r2v[nR*4]; // regions vertices
+ std::map<pFace,pRegion> bFaces; // boundary faces (to 'regs') and
+ // the corresponding region
+ std::map<pVertex,int> v2i; // vertex pointers to local ids
+
+ // --- fill v2i and r2v ---
+
+ pVertex pv;
+ pRegion pr;
+ pFace pf;
+ std::map<pVertex,int>::iterator v2iIt;
+ int vId=0, rId=0;
+ std::set<pRegion>::const_iterator rIt = regs.begin();
+ for (; rIt != regs.end(); rIt++) {
+ // vertices
+ for (int i=0; i<4; i++) {
+ pv = R_vertex(*rIt,i);
+ v2iIt = v2i.find(pv);
+ if ( v2iIt == v2i.end() ) {
+ v2i[pv] = vId;
+ r2v[rId*4+i] = vId;
+ vId++;
+ }
+ else {
+ r2v[rId*4+i] = (*v2iIt).second;
+ }
+ }
+ // boundary faces
+ for (int i=0; i<4; i++) {
+ pf = R_face(*rIt,i);
+ pr = F_otherRegion(pf,*rIt);
+ if ( !pr || regs.find( pr ) == regs.end() ) {
+ bFaces[pf] = *rIt;
+ }
+ }
+ rId++;
+ }
+
+ // --- make the reverse mapping of v2i: i2v ---
+
+ int nV = v2i.size(); // number of vertices involved
+ pVertex i2v[nV]; // local ids to vertex pointers
+
+ std::map<pVertex,int>::const_iterator v2iIter = v2i.begin();
+ for(; v2iIter != v2i.end(); v2iIter++) i2v[v2iIter->second] = v2iIter->first;
+
+ // --- compute right hand side and mass matrix ---
+
+ double dPhidXi[4][3] = {
+ {-1., -1., -1.}, {1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.}
+ };
+
+ double sixth = 1./6.;
+ double oneOver60 = 1./60.;
+ double oneOver120 = 1./120.;
+
+ double rhs[nV], MLump[nV];
+ double vGrad[nV*3]; // distance gradients computed on the vertices
+ int v_nR[nV]; // number of involved regions around vertices
+ for (int i=0; i<nV; i++) {
+ rhs[i] = 0.;
+ MLump[i] = 0.;
+ v_nR[i] = 0;
+ for (int j=0; j<3; j++) vGrad[3*i+j] = 0.;
+ }
+
+
+ double dist[4], ijac[3][3], detJ, dPhiDx[4][3];
+ double rGrad[3];
+ int iR = 0;
+ for ( rIt = regs.begin(); rIt != regs.end(); rIt++ )
+ {
+ // get distances
+ for (int iV = 0; iV<4; iV++) dist[iV] = getDistance(R_vertex(*rIt,iV));
+
+ // get inverse Jacobian and determinant
+ detJ = R_invJacobian(*rIt,ijac);
+
+ // --- gradients ---
+ rGrad[0] = 0.; rGrad[1] = 0.; rGrad[2] = 0.;
+ for (int iSF=0; iSF<4; iSF++)
+ {
+ for ( int iC=0; iC<3; iC++) {
+ dPhiDx[iSF][iC] = ( dPhidXi[iSF][0] * ijac[0][iC] +
+ dPhidXi[iSF][1] * ijac[1][iC] +
+ dPhidXi[iSF][2] * ijac[2][iC] );
+ rGrad[iC] += dist[iSF] * dPhiDx[iSF][iC];
+ }
+ }
+ normalizeVec(rGrad,rGrad);
+ for (int iSF=0; iSF<4; iSF++)
+ {
+ for ( int iC=0; iC<3; iC++) {
+ vGrad[( r2v[iR*4+iSF] )*3+iC] += rGrad[iC];
+ }
+ v_nR[ r2v[iR*4+iSF] ] ++;
+ }
+
+ // --- rhs and mass matrix ---
+ int iId, jId;
+ double detjO60 = detJ * oneOver60;
+ double detjO120 = detJ * oneOver120;
+ for (int iSF=0; iSF<4; iSF++) {
+ iId = r2v[iR*4+iSF];
+ rhs[iId] -= sixth * detJ * (dPhiDx[iSF][0] * rGrad[0] +
+ dPhiDx[iSF][1] * rGrad[1] +
+ dPhiDx[iSF][2] * rGrad[2] );
+
+ for (int j=0; j<4; j++) {
+ if ( iSF == j ) {
+ MLump[ iId ] += detjO60;
+ }
+ else {
+ MLump[ iId ] += detjO120;
+ }
+ }
+ }
+
+ // --- boundary term ---
+
+ double nor[3], term;
+ for (int iF=0; iF<4; iF++ )
+ {
+ pf = R_face(*rIt, iF);
+ if ( bFaces.find(pf) != bFaces.end() )
+ {
+ // we will need the outgoing normal...
+ // ... and the ordered vertices ...
+ F_normal(pf,nor);
+ normalizeVec(nor,nor);
+ pPList fVerts;
+ if ( R_dirUsingFace(*rIt,pf) ) fVerts = F_vertices(pf, 1);
+ else {
+ fVerts = F_vertices(pf, 0);
+ for(int i=0; i<3; i++) nor[i] = -1.*nor[i];
+ }
+
+ // ... the jacobian of the face ...
+ double detJ = 2. * F_area(pf);
+
+ // compute the term
+// #warning "debug: analytical grad"
+// if ( nor[0] > 0.5 ) {
+// printVec(rGrad,"rGrad");
+// rGrad[0]=2;
+// rGrad[1]=0.; rGrad[2]=0.;
+// }
+// if ( nor[0] < -0.5 ) {
+// rGrad[0]=0;
+// rGrad[1]=0.; rGrad[2]=0.;
+// }
+// else {
+// rGrad[1]=0.; rGrad[2]=0.;
+// }
+
+ term = sixth * dotProd( nor, rGrad ) * detJ;
+ for (int iVF=0; iVF<3; iVF++) {
+ rhs [ v2i[(pVertex)PList_item(fVerts,iVF)] ] += term;
+ }
+ }
+ }
+
+ iR++;
+ }
+
+// fprintf (frg,"};\n");
+// fclose (frg);
+// #warning "debug output rhs"
+// FILE *f = fopen ("testrhs.pos", "w");
+// fprintf (f,"View\" mesh \" {\n");
+// iR = 0;
+// for ( rIt = regs.begin(); rIt != regs.end(); rIt++ )
+// {
+// // get the coordinates
+// double xyz[4][3];
+// R_coordP1(*rIt, xyz);
+
+// // get the data at nodes
+// double data[4];
+// pPList verts = R_vertices(pr);
+// void* tmp = 0;
+// int i = 0;
+// while ( pEntity pent = PList_next(verts,&tmp) ) {
+// // data[i] = rhs2(v2i[(pVertex)pent]);
+// data[i] = rhs[r2v[iR*4+i]];
+// i++;
+// }
+// PList_delete(verts);
+
+// // write an element
+// fprintf (f,"SS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g};\n",
+// xyz[0][0],xyz[0][1],xyz[0][2],
+// xyz[1][0],xyz[1][1],xyz[1][2],
+// xyz[2][0],xyz[2][1],xyz[2][2],
+// xyz[3][0],xyz[3][1],xyz[3][2],
+// data[0],data[1],data[2],data[3]);
+
+// iR++;
+// }
+// fprintf (f,"};\n");
+// fclose (f);
+
+
+ // --- solve the system to find curvatures ---
+ for (int iV=0; iV<nV; iV++)
+ {
+ EN_attachDataDbl((pEntity)(i2v[iV]),vCurvId, fabs( rhs[iV] / MLump[iV] ));
+ }
+
+ // --- compute gradients at vertices ---
+ int nbRV;
+ void * del;
+ for ( int iV=0; iV<nV; iV++ )
+ {
+ pv = i2v[iV];
+ if ( EN_getDataPtr((pEntity)pv,vGradId,&del) && del ) delete [] (double*)del;
+
+ double * grad = new double[3];
+ for (int iC=0; iC<3; iC++) grad[iC] = vGrad[iV*3+iC] / (double)(v_nR[iV]);
+
+ EN_attachDataPtr((pEntity)pv,vGradId,grad);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ // GC: to be improved
+ void distanceFunction::smoothCurvature(int nbSmoothings) const
+ {
+ pVertex pv, pv2;
+ double curv, weights, locCurv;
+ pPList vEdges;
+ pEdge edge;
+
+ for (int iS=0; iS < nbSmoothings; iS++)
+ {
+ VIter vit = M_vertexIter(mesh);
+ while ( ( pv = VIter_next(vit) ) )
+ {
+ if ( EN_getDataDbl((pEntity)pv,vCurvId,&locCurv ) )
+ {
+ weights = 0.;
+ curv = 0.;
+ vEdges = V_edges(pv);
+ void * tmp = NULL;
+ while ( ( edge = (pEdge)PList_next(vEdges,&tmp) ) ) {
+ double tmpCurv;
+ pv2 = E_otherVertex(edge,pv);
+ if ( EN_getDataDbl((pEntity)pv2,vCurvId,&tmpCurv ) )
+ {
+ double invDistSq = 1. / E_length(edge);
+ curv += tmpCurv * invDistSq;
+ weights += invDistSq;
+ }
+ }
+
+ if ( weights < MAdTOL ) curv = locCurv;
+ else {
+ curv /= weights;
+ curv = 0.5 * ( curv + locCurv );
+ }
+
+ EN_attachDataDbl((pEntity)pv,vCurvId, curv);
+ }
+ }
+ VIter_delete(vit);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ bool distanceFunction::getCurvature(const pVertex pv, double *c) const
+ {
+ if ( EN_getDataDbl((pEntity)pv, vCurvId, c) ) return true;
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::attachCurvature(pVertex pv, double curv) const
+ {
+ EN_attachDataDbl((pEntity)pv,vCurvId,curv);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::clearCurvature() const
+ {
+ pVertex pv;
+ VIter vit = M_vertexIter(mesh);
+ while ( ( pv = VIter_next(vit) ) )
+ {
+ EN_deleteData((pEntity)pv,vCurvId);
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ void distanceFunction::outputCurvature(const char * fn) const
+ {
+ MAdAttachedNodalDataOutput(mesh, fn, vCurvId);
+ }
+
+ // -------------------------------------------------------------------
+}
diff --git a/Adapt/utils/DistanceFunction.h b/Adapt/utils/DistanceFunction.h
new file mode 100644
index 0000000..1e8b074
--- /dev/null
+++ b/Adapt/utils/DistanceFunction.h
@@ -0,0 +1,134 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_DISTANCEFUNCTION
+#define _H_DISTANCEFUNCTION
+
+#include "MeshDataBaseInterface.h"
+#include "DistanceToPoints.h"
+#include <set>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // This class computes and stores:
+ // - the distance to a set of vertices, edges or faces
+ // (as attached double),
+ // - the gradient of the distance (as attached pointer),
+ // - the Laplacian of the distance (as attached double).
+ //
+ // There are two ways to compute the distance:
+ // - to a set of vertices (inacurate to represent a wall)
+ // - to a set of edges(2D)/faces(3D) (more accurate, more expensive)
+ // The choice is governed by the variable 'distToEntities'
+ // -------------------------------------------------------------------
+ class distanceFunction {
+
+ public:
+
+ distanceFunction(pMesh m, bool _distToEntities);
+ ~distanceFunction();
+
+ void computeTree(const std::set<pVertex>&, const std::set<pEntity>&);
+
+ void clearVertexData(pVertex pv) const;
+
+ // Distance
+
+ void computeAllDistances() const;
+ double getDistance(const pVertex pv) const;
+ void clearDistance(const pVertex pv) const;
+ void clearDistances() const;
+
+ double computeDistance(const double xyz[3]) const;
+ double computeDistSq (const double xyz[3]) const;
+
+ void outputDistance(const char * fn) const;
+
+ // Gradient of the distance
+
+ void computeAllDistAndGrad() const; // the most accurate for gradients
+
+ void computeGradientAtVertices(); // not accurate
+ void clearGradientAtVertices();
+ bool getGradient(const pVertex pv, double grad[3]) const;
+ bool getGradientOnEntity(const pEntity entity,
+ const double xyz[3],
+ double grad[3]) const;
+ void attachGradient(pVertex pv, double grad[3]) const;
+
+ void outputGradAtVertices(const char * fn) const;
+
+ // Curvature ( Laplacian of the distance )
+
+ void computeGradientAndCurvature(const std::set<pRegion>& regs); // not accurate...
+
+ void computeCurvature(const std::set<pRegion>& regs);
+ void smoothCurvature(int nbSmoothings=1) const;
+ bool getCurvature(const pVertex pv, double *c) const;
+ bool getCurvatureOnEntity(const pEntity entity,
+ const double xyz[3],
+ double *curv) const;
+ void clearCurvature() const;
+ void attachCurvature(pVertex pv, double curv) const;
+
+ void outputCurvature(const char * fn) const;
+
+ private:
+
+ double computeDistance(const pVertex pv) const;
+ void computeGradientInElements() const;
+ void clearGradientInElements() const;
+
+ bool getGradientOnEdge(const pEdge edge,
+ const double xyz[3],
+ double grad[3]) const;
+ bool getGradientOnEdgeParam(const pEdge pE,
+ const double u,
+ double grad[3]) const;
+ bool getGradientOnFace(const pFace face,
+ const double xyz[3],
+ double grad[3]) const;
+ bool getGradientOnFaceParam(const pFace face,
+ const double u[2],
+ double grad[3]) const;
+ bool getGradientOnRegion(const pRegion region,
+ const double xyz[3],
+ double grad[3]) const;
+ bool getGradientOnRegionParam(const pRegion region,
+ const double u[3],
+ double grad[3]) const;
+
+ private:
+
+ pMesh mesh;
+ pMeshDataId distId, vGradId, rGradId, vCurvId;
+
+ // true: distance computed to a set of edges (2D) or faces (3D)
+ // false: distance computed to a set of vertices
+ bool distToEntities;
+
+ int nVert, nEnt;
+ int nVE; // number of vertices in a wall entity
+ double * xyzV; // coordinates of the vertices sorted by local ids with contiguous xyz
+ int * entToV; // entities vertices (by local id)
+ std::multimap<int,int> vToEnt; // vertices entities
+ SearchTool * kdSearch;
+ std::map<pVertex,int> pvToSearchId;
+
+ };
+
+ // -------------------------------------------------------------------
+}
+
+#endif
diff --git a/Adapt/utils/DistanceToPoints.h b/Adapt/utils/DistanceToPoints.h
new file mode 100644
index 0000000..149be91
--- /dev/null
+++ b/Adapt/utils/DistanceToPoints.h
@@ -0,0 +1,148 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_DISTANCETOPOINTS
+#define _H_DISTANCETOPOINTS
+
+#ifdef _HAVE_ANN_
+#include <ANN/ANN.h>
+#endif
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class MAd_searchTool {
+
+ public:
+ MAd_searchTool() {
+ printf("Error: no search tool implemented: flag _HAVE_ANN_ not set\n");
+ throw;
+ }
+ void reset() { throw; }
+ void allocatePoints(int n) { throw; }
+ void addPoint(int index, double xyz[3]) { throw; }
+ void allocateTree(int n) { throw; }
+ double computeDistanceSq(const double xyz[3], int * id=NULL) const { throw; }
+ };
+
+ // -------------------------------------------------------------------
+#ifdef _HAVE_ANN_
+ class ANN_searchTool {
+
+ public:
+
+ ANN_searchTool()
+ {
+ kdTree = NULL;
+ points = NULL;
+ }
+
+ ~ANN_searchTool()
+ {
+ if (kdTree) { delete kdTree; kdTree = NULL; }
+ if (points) { annDeallocPts(points); points = NULL; }
+ annClose();
+ }
+
+ void reset()
+ {
+ if (kdTree) { delete kdTree; kdTree = NULL; }
+ if (points) { annDeallocPts(points); points = NULL; }
+ }
+
+ void allocatePoints(int n)
+ {
+ if (points) annDeallocPts(points);
+ points = annAllocPts(n,3);
+ }
+
+ void addPoint(int index, double xyz[3])
+ {
+ for (int i=0; i<3; i++) points[index][i] = xyz[i];
+ }
+
+ void allocateTree(int n)
+ {
+ if (kdTree) delete kdTree;
+ kdTree = new ANNkd_tree(points, n, 3);
+ }
+
+ double computeDistanceSq(const double xyz[3], int * id=NULL) const
+ {
+ if (!kdTree) {
+ printf("Error: no research tree built\n");
+ throw;
+ }
+
+ double xyz_copy[3]; // because the first argument of annkSearch is not const
+ for (int i=0; i<3; i++) xyz_copy[i] = xyz[i];
+ int maxpts = 1;
+ // the use of allocation is done due to ms visual c++ compiler
+ // that do not support c99 standard (it uses the c95 et c++98 standards)
+ ANNidx* index= new ANNidx[maxpts];
+ ANNdist* distSq= new ANNdist[maxpts];
+ kdTree->annkSearch(xyz_copy, maxpts, index, distSq);
+ double theDistSq = distSq[0];
+ if ( id ) *id = index[0];
+ delete [] index;
+ delete [] distSq;
+ return theDistSq;
+ }
+
+ // Compute gradient of the square distance to the cloud of points
+ // by non-centered differences. Central differences would lead to
+ // zero gradients for points located on the walls (distance is not signed).
+ double gradDistanceSq(const double xyz[3], double grad[3]) const
+ {
+ double dSq = computeDistanceSq(xyz);
+ double eps = 1.e-3;
+ double dEps[2];
+
+ int maxpts = 1;
+ ANNidx* index= new ANNidx[maxpts];
+ ANNdist* distSq= new ANNdist[maxpts];
+ double tmp[3];
+ tmp[0] = xyz[0]; tmp[1] = xyz[1]; tmp[2] = xyz[2];
+ for (int i=0; i<3; i++) {
+ tmp[i] += eps;
+ kdTree->annkSearch(tmp, maxpts, index, distSq);
+ dEps[0] = distSq[0];
+ tmp[i] -= 2*eps;
+ kdTree->annkSearch(tmp, maxpts, index, distSq);
+ dEps[1] = distSq[1];
+ tmp[i] += eps;
+ grad[i] = 1000. * ( dEps[1] - dEps[0] );
+ }
+ }
+
+ private:
+
+ ANNkd_tree * kdTree;
+ ANNpoint * points;
+ };
+
+ typedef ANN_searchTool SearchTool;
+
+ // -------------------------------------------------------------------
+#else
+
+ typedef MAd_searchTool SearchTool;
+
+ // -------------------------------------------------------------------
+#endif
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/utils/History.cc b/Adapt/utils/History.cc
new file mode 100644
index 0000000..a783c30
--- /dev/null
+++ b/Adapt/utils/History.cc
@@ -0,0 +1,144 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "History.h"
+
+#include <stdarg.h>
+#include <fstream>
+#include <iostream>
+#include <stdlib.h>
+using std::ostream;
+
+namespace MAd {
+
+ static int actionIntParameters[UNKNOWN_ACTION] = {1,1,1,1,1};
+
+ // -------------------------------------------------------------------
+ void History::initialize()
+ {
+ open = false;
+ refCount = -1;
+ }
+
+ // -------------------------------------------------------------------
+ void History::finalize()
+ {
+ journal.clear();
+ refJournal.clear();
+ }
+
+ // -------------------------------------------------------------------
+ void History::add(int ot, actionType at, ...)
+ {
+ if ( !open ) return;
+
+ va_list ap;
+ va_start(ap, at);
+
+ std::vector<int> intParams;
+ for (int iInt=0; iInt < actionIntParameters[at]; iInt++) {
+ intParams.push_back(va_arg(ap, int));
+ }
+
+ va_end(ap);
+
+ action act;
+ act.opType = ot;
+ act.actType = at;
+ act.intParams = intParams;
+
+ add(act);
+ }
+
+ // -------------------------------------------------------------------
+ void History::add(action act)
+ {
+ if ( !open ) return;
+
+ journal.push_back(act);
+
+ if ( !compare() ) {
+ std::cerr << "Error in History: operations are not the same as in the reference journal\n";
+ flushJournal("journal_for_diff");
+ exit(1);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ bool History::compare()
+ {
+ if ( !open ) return false;
+
+ if ( refJournal.empty() || refCount >= (int) refJournal.size() ) return true;
+
+ for (; refCount < (int) journal.size(); refCount++) {
+ if ( journal[refCount] != refJournal[refCount] ) return false;
+ }
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void History::loadJournal(std::string name)
+ {
+ FILE * f = fopen(name.c_str(),"r");
+ if ( !f ) {
+ std::cerr << "Error: could not open file " << name << std::endl; throw;
+ }
+
+ int opType;
+ int actType;
+ while ( fscanf(f,"%d %d",&opType,&actType) != EOF ) {
+
+ std::vector<int> intParams;
+ int par;
+ for (int iPar=0; iPar<actionIntParameters[actType]; iPar++) {
+ fscanf(f,"%d",&par);
+ intParams.push_back(par);
+ }
+
+ action act;
+ act.opType = opType;
+ act.actType = (actionType) actType;
+ act.intParams = intParams;
+
+ refJournal.push_back(act);
+ }
+
+ fclose(f);
+
+ refCount = 0;
+ }
+
+ // -------------------------------------------------------------------
+ void History::flushJournal(ostream& out) const
+ {
+ for (int iAct=0; iAct < (int) journal.size(); iAct++) {
+ action act = journal[iAct];
+ out << act.opType << "\t" << act.actType;
+ for (int iP=0; iP<actionIntParameters[act.actType]; iP++) {
+ out << "\t"<< act.intParams[iP];
+ }
+ out << "\n";
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void History::flushJournal(std::string name) const
+ {
+ std::ofstream fileOut(name.c_str());
+ flushJournal(fileOut);
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/utils/History.h b/Adapt/utils/History.h
new file mode 100644
index 0000000..435c743
--- /dev/null
+++ b/Adapt/utils/History.h
@@ -0,0 +1,91 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_HISTORY
+#define _H_HISTORY
+
+#include "MAdSingleton.h"
+
+#include <vector>
+#include <ostream>
+#include <string>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ enum actionType {
+ OP_CHECKCONSTRAINTS = 0,
+ OP_CHECKGEOMETRY = 1,
+ OP_CHECKSHAPES = 2,
+ OPERATOR_APPLY = 3,
+ OPERATOR_UNAPPLY = 4,
+ UNKNOWN_ACTION = 5
+ };
+
+ struct action {
+ int opType;
+ actionType actType;
+ std::vector<int> intParams;
+
+ bool operator!=(const action& other) {
+ if ( opType != other.opType ) return true;
+ if ( actType != other.actType ) return true;
+ if ( intParams.size() != other.intParams.size() ) return true;
+ for (unsigned int i=0; i<intParams.size(); i++) {
+ if ( intParams[i] != other.intParams[i] ) return true;
+ }
+ return false;
+ }
+ };
+
+ // -------------------------------------------------------------------
+ class History {
+
+ public:
+
+ History() {};
+ ~History() {};
+
+ void initialize();
+ void finalize();
+
+ void openJournal() { open = true; };
+ void closeJournal() { open = false; };
+
+ void add(int, actionType,...);
+ void add(action);
+
+ bool compare();
+
+ void flushJournal(std::ostream& out) const;
+ void flushJournal(std::string name) const;
+
+ void loadJournal(std::string name);
+
+ private:
+
+ bool open; // indicates if the journal is in use
+
+ std::vector<action> journal; // list of actions
+
+ std::vector<action> refJournal; // journal to compare with
+ int refCount; // position of the next action to compare
+ };
+
+ // -------------------------------------------------------------------
+
+ typedef MAdSingleton<History> HistorySgl;
+
+}
+
+#endif
diff --git a/Adapt/utils/MAdLinearSystem.h b/Adapt/utils/MAdLinearSystem.h
new file mode 100644
index 0000000..7e6e58e
--- /dev/null
+++ b/Adapt/utils/MAdLinearSystem.h
@@ -0,0 +1,126 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LINEARSYSTEM_MAD
+#define _H_LINEARSYSTEM_MAD
+
+namespace MAd {
+
+ // A class that encapsulates a linear system solver interface :
+ // building a sparse matrix, solving a linear system
+
+ // -------------------------------------------------------------------
+ enum SolverType { GMRES, CG };
+
+ // -------------------------------------------------------------------
+ class MAdLinearSystem {
+
+ public:
+
+ MAdLinearSystem (): sType(GMRES),fill(0),eps(1.e-12) {}
+ virtual ~MAdLinearSystem () {}
+
+ public:
+
+ virtual bool isAllocated () const = 0;
+ virtual void allocate (int nbRows) = 0;
+ virtual void addToMatrix (int _row, int _col, double val) = 0;
+ virtual double getFromMatrix (int _row, int _col) const = 0;
+ virtual void addToRightHandSide (int _row, double val) = 0;
+ virtual double getFromRightHandSide (int _row) const = 0;
+ virtual double getFromSolution (int _row) const = 0;
+ virtual void zeroMatrix () = 0;
+ virtual void zeroRightHandSide () = 0;
+ virtual void reorder() = 0;
+ virtual int systemSolve () = 0;
+ virtual void set_nnz(int row,int nz){}
+ virtual void allocate_matrix(){}
+
+ virtual void setSolver(SolverType _type) {sType = _type;}
+ void setFillIn(int _k) {fill=_k;}
+ void setEps(double _eps) {eps=_eps;}
+ virtual void setPrec(double){}
+ virtual void setNoisy(int){}
+
+ protected:
+
+ SolverType sType;
+ int fill;
+ double eps;
+
+ };
+
+ // -------------------------------------------------------------------
+ class MAdLinearSystemNull : public MAdLinearSystem {
+
+ public:
+
+ MAdLinearSystemNull ()
+ {
+ printf("Error: no linear systems solver available\n");
+ throw;
+ }
+
+ public:
+
+ bool isAllocated () const { return false; }
+ void allocate (int nbRows) {}
+ void addToMatrix (int _row, int _col, double val) {}
+ double getFromMatrix (int _row, int _col) const { return 0.; }
+ void addToRightHandSide (int _row, double val) {}
+ double getFromRightHandSide (int _row) const { return 0.; }
+ double getFromSolution (int _row) const { return 0.; }
+ void zeroMatrix () {}
+ void zeroRightHandSide () {}
+ void reorder() {}
+ int systemSolve () { return 0; }
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_PETSC_
+#include "MAdLinearSystemPETSc.h"
+namespace MAd {
+ typedef MAdLinearSystemPETSc MAdLinearSystemDef;
+}
+#else
+
+#ifdef _HAVE_SPARSKIT_
+#include "MAdLinearSystemSparskit.h"
+namespace MAd {
+ typedef MAdLinearSystemSparskit MAdLinearSystemDef;
+}
+#else
+
+#ifdef _HAVE_GMM_
+#include "MAdLinearSystemGmm.h"
+namespace MAd {
+ typedef MAdLinearSystemGmm MAdLinearSystemDef;
+}
+#else
+namespace MAd {
+ typedef MAdLinearSystemNull MAdLinearSystemDef;
+}
+#endif // end gmm
+#endif // end sparskit
+#endif // end PETSc
+
+// -------------------------------------------------------------------
+
+#endif
+
+
diff --git a/Adapt/utils/MAdLinearSystemGmm.h b/Adapt/utils/MAdLinearSystemGmm.h
new file mode 100644
index 0000000..c2d986b
--- /dev/null
+++ b/Adapt/utils/MAdLinearSystemGmm.h
@@ -0,0 +1,111 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LINEARSYSTEMGMM_MAD
+#define _H_LINEARSYSTEMGMM_MAD
+
+#ifdef _HAVE_GMM_
+
+// Interface to GMM++
+
+#include "MAdLinearSystem.h"
+
+#include <gmm.h>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class MAdLinearSystemGmm : public MAdLinearSystem {
+
+ public :
+
+ MAdLinearSystemGmm () : MAdLinearSystem(), _a(0), _b(0), _x(0), _prec(1.e-8), _noisy(0) {}
+ ~MAdLinearSystemGmm ()
+ {
+ delete _a;
+ delete _b;
+ delete _x;
+ }
+
+ public:
+
+ bool isAllocated () const {return _a != 0;}
+ void allocate (int _nbRows)
+ {
+ if (_a) delete _a;
+ if (_x) delete _x;
+ if (_b) delete _b;
+ _a = new gmm::row_matrix< gmm::wsvector<double> >(_nbRows,_nbRows);
+ _b = new std::vector<double>(_nbRows);
+ _x = new std::vector<double>(_nbRows);
+ }
+ void addToMatrix (int _row, int _col, double _val)
+ {
+ if (_val != 0.0) (*_a)(_row, _col) += _val;
+ }
+ double getFromMatrix (int _row, int _col) const
+ {
+ return (*_a)(_row, _col);
+ }
+ void addToRightHandSide (int _row, double _val)
+ {
+ if (_val != 0.0) (*_b)[_row]+=_val;
+ }
+ double getFromRightHandSide (int _row) const
+ {
+ return (*_b)[_row];
+ }
+ double getFromSolution (int _row) const
+ {
+ return (*_x)[_row];
+ }
+ void zeroMatrix ()
+ {
+ gmm::clear(*_a);
+ }
+ void zeroRightHandSide ()
+ {
+ for (unsigned int i = 0; i < _b->size(); i++) (*_b)[i] = 0;
+ }
+ void reorder () {
+
+ }
+ void setPrec(double p){_prec=p;}
+ void setNoisy(int n){_noisy=n;}
+ int systemSolve ()
+ {
+ //gmm::ilut_precond< gmm::row_matrix< gmm::wsvector<double> > > P(*_a, fill, _prec);
+ gmm::ildltt_precond< gmm::row_matrix< gmm::wsvector<double> > > P(*_a, fill, _prec);
+ gmm::iteration iter(eps);
+ iter.set_noisy(_noisy);
+ // gmm::sequential_additive_schwarz(*_a, *_x, *_b, P, vB, iter, local_solver, global_solver)
+ if (sType==GMRES)gmm::gmres(*_a, *_x, *_b, P, 100, iter); // execute the GMRES algorithm
+ else gmm::cg(*_a, *_x, *_b, P, iter); // execute the CG algorithm
+ return 1;
+ }
+
+ private:
+
+ gmm::row_matrix<gmm::wsvector<double> > *_a;
+ std::vector<double> *_b, *_x;
+ double _prec;
+ int _noisy;
+ };
+
+ // -------------------------------------------------------------------
+
+#endif
+
+}
+
+#endif
diff --git a/Adapt/utils/MAdLinearSystemPETSc.h b/Adapt/utils/MAdLinearSystemPETSc.h
new file mode 100644
index 0000000..f5a68e0
--- /dev/null
+++ b/Adapt/utils/MAdLinearSystemPETSc.h
@@ -0,0 +1,215 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Richard Comblen, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LINEARSYSTEMPETSC_MAD
+#define _H_LINEARSYSTEMPETSC_MAD
+
+// -------------------------------------------------------------------
+// Interface to PETSc
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_PETSC_
+
+#include "MAdLinearSystem.h"
+#include "petsc.h"
+#include "petscksp.h"
+#include "petscmat.h"
+#include "petscvec.h"
+#include <iostream>
+
+namespace MAd {
+ class MAdLinearMatrixPETSc {
+ private:
+ int * nnz;
+ int local_size, global_size;
+ bool allocated, assembled;
+ public:
+ Mat mat;
+ MAdLinearMatrixPETSc(int _local_size, int _global_size) {
+ local_size = _local_size;
+ global_size = _global_size;
+ nnz = new int[local_size];
+ mat = NULL;
+ allocated = false;
+ assembled = false;
+ }
+ ~MAdLinearMatrixPETSc() {
+ if(mat) MatDestroy(mat);
+ delete [] nnz;
+ }
+ void set_nnz(int row, int nz){
+ nnz[row] = nz;
+ }
+ // You must call set_nnz before!
+ void allocate(){
+ if(!allocated){
+ MatCreate(PETSC_COMM_WORLD, &mat);
+ MatSetSizes(mat,local_size,local_size,global_size,global_size);
+ MatSetFromOptions(mat);
+ // MatMPIAIJSetPreallocationCSR(mat,sparsity->rowstart,sparsity->colind,NULL);
+ MatSeqAIJSetPreallocation(mat,0,nnz);
+ allocated=true;
+ }
+ }
+ void add(int row, int col, double val){
+ MatSetValue(mat, row, col, val, ADD_VALUES);
+ assembled = false;
+ }
+ void assemble()
+ {
+ if(assembled) return;
+ MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY);
+ MatAssemblyEnd (mat, MAT_FINAL_ASSEMBLY);
+#if PETSC_VERSION_MAJOR==3
+ MatSetOption(mat, MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);
+ MatSetOption(mat, MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
+#else
+ MatSetOption(mat, MAT_NO_NEW_NONZERO_LOCATIONS);
+#endif
+ assembled = true;
+ }
+ void zero(){
+ //assemble();
+ MatZeroEntries(mat);
+ }
+ };
+ class MAdLinearVectorPETSc {
+ private:
+ int local_size, global_size, nghosts;
+ double * entries;
+ public:
+ Vec vec;
+ MAdLinearVectorPETSc(int _local_size, int _global_size){
+ global_size = _global_size;
+ local_size = _local_size;
+ nghosts = 0;
+ entries = new double[local_size+nghosts];
+ VecCreateMPIWithArray(MPI_COMM_WORLD,local_size,global_size,entries,&vec);
+ VecAssemblyBegin(vec);
+ VecAssemblyEnd(vec);
+ VecSet(vec, 0);
+ get_array();
+ }
+ ~MAdLinearVectorPETSc(){
+ VecDestroy(vec);
+ delete []entries;// Check whether Petsc does destroy it or not...
+ }
+ inline double& operator()(int row){
+ return entries[row];
+ }
+ void zero(){
+ for(int i=0;i<local_size+nghosts;i++){
+ entries[i]=0;
+ }
+ }
+ void gather(){
+ // To be implemented - see slim_vector.cc
+ }
+ void scatter(){
+ // To be implemented - see slim_vector.cc
+ }
+ void get_array(){
+ VecGetArray(vec,&entries);
+ }
+ void restore_array(){
+ VecRestoreArray(vec,&entries);
+ }
+ };
+
+ // -------------------------------------------------------------------
+ class MAdLinearSystemPETSc : public MAdLinearSystem {
+
+ private:
+ MAdLinearMatrixPETSc * matrix;
+ MAdLinearVectorPETSc * rhs;
+ MAdLinearVectorPETSc * X;
+ KSP ksp;
+
+ public:
+
+ MAdLinearSystemPETSc():
+ MAdLinearSystem()
+ {
+ PetscInitialize(0,NULL, NULL, NULL);
+ KSPCreate(PETSC_COMM_WORLD, &ksp);
+ }
+ ~MAdLinearSystemPETSc ()
+ {
+ KSPDestroy(ksp);
+ delete matrix;
+ delete rhs;
+ delete X;
+ }
+ bool isAllocated () const {throw;}
+ void allocate (int nbRows){
+ int local_size, global_size;
+ local_size = global_size = nbRows;
+ matrix = new MAdLinearMatrixPETSc(local_size, global_size);
+ rhs = new MAdLinearVectorPETSc(local_size, global_size);
+ X = new MAdLinearVectorPETSc(local_size, global_size);
+ }
+ void addToMatrix (int row, int col, double val) {
+ matrix->add(row,col,val);
+ }
+ double getFromMatrix (int _row, int _col) const {
+ throw;
+ }
+ void addToRightHandSide (int row, double val) {
+ (*rhs)(row) += val;
+ }
+ double getFromRightHandSide (int row) const {
+ return (*rhs)(row);
+ }
+ double getFromSolution (int row) const {
+ return (*X)(row);
+ }
+ void zeroMatrix () {
+ matrix->zero();
+ }
+ void zeroRightHandSide () {
+ rhs->zero();
+ }
+ void reorder () {
+ }
+ void set_nnz(int row,int nz){
+ matrix->set_nnz(row,nz);
+ }
+ void allocate_matrix(){
+ matrix->allocate();
+ }
+ void setSolver(SolverType _type) {
+ }
+ int systemSolve () {
+ rhs->restore_array();
+ X->restore_array();
+ matrix->assemble();
+ std::string options;
+ options="-pc_type bjacobi -sub_pc_type icc -ksp_type cg -ksp_rtol 1e-6";
+// options="-pc_type hypre -pc_hypre_type boomeramg -pc_hypre_boomeramg_print_statistics -ksp_type gmres -ksp_rtol 1e-7 -ksp_monitor";
+ PetscOptionsInsertString(options.c_str());
+ KSPSetFromOptions(ksp);
+ KSPSetOperators (ksp, matrix->mat, matrix->mat, DIFFERENT_NONZERO_PATTERN);
+ KSPSolve(ksp, rhs->vec, X->vec);
+
+ X->get_array();
+ rhs->get_array();
+ KSPConvergedReason reason;
+ return KSPGetConvergedReason(ksp,&reason);
+ }
+
+ };
+}
+
+#endif
+
+#endif
diff --git a/Adapt/utils/MAdLinearSystemSparskit.h b/Adapt/utils/MAdLinearSystemSparskit.h
new file mode 100644
index 0000000..a578c1e
--- /dev/null
+++ b/Adapt/utils/MAdLinearSystemSparskit.h
@@ -0,0 +1,106 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LINEARSYSTEMSPARSKIT_MAD
+#define _H_LINEARSYSTEMSPARSKIT_MAD
+
+// -------------------------------------------------------------------
+// Interface to Y Saad's sparskit lib
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_SPARSKIT_
+
+#include "MAdLinearSystem.h"
+#include "MAdMessage.h"
+
+#include "CSR_Matrix.h"
+#include "CSR_Vector.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class MAdLinearSystemSparskit : public MAdLinearSystem {
+
+ public:
+
+ MAdLinearSystemSparskit ():
+ MAdLinearSystem(),_a(0),_b(0),_x(0)
+ {
+ }
+ ~MAdLinearSystemSparskit ()
+ {
+ delete _a;
+ delete _b;
+ delete _x;
+ }
+ bool isAllocated () const {return _a != 0;}
+ void allocate (int _nbRows)
+ {
+ if (_a) delete _a;
+ if (_b) delete _b;
+ if (_x) delete _x;
+ _a = new CSR_Matrix (_nbRows);
+ _b = new CSR_Vector (_nbRows);
+ _x = new CSR_Vector (_nbRows);
+ }
+ void addToMatrix (int _row, int _col, double _val) {
+ if (_val != 0.0) _a->AddMatrix (_row+1, _col+1, _val);
+ }
+ double getFromMatrix (int _row, int _col) const {
+ return _a->GetMatrix (_row+1,_col+1);
+ }
+ void addToRightHandSide (int _row, double _val) {
+ if (_val != 0.0) _b->AddVal(_row+1, _val);
+ }
+ double getFromRightHandSide (int _row) const {
+ return _b->GetVal (_row+1);
+ }
+ double getFromSolution (int _row) const {
+ return _x->GetVal (_row+1);
+ }
+ void zeroMatrix () {
+ _a->ZeroMatrix();
+ }
+ void zeroRightHandSide () {
+ _b->ZeroArray();
+ }
+ void reorder () {
+
+ }
+ void setSolver(SolverType _type) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,"CG not available in Sparskit, GMRES will be used\n");
+ sType = GMRES;
+ }
+ int systemSolve () {
+ _a->EndOfAssembly();
+ std::string solver = "gmres";
+ // if (sType == CG) solver = "cg";
+ SPARSKIT_LINEAR_SOLVER_ ( "rcmk","ilut",solver,fill,eps,*_a,*_b,*_x);
+ return 1;
+ }
+
+ private:
+
+ CSR_Matrix *_a;
+ CSR_Vector *_b;
+ CSR_Vector *_x;
+
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
+
+#endif
diff --git a/Adapt/utils/MAdStatistics.cc b/Adapt/utils/MAdStatistics.cc
new file mode 100644
index 0000000..5269899
--- /dev/null
+++ b/Adapt/utils/MAdStatistics.cc
@@ -0,0 +1,60 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdStatistics.h"
+
+using std::ostream;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void MAdStatistics::initialize()
+ {
+ t_eSplits = 0.;
+ t_eCollapses = 0.;
+ t_eSwaps = 0.;
+ t_rSlivers = 0.;
+ t_fSlivers = 0.;
+
+ num_eSplits = 0;
+ num_eCollapses = 0;
+ num_eSwaps = 0;
+
+ numInfLoops = 0;
+ }
+
+ // -------------------------------------------------------------------
+ void MAdStatistics::finalize()
+ {
+ }
+
+ // -------------------------------------------------------------------
+ void MAdStatistics::print(ostream& out) const
+ {
+ out << "\n*** Statistics about local mesh modifications *** \n\n";
+
+ out << "Time spent in the different operators:\n";
+ double t_Total = t_eSplits + t_eCollapses + t_eSwaps + t_rSlivers + t_fSlivers;
+ out << "Edge splits\tEdge collapses\tEdge swaps\tSlivers\tTotal\n"
+ << t_eSplits <<"\t"<< t_eCollapses <<"\t"<< t_eSwaps <<"\t"
+ << t_rSlivers+t_fSlivers <<"\t"<< t_Total <<"\n\n";
+
+ out << "Number of elementary operations (excluding sliver handling):\n";
+ out << "Edge splits\tEdge collapses\tEdge swaps\n"
+ << num_eSplits <<"\t"<< num_eCollapses <<"\t"<< num_eSwaps << "\n\n";
+
+ out << "Number of infinite loops:\t" << numInfLoops << "\n\n";
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/utils/MAdStatistics.h b/Adapt/utils/MAdStatistics.h
new file mode 100644
index 0000000..df95304
--- /dev/null
+++ b/Adapt/utils/MAdStatistics.h
@@ -0,0 +1,94 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADSTATISTICS
+#define _H_MADSTATISTICS
+
+#include "MAdSingleton.h"
+
+#include <iostream>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class MAdStatistics {
+
+ public:
+
+ MAdStatistics() {};
+ ~MAdStatistics() {};
+
+ void initialize();
+ void finalize();
+
+ void print(std::ostream& out) const;
+
+ // -----------------------
+ // CPU time
+ // -----------------------
+
+ private:
+
+ double t_eSplits, t_eCollapses, t_eSwaps, t_rSlivers, t_fSlivers;
+
+ public:
+
+ void addCPUESplits (double dt) { t_eSplits += dt; }
+ void addCPUECollapses (double dt) { t_eCollapses += dt; }
+ void addCPUESwaps (double dt) { t_eSwaps += dt; }
+ void addCPURSlivers (double dt) { t_rSlivers += dt; }
+ void addCPUFSlivers (double dt) { t_fSlivers += dt; }
+
+ double getCPUESplits () const { return t_eSplits; }
+ double getCPUECollapses () const { return t_eCollapses; }
+ double getCPUESwaps () const { return t_eSwaps; }
+ double getCPURSlivers () const { return t_rSlivers; }
+ double getCPUFSlivers () const { return t_fSlivers; }
+
+
+ // -----------------------------
+ // Elementary operations count
+ // -----------------------------
+
+ private:
+
+ int num_eSplits, num_eCollapses, num_eSwaps;
+
+ public:
+
+ void addNumESplits (int num) { num_eSplits += num; }
+ void addNumECollapses (int num) { num_eCollapses += num; }
+ void addNumESwaps (int num) { num_eSwaps += num; }
+
+
+ // -----------------------------
+ // Others
+ // -----------------------------
+
+ private:
+
+ int numInfLoops;
+
+ public:
+
+ void addInfiniteLoops(int num) { numInfLoops += num; }
+
+ };
+
+ // -------------------------------------------------------------------
+
+ typedef MAdSingleton<MAdStatistics> MAdStatisticsSgl;
+
+}
+
+#endif
diff --git a/Adapt/utils/MAdTimeManager.cc b/Adapt/utils/MAdTimeManager.cc
new file mode 100644
index 0000000..ea341e7
--- /dev/null
+++ b/Adapt/utils/MAdTimeManager.cc
@@ -0,0 +1,48 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdTimeManager.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void MAdTimeManager::initialize()
+ {
+ time = 0.;
+ }
+
+ // -------------------------------------------------------------------
+ void MAdTimeManager::finalize()
+ {
+ }
+
+ // -------------------------------------------------------------------
+ void MAdTimeManager::setTime(double _t)
+ {
+ time = _t;
+ }
+
+ // -------------------------------------------------------------------
+ void MAdTimeManager::incrementTime(double dt)
+ {
+ time += dt;
+ }
+
+ // -------------------------------------------------------------------
+ double MAdTimeManager::getTime() const
+ {
+ return time;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/utils/MAdTimeManager.h b/Adapt/utils/MAdTimeManager.h
new file mode 100644
index 0000000..c745d90
--- /dev/null
+++ b/Adapt/utils/MAdTimeManager.h
@@ -0,0 +1,49 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADTIMEMANAGER
+#define _H_MADTIMEMANAGER
+
+#include "MAdSingleton.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class MAdTimeManager {
+
+ public:
+
+ MAdTimeManager() {};
+ ~MAdTimeManager() {};
+
+ void initialize();
+ void finalize();
+
+ void setTime(double);
+ void incrementTime(double);
+
+ double getTime() const;
+
+ private:
+
+ double time;
+
+ };
+
+ // -------------------------------------------------------------------
+
+ typedef MAdSingleton<MAdTimeManager> MAdTimeManagerSgl;
+
+}
+
+#endif
diff --git a/Adapt/utils/NodalDataManager.cc b/Adapt/utils/NodalDataManager.cc
new file mode 100644
index 0000000..cad2d15
--- /dev/null
+++ b/Adapt/utils/NodalDataManager.cc
@@ -0,0 +1,614 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "NodalDataManager.h"
+#include "CallBackManager.h"
+#include "MAdOutput.h"
+
+#include "MSops.h"
+
+#include <iostream>
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::vector;
+using std::set;
+using std::ostream;
+using std::string;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void P1CBFunction (pPList before, pPList after, void *dataNames,
+ operationType type , pEntity ppp) {
+
+ set<string>* knownDataNames = static_cast<set<string>*>(dataNames);
+
+ switch (type) {
+ case MAd_ESPLIT: {
+ // In the edge split case, we have to interpolate the data at the new node
+
+ set<string>::const_iterator tIter = (*knownDataNames).begin();
+ set<string>::const_iterator tLast = (*knownDataNames).end();
+ for (; tIter != tLast; tIter++ ) {
+
+ pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+
+ // find the old edge
+ void *tmp=0;
+ pEntity pE = PList_next(before,&tmp);
+ double t = E_linearParams((pEdge)pE,(pVertex)ppp);
+
+ // get datas at old nodes
+ double data0 = 0.;
+ pVertex pV0 = E_vertex((pEdge)pE, 0);
+ int gotit0 = EN_getDataDbl((pEntity)pV0, dataId, &data0);
+
+ double data1 = 0.;
+ pVertex pV1 = E_vertex((pEdge)pE, 1);
+ int gotit1 = EN_getDataDbl((pEntity)pV1, dataId, &data1);
+
+ if (!gotit0 || !gotit1) {
+ printf("Error: one of the nodes has no data attached to with name %s",
+ (*tIter).c_str());
+ throw;
+ }
+
+ // Interpolate the data at the new node.
+ double newData = (1.-t) * data0 + t * data1;
+
+ // attach it
+ EN_attachDataDbl(ppp, dataId, newData);
+ }
+
+ break;
+ }
+ case MAd_ECOLLAPSE: {
+ // In the edge collapse case, we have to delete the datas attached to the deleted node
+
+ set<string>::const_iterator tIter = (*knownDataNames).begin();
+ set<string>::const_iterator tLast = (*knownDataNames).end();
+ for (; tIter != tLast; tIter++ ) {
+
+ pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+ EN_deleteData(ppp, dataId);
+ }
+
+ break;
+ }
+ case MAd_ESWAP:
+ case MAd_FSWAP: {
+ // nothing to be done (no modification at nodes)
+ break;
+ }
+ case MAd_RREMOVE: {
+ void * temp = NULL;
+ while ( pEntity pE = PList_next(before,&temp) ) {
+ if ( EN_type(pE) == 0 ) {
+ set<string>::const_iterator tIter = (*knownDataNames).begin();
+ set<string>::const_iterator tLast = (*knownDataNames).end();
+ for (; tIter != tLast; tIter++ ) {
+ pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+ EN_deleteData( (pVertex)pE, dataId);
+ }
+ }
+ }
+ break;
+ }
+ case MAd_UNKNOWNOPERATION:
+ case MAd_VERTEXMOVE:
+ case MAd_FCOLLAPSE:
+ case MAd_DESPLTCLPS:
+ default: {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Not implemented for mesh modification %d",
+ type);
+ }
+ }
+
+ }
+
+ // -------------------------------------------------------------------
+ void P1VecCBFunction (pPList before, pPList after, void *dataNames,
+ operationType type , pEntity ppp) {
+
+ set<string>* knownDataNames = static_cast<set<string>*>(dataNames);
+
+ switch (type) {
+ case MAd_ESPLIT: {
+ // In the edge split case, we have to interpolate the data at the new node
+
+ set<string>::const_iterator tIter = (*knownDataNames).begin();
+ set<string>::const_iterator tLast = (*knownDataNames).end();
+ for (; tIter != tLast; tIter++ ) {
+
+ pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+
+ // find the old edge
+ void *tmp=0;
+ pEntity pE = PList_next(before,&tmp);
+ double t = E_linearParams((pEdge)pE,(pVertex)ppp);
+
+ // get coordinates and datas at old nodes
+ void * data0 = NULL;
+ pVertex pV0 = E_vertex((pEdge)pE, 0);
+ int gotit0 = EN_getDataPtr((pEntity)pV0, dataId, &data0);
+ vector<double> * vec0 = (vector<double>*) data0;
+
+ void * data1 = NULL;
+ pVertex pV1 = E_vertex((pEdge)pE, 1);
+ int gotit1 = EN_getDataPtr((pEntity)pV1, dataId, &data1);
+ vector<double> * vec1 = (vector<double>*) data1;
+
+ if (!gotit0 || !gotit1) {
+ printf("Error: one of the nodes has no data attached to with name %s",
+ (*tIter).c_str());
+ throw;
+ }
+
+ // Interpolate the data at the new node.
+ vector<double> * newData = new vector<double>;
+ for (int i=0; i<3; i++) (*newData).push_back( (1.-t) * (*vec0)[i] + t * (*vec1)[i] );
+
+ // attach it
+ EN_attachDataPtr(ppp, dataId, newData);
+ }
+
+ break;
+ }
+ case MAd_ECOLLAPSE: {
+ // In the edge collapse case, we have to delete the datas attached to the deleted node
+
+ set<string>::const_iterator tIter = (*knownDataNames).begin();
+ set<string>::const_iterator tLast = (*knownDataNames).end();
+ for (; tIter != tLast; tIter++ ) {
+
+ pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+ void * data = NULL;
+ int gotit = EN_getDataPtr((pEntity)ppp, dataId, &data);
+ vector<double> * vec = (vector<double>*) data;
+ if (gotit && vec) delete vec;
+ EN_deleteData(ppp, dataId);
+ }
+
+ break;
+ }
+ case MAd_ESWAP:
+ case MAd_FSWAP: {
+ // nothing to be done (no modification at nodes)
+ break;
+ }
+ case MAd_RREMOVE: {
+ void * temp = NULL;
+ while ( pEntity pE = PList_next(before,&temp) ) {
+ if ( EN_type(pE) == 0 ) {
+ set<string>::const_iterator tIter = (*knownDataNames).begin();
+ set<string>::const_iterator tLast = (*knownDataNames).end();
+ for (; tIter != tLast; tIter++ ) {
+ pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+ void * data = NULL;
+ int gotit = EN_getDataPtr((pEntity)ppp, dataId, &data);
+ vector<double> * vec = (vector<double>*) data;
+ if (gotit && vec) delete vec;
+ EN_deleteData((pVertex)pE, dataId);
+ }
+ }
+ }
+ break;
+ }
+ case MAd_UNKNOWNOPERATION:
+ case MAd_VERTEXMOVE:
+ case MAd_FCOLLAPSE:
+ case MAd_DESPLTCLPS:
+ default: {
+ printf("Error in NodalDataManager: Callback function not implemented for mesh modification %d",
+ type);
+ throw;
+ }
+ }
+
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::initialize(pMesh m)
+ {
+ mesh = m;
+
+ prefix = "NodalDataManagerId_";
+ prefixVec = prefix + "Vec_";
+
+ coordNameBase = "StoredCoordinates__";
+
+ if(knownDataNames )
+ {
+ knownDataNames->clear();
+ }
+ else
+ {
+ knownDataNames= new set<string>();
+ }
+ if ( knownDataVecNames )
+ {
+ knownDataVecNames->clear();
+ }
+ else
+ {
+ knownDataVecNames = new set<string>();
+ }
+
+ CallBackManagerSgl::instance().registerCallBack(P1CBFunction, knownDataNames );
+ CallBackManagerSgl::instance().registerCallBack(P1VecCBFunction,knownDataVecNames);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::setMesh(pMesh m)
+ {
+ mesh = m;
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::finalize()
+ {
+ removeAllData();
+ if (knownDataNames)
+ {
+ delete knownDataNames;
+ knownDataNames = NULL;
+ }
+ if (knownDataVecNames)
+ {
+ delete knownDataVecNames;
+ knownDataVecNames = NULL;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::diagnostics (ostream& out) const
+ {
+ out << "\nContent of the nodal data manager:\n";
+
+ out << "\n - Double scalar : " << knownDataNames->size() << " fields:\n";
+ set<string>::iterator iIter;
+ set<string>::iterator iLast;
+ iIter = (*knownDataNames).begin();
+ iLast = (*knownDataNames).end();
+ for (; iIter != iLast; iIter++) {
+ out << " - "<< *iIter << "\n";
+ }
+
+ out << "\n - Double vector : " << knownDataVecNames->size() << " vector fields:\n";
+ iIter = (*knownDataVecNames).begin();
+ iLast = (*knownDataVecNames).end();
+ for (; iIter != iLast; iIter++) {
+ out << " - "<< *iIter << "\n";
+ }
+
+ out << "\n" << endl;
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::removeAllData()
+ {
+ set<string>::iterator iIter;
+ set<string>::iterator iLast;
+
+ iIter = (*knownDataNames).begin();
+ iLast = (*knownDataNames).end();
+ for (; iIter != iLast; iIter++) removeData(*iIter);
+
+ iIter = (*knownDataVecNames).begin();
+ iLast = (*knownDataVecNames).end();
+ for (; iIter != iLast; iIter++) removeVData(*iIter);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::registerData(string name, const vector<double> datas)
+ {
+ string dataName = prefix + name;
+
+ // check that this name doesn't exists yet
+ if ( nameExists(dataName,0) ) {
+ cerr << "Error: this scalar data \'"<<name<<"\' is already registered in the NodalDataManager\n";
+ throw;
+ }
+
+ // check that the number of datas is equal to the number of nodes in the mesh
+ int nbDatas = datas.size();
+ if ( nbDatas != M_numVertices(mesh) ) {
+ cerr<< "Error: wrong number of datas ("<<nbDatas<<") with "<<M_numVertices(mesh)<<" nodes\n";
+ throw;
+ }
+
+ // add this name to the list
+ (*knownDataNames).insert(dataName);
+
+ // attach the data at nodes
+ pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+ int i = 0;
+ VIter vit = M_vertexIter(mesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ EN_attachDataDbl((pEntity)pv,id,datas[i]);
+ i++;
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::registerVData(string name,
+ const vector<vector<double> > datas)
+ {
+ string dataName = prefixVec + name;
+
+ // check that this name doesn't exists yet
+ if ( nameExists(dataName,1) ) {
+ cerr << "Error: this vectorial data \'"<<name<<"\' is already registered in the NodalDataManager\n";
+ throw;
+ }
+
+ // check that the number of datas is equal to the number of nodes in the mesh
+ int nbDatas = datas.size();
+ if ( nbDatas != M_numVertices(mesh) ) {
+ cerr<< "Error: wrong number of datas ("<<nbDatas<<") with "<<M_numVertices(mesh)<<" nodes\n";
+ throw;
+ }
+
+ // add this name to the list
+ (*knownDataVecNames).insert(dataName);
+
+ // attach the data at nodes
+ pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+ int i = 0;
+ VIter vit = M_vertexIter(mesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ vector<double> * copy = new vector<double>(datas[i]);
+ EN_attachDataPtr((pEntity)pv,id,copy);
+ i++;
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::getMeshData(string name, vector<double> * result) const
+ {
+ string dataName = prefix + name;
+
+ // check that this name exists
+ if ( !nameExists(dataName,0) ) {
+ cerr << "Error: this scalar data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+ throw;
+ }
+
+ result->clear();
+
+ pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+
+ int i = 0;
+ VIter vit = M_vertexIter(mesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ double theDbl;
+ EN_getDataDbl((pEntity)pv,id,&theDbl);
+ result->push_back(theDbl);
+ i++;
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::getMeshVData(string name, vector<vector<double> > * result) const
+ {
+ string dataName = prefixVec + name;
+
+ // check that this name exists
+ if ( !nameExists(dataName,1) ) {
+ cerr << "Error: this vectorial data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+ throw;
+ }
+
+ result->clear();
+
+ pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+
+ int i = 0;
+ VIter vit = M_vertexIter(mesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ void * tmp = 0;
+ EN_getDataPtr((pEntity)pv,id,&tmp);
+ vector<double> * vec = (vector<double>*) tmp;
+ result->push_back(*vec);
+ i++;
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::getData(string name, pVertex pv, double* res) const
+ {
+ string dataName = prefix + name;
+
+ // check that this name exists
+ if ( !nameExists(dataName,0) ) {
+ cerr << "Error: this scalar data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+ throw;
+ }
+
+ pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+
+ EN_getDataDbl((pEntity)pv,id,res);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::getVData(string name, pVertex pv, vector<double>& res) const
+ {
+ string dataName = prefixVec + name;
+
+ // check that this name exists
+ if ( !nameExists(dataName,1) ) {
+ cerr << "Error: this vectorial data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+ throw;
+ }
+
+ pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+
+ void * tmp = 0;
+ EN_getDataPtr((pEntity)pv,id,&tmp);
+ res.clear();
+ for (int i=0; i<3; i++) res.push_back( (*( (vector<double>*) tmp))[i] );
+
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::removeData(string name)
+ {
+ string dataName = prefix + name;
+
+ if ( !nameExists(dataName,0) ) return;
+
+ // remove it from the list of names
+ set<string>::iterator iIter = (*knownDataNames).find(dataName);
+ (*knownDataNames).erase(iIter);
+
+ // delete the datas at nodes
+ pMeshDataId id = MD_lookupMeshDataId( (dataName).c_str() );
+ VIter vit = M_vertexIter(mesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ EN_deleteData((pEntity)pv,id);
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::removeVData(string name)
+ {
+ string dataName = prefixVec + name;
+
+ if ( !nameExists(dataName,1) ) return;
+
+ // remove it from the list of names
+ set<string>::iterator iIter = (*knownDataVecNames).find(dataName);
+ (*knownDataVecNames).erase(iIter);
+
+ // delete the datas at nodes
+ pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+ VIter vit = M_vertexIter(mesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ void * data = NULL;
+ int gotit = EN_getDataPtr((pEntity)pv, id, &data);
+ vector<double> * vec = (vector<double>*) data;
+ if (gotit && vec) delete vec;
+ EN_deleteData((pEntity)pv, id);
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::writeData(string name, const char *fn)
+ {
+ string dataName = prefix + name;
+
+ // check that this name exists
+ if ( !nameExists(dataName,0) ) {
+ cerr << "Error: this data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+ throw;
+ }
+
+ pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+
+ MAdAttachedNodalDataOutput(mesh, fn, id);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::writeVData(string name, const char *fn)
+ {
+ string dataName = prefixVec + name;
+
+ // check that this name exists
+ if ( !nameExists(dataName,1) ) {
+ cerr << "Error: this data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+ throw;
+ }
+
+ pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Output for vectorial attached data is not implemented");
+ // it is implemented for double arrays, not vectors.
+ // This class should store double arrays too, to be done (GC).
+ // MAdAttachedNodalDataVecOutput(mesh, fn, id);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::storeCoordinates()
+ {
+ removeCoordinates();
+
+ // add the coordinates name to the list
+ string coordName = prefixVec + coordNameBase;
+ (*knownDataVecNames).insert(coordName);
+
+ // attach the data at nodes
+ pMeshDataId id = MD_lookupMeshDataId( coordName.c_str() );
+ VIter vit = M_vertexIter(mesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ double xyz[3]; V_coord(pv,xyz);
+ vector<double> * vec = new vector<double>;
+ for (int j = 0; j<3; j++) (*vec).push_back(xyz[j]);
+ EN_attachDataPtr((pEntity)pv,id,vec);
+ }
+ VIter_delete(vit);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::getStoredCoordinates(pVertex pv, vector<double>& res)
+ {
+ getVData(coordNameBase,pv,res);
+ }
+
+ // -------------------------------------------------------------------
+ void NodalDataManager::removeCoordinates()
+ {
+ removeVData(coordNameBase);
+ }
+
+ // -------------------------------------------------------------------
+ bool NodalDataManager::isCoordinates()
+ {
+ string coordName = prefixVec + coordNameBase;
+ return nameExists(coordName,1);
+ }
+
+ // -------------------------------------------------------------------
+
+ bool NodalDataManager::nameExists(string dataName, int vec) const
+ {
+ if ( vec == 0 ) {
+ set<string>::iterator iIter = (*knownDataNames).find(dataName);
+ if ( iIter == (*knownDataNames).end() ) return false;
+ else return true;
+ }
+ if ( vec == 1 ) {
+ set<string>::iterator iIter = (*knownDataVecNames).find(dataName);
+ if ( iIter == (*knownDataVecNames).end() ) return false;
+ else return true;
+ }
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/utils/NodalDataManager.h b/Adapt/utils/NodalDataManager.h
new file mode 100644
index 0000000..ad4cbd7
--- /dev/null
+++ b/Adapt/utils/NodalDataManager.h
@@ -0,0 +1,103 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_NODALDATAMANAGER
+#define _H_NODALDATAMANAGER
+
+#include "MSops.h"
+
+#include "MAdSingleton.h"
+
+#include <vector>
+#include <string>
+#include <set>
+#include <iostream>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+
+ class NodalDataManager {
+
+ public:
+
+ NodalDataManager():mesh(NULL),
+ knownDataNames(NULL), knownDataVecNames(NULL){};
+ ~NodalDataManager() {};
+
+ void initialize(pMesh m);
+ void setMesh(pMesh m);
+ void finalize();
+
+ void removeAllData();
+
+ void diagnostics (std::ostream& out) const;
+
+ // will attach the datas to the nodes of the mesh
+ // order in vector is the node iterator order
+ void registerData (std::string name, const std::vector<double>);
+ void registerVData (std::string name, const std::vector<std::vector<double> >);
+
+ // will fill the variable with the datas attached to the nodes
+ // this function does not allocate memory
+ // order in vector is the node iterator order
+ void getMeshData (std::string name, std::vector<double> *) const;
+ void getMeshVData (std::string name, std::vector<std::vector<double> > *) const;
+
+ // get the data at a node
+ void getData (std::string name, pVertex pv, double* res) const;
+ void getVData (std::string name, pVertex pv, std::vector<double>& res) const;
+
+ // will delete the data attached to the nodes
+ void removeData (std::string name);
+ void removeVData (std::string name);
+
+ // write the data in a postprocessing file
+ void writeData (std::string name, const char *fn);
+ void writeVData (std::string name, const char *fn);
+
+ // functions to keep track of the initial coordinates
+ void storeCoordinates();
+ void getStoredCoordinates(pVertex pv, std::vector<double>& res);
+ void removeCoordinates();
+ bool isCoordinates();
+
+ private:
+
+ pMesh mesh;
+
+ // prefix for identification of the datas from this manager
+ // ensures there is no clash with other datas
+ std::string prefix;
+ std::string prefixVec;
+
+ // identifier for the coordinates
+ std::string coordNameBase;
+
+ // stored with the prefix
+ std::set<std::string>* knownDataNames;
+ std::set<std::string>* knownDataVecNames;
+
+ private:
+
+ bool nameExists(std::string name, int vec) const;
+
+ };
+
+ // -------------------------------------------------------------------
+
+ typedef MAdSingleton<NodalDataManager> NodalDataManagerSgl;
+
+}
+
+#endif
diff --git a/Benchmarks/meshInfo/Makefile b/Benchmarks/meshInfo/Makefile
new file mode 100644
index 0000000..d7c290d
--- /dev/null
+++ b/Benchmarks/meshInfo/Makefile
@@ -0,0 +1,59 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../../variables
+
+BIN = $(MAdROOT)/bin/meshInfo
+
+INC = ${MAdLib_INCLUDES}\
+ ${DASH}I$(MAdROOT)/Geo\
+ ${DASH}I$(MAdROOT)/Mesh\
+ ${DASH}I$(MAdROOT)/Common\
+ ${DASH}I$(MAdROOT)/Adapt\
+ ${DASH}I$(MAdROOT)/Adapt/constraint\
+ ${DASH}I$(MAdROOT)/Adapt/operator\
+ ${DASH}I$(MAdROOT)/Adapt/output\
+ ${DASH}I$(MAdROOT)/Adapt/quality\
+ ${DASH}I$(MAdROOT)/Adapt/repositioning\
+ ${DASH}I$(MAdROOT)/Adapt/sizeField\
+ ${DASH}I$(MAdROOT)/Adapt/utils
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = main.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${BIN}: ${OBJ}
+ ${LINKER} ${OPTIM} ${DASH}o $@ $(OBJ) ${MAdLib_LIBS}
+
+cpobj: ${OBJ}
+ cp -f ${OBJ} $(MAdROOT)/bin/
+
+.cc${OBJEXT}:
+ ${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+ ${RM} *.o *.obj
+
+purge:
+ ${RM} *.msh *.geo *.pos
+
+depend:
+ (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+ ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+ ) > Makefile.new
+ cp Makefile Makefile.bak
+ cp Makefile.new Makefile
+ rm -f Makefile.new
\ No newline at end of file
diff --git a/Benchmarks/meshInfo/main.cc b/Benchmarks/meshInfo/main.cc
new file mode 100644
index 0000000..b5372dd
--- /dev/null
+++ b/Benchmarks/meshInfo/main.cc
@@ -0,0 +1,123 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MSops.h"
+#include "AdaptInterface.h"
+#include "NullSField.h"
+#include "AnalyticalSField.h"
+#include "MAdResourceManager.h"
+#include "MAdLib.h"
+
+#include <iostream>
+using std::cout;
+#include <sys/resource.h>
+#include <string>
+using std::string;
+
+using namespace MAd;
+
+#ifdef PARALLEL
+#include "mpi.h"
+#endif
+
+// ----------------------------------------------------------------------
+void displayMemoryUsage(string step="")
+{
+ MAdResourceManagerSgl::instance().printMemoryUsage(step,std::cout);
+}
+
+// ----------------------------------------------------------------------
+int main(int argc, char* argv[]) {
+
+ MAdLibInitialize(&argc, &argv);
+
+ displayMemoryUsage("initialized");
+
+ // Check input
+ // ------------
+ if ( argc != 3 && argc != 2 ) {
+ printf("Error: usage: \'executable mshFile [geoFile]\'\n");
+ exit(0);
+ }
+ string meshFile = argv[1];
+
+ // Build tools
+ // ------------
+ printf ("Analyzing mesh %s...\n\n",meshFile.c_str());
+
+ // --- Reading model ---
+ pGModel model = 0;
+ GM_create(&model,"theModel");
+
+ if ( argc == 3 ) {
+ string geoFile = argv[2];
+ GM_readFromGEO(model, geoFile.c_str());
+ }
+ else {
+ GM_readFromMSH(model, meshFile.c_str());
+ }
+
+ displayMemoryUsage("built model");
+
+ pMesh mesh = M_new(model);
+ M_load(mesh,meshFile.c_str());
+
+ displayMemoryUsage("built mesh");
+
+ SizeFieldBase * sizeField = new AnalyticalSField("1.");
+
+ MeshAdapter* ma = new MeshAdapter(mesh,sizeField);
+
+ displayMemoryUsage("built adapter");
+
+ // temporary info
+// int nbVolEdges = 0;
+// int dim = M_dim(mesh);
+// int numR[20];
+// for (int i=0; i<20; i++) numR[i]=0;
+// EIter ei = M_edgeIter(mesh);
+// while ( pEdge edge = EIter_next(ei) ) {
+// if ( E_whatInType(edge) == dim ) {
+// int num = E_numRegions(edge);
+// numR[num] = numR[num]++;
+// nbVolEdges++;
+// }
+// }
+// EIter_delete(ei);
+// printf("Num points in edges crown:\n");
+// printf("Edges: %d\n",nbVolEdges);
+
+// for (int i=0; i<20; i++) {
+// double ratio = ( (double) (numR[i]) ) / ( (double)nbVolEdges );
+// printf("%d\t%d\t%f\n",i,numR[i],ratio);
+// }
+// printf("\n");
+
+
+ // Outputs
+ // --------
+ ma->printStatistics(std::cout);
+ ma->writePos("meanRatio.pos",OD_MEANRATIO);
+
+ // Cleaning
+ // ---------
+ if (ma) delete ma;
+ if (sizeField) delete sizeField;
+ M_delete(mesh);
+ GM_delete(model);
+
+ displayMemoryUsage("cleaned");
+
+ MAdLibFinalize();
+}
+
+// ----------------------------------------------------------------------
diff --git a/Benchmarks/moveIt/Makefile b/Benchmarks/moveIt/Makefile
new file mode 100644
index 0000000..995be41
--- /dev/null
+++ b/Benchmarks/moveIt/Makefile
@@ -0,0 +1,59 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../../variables
+
+BIN = $(MAdROOT)/bin/moveIt
+
+INC = ${MAdLib_INCLUDES}\
+ ${DASH}I$(MAdROOT)/Geo\
+ ${DASH}I$(MAdROOT)/Mesh\
+ ${DASH}I$(MAdROOT)/Common\
+ ${DASH}I$(MAdROOT)/Adapt\
+ ${DASH}I$(MAdROOT)/Adapt/constraint\
+ ${DASH}I$(MAdROOT)/Adapt/operator\
+ ${DASH}I$(MAdROOT)/Adapt/output\
+ ${DASH}I$(MAdROOT)/Adapt/quality\
+ ${DASH}I$(MAdROOT)/Adapt/repositioning\
+ ${DASH}I$(MAdROOT)/Adapt/sizeField\
+ ${DASH}I$(MAdROOT)/Adapt/utils
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = main.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${BIN}: ${OBJ}
+ ${LINKER} ${OPTIM} ${DASH}o $@ $(OBJ) ${MAdLib_LIBS}
+
+cpobj: ${OBJ}
+ cp -f ${OBJ} $(MAdROOT)/bin/
+
+.cc${OBJEXT}:
+ ${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+ ${RM} *.o *.obj
+
+purge:
+ ${RM} *.msh *.geo *.pos MyParams.h example/tube/result/*
+
+depend:
+ (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+ ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+ ) > Makefile.new
+ cp Makefile Makefile.bak
+ cp Makefile.new Makefile
+ rm -f Makefile.new
\ No newline at end of file
diff --git a/Benchmarks/moveIt/Parameters.h b/Benchmarks/moveIt/Parameters.h
new file mode 100644
index 0000000..98b29a8
--- /dev/null
+++ b/Benchmarks/moveIt/Parameters.h
@@ -0,0 +1,246 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_PARAMETERS
+#define _H_PARAMETERS
+
+#include "AdaptInterface.h"
+#include "SizeFieldBase.h"
+#include "LocalSizeField.h"
+
+#include <string.h>
+using std::string;
+#include <list>
+#include <set>
+#include <vector>
+using std::vector;
+
+// ----------------------------------------------------------------------
+enum KinematicType {
+ KT_DISPLACEMENT,
+ KT_VELOCITY
+};
+
+// ----------------------------------------------------------------------
+enum OrientationType {
+ ORT_ISOTROPIC,
+ ORT_ANISOTROPIC
+};
+
+// ----------------------------------------------------------------------
+// ----------------------------------------------------------------------
+struct LocalSFDef {
+ string name;
+ bool distToFaces;
+ bool isotropic;
+ double radius;
+ string sizeN, sizeT;
+ bool limit;
+ double limitSizeTg;
+ double maxCurv;
+};
+
+// ----------------------------------------------------------------------
+struct SizeFieldDef
+{
+ MAd::sFieldType type; // analytical or piecewise linear
+
+ // analytical size fields
+ OrientationType orientation;
+ string isoSize;
+ vector<string> anisoSize;
+ vector<string> anisoDir0, anisoDir1, anisoDir2;
+
+ // piecewise linear size fields
+ string pwlSource; // curvature or initial length
+
+ // curvature parameters
+ bool curv_aniso;
+ double curv_alpha, curv_hMin;
+};
+
+// ----------------------------------------------------------------------
+struct ObjectDef {
+
+ string name;
+
+ // geometry
+ int geomLevel; // 0=point,1=line,2=surface,3=region
+ std::set<int> geomTags;
+
+ // kinematics
+ KinematicType kinType;
+ vector<string> kinExpression;
+
+ // size fields
+ std::list<LocalSFDef> sizes;
+};
+
+// ----------------------------------------------------------------------
+struct MoveParameters {
+
+ // global input specifications
+ // ---------------------------
+
+ string meshFileName;
+ string geoFileName;
+
+ // global output parameters
+ // ------------------------
+
+ int outFrequency;
+ string outType; // "Msh", "Pos" or "MshAndPos"(def)
+ string outPrefix;
+
+ // Global task parameters
+ // ----------------------
+
+ string task; // MobileObject(def),...
+
+ // debugging parmeters
+ // --------------------
+
+ int debugLevel;
+ bool openJournal;
+ string referenceJournal;
+ bool sliverReports;
+ bool testSliverOperators;
+
+ // Mesh adaptation
+ // ----------------
+
+ int maxInnerIter;
+ double lowerLength, upperLength;
+ double infLength;
+ double swapMinImproveRatio;
+ double sliverQuality;
+
+ bool splitCanMakeSlivers, collapseCanMakeSlivers;
+ double makeSliverInSplitLenSqBound, makeSliverInCollapseLenSqBound;
+
+ bool collapseOnBoundary;
+ double clpOnBdryTolerance;
+
+ bool swapOnBoundary;
+ double swapOnBdryTolerance;
+
+ bool trackGeometry;
+ bool snap_cavityIsMesh;
+ int snap_thickness;
+ double snap_chi;
+
+ bool SFSmoothing;
+ double SFSmoothGrad;
+
+ // Moving objects
+ // --------------
+
+ std::vector<ObjectDef> objects;
+
+ // Size Field parameters
+ // ---------------------
+
+ std::list<SizeFieldDef> sizes;
+
+ // Node motion
+ // -----------
+
+ string nodeMotionType; // None(def), ForceBoundaries, ElasticAnalogy
+ bool elasticIsMeshTheCavity;
+ int elasticCavityThickness;
+ double elasticStiffnessAlteration;
+
+ // Time parameters
+ // ---------------
+
+ int maxNbTimeSteps;
+ double timeStep;
+ double finalTime;
+
+};
+
+// ----------------------------------------------------------------------
+// this function set the parameters to the values of a particular test case
+extern void setCurrentParameters(MoveParameters *);
+
+// ----------------------------------------------------------------------
+void setDefaultParameters(MoveParameters * params)
+{
+ params->meshFileName = "";
+ params->geoFileName = "";
+
+ params->outFrequency = 1;
+ params->outType = "MshAndPos";
+ params->outPrefix = "result/";
+
+ params->task = "MobileObject";
+
+ params->debugLevel = 1;
+ params->openJournal = false;
+ params->referenceJournal = "";
+ params->sliverReports = false;
+ params->testSliverOperators = false;
+
+ params->maxInnerIter = 10;
+ params->lowerLength = 1./sqrt(3.);
+ params->upperLength = sqrt(3.);
+ params->infLength = 1.e14;
+ params->swapMinImproveRatio = 1.0;
+ params->sliverQuality = 0.02;
+
+ params->splitCanMakeSlivers = true;
+ params->makeSliverInSplitLenSqBound = 10.;
+ params->collapseCanMakeSlivers = true;
+ params->makeSliverInCollapseLenSqBound = 0.1;
+
+ params->collapseOnBoundary = true;
+ params->clpOnBdryTolerance = 1.e-6;
+
+ params->swapOnBoundary = true;
+ params->swapOnBdryTolerance = 1.e-6;
+
+ params->trackGeometry = false;
+ params->snap_cavityIsMesh = false;
+ params->snap_thickness = 3;
+ params->snap_chi = 1.;
+
+ params->SFSmoothing = false;
+ params->SFSmoothGrad = 1.;
+
+ params->objects.clear();
+
+ params->sizes.clear();
+
+ params->nodeMotionType = "None";
+ params->elasticIsMeshTheCavity = true;
+ params->elasticCavityThickness = 3;
+ params->elasticStiffnessAlteration = 1.0;
+
+ params->maxNbTimeSteps = 1000000;
+ params->timeStep = 0.1;
+ params->finalTime = -1.0;
+}
+
+// ----------------------------------------------------------------------
+MoveParameters getParameters()
+{
+ MoveParameters params;
+ setDefaultParameters(¶ms);
+ setCurrentParameters(¶ms);
+
+ return params;
+}
+
+// ----------------------------------------------------------------------
+
+#endif
diff --git a/Benchmarks/moveIt/README b/Benchmarks/moveIt/README
new file mode 100644
index 0000000..7390d7b
--- /dev/null
+++ b/Benchmarks/moveIt/README
@@ -0,0 +1,32 @@
+MAdLib - Benchmarks - moveIt
+
+Description
+------------
+
+This benchmark allows to define a motion of the domain boundaries
+and adapt the mesh accordingly.
+
+How to use it ?
+----------------
+
+The parameters of the computations are defined in a file called
+'MyParams.h' which has to be located in this directory and will
+be included during the compilation of the executable.
+You can make a link to the .h file you defined in a subdirectory
+for instance.
+
+The 'MyParams.h' file has to be written according to the template
+defined in 'Parameters.h'.
+
+In the 'MyParams.h' file, a target mesh file with a '.msh'
+extension is required. In order to produce it, download Gmsh at
+<http://www.geuz.org/gmsh> and run:
+
+gmsh -3 -optimize 'the_geo_file'
+
+where 'the_geo_file' is a file with a '.geo' extension, the
+native CAD file format of Gmsh.
+
+Once the executable is compiled, run it without any argument. The
+output will be produced and stored according to the parameters
+contained in the 'MyParams.h' file at the time of the compilation.
diff --git a/Benchmarks/moveIt/examples/tube/MyParams.h b/Benchmarks/moveIt/examples/tube/MyParams.h
new file mode 100644
index 0000000..20e567b
--- /dev/null
+++ b/Benchmarks/moveIt/examples/tube/MyParams.h
@@ -0,0 +1,199 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MYPARAMS
+#define _H_MYPARAMS
+
+#include "Parameters.h"
+
+// ----------------------------------------------------------------------
+void setCurrentParameters(MoveParameters * params) {
+
+ params->meshFileName = "tube.msh";
+// params->geoFileName="tube_fullGeo.geo";
+
+ // global output parameters
+ // ------------------------
+
+ params->outFrequency = 10;
+ params->outType = "Msh"; // "Msh", "Pos" or "MshAndPos"
+ params->outPrefix = "result/";
+
+ // Global task parameters
+ // ----------------------
+
+ params->task = "MobileObject";
+
+ // debugging parmeters
+ // --------------------
+
+ params->debugLevel = 0;
+ params->openJournal = false;
+ params->referenceJournal = "";
+ params->sliverReports = false;
+ params->testSliverOperators = false;
+
+ // Mesh adaptation
+ // ----------------
+
+ params->maxInnerIter = 10;
+ params->lowerLength = 0.577;
+ params->upperLength = 1.732;
+ params->swapMinImproveRatio = 1.0;
+ params->sliverQuality = 0.02;
+ params->splitCanMakeSlivers = true;
+ params->makeSliverInSplitLenSqBound = 0.1;
+ params->collapseCanMakeSlivers = true;
+ params->makeSliverInCollapseLenSqBound = 10.;
+ params->collapseOnBoundary = true;
+ params->clpOnBdryTolerance = 1.e-6;
+ params->swapOnBoundary = true;
+ params->swapOnBdryTolerance = 1.e2;
+ params->trackGeometry = false;
+// params->snap_cavityIsMesh = false;
+// params->snap_thickness = 3;
+// params->snap_chi = 1.;
+
+ params->SFSmoothing = true;
+ params->SFSmoothGrad = 1.;
+
+ // Node motion
+ // -----------
+
+ params->nodeMotionType = "ElasticAnalogy";
+ params->elasticStiffnessAlteration = 1.0;
+ params->elasticIsMeshTheCavity = true;
+ params->elasticCavityThickness = 0;
+
+ // Time parameters
+ // ---------------
+
+ params->timeStep = 0.01;
+ params->finalTime = 4.0;
+// params->maxNbTimeSteps = 1;
+
+
+ // Moving objects
+ // --------------
+
+ // --- The cylinder ---
+
+ ObjectDef cylinder;
+ cylinder.name = "Cylinder";
+ cylinder.geomLevel = 2;
+ cylinder.geomTags.insert(8);
+ cylinder.geomTags.insert(12);
+ cylinder.geomTags.insert(16);
+ cylinder.geomTags.insert(20);
+ cylinder.geomTags.insert(22);
+ cylinder.geomTags.insert(126);
+ cylinder.kinType = KT_VELOCITY;
+ cylinder.kinExpression.push_back("0.");
+ cylinder.kinExpression.push_back("0.");
+ cylinder.kinExpression.push_back("1.*sign(sin(2.*3.14159265/8.*t+1.e-6))");
+
+ LocalSFDef localSFCyl;
+ localSFCyl.name = "CylinderSF";
+ localSFCyl.radius = 1.;
+ localSFCyl.distToFaces = false;
+ localSFCyl.isotropic = true;
+ localSFCyl.sizeN = "0.1+0.5*x";
+
+ cylinder.sizes.push_back(localSFCyl);
+
+ params->objects.push_back(cylinder);
+
+ // --- The tube ---
+
+ ObjectDef tube;
+ tube.name = "Tube";
+ tube.geomLevel = 2;
+ tube.geomTags.insert(40);
+ tube.geomTags.insert(44);
+ tube.geomTags.insert(48);
+ tube.geomTags.insert(52);
+ tube.geomTags.insert(56);
+ tube.geomTags.insert(60);
+ tube.geomTags.insert(64);
+ tube.geomTags.insert(68);
+ tube.geomTags.insert(71);
+ tube.geomTags.insert(106);
+ tube.kinType = KT_VELOCITY;
+ tube.kinExpression.push_back("0.");
+ tube.kinExpression.push_back("0.");
+ tube.kinExpression.push_back("-1.*sign(sin(2.*3.14159265/8.*t+1.e-6))");
+
+ LocalSFDef localSFTube;
+ localSFTube.name = "tubeSF";
+ localSFTube.radius = 1.;
+ localSFTube.distToFaces = false;
+ localSFTube.isotropic = true;
+ localSFTube.sizeN = "0.2+0.4*x";
+
+ tube.sizes.push_back(localSFTube);
+
+ params->objects.push_back(tube);
+
+ // --- The box ---
+
+// ObjectDef box;
+// box.name = "Box";
+// box.geomLevel = 2;
+// box.geomTags.insert(110);
+// box.geomTags.insert(114);
+// box.geomTags.insert(118);
+// box.geomTags.insert(122);
+// box.geomTags.insert(124);
+// box.geomTags.insert(131);
+// box.kinType = KT_DISPLACEMENT;
+// box.kinExpression.push_back("0.");
+// box.kinExpression.push_back("0.");
+// box.kinExpression.push_back("0.");
+
+// params->objects.push_back(box);
+
+ // Size Field parameters
+ // ---------------------
+
+ SizeFieldDef analSF;
+ analSF.type = MAd::ANALYTICALSFIELD;
+ analSF.orientation = ORT_ISOTROPIC;
+ analSF.isoSize = "0.6";
+// analSF.orientation = ORT_ANISOTROPIC;
+// vector<string> myAnisoSize;
+// myAnisoSize.push_back("0.3");
+// myAnisoSize.push_back("0.6");
+// myAnisoSize.push_back("0.6");
+// analSF.anisoSize = myAnisoSize;
+// vector<string> anisoDir0;
+// anisoDir0.push_back("1.");
+// anisoDir0.push_back("0.");
+// anisoDir0.push_back("0.");
+// analSF.anisoDir0 = anisoDir0;
+// vector<string> anisoDir1;
+// anisoDir1.push_back("0.");
+// anisoDir1.push_back("1.");
+// anisoDir1.push_back("0.");
+// analSF.anisoDir1 = anisoDir1;
+// vector<string> anisoDir2;
+// anisoDir2.push_back("0.");
+// anisoDir2.push_back("0.");
+// anisoDir2.push_back("1.");
+// analSF.anisoDir2 = anisoDir2;
+
+ params->sizes.push_back(analSF);
+}
+
+// ----------------------------------------------------------------------
+
+#endif
diff --git a/Benchmarks/moveIt/examples/tube/result/quality b/Benchmarks/moveIt/examples/tube/result/quality
new file mode 100644
index 0000000..fe2a50c
--- /dev/null
+++ b/Benchmarks/moveIt/examples/tube/result/quality
@@ -0,0 +1,3 @@
+iter mean quality worst quality
+0 0.559586 1.71371e-06
+0 5.759428e-01 2.011903e-02
diff --git a/Benchmarks/moveIt/examples/tube/tube.geo b/Benchmarks/moveIt/examples/tube/tube.geo
new file mode 100644
index 0000000..a3c0d17
--- /dev/null
+++ b/Benchmarks/moveIt/examples/tube/tube.geo
@@ -0,0 +1,85 @@
+// -*- C++ -*-
+
+lc1 = 0.1;//0.1
+lc2 = 0.2;//0.4
+lcBox = 0.6;//0.6
+
+// cylinders parameters
+r = 0.9;
+R = 1.;
+dR = 0.2;
+L1 = 3.;
+L2 = 3.;
+dL = 1.;
+
+// external box parameters
+B1 = 2.;
+B2 = 2.;
+B3 = 3.;
+
+// first cylinder (small one)
+Point(1) = {0,0,0,lc1};
+Point(2) = {r,0,0,lc1};
+Point(3) = {0,r,0,lc1};
+Point(4) = {0,-r,0,lc1};
+Point(5) = {-r,0,0,lc1};
+Circle(1) = {2,1,3};
+Circle(2) = {3,1,5};
+Circle(3) = {5,1,4};
+Circle(4) = {4,1,2};
+Extrude {0,0,L1} {
+ Line{3,2,1,4};
+}
+Line Loop(21) = {13,9,5,17};
+Plane Surface(22) = {21};
+
+// tube
+Point(20) = {R,0,L1+dL,lc2};
+Point(21) = {-R,0,L1+dL,lc2};
+Point(22) = {0,R,L1+dL,lc2};
+Point(23) = {0,-R,L1+dL,lc2};
+Point(24) = {0,-R-dR,L1+dL,lc2};
+Point(25) = {0,+R+dR,L1+dL,lc2};
+Point(26) = {R+dR,0,L1+dL,lc2};
+Point(27) = {-R-dR,0,L1+dL,lc2};
+Point(28) = {0,0,L1+dL,lc2};
+Circle(29) = {23,28,20};
+Circle(30) = {20,28,22};
+Circle(31) = {22,28,21};
+Circle(32) = {21,28,23};
+Circle(33) = {24,28,26};
+Circle(34) = {26,28,25};
+Circle(35) = {25,28,27};
+Circle(36) = {27,28,24};
+Extrude {0,0,L2} {
+ Line{36,33,34,35,31,30,29,32};
+}
+Line Loop(69) = {45,49,37,41};
+Line Loop(70) = {53,65,61,57};
+Plane Surface(71) = {69,70};
+Line Loop(104) = {35,36,33,34};
+Line Loop(105) = {32,29,30,31};
+Plane Surface(106) = {104,105};
+
+// // external box
+Point(62) = {B3,B3,-B1,lcBox};
+Point(63) = {-B3,B3,-B1,lcBox};
+Point(64) = {-B3,-B3,-B1,lcBox};
+Point(65) = {B3,-B3,-B1,lcBox};
+Line(82) = {64,63};
+Line(83) = {63,62};
+Line(84) = {62,65};
+Line(85) = {65,64};
+Extrude {0,0,B1+L1+dL+L2+B2} {
+ Line{82,83,84,85};
+}
+Line Loop(123) = {107,111,115,119};
+Plane Surface(124) = {123};
+Line Loop(125) = {2,3,4,1};
+Plane Surface(126) = {125};
+Line Loop(130) = {84,85,82,83};
+Plane Surface(131) = {130};
+Surface Loop(132) = {124,110,131,118,122,114};
+Surface Loop(133) = {52,106,40,44,48,71,60,56,68,64};
+Surface Loop(134) = {12,126,8,20,16,22};
+Volume(135) = {132,133,134};
diff --git a/Benchmarks/moveIt/examples/tube/tube.mad b/Benchmarks/moveIt/examples/tube/tube.mad
new file mode 100644
index 0000000..c80e3a0
--- /dev/null
+++ b/Benchmarks/moveIt/examples/tube/tube.mad
@@ -0,0 +1,144 @@
+//-*- C++ -*-
+
+Input {
+ Mesh {
+ MshFile = "tube.msh"; // gmsh -3 -optimize tube.geo
+ //GeoFile = "tube.geo";
+ //MshFile = "tube_fullGeo.msh"; // gmsh -3 -optimize tube_fullGeo.geo -parametric
+ //GeoFile = "tube_fullGeo.geo";
+ }
+}
+Output {
+ Prefix = "result/";
+ Frequency = 100;
+ Type = Msh;
+}
+Task {
+ Type = MobileObject; // RemoveRegion SizeField RemoveSliverFaces LaplaceSmoothing GeoConstraints TopoConstraints FaceSwap UglyMesh RemoveSliverRegions DESC EdgeSwap GeoMatcher EdgeSplit EdgeCollapse EdgeSplitCollapse FaceCollapse OptimizeLength OptimizeShape None
+}
+Debug {
+ DebugLevel = 1;
+// OpenJournal = Yes;
+// ReferenceJournal = "";
+// ReportSlivers = Yes;
+}
+Adaptation {
+// LowerLengthBound = 0.58; // 1/sqrt(3)
+// UpperLengthBound = 1.73; // sqrt(3)
+// SwapMinImproveRatio = 1.0;
+// SliverQuality = 0.02;
+// SplitCanMakeSlivers = Yes;
+// CollapseCanMakeSlivers = Yes;
+// SliverLowerLengthSqBound = 0.32; // 1/sqrt(10)
+// SliverUpperLengthSqBound = 3.16; // sqrt(10)
+// CollapseOnBoundary = Yes;
+// BoundaryCollapses {
+// Tolerance = 1.e-2;
+// }
+// SwapOnBoundary = Yes;
+// BoundarySwaps {
+// Tolerance = 1.e6;
+// }
+// TrackGeometry = No;
+// VertexSnapping {
+// IsMeshTheCavity = Yes;
+// CavityThickness = 0;
+// StiffnessAlteration = 1.;
+// }
+ SmoothSizeField = Yes;
+ SizeFieldSmoothing {
+ // MaximumGradient = 1.000000e+00;
+ }
+}
+MovingObjects {
+ Object = "Cylinder" {
+ Geometry {
+ GeometricalType = Face;
+ GeometricalTags = [8 12 16 20 22 126];
+ }
+ Kinematics {
+
+ KinematicsSpecification = Velocity;
+ Velocity {
+ Formulation = ["0." "0." "1.*sign(sin(2.*3.14159265/8.*t+1.e-6))"];
+ // Formulation = ["0." "0." "1."];
+ //Formulation = ["0." "0." "0."];
+ }
+ }
+ LocalSizeField {
+ DistanceComputation = ToWallVertices;
+ Orientation = Isotropic;
+ Radius = 1.0;
+ Isotropic {
+ Size = "0.1+(x/1.0)*(0.6-0.1)"; // linear
+ //Size = "0.02+(sqrt(x)/sqrt(0.5))*(0.2-0.02)"; // sqrt
+ }
+ Anisotropic {
+ NormalSize = "0.02+(x/1.0)*(0.4-0.02)"; // linear
+ TangentSize = "0.4";
+ }
+ CurvatureBasedLimiter {
+ Enable = No;
+ TangentSizeOverRadius = 0.4;
+ }
+ }
+ }
+ Object = "Tube" {
+ Geometry {
+ GeometricalType = Face;
+ GeometricalTags = [40 44 48 52 56 60 64 68 71 106];
+ }
+ Kinematics {
+ KinematicsSpecification = Velocity;
+ Velocity {
+ Formulation = ["0." "0." "-1.*sign(sin(2.*3.14159265/8.*t+1.e-6))"];
+ //Formulation = ["0." "0." "-1."];
+ //Formulation = ["0." "0." "0."];
+ }
+ }
+ LocalSizeField {
+ DistanceComputation = ToWallVertices;
+ Orientation = Isotropic;
+ Radius = 1.0;
+ Isotropic {
+ Size = "0.2+(x/1.0)*(0.6-0.2)"; // linear
+ }
+ Anisotropic {
+ NormalSize = "0.02+(x/1.0)*(0.4-0.02)"; // linear
+ TangentSize = "0.4";
+ }
+ CurvatureBasedLimiter {
+ Enable = No;
+ TangentSizeOverRadius = 0.4;
+ }
+ }
+ }
+}
+SizeField {
+ Type = Analytical;
+ Analytical {
+ OrientationType = Isotropic; // Isotropic Anisotropic
+ Isotropic {
+ Length = "0.6";
+ }
+// Anisotropic {
+// Lengths = ["0.6" "0.3" "0.2"];
+// Direction1 = ["1." "0." "0."];
+// Direction2 = ["0." "1." "0."];
+// Direction3 = ["0." "0." "1."];
+// }
+ }
+}
+NodeMotion {
+ Type = ElasticAnalogy; // ElasticAnalogy ForceBoundaries None
+ ElasticParameters {
+ StiffnessAlteration = 1.;
+ IsMeshTheCavity = Yes;
+ // CavityThickness = 3;
+ }
+}
+TimeSpecifications {
+ // MaxTimeSteps = 4000;
+ TimeStep = 0.01;
+ FinalTime = 4.0;
+}
diff --git a/Benchmarks/moveIt/examples/tube/tube_fullGeo.geo b/Benchmarks/moveIt/examples/tube/tube_fullGeo.geo
new file mode 100644
index 0000000..667d083
--- /dev/null
+++ b/Benchmarks/moveIt/examples/tube/tube_fullGeo.geo
@@ -0,0 +1,130 @@
+Point (1) = {0, 0, 0, 0.1};
+Point (2) = {0.9, 0, 0, 0.1};
+Point (3) = {0, 0.9, 0, 0.1};
+Point (4) = {0, -0.9, 0, 0.1};
+Point (5) = {-0.9, 0, 0, 0.1};
+Point (6) = {-0.9, 0, 3, 0.1};
+Point (7) = {0, 0, 3, 0.1};
+Point (8) = {0, -0.9, 3, 0.1};
+Point (9) = {0, 0.9, 3, 0.1};
+Point (10) = {0.9, 0, 3, 0.1};
+Point (20) = {1, 0, 4, 0.4};
+Point (21) = {-1, 0, 4, 0.4};
+Point (22) = {0, 1, 4, 0.4};
+Point (23) = {0, -1, 4, 0.4};
+Point (24) = {0, -1.2, 4, 0.4};
+Point (25) = {0, 1.2, 4, 0.4};
+Point (26) = {1.2, 0, 4, 0.4};
+Point (27) = {-1.2, 0, 4, 0.4};
+Point (28) = {0, 0, 4, 0.4};
+Point (29) = {-1.2, 0, 7, 0.4};
+Point (30) = {0, 0, 7, 0.4};
+Point (31) = {0, -1.2, 7, 0.4};
+Point (34) = {1.2, 0, 7, 0.4};
+Point (37) = {0, 1.2, 7, 0.4};
+Point (38) = {0, 1, 7, 0.4};
+Point (40) = {-1, 0, 7, 0.4};
+Point (41) = {1, 0, 7, 0.4};
+Point (42) = {0, -1, 7, 0.4};
+Point (62) = {3, 3, -2, 0.6};
+Point (63) = {-3, 3, -2, 0.6};
+Point (64) = {-3, -3, -2, 0.6};
+Point (65) = {3, -3, -2, 0.6};
+Point (66) = {-3, -3, 9, 0.6};
+Point (67) = {-3, 3, 9, 0.6};
+Point (69) = {3, 3, 9, 0.6};
+Point (71) = {3, -3, 9, 0.6};
+Circle (1) = {2, 1, 3};
+Circle (2) = {3, 1, 5};
+Circle (3) = {5, 1, 4};
+Circle (4) = {4, 1, 2};
+Circle (5) = {6, 7, 8};
+Line (6) = {5, 6};
+Line (7) = {4, 8};
+Circle (9) = {9, 7, 6};
+Line (10) = {3, 9};
+Circle (13) = {10, 7, 9};
+Line (14) = {2, 10};
+Circle (17) = {8, 7, 10};
+Circle (29) = {23, 28, 20};
+Circle (30) = {20, 28, 22};
+Circle (31) = {22, 28, 21};
+Circle (32) = {21, 28, 23};
+Circle (33) = {24, 28, 26};
+Circle (34) = {26, 28, 25};
+Circle (35) = {25, 28, 27};
+Circle (36) = {27, 28, 24};
+Circle (37) = {29, 30, 31};
+Line (38) = {27, 29};
+Line (39) = {24, 31};
+Circle (41) = {31, 30, 34};
+Line (43) = {26, 34};
+Circle (45) = {34, 30, 37};
+Line (47) = {25, 37};
+Circle (49) = {37, 30, 29};
+Circle (53) = {38, 30, 40};
+Line (54) = {22, 38};
+Line (55) = {21, 40};
+Circle (57) = {41, 30, 38};
+Line (58) = {20, 41};
+Circle (61) = {42, 30, 41};
+Line (62) = {23, 42};
+Circle (65) = {40, 30, 42};
+Line (82) = {64, 63};
+Line (83) = {63, 62};
+Line (84) = {62, 65};
+Line (85) = {65, 64};
+Line (107) = {66, 67};
+Line (108) = {64, 66};
+Line (109) = {63, 67};
+Line (111) = {67, 69};
+Line (113) = {62, 69};
+Line (115) = {69, 71};
+Line (117) = {65, 71};
+Line (119) = {71, 66};
+Line Loop (8) = {3, 7, -5, -6};
+Ruled Surface (8) = {8};
+Line Loop (12) = {2, 6, -9, -10};
+Ruled Surface (12) = {12};
+Line Loop (16) = {1, 10, -13, -14};
+Ruled Surface (16) = {16};
+Line Loop (20) = {4, 14, -17, -7};
+Ruled Surface (20) = {20};
+Line Loop (22) = {13, 9, 5, 17};
+Plane Surface (22) = {22};
+Line Loop (40) = {36, 39, -37, -38};
+Ruled Surface (40) = {40};
+Line Loop (44) = {33, 43, -41, -39};
+Ruled Surface (44) = {44};
+Line Loop (48) = {34, 47, -45, -43};
+Ruled Surface (48) = {48};
+Line Loop (52) = {35, 38, -49, -47};
+Ruled Surface (52) = {52};
+Line Loop (56) = {31, 55, -53, -54};
+Ruled Surface (56) = {56};
+Line Loop (60) = {30, 54, -57, -58};
+Ruled Surface (60) = {60};
+Line Loop (64) = {29, 58, -61, -62};
+Ruled Surface (64) = {64};
+Line Loop (68) = {32, 62, -65, -55};
+Ruled Surface (68) = {68};
+Line Loop (71) = {45, 49, 37, 41, -57, -61, -65, -53};
+Plane Surface (71) = {71};
+Line Loop (106) = {35, 36, 33, 34, -31, -30, -29, -32};
+Plane Surface (106) = {106};
+Line Loop (110) = {82, 109, -107, -108};
+Ruled Surface (110) = {110};
+Line Loop (114) = {83, 113, -111, -109};
+Ruled Surface (114) = {114};
+Line Loop (118) = {84, 117, -115, -113};
+Ruled Surface (118) = {118};
+Line Loop (122) = {85, 108, -119, -117};
+Ruled Surface (122) = {122};
+Line Loop (124) = {107, 111, 115, 119};
+Plane Surface (124) = {124};
+Line Loop (126) = {2, 3, 4, 1};
+Plane Surface (126) = {126};
+Line Loop (131) = {84, 85, 82, 83};
+Plane Surface (131) = {131};
+Surface Loop (135) = {124, 110, 131, 118, 122, 114, 52, 106, 40, 44, 48, 71, 60, 56, 68, 64, 12, 126, 8, 20, 16, 22};
+Volume (135) = {135};
diff --git a/Benchmarks/moveIt/main.cc b/Benchmarks/moveIt/main.cc
new file mode 100644
index 0000000..4dd8097
--- /dev/null
+++ b/Benchmarks/moveIt/main.cc
@@ -0,0 +1,1185 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+// the template parameter file for this executable
+#include "Parameters.h"
+// the parameter file for the current test case
+#ifdef _HAVE_PARSER_
+ #include "moveItParse.h"
+#else
+ #include "MyParams.h"
+#endif
+
+#include "MAdLib.h"
+#include "MathUtils.h"
+#include "MAdResourceManager.h"
+
+#include <iostream>
+#include <sstream>
+#include <math.h>
+#include <sys/time.h>
+#include <fstream>
+#include <stdlib.h>
+#include <vector>
+#include <set>
+
+#ifdef PARALLEL
+ #include "mpi.h"
+#endif
+
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::stringstream;
+using std::ofstream;
+using std::vector;
+using std::set;
+
+using namespace MAd;
+
+// ----------------------------------------------------------------------
+#ifdef PARALLEL
+class EmptyExchanger : public MDB_DataExchanger
+{
+public:
+ EmptyExchanger(int _tag): MDB_DataExchanger(_tag) {}
+ ~EmptyExchanger() {}
+
+ void * sendData (pEntity pe, // in
+ int iProcDest, // in
+ int &_size ) {
+ _size = 0;
+ return NULL;
+ }
+ void receiveData (pEntity pe, //in
+ int iProcSender, //in
+ void *buf ) {}
+ void deleteExternalData( pEntity pe) const {}
+};
+#endif
+
+
+// ----------------------------------------------------------------------
+double CPUTime() {
+
+#ifdef PARALLEL
+ return MPI_Wtime();
+#else
+ struct timeval tp;
+ struct timezone tz;
+
+ gettimeofday(&tp,&tz);
+
+ return ((double) tp.tv_sec +
+ (double) ((double) .000001 * (double) tp.tv_usec));
+#endif
+}
+
+// ----------------------------------------------------------------------
+void displayMemoryUsage(string step="")
+{
+ MAdResourceManagerSgl::instance().printMemoryUsage(step,std::cout);
+}
+
+// ----------------------------------------------------------------------
+void writeSolution(MeshAdapter* ma, int iter, string type)
+{
+ stringstream ss;
+ string iterStr; ss << iter; ss >> iterStr;
+
+ if ( !strcmp(type.c_str(),"Pos") || !strcmp(type.c_str(),"MshAndPos") ) {
+ string namePos = "result" + iterStr + ".pos";
+ ma->writePos(namePos,OD_SIZEFIELD_MEAN);
+ }
+
+ if ( !strcmp(type.c_str(),"Msh") || !strcmp(type.c_str(),"MshAndPos") ) {
+ string nameMsh = "result" + iterStr + ".msh";
+ ma->writeMsh(nameMsh);
+ }
+
+// #warning "output curvature"
+// string nameCurv = "curvature" + iterStr;
+// ma->writeVolumicCurvature(nameCurv);
+}
+
+// ----------------------------------------------------------------------
+void setMobileObject(mobileObject* mob, pMesh mesh, ObjectDef def)
+{
+ // --- Name ---
+ string name = def.name;
+ mob->setName(name);
+
+ // --- Geometry ---
+ int type = def.geomLevel;
+ set<int>::const_iterator gIter = def.geomTags.begin();
+ set<int>::const_iterator gLast = def.geomTags.end();
+ for (; gIter != gLast; gIter++) {
+ for (int iTag = (*gIter); iTag <= (*gIter); iTag++) {
+ mob->addGEntity(type,iTag);
+ }
+ }
+
+ // --- Kinematics ---
+ KinematicType kinType = def.kinType;
+ if ( kinType == KT_DISPLACEMENT ) {
+ mob->setDxKinematics(def.kinExpression);
+ }
+ else {
+ mob->setVKinematics(PARSED, NULL, NULL, def.kinExpression);
+ }
+
+ // --- Local size fields ---
+ std::list<LocalSFDef>::const_iterator sIter = def.sizes.begin();
+ std::list<LocalSFDef>::const_iterator sLast = def.sizes.end();
+ for (; sIter != sLast; sIter++) {
+ LocalSizeField* locSField = new LocalSizeField(mesh, (*sIter).name,
+ (*sIter).distToFaces);
+ bool iso = (*sIter).isotropic;
+ double radius = (*sIter).radius;
+ string sizeN = (*sIter).sizeN;
+ string sizeT = (*sIter).sizeT;
+ bool limit = (*sIter).limit;
+ double limitSizeTg = (*sIter).limitSizeTg;
+ double maxCurv = (*sIter).maxCurv;
+ if ( iso ) locSField->setIsoSize(radius,sizeN);
+ else locSField->setAnisoSize(radius,sizeN,sizeT);
+ if ( limit ) locSField->setCurvatureLimiter(limitSizeTg, maxCurv);
+
+ set<int>::const_iterator gIter = def.geomTags.begin();
+ set<int>::const_iterator gLast = def.geomTags.end();
+ for (; gIter != gLast; gIter++) {
+ for (int iTag = (*gIter); iTag <= (*gIter); iTag++) {
+ locSField->addGeometricEntity(type,iTag);
+ }
+ }
+ locSField->updateTree();
+ mob->addLocalSField(locSField);
+
+// #warning "debug"
+// locSField->printPosAnisotropic(mesh,"locSF");
+ }
+}
+
+// ----------------------------------------------------------------------
+void deleteObjects(mobileObjectSet* objSet)
+{
+ set<mobileObject*> objs = objSet->getObjects();
+ set<mobileObject*>::iterator oIter = objs.begin();
+ for (; oIter != objs.end(); oIter++) {
+
+ mobileObject * mob = *oIter;
+
+ // clean size fields
+ set<LocalSizeField* > localSFs = mob->getSizes();
+ set<LocalSizeField* >::iterator sIter = localSFs.begin();
+ for (; sIter != localSFs.end(); sIter++) {
+ if (*sIter) delete (*sIter);
+ }
+
+ // delete object
+ if (mob) delete mob;
+ }
+}
+
+// ----------------------------------------------------------------------
+int main(int argc, char* argv[])
+{
+ double main_t0 = CPUTime();
+
+ MAdLibInitialize(&argc,&argv);
+
+ displayMemoryUsage("initialized");
+
+#ifdef _HAVE_PARSER_
+ parseControlFile(argc,argv);
+#endif
+
+ MoveParameters parameters = getParameters();
+
+ // ------------------------------------------------
+ // setup the output
+ // ------------------------------------------------
+
+ string outputType = parameters.outType;
+ int outputFrequency = parameters.outFrequency;
+ string outputPrefix = parameters.outPrefix;
+
+ // ------------------------------------------------
+ // load the mesh
+ // ------------------------------------------------
+
+ cout << "Loading the mesh...\n";
+ double cpu_mesh_0 = CPUTime();
+
+ // --- Reading model ---
+ string meshFileName = parameters.meshFileName;
+ string geoFileName = parameters.geoFileName;
+ pGModel model = 0;
+ GM_create(&model,"theModel");
+ if ( !geoFileName.empty() ) GM_read(model, geoFileName.c_str());
+ else GM_readFromMSH(model, meshFileName.c_str());
+
+ // --- Reading mesh ---
+ pMesh mesh = M_new(model);
+ M_load(mesh,meshFileName.c_str());
+// M_writeMsh (mesh, (outputPrefix + "initMesh.msh").c_str(), 2, NULL);
+
+ double cpu_mesh_tot = CPUTime() - cpu_mesh_0;
+ cout << "Loaded the mesh in "<<cpu_mesh_tot<<" seconds\n";
+ displayMemoryUsage("Mesh loaded");
+
+ // ------------------------------------------------
+ // build the mesh adapter
+ // ------------------------------------------------
+
+ cout << "Building the mesh adapter...\n";
+ double cpu_ma_0 = CPUTime();
+ MeshAdapter* ma = new MeshAdapter(mesh);
+
+ ma->setOutputPrefix(outputPrefix);
+
+ ma->setMaxIterationsNumber(parameters.maxInnerIter);
+
+ double lowerLenghtBound = parameters.lowerLength;
+ double upperLenghtBound = parameters.upperLength;
+ ma->setEdgeLenSqBounds( lowerLenghtBound * lowerLenghtBound,
+ upperLenghtBound * upperLenghtBound );
+
+ ma->setSwapMinImproveRatio (parameters.swapMinImproveRatio);
+ ma->setSliverQuality (parameters.sliverQuality);
+ ma->setSliverPermissionInESplit (parameters.splitCanMakeSlivers,
+ parameters.makeSliverInSplitLenSqBound);
+ ma->setSliverPermissionInECollapse (parameters.collapseCanMakeSlivers,
+ parameters.makeSliverInCollapseLenSqBound);
+ ma->setCollapseOnBoundary (parameters.collapseOnBoundary,
+ parameters.clpOnBdryTolerance);
+ ma->setSwapOnBoundary (parameters.swapOnBoundary,
+ parameters.swapOnBdryTolerance);
+ ma->setGeoTracking (parameters.trackGeometry,
+ parameters.snap_cavityIsMesh,
+ parameters.snap_thickness,
+ parameters.snap_chi);
+ ma->setSizeFieldSmoothing (parameters.SFSmoothing,
+ parameters.SFSmoothGrad);
+ ma->setInfiniteLength(parameters.infLength);
+
+#ifdef PARALLEL
+ EmptyExchanger * dExch = new EmptyExchanger(4238458);
+ ma->setDataExchanger( dExch );
+#endif
+
+ ma->setSFUpdateFrequency(0);
+
+ double cpu_ma_tot = CPUTime() - cpu_ma_0;
+ cout << "Built the mesh adapter in "<<cpu_ma_tot<<" seconds\n";
+
+ displayMemoryUsage("Mesh adapter built");
+
+// #warning "debug"
+// ma->writePos("testCurvMaxVec.pos",OD_CURVATURE_MAX_VEC);
+// printf("Written!");
+
+ // ------------------------------------------------
+ // build the size fields
+ // ------------------------------------------------
+ cout << "Buidling the size fields...\n";
+ double cpu_sf_0 = CPUTime();
+
+ set<pSField> sizeFields;
+
+ std::list<SizeFieldDef>::const_iterator sIter = parameters.sizes.begin();
+ std::list<SizeFieldDef>::const_iterator sLast = parameters.sizes.end();
+ for (; sIter != sLast; sIter++) {
+
+ SizeFieldBase* sizeField = NULL;
+
+ if ( (*sIter).type == ANALYTICALSFIELD )
+ {
+ OrientationType orient = (*sIter).orientation;
+ if ( orient == ORT_ISOTROPIC ) {
+ sizeField = new AnalyticalSField((*sIter).isoSize);
+ }
+ else {
+ sizeField = new AnalyticalSField((*sIter).anisoSize,
+ (*sIter).anisoDir0,
+ (*sIter).anisoDir1,
+ (*sIter).anisoDir2);
+ }
+ }
+ else if ( (*sIter).type == DISCRETESFIELD )
+ {
+ sizeField = new PWLSField(mesh);
+ string source = (*sIter).pwlSource;
+ if ( !strcmp(source.c_str(),"InitialLength") ) {
+ ((PWLSField*) sizeField)->setCurrentSize();
+ }
+ else if ( !strcmp(source.c_str(),"Curvature") ) {
+ bool aniso = (*sIter).curv_aniso;
+ double alpha = (*sIter).curv_alpha;
+ double hMin = (*sIter).curv_hMin;
+ ((PWLSField*) sizeField)->setCurvatureSize(aniso,alpha,hMin);
+ }
+ else throw;
+ }
+ else throw;
+
+ sizeFields.insert(sizeField);
+ ma->addSizeField(sizeField);
+ }
+
+ double cpu_sf_tot = CPUTime() - cpu_sf_0;
+ cout << "Built the size field in "<<cpu_sf_tot<<" seconds\n";
+
+ displayMemoryUsage("Size fields built");
+
+// #warning "debug"
+// ma->writePos("testSF.pos",OD_SIZEFIELD_MEAN);
+
+ ma->printStatistics(cout);
+
+
+ // ------------------------------------------------
+ // setup the quality monitoring
+ // ------------------------------------------------
+
+ string qualityFileName = outputPrefix + "quality";
+ FILE* qualFile = fopen(qualityFileName.c_str(),"w");
+ if (!qualFile) {
+ cerr << "Could not open the quality file " << qualityFileName << endl;
+ throw;
+ }
+
+ double meanShape, worstShape;
+ ma->getStatistics(&meanShape,&worstShape);
+ fprintf(qualFile,"iter\tmean quality\tworst quality\n");
+ fprintf(qualFile,"%d\t%g\t%g\n",0,meanShape,worstShape);
+ fclose(qualFile);
+
+ // ------------------------------------------------
+ // setup the cpu time monitoring
+ // ------------------------------------------------
+
+ string cpuFileName = outputPrefix + "cpu";
+ FILE* cpuFile = fopen(cpuFileName.c_str(),"w");
+ if (!cpuFile) {
+ cerr << "Could not open the cpu report file " << cpuFileName << endl;
+ throw;
+ }
+
+ fprintf(cpuFile,"iter\tnodes motion\tadaptation\toutputs \taccumulated nm\taccum adapt\taccum out\ttotal\n");
+ fclose(cpuFile);
+
+ string produceCpuInfo = "cat /proc/cpuinfo > \"" + outputPrefix + "cpuinfo\"";
+ system(produceCpuInfo.c_str());
+
+ // ------------------------------------------------
+ // setup the mesh size monitoring
+ // ------------------------------------------------
+
+ string MSFileName = outputPrefix + "meshSize";
+ FILE* MSFile = fopen(MSFileName.c_str(),"w");
+ if (!MSFile) {
+ cerr << "Could not open the mesh size report file " << MSFileName << endl;
+ throw;
+ }
+
+ fprintf(MSFile,"iter\t#nodes\t#edges\t#faces\t#regions\n");
+ fprintf(MSFile,"init\t%d\t%d\t%d\t%d\n",
+ M_numVertices(mesh),M_numEdges(mesh),M_numFaces(mesh),M_numRegions(mesh));
+ fclose(MSFile);
+
+ // ------------------------------------------------
+ // setup debug tools
+ // ------------------------------------------------
+
+ int debugLevel = parameters.debugLevel;
+ ma->setDebugLevel(debugLevel);
+
+ // --- cross checks between two executions ---
+ bool openJournal = parameters.openJournal;
+ if ( openJournal ) {
+
+ // Will hold a list of operations and checks in this execution
+ ma->openJournal();
+
+ // Will compare the list to another one (and abort if different)
+ string refJournalName = parameters.referenceJournal;
+ if ( !refJournalName.empty() ) {
+ std::cout<<"Warning: comparing execution with the journal \'"
+ << refJournalName << "\'\n";
+ ma->setReferenceJournal(refJournalName);
+ }
+ }
+
+ // --- slivers output ---
+ bool sliverReports = parameters.sliverReports;
+ if ( sliverReports ) {
+ ma->enableSliverReports();
+ }
+ bool sliverOps = parameters.testSliverOperators;
+ ma->testSliverOperators(sliverOps);
+
+ displayMemoryUsage("Monitoring and debug tools set");
+
+ // ------------------------------------------------
+ // TEST MOBILE OBJECTS
+ // ------------------------------------------------
+
+ if ( !strcmp(parameters.task.c_str(),"MobileObject") ) {
+
+#ifndef PARALLEL
+ ma->storeInitialCoordinates();
+
+ displayMemoryUsage("Initial coordinates stored");
+
+ // ---- build the mobile objects ----
+ cout << "Building the mobile objects...\n";
+ double cpu_mobj_0 = CPUTime();
+ mobileObjectSet* objs = new mobileObjectSet();
+ for (unsigned int iObj = 0; iObj < parameters.objects.size(); iObj++) {
+ mobileObject* mob = new mobileObject(mesh);
+ setMobileObject(mob,mesh,parameters.objects[iObj]);
+ objs->insert(mob);
+ }
+ ma->registerObjects(objs);
+ double cpu_mobj_tot = CPUTime() - cpu_mobj_0;
+ cout << "Built the mobile objects in "<<cpu_mobj_tot<<" seconds\n";
+ displayMemoryUsage("Mobile objects built");
+
+// #warning "Size field printed to debug"
+// ma->writePos("sizeFieldInitMean.pos", OD_SIZEFIELD_MEAN);
+// ma->writePos("sizeFieldInitMin.pos", OD_SIZEFIELD_MIN);
+// ma->writePos("sizeFieldInitMax.pos", OD_SIZEFIELD_MAX);
+// ma->writePos("sizeFieldInit0.pos",OD_ANISO_SF_AXIS0);
+// ma->writePos("sizeFieldInit1.pos",OD_ANISO_SF_AXIS1);
+// ma->writePos("sizeFieldInit2.pos",OD_ANISO_SF_AXIS2);
+// #warning "output curvature"
+// string nameCurv = "curvatureInit";
+// ma->writeVolumicCurvature(nameCurv);
+
+ // ---- get node motion parameters ----
+ string nodeMotionType = parameters.nodeMotionType;
+ double elasticChi = parameters.elasticStiffnessAlteration;
+ bool elasticCavityMesh = parameters.elasticIsMeshTheCavity;
+ int elasticCavityThick = parameters.elasticCavityThickness;
+#else
+ string nodeMotionType = "None";
+ double elasticChi;
+ bool elasticCavityMesh;
+ int elasticCavityThick;
+#endif
+
+ // ---- get time parameters ----
+ double dtGlob = parameters.timeStep;
+ double finalTime = parameters.finalTime;
+ int maxTimeSteps = parameters.maxNbTimeSteps;
+
+ // ---- the loop ----
+ double cpu_t0 = CPUTime();
+ double t = 0., dt_iter = 0.;
+ int iter = 0;
+ double cpu_move = 0., cpu_adapt = 0., cpu_output = 0.;
+ while (iter <= maxTimeSteps && t < finalTime)
+ {
+ double cpu_t1 = CPUTime();
+ if ( iter > 0 ) // a first step is performed with the adaptation before any motion occurs
+ {
+ // --- find time step for this iteration ---
+ double t_left_tot = std::max(finalTime - t, 0.0);
+ dt_iter = std::min(dtGlob, t_left_tot);
+
+ // --- move nodes (dummy move and Laplace smoothing) ---
+ if ( !strcmp(nodeMotionType.c_str(),"ForceBoundaries") ) {
+
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Forcing boundaries is followed by Laplace smoothing");
+ throw;
+
+ double part;
+ if (!ma->partlyMoveObjects(t, dt_iter, &part)) {
+ cout <<"Could not perform a forced move\n";
+ ma->abort(__LINE__,__FILE__);
+ }
+ dt_iter *= part;
+
+ if ( debugLevel >= 1 && !(ma->checkTheMesh()) ) ma->abort(__LINE__,__FILE__);
+ ma->LaplaceSmoothing(OPTIMAL);
+ if ( debugLevel >= 1 && !(ma->checkTheMesh()) ) ma->abort(__LINE__,__FILE__);
+ }
+
+ t += dt_iter; ma->setTime(t);
+ printf("\nGlobal time step %d, t = %f, dt = %f\n\n",iter,t,dt_iter);
+
+ // --- move nodes (elasticity analogy) ---
+ if ( !strcmp(nodeMotionType.c_str(),"ElasticAnalogy") ) {
+ ma->moveObjectsAndReposition(t, dt_iter,
+ elasticChi,
+ elasticCavityMesh,
+ elasticCavityThick);
+ displayMemoryUsage("Nodes repositionned");
+ }
+ }
+ double cpu_t2 = CPUTime();
+ cpu_move += ( cpu_t2 - cpu_t1 );
+
+ // --- adapt the mesh ---
+ ma->run();
+ double cpu_t3 = CPUTime();
+ cpu_adapt += ( cpu_t3 - cpu_t2 );
+ displayMemoryUsage("After adaptation");
+
+ // --- outputs ---
+
+ { // full mesh
+ if ( ( outputFrequency > 0 ) &&
+ ( (iter%outputFrequency) == 0 ) ) {
+ writeSolution(ma,iter,outputType);
+ }
+ displayMemoryUsage("After outputs");
+ }
+
+ { // quality monitor
+ ma->getStatistics(&meanShape,&worstShape);
+ FILE* qf = fopen(qualityFileName.c_str(),"a");
+ fprintf(qf,"%d\t%e\t%e\n",iter,meanShape,worstShape);
+ fclose(qf);
+ }
+
+ { // cpu monitor
+ double cpu_t4 = CPUTime();
+ cpu_output += ( cpu_t4 - cpu_t3 );
+
+ FILE* cpuF = fopen(cpuFileName.c_str(),"a");
+ fprintf(cpuF,"%d\t%e\t%e\t%e\t%e\t%e\t%e\t%e\n",
+ iter, cpu_t2 - cpu_t1, cpu_t3 - cpu_t2, cpu_t4 - cpu_t3,
+ cpu_move, cpu_adapt, cpu_output, cpu_t4 - cpu_t0 );
+ fclose(cpuF);
+ }
+
+ { // mesh size monitor
+ FILE* msf = fopen(MSFileName.c_str(),"a");
+ fprintf(msf,"%d\t%d\t%d\t%d\t%d\n",
+ iter,M_numVertices(mesh),M_numEdges(mesh),M_numFaces(mesh),M_numRegions(mesh));
+ fclose(msf);
+ }
+
+ { // slivers stats
+ if ( (iter%10) == 0 ) {
+ ofstream sliverOut( (outputPrefix + "slivers_tmp").c_str() );
+ ma->printSliverRegionStatistics(sliverOut);
+ }
+ }
+
+ { // operations stats
+ if ( (iter%10) == 0 ) {
+ ofstream operationsOut( (outputPrefix + "statistics_tmp").c_str() );
+ ma->printStatistics(operationsOut);
+ }
+ }
+
+ { // journal
+ if ( (iter%10) == 0 ) {
+ ofstream journalOut( (outputPrefix + "journal_tmp").c_str() );
+ ma->flushJournal(journalOut);
+ }
+ }
+
+ displayMemoryUsage("After monitors");
+ iter++;
+ }
+
+#ifndef PARALLEL
+ if (objs) {
+ deleteObjects(objs);
+ delete objs;
+ }
+ displayMemoryUsage("Objects deleted");
+
+ ma->removeStoredCoordinates();
+ displayMemoryUsage("Stored coordinates deleted");
+#endif
+ }
+
+ // ------------------------------------------------
+ // TEST REMOVE REGION
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"RemoveRegion") )
+ {
+ for (int i=0; i<1; i++) {
+ int numOp = 0;
+ int oriNumFaces = M_numFaces(mesh);
+ int count = 0;
+ FIter fi = M_faceIter(mesh);
+ pFace pf;
+ while ( ( pf = FIter_next(fi) ) && ( count < oriNumFaces ) ) {
+ count++;
+ if (F_numRegions(pf) != 1) continue;
+ else {
+ pRegion pr = F_region(pf,0);
+ if (!pr) pr = F_region(pf,1);
+ if ( ma->removeRegion(pr) ) numOp++;
+ }
+ }
+ FIter_delete(fi);
+ cout << "Num region removed: "<<numOp<<endl;
+ }
+ }
+
+ // ------------------------------------------------
+ // test size fields intersection or smoothing
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"SizeField") )
+ {
+ ma->writePos("testSF.pos",OD_SIZEFIELD_MEAN);
+ ma->writePos("aniso0.pos",OD_ANISO_SF_AXIS0);
+ ma->writePos("aniso1.pos",OD_ANISO_SF_AXIS1);
+ ma->writePos("aniso2.pos",OD_ANISO_SF_AXIS2);
+
+ PWLSField* testSF = new PWLSField(mesh);
+ string h = "2.*x+0.1";
+ AnalyticalSField* testASF = new AnalyticalSField(h);
+
+ testSF->intersect(testASF);
+// testSF->smooth(0.5);
+
+ MeshAdapter* testMA = new MeshAdapter(mesh,testSF);
+
+ testMA->writePos("sizeField.pos",OD_SIZEFIELD_MEAN);
+ // testMA->writePos("sizeFieldSmoothed.pos",OD_SIZEFIELD_MEAN);
+
+ exit(0);
+ }
+
+ // ------------------------------------------------
+ // TEST REMOVE SLIVER FACES
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"RemoveSliverFaces") )
+ {
+ for (int i=0; i<10; i++) {
+ ma->removeSlivers();
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+ }
+ }
+
+ // ------------------------------------------------
+ // TEST LAPLACE SMOOTHING
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"LaplaceSmoothing") )
+ {
+ for (int i=0; i<1; i++) {
+ ma->LaplaceSmoothing(FAST);
+ cout << "Smoothing "<<i<<" operated\n";
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+ }
+ }
+
+ // ------------------------------------------------
+ // TEST GEOMETRIC CONSTRAINTS
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"GeoConstraints") )
+ {
+ ma->setConstraint(2,5);
+ ma->removeConstraint(2,5);
+ }
+
+ // ------------------------------------------------
+ // TEST CONSTRAINTS
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"TopoConstraints") )
+ {
+ FIter fi = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fi) ) {
+ int gtag = GEN_tag ( EN_whatIn ((pEntity)pf) );
+ int gtype = GEN_type( EN_whatIn ((pEntity)pf) );
+ if ( gtype == 2 && ( gtag == 5 || gtag == 22 || gtag == 14 || gtag == 27 ) ) ma->setConstraint((pEntity)pf);
+ }
+ FIter_delete(fi);
+
+ VIter vi = M_vertexIter(mesh);
+ pVertex pv;
+ while ( ( pv = VIter_next(vi) ) ) {
+ // int gtag = GEN_tag ( EN_whatIn ((pEntity)pv) );
+ int gtype = GEN_type( EN_whatIn ((pEntity)pv) );
+ if ( gtype == 0 ) EN_constrain((pEntity)pv);
+ }
+ VIter_delete(vi);
+ }
+
+ // ------------------------------------------------
+ // TEST FACE SWAP OPERATOR
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"FaceSwap") )
+ {
+ for (int i=0; i<5; i++) {
+ int count=0, numOp=0;
+ int oriNumFaces = M_numFaces(mesh);
+ FIter fi = M_faceIter(mesh);
+ pFace pf;
+ while ( ( pf = FIter_next(fi) ) && ( count < oriNumFaces ) ) {
+ int res = ma->swapFace(pf);
+ if ( res ) numOp++;
+ count++;
+ }
+ FIter_delete(fi);
+ cout << "Num face swaps: "<<numOp<<endl;
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+
+ int nESwaps = ma->optimiseElementShape();
+ cout<< "Edge swaps applied: "<<nESwaps<<endl;
+ }
+ }
+
+ // ------------------------------------------------
+ // MAKE A BAD MESH
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"UglyMesh") )
+ {
+ ma->uglyTheMesh(0.2,10);
+ ma->writeMsh("uglyMesh.msh");
+ }
+
+ // ------------------------------------------------
+ // TEST REMOVE SLIVER REGIONS
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"RemoveSliverRegions") )
+ {
+ ma->setSliverQuality(0.1);
+ for (int i=0; i<2; i++) {
+ ma->removeSlivers();
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+ }
+ }
+
+ // ------------------------------------------------
+ // TEST DOUBLE-SPLIT-COLLAPSE OPERATOR
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"DESC") )
+ {
+ for (int i=0; i<20; i++) {
+ int numOp = 0;
+ int oriNumRgn = M_numRegions(mesh);
+ int count = 0;
+ RIter ri = M_regionIter(mesh);
+ pRegion pr;
+ while ( ( pr = RIter_next(ri) ) && ( count < oriNumRgn ) ) {
+ pEdge pe1 = R_edge(pr,0);
+ pEdge pe2 = R_gtOppEdg(pr, pe1);
+
+ if ( ma->DSplitCollapseEdge(pr,pe1,pe2) )
+ numOp++;
+ count++;
+ }
+ RIter_delete(ri);
+ cout << "Num double-split-collapses: "<<numOp<<endl;
+
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+ // ma->printStatistics(std::cout);
+
+ // int* nbBefore = new int(0);
+ // int* nbAfter = new int(0);
+ // ma->removeSliverRegions(nbBefore,nbAfter);
+ // cout <<"Nb slivers before->after realignement:\t"<<*nbBefore<<" -> "<<*nbAfter<<endl;
+ }
+ }
+
+ // ------------------------------------------------
+ // TEST EDGE SWAP
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"EdgeSwap") )
+ {
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+ for (int i=0; i<30; i++) {
+ int count = 0;
+ int numOp = 0;
+ int numE = M_numEdges(mesh);
+ EIter ei = M_edgeIter(mesh);
+ while ( pEdge pe = EIter_next(ei) ) {
+ count++;
+ if ( ma->swapEdge(pe) ) numOp++;
+ if ( count > numE ) break;
+ }
+ EIter_delete(ei);
+ cout << "Num edge swaps ("<<i<<"): " << numOp << endl;
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+ writeSolution(ma,i,outputType);
+ }
+ }
+
+ // ------------------------------------------------
+ // TEST GEOMATCHER
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"GeoMatcher") )
+ {
+ for (int i=0; i<8; i++) {
+ int count = 0;
+ int numOp = 0;
+ int numE = M_numEdges(mesh);
+ EIter ei = M_edgeIter(mesh);
+ pEdge pe;
+ while ( ( pe = EIter_next(ei) ) ) {
+ count++;
+ if ( ma->splitEdge(pe) ) {
+ ma->snapVertices();
+ numOp++;
+ }
+ if ( count > numE ) break;
+ }
+ EIter_delete(ei);
+ cout << "Num edge splits ("<<i<<"): " << numOp << endl;
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+ }
+ }
+
+ // ------------------------------------------------
+ // TEST EDGE SPLIT
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"EdgeSplit") )
+ {
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+ for (int i=0; i<5; i++) {
+
+ ma->splitEveryEdgeOnce();
+
+// int count = 0;
+// int numOp = 0;
+// int numE = M_numEdges(mesh);
+// EIter ei = M_edgeIter(mesh);
+// pEdge pe;
+// while ( ( pe = EIter_next(ei) ) ) {
+// count++;
+// if ( E_whatInType(pe) <= 2 && ma->splitEdge(pe) ) { numOp++; }
+// if ( count > numE ) break;
+// }
+// EIter_delete(ei);
+// cout << "Num edge splits ("<<i<<"): " << numOp << endl;
+// if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+
+// // --- Geometry tracking ---
+// cout << "Snapping boundary nodes" << endl;
+// if (numOp) ma->snapVertices();
+
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+ writeSolution(ma,i,outputType);
+ }
+ }
+
+ // ------------------------------------------------
+ // TEST EDGE COLLAPSE
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"EdgeCollapse") )
+ {
+ // GM_writeGEO(model,"testgeo.geo");
+ // ma->writeMsh("MeshInit.msh");
+ for (int i=0; i<10; i++) {
+ double t0 = CPUTime();
+ int count = 0;
+ int nbEdgesInit = M_numEdges(mesh);
+ int numOp = 0;
+ EIter ei = M_edgeIter(mesh);
+ pEdge pe;
+ while ( ( pe = EIter_next(ei) ) ) {
+ count++;
+ if ( ma->collapseEdge(pe) ) { numOp++; }
+ if ( count > nbEdgesInit ) break;
+ }
+ EIter_delete(ei);
+ double dt = CPUTime() - t0;
+ cout << "Num edge collapses ("<<i<<"): " << numOp << " in "<<dt<<" seconds\n";
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+// ma->printStatistics(std::cout);
+ writeSolution(ma,i,outputType);
+ }
+ }
+
+ // ------------------------------------------------
+ // TEST EDGE SPLIT AND COLLAPSE
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"EdgeSplitCollapse") )
+ {
+ for (int i=0; i<20; i++) {
+
+ // --- collapse as many edges as possible ---
+ int totColl = 0;
+ while (1) {
+ int numClp = 0;
+// while (1)
+// {
+// pEdge pe;
+// EIter ei = M_edgeIter(mesh);
+// while ( ( pe = EIter_next(ei) ) ) {
+// if ( ma->collapseEdge(pe) ) { numClp++; break; }
+// }
+// EIter_delete(ei);
+// if ( !pe ) break;
+// if ( !checkMesh(mesh,CHECK_GEOM_COMPATIBILITY,1,std::cout) ) ma->abort(__LINE__,__FILE__);
+// }
+ EIter ei = M_edgeIter(mesh);
+ pEdge pe;
+ while ( ( pe = EIter_next(ei) ) ) {
+ if ( ma->collapseEdge(pe) ) numClp++;
+ }
+ EIter_delete(ei);
+ totColl += numClp;
+ cout << "Num edge collapses: "<< numClp << endl;
+ if ( ! ma->checkTheMesh() ) ma->abort(__LINE__,__FILE__);
+ if ( numClp == 0 ) break;
+ }
+
+ // --- perform many edge splits ---
+ for (int iS=0; iS<2; iS++) {
+ int numSpl = ma->splitEveryEdgeOnce();
+ cout << "Num edge splits: " << numSpl << endl;
+ if ( ! ma->checkTheMesh() ) ma->abort(__LINE__,__FILE__);
+ }
+
+ // --- Geometry tracking ---
+// if (numSpl) ma->snapVertices();
+// if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+
+ writeSolution(ma,i,outputType);
+ }
+
+ /*
+ for (int i=0; i<10; i++) {
+ int count = 0;
+ int oriNumEdges = M_numEdges(mesh);
+ int numClp = 0, numSpl = 0;
+ EIter ei = M_edgeIter(mesh);
+ pEdge pe;
+ while ( ( pe = EIter_next(ei) ) ) {
+ count++;
+ if ( E_whatInType(pe) <= 2 )
+ {
+ if ( (count%3) == 0 ) {
+ if ( ma->splitEdge(pe) ) numSpl++;
+ }
+ else {
+ if ( ma->collapseEdge(pe) ) numClp++;
+ }
+ }
+ if ( count > oriNumEdges ) break;
+ }
+ EIter_delete(ei);
+ cout << "Num edge splits ("<<i<<"): " << numSpl << endl;
+ cout << "Num edge collapses ("<<i<<"): " << numClp << endl;
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+
+ // --- Geometry tracking ---
+ if (numSpl) ma->snapVertices();
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+
+ writeSolution(ma,i,outputType);
+// ma->printStatistics(std::cout);
+ }
+ */
+ }
+
+ // ------------------------------------------------
+ // TEST FACE COLLAPSE OPERATOR
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"FaceCollapse") )
+ {
+ for (int i=0; i<10; i++) {
+ int numOp = 0;
+ int oriNumFaces = M_numFaces(mesh);
+ int count = 0;
+ FIter fi = M_faceIter(mesh);
+ pFace pf;
+ while ( ( pf = FIter_next(fi) ) && ( count < oriNumFaces ) ) {
+ for (int j=0; j<3; j++) {
+ pEdge pe = F_edge(pf,j);
+ if ( ma->collapseFace(pf,pe) ) {
+ numOp++;
+ break;
+ }
+ }
+ count++;
+ }
+ FIter_delete(fi);
+ cout << "Num face collapse: "<<numOp<<endl;
+ if ( !checkMesh(mesh,CHECK_ALL,1) ) ma->abort(__LINE__,__FILE__);
+// ma->printStatistics(std::cout);
+ }
+ }
+
+ // ------------------------------------------------
+ // TEST OPTIMISE EDGE LENGTH
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"OptimizeLength") )
+ {
+ cout<<"Split collapses applied: "<<ma->optimiseEdgeLength()<<endl;
+ }
+
+ // ------------------------------------------------
+ // TEST OPTIMISE SHAPE
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"OptimizeShape") )
+ {
+ int nSwaps = ma->optimiseElementShape();
+ cout<< "Swaps applied: "<<nSwaps<<endl;
+ }
+
+ // ------------------------------------------------
+ // TEST METRIC
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"Metric") )
+ {
+ double h[3] = { 2., 3., 10. };
+ double e[3][3] = {
+ {sqrt(2.)/2., sqrt(2.)/2., 0.},
+ {0., 0., 1.},
+ {sqrt(2.)/2., -sqrt(2.)/2., 0.}
+ };
+
+ MAdMetric M = MAdMetric(h[0],h[1],h[2],e[0],e[1],e[2]);
+
+ doubleMatrix V = doubleMatrix(3,3);
+ doubleVector S = doubleVector(3);
+ M.eig(V,S,true);
+
+ printVec(h,"h");
+ printMat(e,"e");
+ V.print("V");
+ S.print("S");
+ }
+
+ // ------------------------------------------------
+ // TEST CURVATURES
+ // ------------------------------------------------
+
+ else if ( !strcmp(parameters.task.c_str(),"Curvatures") )
+ {
+ ma->writePos("CurvDiv.pos",OD_CURVATURE_DIV);
+ ma->writePos("CurvMax.pos",OD_CURVATURE_MAX);
+ ma->writePos("CurvMin.pos",OD_CURVATURE_MIN);
+ ma->writePos("CurvMaxVec.pos",OD_CURVATURE_MAX_VEC);
+ ma->writePos("CurvMinVec.pos",OD_CURVATURE_MIN_VEC);
+
+// FIter fi = M_faceIter(mesh);
+// pFace pf;
+// while ( ( pf = FIter_next(fi) ) )
+// {
+// if ( F_whatInType(pf) != 2 ) continue;
+
+// pGEntity pge = F_whatIn(pf);
+// {
+// double u[2] = { 0., 0. };
+// double xyz[3];
+// GF_xyz( (pGFace) pge, u[0], u[1], xyz);
+// printf("u: %f, v: %f\n",u[0],u[1]);
+// printVec(xyz,"xyz");
+// }
+
+// double u[2] = { 0.5, 0.5 };
+// double xyz[3];
+// GF_xyz( (pGFace) pge, u[0], u[1], xyz);
+// printf("u: %f, v: %f\n",u[0],u[1]);
+// printVec(xyz,"xyz");
+
+// double divCurv = GF_curvature( (pGFace)pge, u);
+// double dirMax[3], dirMin[3], maxCurv, minCurv;
+// double mCurv = GF_curvatures( (pGFace)pge, u,
+// dirMax, dirMin, &maxCurv, &minCurv);
+
+// printVec(dirMax,"dirMax");
+// printVec(dirMin,"dirMin");
+// printf("Max curv: %f, min curv: %f, div curv: %f\n",maxCurv,minCurv,divCurv);
+
+// double tmp[3];
+// tmp[0] = dotProd(xyz,dirMax);
+// tmp[1] = dotProd(xyz,dirMin);
+// tmp[2] = dotProd(dirMin,dirMax);
+// printVec(tmp,"sould be 0 vector");
+
+// break;
+// }
+// FIter_delete(fi);
+ }
+
+ // ------------------------------------------------
+ else if ( !strcmp(parameters.task.c_str(),"None") )
+ {
+ }
+
+ else {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Unknown task %s",parameters.task.c_str());
+ }
+
+ // ------------------------------------------------
+ // Write final result
+ // ------------------------------------------------
+
+ ma->writeMsh("result.msh");
+// ma->writePos("result.pos",OD_MEANRATIO);
+
+// #warning "Size field printed to debug"
+// ma->writePos("sizeFieldFinalMean.pos", OD_SIZEFIELD_MEAN);
+// ma->writePos("sizeFieldFinalMin.pos", OD_SIZEFIELD_MIN);
+// ma->writePos("sizeFieldFinalMax.pos", OD_SIZEFIELD_MAX);
+// ma->writePos("sizeFieldFinal0.pos",OD_ANISO_SF_AXIS0);
+// ma->writePos("sizeFieldFinal1.pos",OD_ANISO_SF_AXIS1);
+// ma->writePos("sizeFieldFinal2.pos",OD_ANISO_SF_AXIS2);
+// #warning "output curvature"
+// ma->writeVolumicCurvature("curvatureFinal");
+
+ ma->printStatistics(cout);
+ ofstream statOut((outputPrefix + "statistics").c_str());
+ ma->printStatistics(statOut);
+
+ ofstream sliverOut((outputPrefix + "slivers").c_str());
+ ma->printSliverRegionStatistics(sliverOut);
+
+ ofstream journalOut((outputPrefix + "journal").c_str());
+ ma->flushJournal(journalOut);
+
+ // ------------------------------------------------
+ // Clean up
+ // ------------------------------------------------
+
+ if (ma) delete ma;
+ set<pSField>::iterator sfIter = sizeFields.begin();
+ set<pSField>::iterator sfLast = sizeFields.end();
+ for (; sfIter != sfLast; sfIter++) {
+ delete (*sfIter);
+ }
+ displayMemoryUsage("Adapter and size fields deleted");
+
+ if (mesh) M_delete(mesh);
+ if (model) GM_delete(model);
+ displayMemoryUsage("Mesh and model deleted");
+
+ MAdLibFinalize();
+
+ printf("Total execution time: %f seconds\n", CPUTime()-main_t0);
+}
+
+// ----------------------------------------------------------------------
diff --git a/Benchmarks/moveIt/moveItParse.h b/Benchmarks/moveIt/moveItParse.h
new file mode 100644
index 0000000..df96ca6
--- /dev/null
+++ b/Benchmarks/moveIt/moveItParse.h
@@ -0,0 +1,563 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MOVEITPARSE_
+#define _H_MOVEITPARSE_
+
+#ifdef _HAVE_PARSER_
+
+#include "Parser.h"
+
+#include "MSops.h"
+#include "MAdMessage.h"
+#include "Parameters.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+
+extern int yyCMDparse();
+
+//==============================================================================
+// Control file definition
+//==============================================================================
+
+void DefineMMCtrlFile() {
+
+ // global input specifications
+ // ---------------------------
+
+ ClassParameter& input = Parser::instance().add("Input");
+ ClassParameter& inputMesh = input.add("Mesh");
+ inputMesh.addString("MshFile","");
+ inputMesh.addString("GeoFile","");
+
+ // global output parameters
+ // ------------------------
+
+ ClassParameter& output = Parser::instance().add("Output");
+ output.addString("Prefix","result/");
+ output.addInteger("Frequency",1);
+ output.addToken("Type",3,"MshAndPos","Msh","Pos","MshAndPos");
+
+ // Task parameters
+ // ----------------
+
+ ClassParameter& task = Parser::instance().add("Task");
+ task.addToken("Type",22,
+ "MobileObject",
+ "RemoveRegion",
+ "SizeField",
+ "RemoveSliverFaces",
+ "LaplaceSmoothing",
+ "GeoConstraints",
+ "TopoConstraints",
+ "FaceSwap",
+ "UglyMesh",
+ "RemoveSliverRegions",
+ "DESC",
+ "EdgeSwap",
+ "GeoMatcher",
+ "EdgeSplit",
+ "EdgeCollapse",
+ "EdgeSplitCollapse",
+ "FaceCollapse",
+ "OptimizeLength",
+ "OptimizeShape",
+ "Metric",
+ "Curvatures",
+ "None",
+ "MobileObject");
+
+ // debug parameters
+ // -----------------
+
+ ClassParameter& debug = Parser::instance().add("Debug");
+ debug.addInteger("DebugLevel",1);
+ debug.addToken("OpenJournal",2,"Yes","No","No");
+ debug.addString("ReferenceJournal","");
+ debug.addToken("ReportSlivers",2,"Yes","No","No");
+ debug.addToken("TestSliverOperators",2,"Yes","No","No");
+
+ // Mesh adaptation
+ // ----------------
+
+ ClassParameter& ma = Parser::instance().add("Adaptation");
+ ma.addInteger("MaxNumberOfInnerIteration",10);
+ ma.addDouble("LowerLengthBound",1./sqrt(3.));
+ ma.addDouble("UpperLengthBound",sqrt(3.));
+ ma.addDouble("InfiniteEdgeLength",1.e14);
+ ma.addDouble("SwapMinImproveRatio",1.0);
+ ma.addDouble("SliverQuality",0.02);
+ ma.addToken("SplitCanMakeSlivers",2,"No","Yes","Yes");
+ ma.addToken("CollapseCanMakeSlivers",2,"No","Yes","Yes");
+ ma.addDouble("SliverLowerLengthSqBound",0.1);
+ ma.addDouble("SliverUpperLengthSqBound",10.);
+ ma.addToken("CollapseOnBoundary",2,"No","Yes","Yes");
+ ClassParameter& mabound = ma.add("BoundaryCollapses");
+ mabound.addDouble("Tolerance",1.e-6);
+ ma.addToken("SwapOnBoundary",2,"No","Yes","Yes");
+ ClassParameter& maboundswp = ma.add("BoundarySwaps");
+ maboundswp.addDouble("Tolerance",1.e-6);
+ ma.addToken("TrackGeometry",2,"No","Yes","No");
+ ClassParameter& masnap = ma.add("VertexSnapping");
+ masnap.addToken("IsMeshTheCavity",2,"No","Yes","No");
+ masnap.addInteger("CavityThickness",3);
+ masnap.addDouble("StiffnessAlteration",1.0);
+ ma.addToken("SmoothSizeField",2,"No","Yes","No");
+ ClassParameter& smoo = ma.add("SizeFieldSmoothing");
+ smoo.addDouble("MaximumGradient",1.0);
+
+ // moving objects
+ // --------------
+
+ ClassParameter& mo = Parser::instance().add("MovingObjects");
+ ClassParameter& object = mo.addMultiple("Object");
+
+ // geometry
+ ClassParameter& obj_geom = object.add("Geometry");
+ obj_geom.addToken("GeometricalType",4,"Vertex","Edge","Face","Region","Face");
+ obj_geom.addIntegerRange("GeometricalTags");
+
+ // kinematics
+ ClassParameter& obj_kin = object.add("Kinematics");
+ obj_kin.addToken("KinematicsSpecification",2,"Displacement","Velocity","Displacement");
+ ClassParameter& kinDx = obj_kin.add("Displacement");
+ kinDx.addStringList("Formulation");
+ ClassParameter& kinV = obj_kin.add("Velocity");
+ kinV.addStringList("Formulation");
+
+ // size field
+ ClassParameter& locS = object.addMultiple("LocalSizeField");
+// locS.addDouble("Radius",0.);
+// locS.addToken("SizeFunction",2,"Linear","Sqrt","Linear");
+// locS.addDouble("SizeOnObject",1.);
+// locS.addDouble("SizeOutside",1.);
+// locS.addToken("Orientation",2,"Isotropic","Anisotropic","Isotropic");
+// ClassParameter& anisoLsf = locS.add("Anisotropic");
+// anisoLsf.addDouble("SizeTangent",1.);
+ locS.addToken("DistanceComputation",2,"ToWallVertices","ToWallFaces","ToWallVertices");
+ locS.addToken("Orientation",2,"Isotropic","Anisotropic","Isotropic");
+ locS.addDouble("Radius",0.);
+ ClassParameter& isoLsf = locS.add("Isotropic");
+ isoLsf.addString("Size","");
+ ClassParameter& anisoLsf = locS.add("Anisotropic");
+ anisoLsf.addString("NormalSize","");
+ anisoLsf.addString("TangentSize","");
+ ClassParameter& limiter = locS.add("CurvatureBasedLimiter");
+ limiter.addToken("Enable",2,"Yes","No","No");
+ limiter.addDouble("TangentSizeOverRadius",1.);
+ limiter.addDouble("CurvatureLimiter",1.e6);
+
+ // Size Field parameters
+ // ---------------------
+
+ ClassParameter& sf = Parser::instance().addMultiple("SizeField");
+ sf.addToken("Type",2,"Analytical","PiecewiseLinear","Analytical");
+ ClassParameter& sf_an = sf.add("Analytical");
+ sf_an.addToken("OrientationType",2,"Isotropic","Anisotropic","Isotropic");
+ ClassParameter& sf_an_iso = sf_an.add("Isotropic");
+ sf_an_iso.addString("Length","");
+ ClassParameter& sf_an_aniso = sf_an.add("Anisotropic");
+ sf_an_aniso.addStringList("Lengths");
+ sf_an_aniso.addStringList("Direction1");
+ sf_an_aniso.addStringList("Direction2");
+ sf_an_aniso.addStringList("Direction3");
+ ClassParameter& sf_pwl = sf.add("PiecewiseLinear");
+ sf_pwl.addToken("Source",2,"InitialLength","Curvature","Curvature");
+ ClassParameter& sf_pwl_curv = sf_pwl.add("Curvature");
+ sf_pwl_curv.addToken("Anisotropic",2,"Yes","No","Yes");
+ sf_pwl_curv.addDouble("Alpha",2.);
+ sf_pwl_curv.addDouble("MinimalLength",1.e-4);
+
+ // Node motion
+ // -----------
+
+ ClassParameter& nm = Parser::instance().add("NodeMotion");
+ nm.addToken("Type",3,"ElasticAnalogy","ForceBoundaries","None","None");
+ ClassParameter& maelas = nm.add("ElasticParameters");
+ maelas.addToken("IsMeshTheCavity",2,"No","Yes","Yes");
+ maelas.addInteger("CavityThickness",3);
+ maelas.addDouble("StiffnessAlteration",1.0);
+
+ // Time parameters
+ // ---------------
+
+ ClassParameter& time = Parser::instance().add("TimeSpecifications");
+ time.addInteger("MaxTimeSteps",1000000);
+ time.addDouble("TimeStep",0.1);
+ time.addDouble("FinalTime",-1.0);
+}
+
+//==============================================================================
+// Parsing functions
+//==============================================================================
+
+string parseMMCommandLine(int argc,char** argv) {
+
+ string inputFile = "";
+ string templateFile = "";
+
+ bool inputFileSpecified = false;
+ bool dumpTemplate = false;
+
+ if (argc == 1) {
+ dumpTemplate = true;
+ }
+ else if ( argc==2 ){
+ inputFileSpecified = true;
+ inputFile = argv[1];
+ }
+ else {
+ std::cerr << "Usages:" << argv[0]<<" control_file"<<std::endl;
+ exit(1);
+ }
+
+ // dump a template file
+
+ if (dumpTemplate) {
+ templateFile = "template.mad";
+ FILE* fpcheck = fopen(templateFile.c_str(),"w");
+ fprintf(fpcheck,"//-*- C++ -*-\n");
+ printf("Writing a template parameter tree to file \'%s\'\n",templateFile.c_str());
+ Parser::instance().print(fpcheck);
+ fclose(fpcheck);
+ exit(1);
+ }
+
+ // read the parameters
+
+ if (!inputFileSpecified || inputFile == "") {
+ printf("No parameter file was specified - exiting");
+ exit(1);
+ }
+
+ return inputFile;
+}
+
+// -----------------------------------------------------------------------------
+bool parseMMCtrlFile(const string& inputFile) {
+
+ FILE* fp = freopen(inputFile.c_str(), "r", stdin);
+ if (!fp) {
+ printf("Error: could not open parameter file \'%s\'\n",inputFile.c_str());
+ return false;
+ }
+
+ yyCMDparse();
+
+ return true;
+}
+
+// ----------------------------------------------------------------------
+// Parse the control file
+void parseControlFile(int argc, char* argv[])
+{
+ cout << "Parsing the control file...\n";
+ DefineMMCtrlFile();
+ string inputFile = parseMMCommandLine(argc,argv);
+ parseMMCtrlFile(inputFile);
+}
+
+// ----------------------------------------------------------------------
+void setCurrentParameters(MoveParameters * params)
+{
+ // ------------------------------------------------
+ // Fill in 'params' with the parsed values
+ // ------------------------------------------------
+ cout << "Fill in the parameters from the control file...\n";
+
+ // mesh and geometry parameters
+ // -----------------------------
+
+ ClassParameter& input = Parser::instance().get("Input");
+ ClassParameter& inputMesh = input.get("Mesh");
+ params->meshFileName = inputMesh.getString("MshFile");
+ params->geoFileName = inputMesh.getString("GeoFile");
+
+ // global output parameters
+ // ------------------------
+
+ ClassParameter& outputParam = Parser::instance().get("Output");
+ params->outType = outputParam.getToken("Type");
+ params->outFrequency = outputParam.getInteger("Frequency");
+ params->outPrefix = outputParam.getString("Prefix");
+
+ // Global task parameters
+ // ----------------------
+
+ ClassParameter& taskParams = Parser::instance().get("Task");
+ params->task = taskParams.getToken("Type");
+
+ // debugging parmeters
+ // --------------------
+
+ ClassParameter& debugParams = Parser::instance().get("Debug");
+ params->debugLevel = debugParams.getInteger("DebugLevel");
+
+ params->openJournal = false;
+ string openJournal = debugParams.getToken("OpenJournal");
+ if ( !strcmp(openJournal.c_str(),"Yes") ) params->openJournal = true;
+
+ params->referenceJournal = debugParams.getString("ReferenceJournal");
+
+ params->sliverReports = false;
+ string sliverReports = debugParams.getToken("ReportSlivers");
+ if ( !strcmp(sliverReports.c_str(),"Yes") ) params->sliverReports = true;
+
+ params->testSliverOperators = false;
+ string sliverOps = debugParams.getToken("TestSliverOperators");
+ if ( !strcmp(sliverOps.c_str(),"Yes") ) params->testSliverOperators = true;
+
+ // Mesh adaptation
+ // ----------------
+
+ ClassParameter& adParam = Parser::instance().get("Adaptation");
+ params->maxInnerIter = adParam.getInteger("MaxNumberOfInnerIteration");
+ params->lowerLength = adParam.getDouble("LowerLengthBound");
+ params->upperLength = adParam.getDouble("UpperLengthBound");
+ params->infLength = adParam.getDouble("InfiniteEdgeLength");
+ params->swapMinImproveRatio = adParam.getDouble("SwapMinImproveRatio");
+ params->sliverQuality = adParam.getDouble("SliverQuality");
+
+ params->splitCanMakeSlivers = false;
+ string slivSpl = adParam.getToken("SplitCanMakeSlivers");
+ if ( !strcmp(slivSpl.c_str(),"Yes") ) params->splitCanMakeSlivers = true;
+ params->makeSliverInSplitLenSqBound = adParam.getDouble("SliverUpperLengthSqBound");
+
+ params->collapseCanMakeSlivers = false;
+ string slivColl = adParam.getToken("CollapseCanMakeSlivers");
+ if ( !strcmp(slivColl.c_str(),"Yes") ) params->collapseCanMakeSlivers = true;
+ params->makeSliverInCollapseLenSqBound = adParam.getDouble("SliverLowerLengthSqBound");
+
+ params->collapseOnBoundary = false;
+ string clpOnB = adParam.getToken("CollapseOnBoundary");
+ if ( !strcmp(clpOnB.c_str(),"Yes") ) params->collapseOnBoundary = true;
+ params->clpOnBdryTolerance = adParam.get("BoundaryCollapses").getDouble("Tolerance");
+
+ params->swapOnBoundary = false;
+ string swapOnB = adParam.getToken("SwapOnBoundary");
+ if ( !strcmp(swapOnB.c_str(),"Yes") ) params->swapOnBoundary = true;
+ params->swapOnBdryTolerance = adParam.get("BoundarySwaps").getDouble("Tolerance");
+
+ params->trackGeometry = false;
+ string trackGeo = adParam.getToken("TrackGeometry");
+ if ( !strcmp(trackGeo.c_str(),"Yes") ) {
+ if ( params->geoFileName.empty() ) {
+ printf("Error: you have to provide a geometry file if you want to track geometry\n");
+ throw;
+ }
+ params->trackGeometry = true;
+ }
+ ClassParameter& snapParams = adParam.get("VertexSnapping");
+ params->snap_cavityIsMesh = false;
+ if ( !strcmp( snapParams.getToken("IsMeshTheCavity"), "Yes" ) ) {
+ params->snap_cavityIsMesh = true;
+ }
+ params->snap_thickness = snapParams.getInteger("CavityThickness");
+ params->snap_chi = snapParams.getDouble("StiffnessAlteration");
+
+ params->SFSmoothing = false;
+ string smoothSF = adParam.getToken("SmoothSizeField");
+ if ( !strcmp(smoothSF.c_str(),"Yes") ) params->SFSmoothing = true;
+ ClassParameter& smoothParams = adParam.get("SizeFieldSmoothing");
+ params->SFSmoothGrad = smoothParams.getDouble("MaximumGradient");
+
+ // Node motion
+ // -----------
+
+ ClassParameter& reposParams = Parser::instance().get("NodeMotion");
+ params->nodeMotionType = reposParams.getToken("Type");
+ ClassParameter& elParams = reposParams.get("ElasticParameters");
+ params->elasticStiffnessAlteration = elParams.getDouble("StiffnessAlteration");
+ params->elasticIsMeshTheCavity = false;
+ if ( !strcmp( elParams.getToken("IsMeshTheCavity"), "Yes" ) ) {
+ params->elasticIsMeshTheCavity = true;
+ }
+ params->elasticCavityThickness = elParams.getInteger("CavityThickness");
+
+ // Time parameters
+ // ---------------
+
+ ClassParameter& temporalParameters = Parser::instance().get("TimeSpecifications");
+ params->timeStep = temporalParameters.getDouble("TimeStep");
+ params->finalTime = temporalParameters.getDouble("FinalTime");
+ params->maxNbTimeSteps = temporalParameters.getInteger("MaxTimeSteps");
+
+ // Moving objects
+ // --------------
+
+ ClassParameter& objsParam = Parser::instance().get("MovingObjects");
+ for (int iObj = 0; iObj < objsParam.get("Object").size(); iObj++)
+ {
+ ClassParameter& objParam = objsParam.get("Object",iObj);
+
+ ObjectDef object;
+
+ // --- Name ---
+
+ object.name = objParam.getTag();
+
+ // --- Geometry ---
+
+ ClassParameter& geoPar = objParam.get("Geometry");
+ string geomType = geoPar.getToken("GeometricalType");
+ if (geomType == "Vertex") object.geomLevel=0;
+ else if(geomType == "Edge") object.geomLevel=1;
+ else if(geomType == "Face") object.geomLevel=2;
+ else if(geomType == "Region") object.geomLevel=3;
+ else
+ printf("Error: unknown geometrical type %s",geomType.c_str());
+ // get tags of entities
+ // vector<int> geomTags = geoPar.getIntegerList("GeometricalTags");
+ vector<pair<int,int> > geomTags = geoPar.getIntegerRange("GeometricalTags");
+ for (unsigned int iTag = 0; iTag < geomTags.size(); iTag++ )
+ for (int iTag2 = (geomTags[iTag]).first; iTag2 <= (geomTags[iTag]).second; iTag2++)
+ object.geomTags.insert(iTag2);
+
+ // --- Kinematics ---
+
+ ClassParameter& kinPar = objParam.get("Kinematics");
+ string kinType = kinPar.getToken("KinematicsSpecification");
+ if ( !strcmp(kinType.c_str(),"Displacement") ) {
+ object.kinType = KT_DISPLACEMENT;
+ MAd::MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Displacement formulation for object is wrong when using geometry tracking");
+ ClassParameter& kinParDx = kinPar.get("Displacement");
+ object.kinExpression = kinParDx.getStringList("Formulation");
+ }
+
+ else if ( !strcmp(kinType.c_str(),"Velocity") ) {
+ object.kinType = KT_VELOCITY;
+ ClassParameter& kinParV = kinPar.get("Velocity");
+ object.kinExpression = kinParV.getStringList("Formulation");
+ }
+ else throw;
+
+ if (object.kinExpression.size() != 3) {
+ cerr << "Error: exactly 3 components are required in the displacement/velocity strings list\n";
+ throw;
+ }
+
+ // --- Local size fields ---
+
+ for (int iSF = 0; iSF < objParam.get("LocalSizeField").size(); iSF++) {
+ ClassParameter& sizeP = objParam.get("LocalSizeField",iSF);
+
+ LocalSFDef localSF;
+
+ localSF.name = sizeP.getTag();
+
+ string distComp = sizeP.getToken("DistanceComputation");
+ localSF.distToFaces = false;
+ if ( !strcmp( distComp.c_str(), "ToWallFaces" ) ) {
+ localSF.distToFaces = true;
+ }
+
+ localSF.radius = sizeP.getDouble("Radius");
+
+ string iso = sizeP.getToken("Orientation");
+ if ( !strcmp(iso.c_str(),"Isotropic") ) {
+ localSF.isotropic = true;
+ ClassParameter& isoP = sizeP.get("Isotropic");
+ localSF.sizeN = isoP.getString("Size");
+ }
+ else {
+ localSF.isotropic = false;
+ ClassParameter& anisoP = sizeP.get("Anisotropic");
+ localSF.sizeN = anisoP.getString("NormalSize");
+ localSF.sizeT = anisoP.getString("TangentSize");
+ }
+
+ ClassParameter& limiter = sizeP.get("CurvatureBasedLimiter");
+ localSF.limit = false;
+ if ( !strcmp(limiter.getToken("Enable"), "Yes") ) {
+ localSF.limit = true;
+ localSF.limitSizeTg = limiter.getDouble("TangentSizeOverRadius");
+ localSF.maxCurv = limiter.getDouble("CurvatureLimiter");
+ }
+
+ object.sizes.push_back(localSF);
+ }
+
+ params->objects.push_back(object);
+ }
+
+ // Size Field parameters
+ // ---------------------
+
+ for (int iSF = 0; iSF < Parser::instance().get("SizeField").size(); iSF++)
+ {
+ ClassParameter& sfParam = Parser::instance().get("SizeField",iSF);
+ string sfType = sfParam.getToken("Type");
+
+ SizeFieldDef sfDef;
+
+ // Analytical:
+ if ( !strcmp(sfType.c_str(),"Analytical") )
+ {
+ sfDef.type = MAd::ANALYTICALSFIELD;
+
+ ClassParameter& anParam = sfParam.get("Analytical");
+ string orient = anParam.getToken("OrientationType");
+ if ( !strcmp(orient.c_str(),"Isotropic") ) {
+ sfDef.orientation = ORT_ISOTROPIC;
+ sfDef.isoSize = anParam.get("Isotropic").getString("Length");
+ }
+ else {
+ sfDef.orientation = ORT_ANISOTROPIC;
+ ClassParameter& an_anisoParam = anParam.get("Anisotropic");
+
+ sfDef.anisoSize = an_anisoParam.getStringList("Lengths");
+ sfDef.anisoDir0 = an_anisoParam.getStringList("Direction1");
+ sfDef.anisoDir1 = an_anisoParam.getStringList("Direction2");
+ sfDef.anisoDir2 = an_anisoParam.getStringList("Direction3");
+
+ if ( sfDef.anisoSize.size() != 3 ||
+ sfDef.anisoDir0.size() != 3 ||
+ sfDef.anisoDir1.size() != 3 ||
+ sfDef.anisoDir2.size() != 3 ) {
+ cerr << "Invalid number of strings in one of the lists (anisotropic case)\n";
+ throw;
+ }
+ }
+ }
+
+ // Piecewise linear:
+ else if ( !strcmp(sfType.c_str(),"PiecewiseLinear") )
+ {
+ sfDef.type = MAd::DISCRETESFIELD;
+ ClassParameter& sf_pwl = sfParam.get("PiecewiseLinear");
+ sfDef.pwlSource = sf_pwl.getToken("Source");
+ ClassParameter& sf_pwl_curv = sf_pwl.get("Curvature");
+
+ sfDef.curv_aniso = false;
+ if ( !strcmp( sf_pwl_curv.getToken("Anisotropic"), "Yes") ) {
+ sfDef.curv_aniso = true;
+ }
+ sfDef.curv_alpha = sf_pwl_curv.getDouble("Alpha");
+ sfDef.curv_hMin = sf_pwl_curv.getDouble("MinimalLength");
+ }
+
+ else throw;
+
+ params->sizes.push_back(sfDef);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+#endif
+
+#endif
diff --git a/Benchmarks/optimize/Makefile b/Benchmarks/optimize/Makefile
new file mode 100644
index 0000000..48353fe
--- /dev/null
+++ b/Benchmarks/optimize/Makefile
@@ -0,0 +1,59 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../../variables
+
+BIN = $(MAdROOT)/bin/optimize
+
+INC = ${MAdLib_INCLUDES}\
+ ${DASH}I$(MAdROOT)/Geo\
+ ${DASH}I$(MAdROOT)/Mesh\
+ ${DASH}I$(MAdROOT)/Common\
+ ${DASH}I$(MAdROOT)/Adapt\
+ ${DASH}I$(MAdROOT)/Adapt/constraint\
+ ${DASH}I$(MAdROOT)/Adapt/operator\
+ ${DASH}I$(MAdROOT)/Adapt/output\
+ ${DASH}I$(MAdROOT)/Adapt/quality\
+ ${DASH}I$(MAdROOT)/Adapt/repositioning\
+ ${DASH}I$(MAdROOT)/Adapt/sizeField\
+ ${DASH}I$(MAdROOT)/Adapt/utils
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = main.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${BIN}: ${OBJ}
+ ${LINKER} ${OPTIM} ${DASH}o $@ $(OBJ) ${MAdLib_LIBS}
+
+cpobj: ${OBJ}
+ cp -f ${OBJ} $(MAdROOT)/bin/
+
+.cc${OBJEXT}:
+ ${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+ ${RM} *.o *.obj
+
+purge:
+ ${RM} *.msh *.geo *.pos
+
+depend:
+ (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+ ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+ ) > Makefile.new
+ cp Makefile Makefile.bak
+ cp Makefile.new Makefile
+ rm -f Makefile.new
\ No newline at end of file
diff --git a/Benchmarks/optimize/main.cc b/Benchmarks/optimize/main.cc
new file mode 100644
index 0000000..8589bda
--- /dev/null
+++ b/Benchmarks/optimize/main.cc
@@ -0,0 +1,80 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MSops.h"
+#include "AdaptInterface.h"
+#include "NullSField.h"
+#include "AnalyticalSField.h"
+
+#include <iostream>
+using std::cout;
+#include <string>
+using std::string;
+#include <vector>
+using std::vector;
+
+using namespace MAd;
+
+// ----------------------------------------------------------------------
+int main(int argc, char* argv[]) {
+
+ // Check input
+ // ------------
+ if ( argc != 2 ) {
+ printf("Error: usage: \'executable mshFile\'\n");
+ exit(0);
+ }
+ string meshFile = argv[1];
+
+ // Build tools
+ // ------------
+ pGModel model = 0;
+ pMesh mesh = M_new(model);
+ M_load(mesh,meshFile.c_str());
+
+ PWLSField * sizeField = new PWLSField(mesh);
+ sizeField->setCurrentSize();
+// vector<string> h, e0, e1, e2;
+// h.push_back("0.50"); h.push_back("0.05"); h.push_back("0.01");
+// e0.push_back("1.0"); e0.push_back("0.0"); e0.push_back("0.0");
+// e1.push_back("0.0"); e1.push_back("1.0"); e1.push_back("0.0");
+// e2.push_back("0.0"); e2.push_back("0.0"); e2.push_back("1.0");
+// AnalyticalSField* asf = new AnalyticalSField(h, e0, e1, e2);
+
+// MeshAdapter* ma = new MeshAdapter(mesh,asf);
+ MeshAdapter* ma = new MeshAdapter(mesh,sizeField);
+
+ // Output situation before optimization
+ // -------------------------------------
+ printf ("Statistics before optimization: \n");
+ ma->printStatistics(std::cout);
+ ma->writePos("meanRatioBefore.pos",OD_MEANRATIO);
+
+ // Optimize
+ // ---------
+ printf ("Optimizing mesh %s...\n\n",meshFile.c_str());
+ ma->run();
+
+ // Outputs final mesh
+ // -------------------
+ printf ("Statistics after optimization: \n");
+ ma->printStatistics(std::cout);
+ ma->writePos("meanRatioAfter.pos",OD_MEANRATIO);
+ M_writeMsh (mesh, "result.msh", 2, NULL);
+
+ // Cleaning
+ // ---------
+ if (ma) delete ma;
+ if (sizeField) delete sizeField;
+}
+
+// ----------------------------------------------------------------------
diff --git a/Common/MAdDefines.h b/Common/MAdDefines.h
new file mode 100644
index 0000000..b0faeca
--- /dev/null
+++ b/Common/MAdDefines.h
@@ -0,0 +1,35 @@
+// -*- C++ -*-
+
+#ifndef _H_MADDEFINES
+#define _H_MADDEFINES
+
+#define MAdTHIRD 0.33333333333333
+#define MAdSIXTH 0.16666666666667
+
+#define MAdPI 3.14159265358979
+#define MAdPITH 0.31830988618379
+
+#define MAdBIG 1.e14
+#define MAdTOL 1.e-12
+#define MAdTOLSQ 1.e-24
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ enum operationType {
+ MAd_UNKNOWNOPERATION = 0,
+ MAd_VERTEXMOVE = 1,
+ MAd_ESPLIT = 2,
+ MAd_ECOLLAPSE = 3,
+ MAd_FCOLLAPSE = 4,
+ MAd_DESPLTCLPS = 5,
+ MAd_ESWAP = 6,
+ MAd_FSWAP = 7,
+ MAd_RREMOVE = 8
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Common/MAdFieldEvaluator.h b/Common/MAdFieldEvaluator.h
new file mode 100644
index 0000000..5b2da8e
--- /dev/null
+++ b/Common/MAdFieldEvaluator.h
@@ -0,0 +1,81 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADFIELDEVALUATORBASE
+#define _H_MADFIELDEVALUATORBASE
+
+#include <ostream>
+#include <string>
+
+namespace MAd {
+
+ // ----------------------------------------------------------------------
+ class MAdFieldEvaluator{
+ public:
+ virtual bool eval (const double space[3], double time, double* val) const = 0;
+ virtual int order () const = 0;
+ virtual int nbVar () const = 0;
+ virtual ~MAdFieldEvaluator(){};
+
+ virtual void describe(std::ostream& out, const std::string& prefix) const {out << prefix << "Dummy field evaluator \n";}
+ };
+
+ // ----------------------------------------------------------------------
+ class MAdConstantScalar : public MAdFieldEvaluator
+ {
+ double X;
+ public :
+ MAdConstantScalar(double v):X(v){}
+ inline bool eval (const double space[3], double time, double* val) const {
+ val[0] = X;
+ return true;
+ }
+ inline int order() const{
+ return 0;
+ }
+ virtual int nbVar () const {return 1;}
+
+ virtual void describe(std::ostream& out,const std::string& prefix="") const{
+ out << prefix << "Constant scalar field evaluator u(x,y,z,t) = " << X << "\n";
+ }
+
+ };
+
+ // ----------------------------------------------------------------------
+ class MAdConstantVector : public MAdFieldEvaluator
+ {
+ double U,V,W;
+ public:
+ MAdConstantVector(double ux=0,double uy=0,double uz=0):U(ux),V(uy),W(uz){}
+ inline bool eval (const double space[3], double time, double* val) const{
+ val[0] = U;
+ val[1] = V;
+ val[2] = W;
+ return true;
+ }
+ inline int order() const{
+ return 0;
+ }
+ virtual int nbVar () const {return 3;}
+
+ virtual void describe(std::ostream& out,const std::string& prefix="") const{
+ out << prefix << "Constant vector field evaluator u(x,y,z,t) = (" << U << "," << V << "," << W << ")\n";
+ }
+
+ };
+
+ // ----------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Common/MAdLib.cc b/Common/MAdLib.cc
new file mode 100644
index 0000000..57e299e
--- /dev/null
+++ b/Common/MAdLib.cc
@@ -0,0 +1,65 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_GMSH_
+#include "gmsh/Gmsh.h"
+#endif
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+#include "MAdMessage.h"
+#include "MAdResourceManager.h"
+
+#include <string>
+using std::string;
+
+using namespace MAd;
+
+void MAdLibInitialize(int * argc, char** argv[])
+{
+#ifdef PARALLEL
+ MPI_Init(argc,argv);
+ AP_init(argc,argv);
+#endif
+
+#ifdef _HAVE_GMSH_
+ char * tmp[1];
+ tmp[0] = (char*)" ";
+ GmshInitialize(1,tmp);
+ unsigned int i = 1;
+ int j = 0;
+ GmshSetOption("General","Terminal",i,j);
+#endif
+
+ MAdMsgSgl::instance().initialize();
+ MAdResourceManagerSgl::instance().initialize();
+}
+
+void MAdLibFinalize()
+{
+ MAdResourceManagerSgl::instance().finalize();
+ MAdMsgSgl::instance().finalize();
+
+#ifdef _HAVE_GMSH_
+ GmshFinalize();
+#endif
+
+#ifdef PARALLEL
+ MPI_Barrier(MPI_COMM_WORLD);
+ AP_finalize();
+ MPI_Finalize();
+#endif
+}
+
diff --git a/Common/MAdLib.h b/Common/MAdLib.h
new file mode 100644
index 0000000..5d28b37
--- /dev/null
+++ b/Common/MAdLib.h
@@ -0,0 +1,31 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MAD_MADLIB
+#define _H_MAD_MADLIB
+
+// interface to the geometrical model
+#include "ModelInterface.h"
+
+// interface to the mesh
+#include "MeshDataBaseInterface.h"
+
+// interface to mesh adaptation
+#include "AdaptInterface.h"
+
+//! Needed with the Gmsh geometrical model
+void MAdLibInitialize(int * argc, char** argv[]);
+void MAdLibFinalize();
+
+#endif
+
diff --git a/Common/MAdMatrix.cc b/Common/MAdMatrix.cc
new file mode 100644
index 0000000..4a3f14e
--- /dev/null
+++ b/Common/MAdMatrix.cc
@@ -0,0 +1,95 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdMatrix.h"
+
+#if defined(HAVE_LAPACK)
+extern "C" {
+ void dgesv_(int *N, int *nrhs, double *A, int *lda, int *ipiv,
+ double *b, int *ldb, int *info);
+ void dgetrf_(int *M, int *N, double *A, int *lda, int *ipiv, int *info);
+ void dgesvd_(const char* jobu, const char *jobvt, int *M, int *N,
+ double *A, int *lda, double *S, double* U, int *ldu,
+ double *VT, int *ldvt, double *work, int *lwork, int *info);
+ void dgeev_(const char *jobvl, const char *jobvr,
+ int *n, double *a, int *lda,
+ double *wr, double *wi,
+ double *vl, int *ldvl,
+ double *vr, int *ldvr,
+ double *work, int *lwork,
+ int *info);
+}
+#endif
+
+namespace MAd {
+
+#if defined(HAVE_LAPACK)
+
+ template<>
+ bool MAd_BLASLAPACK_Matrix<double>::eig(MAd_BLASLAPACK_Matrix<double> &VL, // left eigenvectors
+ MAd_BLASLAPACK_Vector<double> &DR, // Real part of eigenvalues
+ MAd_BLASLAPACK_Vector<double> &DI, // Im part of eigenvalues
+ MAd_BLASLAPACK_Matrix<double> &VR,
+ bool sortRealPart ) // if true: sorted from max '|DR|' to min '|DR|'
+ {
+ int N = size1(), info;
+ int LWORK = 10*N;
+ double * work = new double[LWORK];
+
+ dgeev_("V","V",
+ &N,_data,
+ &N,DR.data,DI.data,
+ VL._data,&N,
+ VR._data,&N,
+ work,&LWORK,&info);
+
+ delete [] work;
+
+ if(info == 0)
+ {
+ if (sortRealPart) {
+ double tmp[8];
+ // do permutations
+ for (int i=0; i<(size1()-1); i++) {
+ int maxR = i;
+ for (int j=i+1; j<size1(); j++) if ( fabs(DR(j)) > fabs(DR(maxR)) ) maxR = j;
+ if ( maxR != i )
+ {
+ tmp[0] = DR(i); tmp[1] = DI(i);
+ tmp[2] = VL(0,i); tmp[3] = VL(1,i); tmp[4] = VL(2,i);
+ tmp[5] = VR(0,i); tmp[6] = VR(1,i); tmp[7] = VR(2,i);
+
+ DR(i) = DR(maxR); DI(i) = DI(maxR);
+ VL(0,i) = VL(0,maxR); VL(1,i) = VL(1,maxR); VL(2,i) = VL(2,maxR);
+ VR(0,i) = VR(0,maxR); VR(1,i) = VR(1,maxR); VR(2,i) = VR(2,maxR);
+
+ DR(maxR) = tmp[0]; DI(maxR) = tmp[1];
+ VL(0,maxR) = tmp[2]; VL(1,maxR) = tmp[3]; VL(2,maxR) = tmp[4];
+ VR(0,maxR) = tmp[5]; VR(1,maxR) = tmp[6]; VR(2,maxR) = tmp[7];
+ }
+ }
+ }
+ return true;
+ }
+ if(info > 0)
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "QR Algorithm failed to compute all the eigenvalues (info = %d)", info);
+ else
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Wrong %d-th argument in eig (info = %d)", -info);
+
+ return false;
+ }
+
+#endif
+}
diff --git a/Common/MAdMatrix.h b/Common/MAdMatrix.h
new file mode 100644
index 0000000..1fa73d7
--- /dev/null
+++ b/Common/MAdMatrix.h
@@ -0,0 +1,923 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MATRIX_MAD
+#define _H_MATRIX_MAD
+
+#include "MAdMessage.h"
+
+#include <assert.h>
+#include <math.h>
+#include <iostream>
+
+#if defined(_HAVE_GSL_)
+#include <gsl/gsl_linalg.h>
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_blas.h>
+#endif
+
+// -------------------------------------------------------------------
+#if defined(HAVE_BLAS)
+extern "C" {
+ void dgemm_(const char *transa, const char *transb, int *m, int *n, int *k,
+ double *alpha, double *a, int *lda, double *b, int *ldb,
+ double *beta, double *c, int *ldc);
+ void dgemv_(const char *trans, int *m, int *n, double *alpha, double *a,
+ int *lda, double *x, int *incx, double *beta, double *y, int *incy);
+}
+#endif
+
+// -------------------------------------------------------------------
+#if defined(HAVE_LAPACK)
+extern "C" {
+ void dgesv_(int *N, int *nrhs, double *A, int *lda, int *ipiv,
+ double *b, int *ldb, int *info);
+ void dgetrf_(int *M, int *N, double *A, int *lda, int *ipiv, int *info);
+ void dgesvd_(const char* jobu, const char *jobvt, int *M, int *N,
+ double *A, int *lda, double *S, double* U, int *ldu,
+ double *VT, int *ldvt, double *work, int *lwork, int *info);
+ void dgeev_(const char *jobvl, const char *jobvr,
+ int *n, double *a, int *lda,
+ double *wr, double *wi,
+ double *vl, int *ldvl,
+ double *vr, int *ldvr,
+ double *work, int *lwork,
+ int *info);
+}
+#endif
+
+// -------------------------------------------------------------------
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // Basic vector / matrix
+ // -------------------------------------------------------------------
+ template <class SCALAR>
+ class MAd_Vector
+ {
+ private:
+ int r;
+ public:
+ inline int size() const { return r; }
+ SCALAR *data;
+ ~MAd_Vector() { if(data) delete [] data; }
+ MAd_Vector() : r(0)
+ {
+ data = 0;
+ }
+ MAd_Vector(int R) : r(R)
+ {
+ data = new SCALAR[r];
+ scale(0);
+ }
+ MAd_Vector(const MAd_Vector<SCALAR> &other) : r(other.r)
+ {
+ data = new SCALAR[r];
+ for (int i = 0; i < r; ++i) data[i] = other.data[i];
+ }
+ inline MAd_Vector<SCALAR> operator= (const MAd_Vector<SCALAR> &other)
+ {
+ if ( this != &other ) {
+ r = other.r;
+ if (data) delete [] data;
+ data = new SCALAR[r];
+ for (int i = 0; i < r; ++i) data[i] = other.data[i];
+ }
+ return *this;
+ }
+ inline SCALAR operator () (int i) const
+ {
+ return data[i];
+ }
+ inline SCALAR & operator () (int i)
+ {
+ return data[i];
+ }
+ inline double norm()
+ {
+ double n = 0.;
+ for(int i = 0; i < r; ++i) n += data[i] * data[i];
+ return sqrt(n);
+ }
+ inline void scale(const SCALAR s)
+ {
+ for (int i = 0; i < r; ++i) data[i] *= s;
+ }
+ inline void set_all(const double &m)
+ {
+ for (int i = 0; i < r; ++i) data[i] = m;
+ }
+ inline void add(const MAd_Vector &v)
+ {
+ for (int i = 0; i < r; ++i) data[i] += v(i);
+ }
+ void print(std::string name) const
+ {
+ printf("Vector %s:\n ",name.c_str());
+ for (int i = 0; i < r; ++i) printf("%12.5E ",data[i]);
+ printf("\n");
+ }
+ };
+
+ // -------------------------------------------------------------------
+ template <class SCALAR>
+ class MAd_Matrix
+ {
+ private:
+ int _r, _c; // r = nb rows, c = nb columns
+ SCALAR *_data;
+
+ public:
+
+ MAd_Matrix(int R,int C) : _r(R), _c(C)
+ {
+ _data = new SCALAR[_r * _c];
+ scale(0.);
+ }
+ MAd_Matrix(const MAd_Matrix<SCALAR> &other) : _r(other._r), _c(other._c)
+ {
+ _data = new double[_r * _c];
+ memcpy(other);
+ }
+ MAd_Matrix() : _r(0), _c(0), _data(0) {}
+ ~MAd_Matrix() { delete [] _data; }
+
+ public:
+
+ void print()const {
+ printf("matrix(%d,%d)",_r,_c);
+ for(int i=0;i<_r;i++){
+ for(int j=0;j<_c;j++){
+ printf("%0.3e\t",_data[i + _r * j]);
+ }
+ printf("\n");
+ }
+ printf("--------\n");
+ }
+
+ inline int size1() const { return _r; }
+ inline int size2() const { return _c; }
+
+ inline SCALAR operator () (int i, int j) const
+ {
+ return _data[i + _r * j];
+ }
+ inline SCALAR & operator () (int i, int j)
+ {
+ return _data[i + _r * j];
+ }
+
+ MAd_Matrix<SCALAR> & operator = (const MAd_Matrix<SCALAR> &other)
+ {
+ if(this != &other){
+ _r = other._r;
+ _c = other._c;
+ _data = new SCALAR[_r * _c];
+ memcpy(other);
+ }
+ return *this;
+ }
+ void memcpy(const MAd_Matrix &other)
+ {
+ for (int i = 0; i < _r * _c; ++i) _data[i] = other._data[i];
+ }
+
+ void copy(const MAd_Matrix<SCALAR> &a, int i0, int ni, int j0, int nj,
+ int desti0, int destj0)
+ {
+ for(int i = i0, desti = desti0; i < i0 + ni; i++, desti++)
+ for(int j = j0, destj = destj0; j < j0 + nj; j++, destj++)
+ (*this)(desti, destj) = a(i, j);
+ }
+
+ // c = c + data * b
+ inline void mult(const MAd_Matrix<SCALAR> &b, MAd_Matrix<SCALAR> &c)
+ {
+ c.scale(0.);
+ for(int i = 0; i < _r; i++)
+ for(int j = 0; j < b.size2(); j++)
+ for(int k = 0; k < _c; k++)
+ c._data[i + _r * j] += (*this)(i, k) * b(k, j);
+ }
+
+ // y = y + data * x
+ inline void mult(const MAd_Vector<SCALAR> &x, MAd_Vector<SCALAR> &y)
+ {
+ y.scale(0.);
+ for(int i = 0; i < _r; i++)
+ for(int j = 0; j < _c; j++)
+ y._data[i] += (*this)(i, j) * x(j);
+ }
+
+ // data = alpha * ( a * b ) + beta * data
+ inline void blas_dgemm(MAd_Matrix<SCALAR> &a, MAd_Matrix<SCALAR> &b,
+ SCALAR alpha=1., SCALAR beta=1.)
+ {
+ MAd_Matrix<SCALAR> temp(a.size1(), b.size2()); // temp = 0;
+ a.mult(b, temp); // temp = a * b
+ temp.scale(alpha); // temp = alpha * ( a * b )
+ scale(beta);
+ add(temp);
+ }
+
+ inline void set_all(const double &m)
+ {
+ for (int i = 0; i < _r * _c; ++i) _data[i] = m;
+ }
+ inline void setValues(const SCALAR *M[])
+ {
+ for (int i = 0; i < _r ; ++i)
+ for (int j = 0; j < _c ; ++j) _data[i + _r * j] = M[i][j];
+ }
+ inline void scale(const double s)
+ {
+ if(s == 0.)
+ for(int i = 0; i < _r * _c; ++i) _data[i] = 0.;
+ else
+ for(int i = 0; i < _r * _c; ++i) _data[i] *= s;
+ }
+ inline void add(const double &a)
+ {
+ for(int i = 0; i < _r * _c; ++i) _data[i] += a;
+ }
+ inline void add(const MAd_Matrix<SCALAR> &m)
+ {
+ for(int i = 0; i < size1(); i++)
+ for(int j = 0; j < size2(); j++)
+ (*this)(i, j) += m(i, j);
+ }
+
+ inline MAd_Matrix<SCALAR> transpose()
+ {
+ MAd_Matrix<SCALAR> T(size2(), size1());
+ for(int i = 0; i < size1(); i++)
+ for(int j = 0; j < size2(); j++)
+ T(j, i) = (*this)(i, j);
+ return T;
+ }
+ inline bool lu_solve(const MAd_Vector<SCALAR> &rhs, MAd_Vector<SCALAR> &result)
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"LU factorization requires LAPACK");
+ return false;
+ }
+ MAd_Matrix<SCALAR> cofactor(int i, int j) const
+ {
+ int ni = size1();
+ int nj = size2();
+ MAd_Matrix<SCALAR> cof(ni - 1, nj - 1);
+ for(int I = 0; I < ni; I++){
+ for(int J = 0; J < nj; J++){
+ if(J != j && I != i)
+ cof(I < i ? I : I - 1, J < j ? J : J - 1) = (*this)(I, J);
+ }
+ }
+ return cof;
+ }
+ SCALAR determinant() const
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Determinant computation requires LAPACK");
+ return 0.;
+ }
+ bool svd(MAd_Matrix<SCALAR> &V, MAd_Vector<SCALAR> &S)
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Singular value decomposition requires LAPACK");
+ return false;
+ }
+ bool eig(MAd_Matrix<double> &VL, // left eigenvectors
+ MAd_Vector<double> &DR, // Real part of eigenvalues
+ MAd_Vector<double> &DI, // Im part of eigenvalues
+ MAd_Matrix<double> &VR,
+ bool sortRealPart=false )
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Eigen vectors computation requires LAPACK");
+ return false;
+ }
+ void print(std::string name) const
+ {
+ printf("Matrix %s (%d, %d):\n ",name.c_str(),_r,_c);
+ for(int i = 0; i < _r ; ++i) {
+ for(int j = 0; j < _c ; ++j) printf("%12.5E ",(*this)(i, j));
+ printf("\n");
+ }
+ }
+ };
+
+
+// -------------------------------------------------------------------
+// With BLAS / LAPACK
+// -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ template <class SCALAR>
+ class MAd_BLASLAPACK_Vector
+ {
+ private:
+ int r;
+ public:
+ inline int size() const { return r; }
+ SCALAR *data;
+ ~MAd_BLASLAPACK_Vector() { delete [] data; }
+ MAd_BLASLAPACK_Vector() : r(0)
+ {
+ data = 0;
+ }
+ MAd_BLASLAPACK_Vector(int R) : r(R)
+ {
+ data = new SCALAR[r];
+ scale(0);
+ }
+ MAd_BLASLAPACK_Vector(const MAd_BLASLAPACK_Vector<SCALAR> &other) : r(other.r)
+ {
+ data = new double[r];
+ for (int i = 0; i < r; ++i) data[i] = other.data[i];
+ }
+ inline SCALAR operator () (int i) const
+ {
+ return data[i];
+ }
+ inline SCALAR & operator () (int i)
+ {
+ return data[i];
+ }
+ inline double norm()
+ {
+ double n = 0.;
+ for(int i = 0; i < r; ++i) n += data[i] * data[i];
+ return sqrt(n);
+ }
+ inline void scale(const SCALAR s)
+ {
+ for (int i = 0; i < r; ++i) data[i] *= s;
+ }
+ inline void set_all(const double &m)
+ {
+ for (int i = 0; i < r; ++i) data[i] = m;
+ }
+ inline void add(const MAd_BLASLAPACK_Vector &v)
+ {
+ for (int i = 0; i < r; ++i) data[i] += v(i);
+ }
+ void print(std::string name) const
+ {
+ printf("Vector %s:\n ",name.c_str());
+ for (int i = 0; i < r; ++i) printf("%12.5E ",data[i]);
+ printf("\n");
+ }
+ };
+
+ // -------------------------------------------------------------------
+ template <class SCALAR>
+ class MAd_BLASLAPACK_Matrix
+ {
+ private:
+ int _r, _c; // r = nb rows, c = nb columns
+ SCALAR *_data;
+
+ public:
+
+ MAd_BLASLAPACK_Matrix(int R,int C) : _r(R), _c(C)
+ {
+ _data = new SCALAR[_r * _c];
+ scale(0.);
+ }
+ MAd_BLASLAPACK_Matrix(const MAd_BLASLAPACK_Matrix<SCALAR> &other) : _r(other._r), _c(other._c)
+ {
+ _data = new double[_r * _c];
+ memcpy(other);
+ }
+ MAd_BLASLAPACK_Matrix() : _r(0), _c(0), _data(0) {}
+ ~MAd_BLASLAPACK_Matrix() { delete [] _data; }
+
+ public:
+
+ inline int size1() const { return _r; }
+ inline int size2() const { return _c; }
+
+ inline SCALAR operator () (int i, int j) const
+ {
+ return _data[i + _r * j];
+ }
+ inline SCALAR & operator () (int i, int j)
+ {
+ return _data[i + _r * j];
+ }
+
+ MAd_BLASLAPACK_Matrix<SCALAR> & operator = (const MAd_BLASLAPACK_Matrix<SCALAR> &other)
+ {
+ if(this != &other){
+ _r = other._r;
+ _c = other._c;
+ _data = new SCALAR[_r * _c];
+ memcpy(other);
+ }
+ return *this;
+ }
+ void memcpy(const MAd_BLASLAPACK_Matrix &other)
+ {
+ for (int i = 0; i < _r * _c; ++i) _data[i] = other._data[i];
+ }
+
+ void copy(const MAd_BLASLAPACK_Matrix<SCALAR> &a, int i0, int ni, int j0, int nj,
+ int desti0, int destj0)
+ {
+ for(int i = i0, desti = desti0; i < i0 + ni; i++, desti++)
+ for(int j = j0, destj = destj0; j < j0 + nj; j++, destj++)
+ (*this)(desti, destj) = a(i, j);
+ }
+
+ // c = c + data * b
+ inline void mult(const MAd_BLASLAPACK_Matrix<SCALAR> &b, MAd_BLASLAPACK_Matrix<SCALAR> &c)
+ {
+#if defined(HAVE_BLAS)
+ int M = c.size1(), N = c.size2(), K = _c;
+ int LDA = _r, LDB = b.size1(), LDC = c.size1();
+ double alpha = 1., beta = 0.;
+ dgemm_("N", "N", &M, &N, &K, &alpha, _data, &LDA, b._data, &LDB,
+ &beta, c._data, &LDC);
+#else
+ c.scale(0.);
+ for(int i = 0; i < _r; i++)
+ for(int j = 0; j < b.size2(); j++)
+ for(int k = 0; k < _c; k++)
+ c._data[i + _r * j] += (*this)(i, k) * b(k, j);
+#endif
+ }
+
+ // y = y + data * x
+ inline void mult(const MAd_BLASLAPACK_Vector<SCALAR> &x, MAd_BLASLAPACK_Vector<SCALAR> &y)
+ {
+#if defined(HAVE_BLAS)
+ int M = _r, N = _c, LDA = _r, INCX = 1, INCY = 1;
+ double alpha = 1., beta = 0.;
+ dgemv_("N", &M, &N, &alpha, _data, &LDA, x._data, &INCX,
+ &beta, y._data, &INCY);
+#else
+ y.scale(0.);
+ for(int i = 0; i < _r; i++)
+ for(int j = 0; j < _c; j++)
+ y._data[i] += (*this)(i, j) * x(j);
+#endif
+ }
+
+ // data = alpha * ( a * b ) + beta * data
+ inline void blas_dgemm(MAd_BLASLAPACK_Matrix<SCALAR> &a, MAd_BLASLAPACK_Matrix<SCALAR> &b,
+ SCALAR alpha=1., SCALAR beta=1.)
+ {
+#if defined(HAVE_BLAS)
+ int M = size1(), N = size2(), K = a.size2();
+ int LDA = a.size1(), LDB = b.size1(), LDC = size1();
+ dgemm_("N", "N", &M, &N, &K, &alpha, a._data, &LDA, b._data, &LDB,
+ &beta, _data, &LDC);
+#else
+ MAd_BLASLAPACK_Matrix<SCALAR> temp(a.size1(), b.size2()); // temp = 0;
+ a.mult(b, temp); // temp = a * b
+ temp.scale(alpha); // temp = alpha * ( a * b )
+ scale(beta);
+ add(temp);
+#endif
+ }
+
+ inline void set_all(const double &m)
+ {
+ for (int i = 0; i < _r * _c; ++i) _data[i] = m;
+ }
+ inline void setValues(const SCALAR *M[])
+ {
+ for (int i = 0; i < _r ; ++i)
+ for (int j = 0; j < _c ; ++j) _data[i + _r * j] = M[i][j];
+ }
+ inline void scale(const double s)
+ {
+ if(s == 0.)
+ for(int i = 0; i < _r * _c; ++i) _data[i] = 0.;
+ else
+ for(int i = 0; i < _r * _c; ++i) _data[i] *= s;
+ }
+ inline void add(const double &a)
+ {
+ for(int i = 0; i < _r * _c; ++i) _data[i] += a;
+ }
+ inline void add(const MAd_BLASLAPACK_Matrix<SCALAR> &m)
+ {
+ for(int i = 0; i < size1(); i++)
+ for(int j = 0; j < size2(); j++)
+ (*this)(i, j) += m(i, j);
+ }
+
+ inline MAd_BLASLAPACK_Matrix<SCALAR> transpose()
+ {
+ MAd_BLASLAPACK_Matrix<SCALAR> T(size2(), size1());
+ for(int i = 0; i < size1(); i++)
+ for(int j = 0; j < size2(); j++)
+ T(j, i) = (*this)(i, j);
+ return T;
+ }
+ inline bool lu_solve(const MAd_BLASLAPACK_Vector<SCALAR> &rhs, MAd_BLASLAPACK_Vector<SCALAR> &result)
+ {
+#if defined(HAVE_LAPACK)
+ int N = size1(), nrhs = 1, lda = N, ldb = N, info;
+ int *ipiv = new int[N];
+ for(int i = 0; i < N; i++) result(i) = rhs(i);
+ dgesv_(&N, &nrhs, _data, &lda, ipiv, result.data, &ldb, &info);
+ delete [] ipiv;
+ if(info == 0) return true;
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Problem in LAPACK LU (info=%d)", info);
+#else
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"LU factorization requires LAPACK");
+#endif
+ return false;
+ }
+ MAd_BLASLAPACK_Matrix<SCALAR> cofactor(int i, int j) const
+ {
+ int ni = size1();
+ int nj = size2();
+ MAd_BLASLAPACK_Matrix<SCALAR> cof(ni - 1, nj - 1);
+ for(int I = 0; I < ni; I++){
+ for(int J = 0; J < nj; J++){
+ if(J != j && I != i)
+ cof(I < i ? I : I - 1, J < j ? J : J - 1) = (*this)(I, J);
+ }
+ }
+ return cof;
+ }
+ SCALAR determinant() const
+ {
+#if defined(HAVE_LAPACK)
+ MAd_BLASLAPACK_Matrix<SCALAR> tmp(*this);
+ int M = size1(), N = size2(), lda = size1(), info;
+ int *ipiv = new int[std::min(M, N)];
+ dgetrf_(&M, &N, tmp._data, &lda, ipiv, &info);
+ SCALAR det = 1.;
+ for(int i = 0; i < size1(); i++){
+ det *= tmp(i, i);
+ if(ipiv[i] != i + 1) det = -det;
+ }
+ return det;
+#else
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Determinant computation requires LAPACK");
+ return 0.;
+#endif
+ }
+ bool svd(MAd_BLASLAPACK_Matrix<SCALAR> &V, MAd_BLASLAPACK_Vector<SCALAR> &S)
+ {
+#if defined(HAVE_LAPACK)
+ MAd_BLASLAPACK_Matrix<SCALAR> VT(V.size2(), V.size1());
+ int M = size1(), N = size2(), LDA = size1(), LDVT = VT.size1(), info;
+ int LWORK = std::max(3 * std::min(M, N) + std::max(M, N), 5 * std::min(M, N));
+ MAd_BLASLAPACK_Vector<SCALAR> WORK(LWORK);
+ dgesvd_("O", "A", &M, &N, _data, &LDA, S._data, _data, &LDA,
+ VT._data, &LDVT, WORK._data, &LWORK, &info);
+ V = VT.transpose();
+ if(info == 0) return true;
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Problem in LAPACK SVD (info=%d)", info);
+#else
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Singular value decomposition requires LAPACK");
+#endif
+ return false;
+ }
+ bool eig(MAd_BLASLAPACK_Matrix<double> &VL, // left eigenvectors
+ MAd_BLASLAPACK_Vector<double> &DR, // Real part of eigenvalues
+ MAd_BLASLAPACK_Vector<double> &DI, // Im part of eigenvalues
+ MAd_BLASLAPACK_Matrix<double> &VR,
+ bool sortRealPart=false ) // if true: sorted from max '|DR|' to min '|DR|'
+#if defined(HAVE_LAPACK)
+ ;
+#else
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Eigen vectors computation requires LAPACK");
+ return false;
+ }
+#endif
+ void print(std::string name) const
+ {
+ printf("Matrix %s (%d, %d):\n ",name.c_str(),_r,_c);
+ for(int i = 0; i < _r ; ++i) {
+ for(int j = 0; j < _c ; ++j) printf("%12.5E ",(*this)(i, j));
+ printf("\n");
+ }
+ }
+ };
+
+// -------------------------------------------------------------------
+// With GSL
+// -------------------------------------------------------------------
+#ifdef _HAVE_GSL_
+
+ class MAd_GSL_Vector
+ {
+ private:
+ int _r;
+ gsl_vector *_data;
+ friend class MAd_GSL_Matrix;
+
+ public:
+
+ MAd_GSL_Vector(int r) : _r(r)
+ {
+ _data = gsl_vector_calloc(_r);
+ }
+ MAd_GSL_Vector(const MAd_GSL_Vector &other) : _r(other._r)
+ {
+ _data = gsl_vector_calloc(_r);
+ gsl_vector_memcpy(_data, other._data);
+ }
+ ~MAd_GSL_Vector() { gsl_vector_free(_data); }
+
+ inline int size() const { return _r; }
+
+ inline double operator () (int i) const
+ {
+ return gsl_vector_get(_data, i);
+ }
+ inline double & operator () (int i)
+ {
+ return *gsl_vector_ptr(_data, i);
+ }
+ inline double norm()
+ {
+ return gsl_blas_dnrm2(_data);
+ }
+ inline void scale(const double s)
+ {
+ if(s == 0.) gsl_vector_set_zero(_data);
+ else gsl_vector_scale(_data, s);
+ }
+ inline void set_all(const double &m)
+ {
+ gsl_vector_set_all(_data, m);
+ }
+ inline void add(const MAd_GSL_Vector &v)
+ {
+ gsl_vector_add (_data, v._data);
+ }
+ void print(std::string name) const
+ {
+ printf("Vector %s:\n ",name.c_str());
+ for (int i = 0; i < _r; ++i) printf("%12.5E ",gsl_vector_get(_data, i));
+ printf("\n");
+ }
+ };
+
+ // -------------------------------------------------------------------
+ class MAd_GSL_Matrix
+ {
+ private:
+ gsl_matrix *_data;
+
+ public:
+ MAd_GSL_Matrix(int r, int c) { _data = gsl_matrix_calloc(r, c); }
+ MAd_GSL_Matrix(const MAd_GSL_Matrix &other) : _data(0)
+ {
+ if(_data) gsl_matrix_free(_data);
+ _data = gsl_matrix_calloc(other._data->size1, other._data->size2);
+ gsl_matrix_memcpy(_data, other._data);
+ }
+ MAd_GSL_Matrix() : _data(0) {}
+ ~MAd_GSL_Matrix() { if(_data && _data->owner == 1) gsl_matrix_free(_data); }
+
+ public:
+ inline int size1() const { return _data->size1; }
+ inline int size2() const { return _data->size2; }
+ MAd_GSL_Matrix & operator = (const MAd_GSL_Matrix &other)
+ {
+ if(&other != this){
+ if(_data) gsl_matrix_free(_data);
+ _data = gsl_matrix_calloc(other._data->size1, other._data->size2);
+ gsl_matrix_memcpy(_data, other._data);
+ }
+ return *this;
+ }
+ void memcpy(const MAd_GSL_Matrix &other)
+ {
+ gsl_matrix_memcpy(_data, other._data);
+ }
+ inline double operator () (int i, int j) const
+ {
+ return gsl_matrix_get(_data, i, j);
+ }
+ inline double & operator () (int i, int j)
+ {
+ return *gsl_matrix_ptr(_data, i, j);
+ }
+ void copy(const MAd_GSL_Matrix &a, int i0, int ni, int j0, int nj,
+ int desti0, int destj0)
+ {
+ for(int i = i0, desti = desti0; i < i0 + ni; i++, desti++)
+ for(int j = j0, destj = destj0; j < j0 + nj; j++, destj++)
+ (*this)(desti, destj) = a(i, j);
+ }
+ inline void mult(const MAd_GSL_Matrix &b, MAd_GSL_Matrix &c)
+ {
+ gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1., _data, b._data, 0., c._data);
+ }
+ inline void mult(const MAd_GSL_Vector &x, MAd_GSL_Vector &y)
+ {
+ gsl_blas_dgemv(CblasNoTrans, 1., _data, x._data, 0., y._data);
+ }
+ inline void blas_dgemm(MAd_GSL_Matrix &a, MAd_GSL_Matrix &b,
+ double alpha=1., double beta=1.)
+ {
+ gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, alpha, a._data, b._data, beta, _data);
+ }
+ inline void set_all(const double &m)
+ {
+ gsl_matrix_set_all(_data, m);
+ }
+ inline void setValues(const double *M[])
+ {
+ for (int i = 0; i < size1() ; ++i)
+ for (int j = 0; j < size2() ; ++j) *gsl_matrix_ptr(_data, i, j) = M[i][j];
+ }
+ inline void scale(const double s)
+ {
+ if(s == 0.) gsl_matrix_set_zero(_data);
+ else gsl_matrix_scale(_data, s);
+ }
+ inline void add(const double &a)
+ {
+ gsl_matrix_add_constant(_data, a);
+ }
+ inline void add(const MAd_GSL_Matrix &m)
+ {
+ gsl_matrix_add(_data, m._data);
+ }
+ inline MAd_GSL_Matrix transpose()
+ {
+ MAd_GSL_Matrix T(size2(), size1());
+ for(int i = 0; i < size1(); i++)
+ for(int j = 0; j < size2(); j++)
+ T(j, i) = (*this)(i, j);
+ return T;
+ }
+ inline bool lu_solve(const MAd_GSL_Vector &rhs, MAd_GSL_Vector &result)
+ {
+ int s;
+ gsl_permutation *p = gsl_permutation_alloc(size1());
+ gsl_linalg_LU_decomp(_data, p, &s);
+ gsl_linalg_LU_solve(_data, p, rhs._data, result._data);
+ gsl_permutation_free(p);
+ return true;
+ }
+ MAd_GSL_Matrix cofactor(int i, int j) const
+ {
+ int ni = size1();
+ int nj = size2();
+ MAd_GSL_Matrix cof(ni - 1, nj - 1);
+ for(int I = 0; I < ni; I++){
+ for(int J = 0; J < nj; J++){
+ if(J != j && I != i)
+ cof(I < i ? I : I - 1, J < j ? J : J - 1) = (*this)(I, J);
+ }
+ }
+ return cof;
+ }
+ double determinant() const
+ {
+ MAd_GSL_Matrix tmp = *this;
+ gsl_permutation *p = gsl_permutation_alloc(size1());
+ int s;
+ gsl_linalg_LU_decomp(tmp._data, p, &s);
+ gsl_permutation_free(p);
+ return gsl_linalg_LU_det(tmp._data, s);
+ }
+ bool svd(MAd_GSL_Matrix &V, MAd_GSL_Vector &S)
+ {
+ MAd_GSL_Vector tmp(S.size());
+ gsl_linalg_SV_decomp(_data, V._data, S._data, tmp._data);
+ return true;
+ }
+ inline void invert ()
+ {
+ int s;
+ gsl_permutation *p = gsl_permutation_alloc (size1());
+ gsl_linalg_LU_decomp(_data, p, &s);
+ gsl_matrix *data_inv = gsl_matrix_calloc(size1(), size2());
+ gsl_linalg_LU_invert(_data, p, data_inv) ;
+ gsl_matrix_memcpy(_data, data_inv);
+ gsl_matrix_free(data_inv);
+ gsl_permutation_free(p);
+ }
+ inline bool invertSecure(double &det)
+ {
+ int s;
+ gsl_permutation *p = gsl_permutation_alloc (size1());
+ gsl_linalg_LU_decomp(_data, p, &s);
+ det = gsl_linalg_LU_det(_data, s);
+ gsl_matrix *data_inv = gsl_matrix_calloc(size1(), size2());
+ gsl_linalg_LU_invert(_data, p, data_inv);
+ gsl_matrix_memcpy(_data, data_inv);
+ gsl_matrix_free(data_inv);
+ gsl_permutation_free(p);
+ return (det != 0.);
+ }
+ bool eig(MAd_GSL_Matrix &VL, // left eigenvectors
+ MAd_GSL_Vector &DR, // Real part of eigenvalues
+ MAd_GSL_Vector &DI, // Im part of eigenvalues
+ MAd_GSL_Matrix &VR,
+ bool sortRealPart=false )
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Eigen vectors computation requires LAPACK");
+ return false;
+ }
+ void print(std::string name) const
+ {
+ printf("Matrix %s (%d, %d):\n ",name.c_str(),_data->size1,_data->size2);
+ for(int i = 0; i < _data->size1 ; ++i) {
+ for(int j = 0; j < _data->size2 ; ++j) printf("%12.5E ",(*this)(i, j));
+ printf("\n");
+ }
+ }
+ };
+
+#endif
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+
+#if defined(HAVE_LAPACK)
+ typedef MAd_BLASLAPACK_Matrix<double> doubleMatrix;
+ typedef MAd_BLASLAPACK_Vector<double> doubleVector;
+#else
+ #if defined(_HAVE_GSL_)
+ typedef MAd_GSL_Matrix doubleMatrix;
+ typedef MAd_GSL_Vector doubleVector;
+ #else
+ typedef MAd_Matrix<double> doubleMatrix;
+ typedef MAd_Vector<double> doubleVector;
+ #endif
+#endif
+
+ // -------------------------------------------------------------------
+
+ // Should be used for operations on small matrices
+ typedef MAd_Matrix<double> smallMatrix;
+ typedef MAd_Vector<double> smallVector;
+
+ // -------------------------------------------------------------------
+
+}
+
+// -------------------------------------------------------------------
+// Gmsh matrices
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_GMSH_
+
+#include "gmsh/GmshMatrix.h"
+namespace MAd {
+ typedef gmshMatrix<double> gmshMat;
+ typedef gmshVector<double> gmshVec;
+}
+
+#else
+
+namespace MAd {
+
+ class nullVector {
+ public:
+ nullVector() {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Not implemented, Gmsh required");
+ }
+ nullVector(double) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Not implemented, Gmsh required");
+ }
+ inline double operator () (int i) const { return -1.; }
+ void print(const char * name="") const {}
+ };
+ class nullMatrix {
+ public:
+ nullMatrix() {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Not implemented, Gmsh required");
+ }
+ nullMatrix(double, double) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Not implemented, Gmsh required");
+ }
+ inline double operator () (int i, int j) const { return -1.; }
+ void print(const char * name="") const {}
+ };
+
+ typedef nullMatrix gmshMat;
+ typedef nullVector gmshVec;
+}
+
+#endif
+
+ // -------------------------------------------------------------------
+
+#endif
diff --git a/Common/MAdMessage.cc b/Common/MAdMessage.cc
new file mode 100644
index 0000000..2ad99a2
--- /dev/null
+++ b/Common/MAdMessage.cc
@@ -0,0 +1,126 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdMessage.h"
+
+#include <cstdarg>
+#include <iostream>
+#include <sstream>
+#include <stdlib.h>
+
+using std::stringstream;
+using std::string;
+using std::ostream;
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ MAdMsg::MAdMsg()
+ {
+ outStream = &std::cout;
+ errStream = &std::cerr;
+ }
+
+ // -------------------------------------------------------------------
+ void MAdMsg::initialize()
+ {
+ }
+
+ // -------------------------------------------------------------------
+ void MAdMsg::finalize()
+ {
+ }
+
+ // -------------------------------------------------------------------
+ void MAdMsg::registerAbortFct(AbortFunction fct, void * data)
+ {
+ abortFcts.push_back(std::make_pair(fct,data));
+ }
+
+ // -------------------------------------------------------------------
+ void MAdMsg::info(int line,
+ const char* file,
+ const char* fmt,...) const
+ {
+ char buff[1024];
+ va_list args;
+ va_start (args, fmt);
+ vsprintf(buff, fmt, args);
+ va_end (args);
+
+ if ( line >= 0 ) {
+ *outStream << "Info: " << buff << writePosition(line,file) << "" << std::endl;
+ }
+ else {
+ *outStream << "Info: " << buff << std::endl;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MAdMsg::warning(int line,
+ const char* file,
+ const char* fmt,...) const
+ {
+ char buff[1024];
+ va_list args;
+ va_start (args, fmt);
+ vsprintf(buff, fmt, args);
+ va_end (args);
+
+ if ( line >= 0 ) {
+ *outStream << "WARNING: " << buff << writePosition(line,file) << "" << std::endl;
+ }
+ else {
+ *outStream << "WARNING: " << buff << std::endl;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MAdMsg::error(int line,
+ const char* file,
+ const char* fmt,...) const
+ {
+ char buff[1024];
+ va_list args;
+ va_start (args, fmt);
+ vsprintf(buff, fmt, args);
+ va_end (args);
+
+ if ( line >= 0 ) {
+ *outStream << "ERROR: " << buff << writePosition(line,file) << "" << std::endl;
+ }
+ else {
+ *outStream << "ERROR: " << buff << std::endl;
+ }
+
+ // call abort functions
+ std::list<std::pair<AbortFunction,void*> >::const_iterator iter = abortFcts.begin();
+ for (; iter != abortFcts.end(); iter++) {
+ AbortFunction fct = (*iter).first;
+ void * data = (*iter).second;
+ fct(data);
+ }
+
+ abort();
+ }
+
+ // -------------------------------------------------------------------
+ string MAdMsg::writePosition(int line, const char* file) const
+ {
+ stringstream ss;
+ string iStr; ss << line; ss >> iStr;
+ return " (line " + iStr + " in file \'" + file + "\')";
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Common/MAdMessage.h b/Common/MAdMessage.h
new file mode 100644
index 0000000..89c931f
--- /dev/null
+++ b/Common/MAdMessage.h
@@ -0,0 +1,64 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MESSAGE_MAD_
+#define _H_MESSAGE_MAD_
+
+#include "MAdSingleton.h"
+
+#include <ostream>
+#include <list>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // abort function
+ typedef void (*AbortFunction)(void *);
+
+ // -------------------------------------------------------------------
+ class MAdMsg {
+
+ public:
+
+ MAdMsg();
+ ~MAdMsg() {}
+
+ void initialize();
+ void finalize();
+
+ void registerAbortFct(AbortFunction, void *);
+
+ void info (int, const char*, const char*,...) const;
+ void warning(int, const char*, const char*,...) const;
+ void error (int, const char*, const char*,...) const;
+
+ private:
+
+ std::string writePosition(int, const char*) const;
+
+ private:
+
+ std::ostream* outStream;
+ std::ostream* errStream;
+
+ std::list<std::pair<AbortFunction,void*> > abortFcts;
+
+ };
+
+ // -------------------------------------------------------------------
+
+ typedef MAdSingleton<MAdMsg> MAdMsgSgl;
+
+}
+
+#endif
diff --git a/Common/MAdMetric.cc b/Common/MAdMetric.cc
new file mode 100644
index 0000000..416dfb3
--- /dev/null
+++ b/Common/MAdMetric.cc
@@ -0,0 +1,144 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdMetric.h"
+
+namespace MAd {
+
+ MAdMetric::MAdMetric(const double l1, // (h_1)^-2
+ const double l2,
+ const double l3,
+ const double t1[3],
+ const double t2[3],
+ const double t3[3])
+ {
+ // M = e^1 * diag * e^1^t
+ // where the elements of diag are l_i = h_i^-2
+ // and the rows of e are the UNIT and ORTHOGONAL directions
+
+ double e[3][3];
+ e[0][0] = t1[0]; e[0][1] = t1[1]; e[0][2] = t1[2];
+ e[1][0] = t2[0]; e[1][1] = t2[1]; e[1][2] = t2[2];
+ e[2][0] = t3[0]; e[2][1] = t3[1]; e[2][2] = t3[2];
+ invertMat(e);
+
+ double tmp[3][3];
+ tmp[0][0] = l1 * e[0][0]; tmp[0][1] = l2 * e[0][1]; tmp[0][2] = l3 * e[0][2];
+ tmp[1][0] = l1 * e[1][0]; tmp[1][1] = l2 * e[1][1]; tmp[1][2] = l3 * e[1][2];
+ tmp[2][0] = l1 * e[2][0]; tmp[2][1] = l2 * e[2][1]; tmp[2][2] = l3 * e[2][2];
+
+ transpose(e);
+
+ _val[0] = tmp[0][0] * e[0][0] + tmp[0][1] * e[1][0] + tmp[0][2] * e[2][0];
+ _val[1] = tmp[1][0] * e[0][0] + tmp[1][1] * e[1][0] + tmp[1][2] * e[2][0];
+ _val[2] = tmp[1][0] * e[0][1] + tmp[1][1] * e[1][1] + tmp[1][2] * e[2][1];
+ _val[3] = tmp[2][0] * e[0][0] + tmp[2][1] * e[1][0] + tmp[2][2] * e[2][0];
+ _val[4] = tmp[2][0] * e[0][1] + tmp[2][1] * e[1][1] + tmp[2][2] * e[2][1];
+ _val[5] = tmp[2][0] * e[0][2] + tmp[2][1] * e[1][2] + tmp[2][2] * e[2][2];
+ }
+// MAdMetric(const double l1, // (h_1)^-2
+// const double l2,
+// const double l3,
+// const double t1[3],
+// const double t2[3],
+// const double t3[3]){
+// double t1b[3], t2b[3], t3b[3];
+// t1b[0] = t1[0] * l1; t2b[0] = t2[0] * l1; t3b[0] = t3[0] * l1;
+// t1b[1] = t1[1] * l2; t2b[1] = t2[1] * l2; t3b[1] = t3[1] * l2;
+// t1b[2] = t1[2] * l3; t2b[2] = t2[2] * l3; t3b[2] = t3[2] * l3;
+// _val[0] = dotProd (t1b,t1);
+// _val[1] = dotProd (t2b,t1);
+// _val[2] = dotProd (t2b,t2);
+// _val[3] = dotProd (t3b,t1);
+// _val[4] = dotProd (t3b,t2);
+// _val[5] = dotProd (t3b,t3);
+// }
+
+ void MAdMetric::print (const char *s) const
+ {
+ printf(" metric %s : %12.5E %12.5E %12.5E %12.5E %12.5E %12.5E \n",s,
+ (*this)(0,0),(*this)(1,1),(*this)(2,2),
+ (*this)(0,1),(*this)(0,2),(*this)(1,2));
+ }
+
+
+ MAdMetric intersection (const MAdMetric &m1, const MAdMetric &m2)
+ {
+ MAdMetric im1 = m1.invert();
+ doubleMatrix V(3,3);
+ doubleVector S(3);
+ im1 *= m2;
+ im1.eig(V,S,true);
+ double v0[3]; v0[0] = V(0,0); v0[1] = V(1,0); v0[2] = V(2,0);
+ double v1[3]; v1[0] = V(0,1); v1[1] = V(1,1); v1[2] = V(2,1);
+ double v2[3]; v2[0] = V(0,2); v2[1] = V(1,2); v2[2] = V(2,2);
+ double l0 = std::max(dot(v0,m1,v0),dot(v0,m2,v0));
+ double l1 = std::max(dot(v1,m1,v1),dot(v1,m2,v1));
+ double l2 = std::max(dot(v2,m1,v2),dot(v2,m2,v2));
+ MAdMetric iv(l0,l1,l2,v0,v1,v2);
+ return iv;
+ }
+
+ // (1-t) * m1 + t * m2
+ MAdMetric interpolation (const MAdMetric &m1,
+ const MAdMetric &m2,
+ const double t)
+ {
+ MAdMetric im1 = m1.invert();
+ MAdMetric im2 = m2.invert();
+ im1 *= (1.-t);
+ im2 *= t;
+ im1 += im2;
+ return im1.invert();
+ }
+
+ MAdMetric interpolation (const MAdMetric &m1,
+ const MAdMetric &m2,
+ const MAdMetric &m3,
+ const double u,
+ const double v)
+ {
+ MAdMetric im1 = m1.invert();
+ MAdMetric im2 = m2.invert();
+ MAdMetric im3 = m3.invert();
+ im1 *= (1.-u-v);
+ im2 *= u;
+ im3 *= v;
+ im1 += im2;
+ im1 += im3;
+ return im1.invert();
+ }
+
+ MAdMetric interpolation (const MAdMetric &m1,
+ const MAdMetric &m2,
+ const MAdMetric &m3,
+ const MAdMetric &m4,
+ const double u,
+ const double v,
+ const double w)
+ {
+ MAdMetric im1 = m1.invert();
+ MAdMetric im2 = m2.invert();
+ MAdMetric im3 = m3.invert();
+ MAdMetric im4 = m4.invert();
+ im1 *= (1.-u-v-w);
+ im2 *= u;
+ im3 *= v;
+ im4 *= w;
+ im1 += im2;
+ im1 += im3;
+ im1 += im4;
+ return im1.invert();
+ }
+
+}
diff --git a/Common/MAdMetric.h b/Common/MAdMetric.h
new file mode 100644
index 0000000..4160c3e
--- /dev/null
+++ b/Common/MAdMetric.h
@@ -0,0 +1,151 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADMETRIC
+#define _H_MADMETRIC
+
+#include "MAdMatrix.h"
+#include "MathUtils.h"
+
+namespace MAd {
+
+ // class for symmetric positive definite 3x3 matrix
+ class MAdMetric {
+
+ protected:
+ // lower diagonal storage
+ // 00 10 11 20 21 22
+ double _val[6];
+
+ public:
+
+ inline int getIndex(int i, int j) const{
+ static int _index[3][3] = {{0,1,3},{1,2,4},{3,4,5}};
+ return _index[i][j];
+ }
+ void getMat (doubleMatrix & mat) const{
+ for (int i=0;i<3;i++){
+ for (int j=0;j<3;j++){
+ mat(i,j) = _val[getIndex(i,j)];
+ }
+ }
+ }
+ void getMat (double mat[3][3]) const{
+ for (int i=0;i<3;i++){
+ for (int j=0;j<3;j++){
+ mat[i][j] = _val[getIndex(i,j)];
+ }
+ }
+ }
+ void setMat (const double mat[3][3]){
+ for (int i=0;i<3;i++)
+ for (int j=i;j<3;j++)
+ _val[getIndex(i,j)] = mat[i][j];
+ }
+ MAdMetric(const MAdMetric& m){
+ for (int i=0; i<6; i++) _val[i]=m._val[i];
+ }
+ // default constructor, identity
+ MAdMetric(const double v = 1.0){
+ _val[0] = _val[2] = _val[5] = v;
+ _val[1] = _val[3] = _val[4] = 0.0;
+ }
+ MAdMetric(const double l1, // (h_1)^-2
+ const double l2,
+ const double l3,
+ const double t1[3],
+ const double t2[3],
+ const double t3[3]);
+ inline double &operator()(int i, int j){
+ return _val[getIndex(i,j)];
+ }
+ inline double operator()(int i, int j) const{
+ return _val[getIndex(i,j)];
+ }
+ MAdMetric invert () const {
+ double m[3][3];
+ getMat(m);
+ invertMat(m);
+ MAdMetric ithis;
+ ithis.setMat(m);
+ return ithis;
+ }
+ MAdMetric operator + (const MAdMetric &other) const {
+ MAdMetric res(*this);
+ for (int i=0;i<6;i++) res._val[i] += other._val[i];
+ return res;
+ }
+ MAdMetric& operator += (const MAdMetric &other) {
+ for (int i=0;i<6;i++) _val[i] += other._val[i];
+ return *this;
+ }
+ MAdMetric& operator *= (const double &other) {
+ for (int i=0;i<6;i++) _val[i] *= other;
+ return *this;
+ }
+ MAdMetric& operator *= (const MAdMetric &other) {
+ double m1[3][3], m2[3][3], m3[3][3];
+ getMat(m1);
+ other.getMat(m2);
+ matMat(m1,m2,m3);
+ setMat(m3);
+ return *this;
+ }
+ MAdMetric transform (double V[3][3]){
+ double m[3][3], result[3][3], temp[3][3];
+ getMat(m);
+ transpose(V);
+ matMat(V,m,temp);
+ matMat(temp,V,result);
+ MAdMetric a; a.setMat(result);
+ return a;
+ }
+ // s: true if eigenvalues are sorted (from max to min of the absolute value of the REAL part)
+ void eig (doubleMatrix &V, doubleVector &S, bool s=false) const {
+ doubleMatrix me(3,3),right(3,3);
+ doubleVector im(3);
+ getMat(me);
+ me.eig(V,S,im,right,s);
+ }
+ void print(const char *) const;
+ };
+
+ // scalar product with respect to the metric
+ inline double dot(const double a[3], const MAdMetric &m, const double b[3])
+ { return
+ b[0] * ( m(0,0) * a[0] + m(1,0) * a[1] + m(2,0) * a[2] ) +
+ b[1] * ( m(0,1) * a[0] + m(1,1) * a[1] + m(2,1) * a[2] ) +
+ b[2] * ( m(0,2) * a[0] + m(1,2) * a[1] + m(2,2) * a[2] ) ;}
+
+ // compute the largest inscribed ellipsoid...
+ MAdMetric intersection (const MAdMetric &m1,
+ const MAdMetric &m2);
+ MAdMetric interpolation (const MAdMetric &m1,
+ const MAdMetric &m2,
+ const double t);
+ MAdMetric interpolation (const MAdMetric &m1,
+ const MAdMetric &m2,
+ const MAdMetric &m3,
+ const double u,
+ const double v);
+ MAdMetric interpolation (const MAdMetric &m1,
+ const MAdMetric &m2,
+ const MAdMetric &m3,
+ const MAdMetric &m4,
+ const double u,
+ const double v,
+ const double w);
+
+}
+
+#endif
diff --git a/Common/MAdResourceManager.cc b/Common/MAdResourceManager.cc
new file mode 100644
index 0000000..845c7ba
--- /dev/null
+++ b/Common/MAdResourceManager.cc
@@ -0,0 +1,189 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdResourceManager.h"
+#include "MAdMessage.h"
+
+#include <fstream>
+
+#ifdef PARALLEL
+ #include <mpi.h>
+#else
+ #ifndef _WIN_
+ #include <sys/time.h>
+ #else
+ #include <time.h>
+ #include <windows.h>
+ #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
+ #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
+ #else
+ #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
+ #endif
+
+struct timezone
+{
+ int tz_minuteswest; /* minutes W of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+
+int get_time_of_day(struct timeval *tv, struct timezone *tz)
+{
+ FILETIME ft;
+ unsigned __int64 tmpres = 0;
+ static int tzflag;
+
+ if (NULL != tv)
+ {
+ GetSystemTimeAsFileTime(&ft);
+
+ tmpres |= ft.dwHighDateTime;
+ tmpres <<= 32;
+ tmpres |= ft.dwLowDateTime;
+
+ // converting file time
+ tmpres -= DELTA_EPOCH_IN_MICROSECS;
+ tmpres /= 10; // convert into microseconds
+ tv->tv_sec = (long)(tmpres / 1000000UL);
+ tv->tv_usec = (long)(tmpres % 1000000UL);
+ }
+
+ if (NULL != tz)
+ {
+ if (!tzflag)
+ {
+ _tzset();
+ tzflag++;
+ }
+ tz->tz_minuteswest = _timezone / 60;
+ tz->tz_dsttime = _daylight;
+ }
+
+ return 0;
+}
+ #endif
+
+#endif
+
+#if defined(__linux) || defined(linux)
+
+void process_mem_usage(double& vm_usage, double& resident_set)
+{
+ using std::ios_base;
+ using std::ifstream;
+ using std::string;
+
+ vm_usage = 0.0;
+ resident_set = 0.0;
+
+ // 'file' stat seems to give the most reliable results
+ //
+ ifstream stat_stream("/proc/self/stat",ios_base::in);
+
+ // dummy vars for leading entries in stat that we don't care about
+ //
+ string pid, comm, state, ppid, pgrp, session, tty_nr;
+ string tpgid, flags, minflt, cminflt, majflt, cmajflt;
+ string utime, stime, cutime, cstime, priority, nice;
+ string O, itrealvalue, starttime;
+
+ // the two fields we want
+ //
+ unsigned long vsize;
+ long rss;
+
+ stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr
+ >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt
+ >> utime >> stime >> cutime >> cstime >> priority >> nice
+ >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest
+
+ long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
+ vm_usage = vsize / 1024.0 / 1024;
+ resident_set = rss * page_size_kb / 1024;
+}
+
+#endif
+
+// -------------------------------------------------------------------
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void MAdResourceManager::initialize()
+ {
+ }
+
+ // -------------------------------------------------------------------
+ void MAdResourceManager::finalize()
+ {
+ }
+
+ // -------------------------------------------------------------------
+ double MAdResourceManager::getTime() const {
+
+#ifdef PARALLEL
+ return MPI_Wtime();
+#else
+ struct timeval tp;
+ struct timezone tz;
+#ifdef _WIN_
+ get_time_of_day(&tp,&tz);
+#else
+ gettimeofday(&tp,&tz);
+#endif
+
+ return ((double) tp.tv_sec +
+ (double) ((double) .000001 * (double) tp.tv_usec));
+#endif
+ }
+
+ // -------------------------------------------------------------------
+ double MAdResourceManager::elapsedTime() const {
+
+ return ( getTime() - initialTime );
+
+ }
+
+ // -------------------------------------------------------------------
+ bool MAdResourceManager::getMemoryUsage(double& resident_size,
+ double& virtual_size) const
+ {
+#if defined(__linux) || defined(linux)
+ process_mem_usage(virtual_size,resident_size);
+
+#ifdef PARALLEL
+ double send[2] = {virtual_size,resident_size};
+ double recv[2];
+ MPI_Allreduce(send,recv,2,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
+ virtual_size = recv[0];
+ resident_size = recv[1];
+#endif
+ return true;
+#else
+ MAdMsgSgl::instance().info(__LINE__,__FILE__,
+ "Process memory statistics not reliable on this platform");
+ return false;
+#endif
+ }
+
+ // -------------------------------------------------------------------
+ void MAdResourceManager::printMemoryUsage(std::string step,
+ std::ostream& out) const
+ {
+ double ram, virt;
+ getMemoryUsage(ram,virt);
+ out << "Memory usage at step \'"<<step<<"\': "
+ << ram << " Mb (resident), "
+ << virt << " Mb (virtual)\n";
+ }
+}
+
+// -------------------------------------------------------------------
diff --git a/Common/MAdResourceManager.h b/Common/MAdResourceManager.h
new file mode 100644
index 0000000..e6de555
--- /dev/null
+++ b/Common/MAdResourceManager.h
@@ -0,0 +1,54 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADRESOURCEMANAGER
+#define _H_MADRESOURCEMANAGER
+
+#include "MAdSingleton.h"
+#include <iostream>
+#include <string>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class MAdResourceManager {
+
+ public:
+
+ MAdResourceManager() { reset(); };
+ ~MAdResourceManager() {};
+
+ void initialize();
+ void finalize();
+
+ void reset() { initialTime = getTime(); };
+ double elapsedTime() const;
+ double getTime() const;
+
+ //! Gives the amount of memory currently used in the RAM (resident_size)
+ //! and in total (RAM, cache, disk) (virtual_size) \ingroup tools
+ bool getMemoryUsage(double& resident_size, double& virtual_size) const;
+ void printMemoryUsage(std::string step="", std::ostream& out=std::cout) const;
+
+ private:
+
+ double initialTime;
+
+ };
+
+ // -------------------------------------------------------------------
+
+ typedef MAdSingleton<MAdResourceManager> MAdResourceManagerSgl;
+}
+
+#endif
diff --git a/Common/MAdSingleton.h b/Common/MAdSingleton.h
new file mode 100644
index 0000000..4e37ec4
--- /dev/null
+++ b/Common/MAdSingleton.h
@@ -0,0 +1,20 @@
+// -*- C++ -*-
+
+#ifndef MAD_H_MADSINGLETON
+#define MAD_H_MADSINGLETON
+
+template<typename T> class MAdSingleton
+{
+ public:
+
+ static T& instance()
+ {
+ static T theSingleInstance; // suppose T has a default constructor
+ return theSingleInstance;
+ }
+
+ private:
+ MAdSingleton();
+};
+
+#endif
diff --git a/Common/MAdStringFieldEvaluator.cc b/Common/MAdStringFieldEvaluator.cc
new file mode 100644
index 0000000..7a76953
--- /dev/null
+++ b/Common/MAdStringFieldEvaluator.cc
@@ -0,0 +1,143 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_MATHEX_
+
+#include "MAdStringFieldEvaluator.h"
+
+#include <iostream>
+#include <iomanip>
+#include <stdlib.h>
+using std::list;
+using std::vector;
+using std::string;
+
+namespace MAd {
+
+ // ----------------------------------------------------------------------
+ MAdStringFieldEvaluator :: MAdStringFieldEvaluator (int numberOfStrings, ...):
+ MAdFieldEvaluator()
+ {
+ vector<string> exp;
+
+ va_list ap;
+ va_start(ap,numberOfStrings);
+ for (int i=0;i<numberOfStrings;i++){
+ const char *s = va_arg(ap,const char *);
+ string str = s;
+ exp.push_back(str);
+ }
+ va_end(ap);
+
+ buildEvaluators(exp);
+ }
+
+ // ----------------------------------------------------------------------
+ MAdStringFieldEvaluator::MAdStringFieldEvaluator(const vector<string>& exp):
+ MAdFieldEvaluator()
+ {
+ buildEvaluators(exp);
+ }
+
+ // ----------------------------------------------------------------------
+ void MAdStringFieldEvaluator::buildEvaluators(const vector<string>& exp)
+ {
+ vector<string>::const_iterator eIter = exp.begin();
+ for (;eIter!=exp.end();eIter++) {
+
+ smlib::mathex * expr = new smlib::mathex();
+ expr->addvar("x",&x);
+ expr->addvar("y",&y);
+ expr->addvar("z",&z);
+ expr->addvar("t",&t);
+
+ bool success = false;
+ bool parsed = false;
+ try {
+ expr->expression(*eIter);
+ expr->parse();
+ parsed = true;
+ success = true;
+ }
+ catch(smlib::mathex::error e) {
+ std::cout << e.what() << std::endl;
+ if(!parsed) {
+ std::cout << *eIter << std::endl;
+ std::cout << std::setw(expr->stopposition()) << "^" << std::endl;
+ }
+ }
+ if ( !success ){
+ std::cerr << "Error when parsing string field evaluator: possible symbols are exp, log, log10, sqrt, sin, cos, tan, sinh, cosh, tanh, asin, acos, atan, abs, round, floor, ceil, trunc, deg, fac, rad\n";
+ exit(0);
+ }
+ expressions.push_back(expr);
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ MAdStringFieldEvaluator::~MAdStringFieldEvaluator()
+ {
+ std::list<smlib::mathex*>::iterator it = expressions.begin();
+ for (; it!=expressions.end(); ++it) {
+ delete(*it);
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ bool MAdStringFieldEvaluator::eval(const vector<double> space,
+ double time,
+ double * val) const
+ {
+ if (space.size() != 3) throw;
+
+ double spaceTbl[3];
+ for (int i=0; i<3; i++) spaceTbl[i] = space[i];
+
+ return eval(spaceTbl, time, val);
+ }
+
+ // ----------------------------------------------------------------------
+ bool MAdStringFieldEvaluator::eval(const double space[3],
+ double time,
+ double * val) const
+ {
+ x = space[0];
+ y = space[1];
+ z = space[2];
+ t = time;
+
+ int i = 0;
+ std::list<smlib::mathex*>::const_iterator it = expressions.begin();
+ for (; it!=expressions.end(); ++it) {
+ val[i++] = (*it)->eval();
+ }
+
+ return true;
+ }
+
+ // ----------------------------------------------------------------------
+ int MAdStringFieldEvaluator::nbVar() const
+ {
+ return expressions.size();
+ }
+
+ // ----------------------------------------------------------------------
+ int MAdStringFieldEvaluator::order() const
+ {
+ return 3;
+ }
+
+ // ----------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Common/MAdStringFieldEvaluator.h b/Common/MAdStringFieldEvaluator.h
new file mode 100644
index 0000000..d65e964
--- /dev/null
+++ b/Common/MAdStringFieldEvaluator.h
@@ -0,0 +1,108 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADSTRINGFIELDEVALUATOR
+#define _H_MADSTRINGFIELDEVALUATOR
+
+#include "MAdFieldEvaluator.h"
+
+#ifdef _HAVE_MATHEX_
+
+#include "mathex.h"
+
+#include <list>
+#include <cstdarg>
+#include <string>
+#include <vector>
+
+namespace MAd {
+
+ // ----------------------------------------------------------------------
+ class MAdStringFieldEvaluator : public MAdFieldEvaluator
+ {
+
+ public:
+
+ ~MAdStringFieldEvaluator ();
+ // int numberOfStrings is the number of "const char *" given in "..."
+ MAdStringFieldEvaluator (int numberOfStrings, ...);
+ MAdStringFieldEvaluator(const std::vector<std::string>&);
+
+ private:
+
+ void buildEvaluators(const std::vector<std::string>& exp);
+
+ public:
+
+ bool eval (const double space[3], double time, double * val) const ;
+ bool eval (const std::vector<double> space, double time, double * val) const ;
+
+ int nbVar() const;
+ int order() const;
+
+ private:
+
+ mutable double x,y,z,t;
+ std::list<smlib::mathex*> expressions;
+
+ };
+
+}
+
+#else
+
+#include "MAdMessage.h"
+
+namespace MAd {
+
+ // ----------------------------------------------------------------------
+ class MAdStringFieldEvaluator : public MAdFieldEvaluator
+ {
+
+ public:
+
+ ~MAdStringFieldEvaluator () {}
+ MAdStringFieldEvaluator (int, ...)
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "No string evaluation library available");
+ }
+ MAdStringFieldEvaluator(const std::vector<std::string>&)
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "No string evaluation library available");
+ }
+
+ private:
+
+ void buildEvaluators(const std::vector<std::string>&) { throw; }
+
+ public:
+
+ bool eval (const double space[3], double time, double * val) const
+ { throw; return false; }
+ bool eval (const std::vector<double> space, double time, double * val) const
+ { throw; return false; }
+
+ int nbVar() const { throw; return -1; }
+ int order() const { throw; return -1; }
+
+ };
+
+ // ----------------------------------------------------------------------
+
+}
+
+#endif
+
+#endif
diff --git a/Common/MAdVector3.h b/Common/MAdVector3.h
new file mode 100644
index 0000000..b93120b
--- /dev/null
+++ b/Common/MAdVector3.h
@@ -0,0 +1,71 @@
+// -*- C++ -*-
+
+#ifndef _H_MADVECTOR3
+#define _H_MADVECTOR3
+
+#ifdef _HAVE_GMSH_
+
+#include "gmsh/SVector3.h"
+namespace MAd {
+ typedef SVector3 vec3;
+}
+
+#else
+
+#include "MAdMessage.h"
+
+namespace MAd {
+
+ class MAdVector3
+ {
+ public:
+ MAdVector3() {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Metric not implemented in MAdLib, Gmsh required");
+ }
+ MAdVector3(double x, double y, double z) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Metric not implemented in MAdLib, Gmsh required");
+ }
+ MAdVector3(double v) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Metric not implemented in MAdLib, Gmsh required");
+ }
+ MAdVector3(const double *array) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Metric not implemented in MAdLib, Gmsh required");
+ }
+ MAdVector3(const MAdVector3& v) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Metric not implemented in MAdLib, Gmsh required");
+ }
+ inline double x(void) const { return -1.; }
+ inline double y(void) const { return -1.; }
+ inline double z(void) const { return -1.; }
+ inline double norm() { return -1.; }
+ inline double normSq() { return -1.; }
+ double normalize() { return -1.; }
+ void negate() {}
+ double &operator[](int i){ }
+ double operator[](int i) const { return -1.; }
+ double &operator()(int i){ }
+ double operator()(int i) const { return -1.; }
+ MAdVector3 & operator += (const MAdVector3 &a) { return *this; }
+ MAdVector3 & operator -= (const MAdVector3 &a) { return *this; }
+ MAdVector3 & operator *= (const MAdVector3 &a) { return *this; }
+ MAdVector3 & operator *= (const double v) { return *this; }
+ MAdVector3 & operator = (double v) { return *this; }
+ operator double *() { return NULL; }
+ void print(std::string name="") const {}
+ };
+
+ typedef MAdVector3 vec3;
+
+ inline MAdVector3 crossprod(const MAdVector3 &a, const MAdVector3 &b)
+ { return MAdVector3(); }
+
+}
+
+#endif
+
+#endif
diff --git a/Common/Makefile b/Common/Makefile
new file mode 100644
index 0000000..3f66744
--- /dev/null
+++ b/Common/Makefile
@@ -0,0 +1,54 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../variables
+
+LIB = ../lib/libMAdCommon${LIBEXT}
+
+INC = ${MAdLib_INCLUDES}
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = MathUtils.cc\
+ MAdStringFieldEvaluator.cc\
+ MAdMessage.cc\
+ MAdMatrix.cc\
+ MAdMetric.cc\
+ MAdResourceManager.cc\
+ MAdLib.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${LIB}: ${OBJ}
+ ${AR} ${ARFLAGS} ${LIB} ${OBJ}
+ ${RANLIB} ${LIB}
+
+cpobj: ${OBJ}
+ cp -f ${OBJ} ${MAdLib_TMPDIR}/.
+
+.cc${OBJEXT}:
+ ${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+ ${RM} */*.o *.o *.obj
+
+purge:
+
+depend:
+ (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+ ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+ ) > Makefile.new
+ cp Makefile Makefile.bak
+ cp Makefile.new Makefile
+ rm -f Makefile.new
\ No newline at end of file
diff --git a/Common/MathUtils.cc b/Common/MathUtils.cc
new file mode 100644
index 0000000..4fdddf2
--- /dev/null
+++ b/Common/MathUtils.cc
@@ -0,0 +1,728 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MathUtils.h"
+#include "MAdMessage.h"
+#include "MAdDefines.h"
+
+#include <stdio.h>
+#include <math.h>
+
+#ifdef _HAVE_GSL_
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_eigen.h>
+#endif
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // VECTORS
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ void diffVec(const double v1[3], const double v0[3], double v01[3])
+ {
+ v01[0] = v1[0] - v0[0];
+ v01[1] = v1[1] - v0[1];
+ v01[2] = v1[2] - v0[2];
+ }
+
+ // -------------------------------------------------------------------
+ double dotProd(const double v1[3], const double v2[3])
+ {
+ return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+ }
+
+ // -------------------------------------------------------------------
+ void crossProd(const double v1[3], const double v2[3], double cp[3])
+ {
+ cp[0] = v1[1]*v2[2] - v1[2]*v2[1];
+ cp[1] = v1[2]*v2[0] - v1[0]*v2[2];
+ cp[2] = v1[0]*v2[1] - v1[1]*v2[0];
+ }
+
+ // -------------------------------------------------------------------
+ void normalizeVec(const double v[3], double nv[3])
+ {
+ double lSq = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+ if ( lSq <= MAdTOLSQ ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Normalization called for a zero vector");
+ nv[0] = v[0];
+ nv[1] = v[1];
+ nv[2] = v[2];
+ }
+ double invNorm = 1. / sqrt( lSq );
+ nv[0] = v[0] * invNorm ;
+ nv[1] = v[1] * invNorm ;
+ nv[2] = v[2] * invNorm ;
+ }
+
+ // -------------------------------------------------------------------
+ void printVec(const double vec[3], const char * name)
+ {
+ printf("\nPrinting vector %s\n",name);
+ for (int i=0; i<3; i++) printf(" %g",vec[i]);
+ printf("\n\n");
+ }
+
+ // -------------------------------------------------------------------
+ bool isNanVec (const double vec[3])
+ {
+ if ( isnan(vec[0]) || isnan(vec[1]) || isnan(vec[2]) ) return true;
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // MATRICES
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ void transpose(double mat[3][3])
+ {
+ double tmp;
+ tmp = mat[0][1]; mat[0][1] = mat[1][0]; mat[1][0] = tmp;
+ tmp = mat[0][2]; mat[0][2] = mat[2][0]; mat[2][0] = tmp;
+ tmp = mat[1][2]; mat[1][2] = mat[2][1]; mat[2][1] = tmp;
+ }
+
+ // -------------------------------------------------------------------
+ void transpMat(const double mat[3][3], double matT[3][3])
+ {
+ for(int i=0; i<3; i++) for(int j=0; j<3; j++)
+ matT[i][j] = mat[j][i];
+ }
+
+ // -------------------------------------------------------------------
+ double detMat(const double mat[3][3])
+ {
+ return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) -
+ mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
+ mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
+ }
+
+ // -------------------------------------------------------------------
+ double traceMat(const double mat[3][3])
+ {
+ return mat[0][0] + mat[1][1] + mat[2][2];
+ }
+
+ // -------------------------------------------------------------------
+ double traceMatMat(const double mat[3][3])
+ {
+ double a00 = mat[0][0] * mat[0][0] + mat[1][0] * mat[0][1] + mat[2][0] * mat[0][2];
+ double a11 = mat[1][0] * mat[0][1] + mat[1][1] * mat[1][1] + mat[1][2] * mat[2][1];
+ double a22 = mat[2][0] * mat[0][2] + mat[2][1] * mat[1][2] + mat[2][2] * mat[2][2];
+
+ return a00 + a11 + a22;
+ }
+
+ // -------------------------------------------------------------------
+ void vecMat(const double vec[3], const double mat[3][3], double res[3])
+ {
+ res[0] = mat[0][0] * vec[0] + mat[1][0] * vec[1] + mat[2][0] * vec[2];
+ res[1] = mat[0][1] * vec[0] + mat[1][1] * vec[1] + mat[2][1] * vec[2];
+ res[2] = mat[0][2] * vec[0] + mat[1][2] * vec[1] + mat[2][2] * vec[2];
+ }
+
+ // -------------------------------------------------------------------
+ void matVec(const double mat[3][3], const double vec[3], double res[3])
+ {
+ res[0] = mat[0][0] * vec[0] + mat[0][1] * vec[1] + mat[0][2] * vec[2];
+ res[1] = mat[1][0] * vec[0] + mat[1][1] * vec[1] + mat[1][2] * vec[2];
+ res[2] = mat[2][0] * vec[0] + mat[2][1] * vec[1] + mat[2][2] * vec[2];
+ }
+
+ // -------------------------------------------------------------------
+ void matMat(const double mat1[3][3], const double mat2[3][3], double res[3][3])
+ {
+ res[0][0] = mat1[0][0] * mat2[0][0] + mat1[0][1] * mat2[1][0] + mat1[0][2] * mat2[2][0];
+ res[0][1] = mat1[0][0] * mat2[0][1] + mat1[0][1] * mat2[1][1] + mat1[0][2] * mat2[2][1];
+ res[0][2] = mat1[0][0] * mat2[0][2] + mat1[0][1] * mat2[1][2] + mat1[0][2] * mat2[2][2];
+
+ res[1][0] = mat1[1][0] * mat2[0][0] + mat1[1][1] * mat2[1][0] + mat1[1][2] * mat2[2][0];
+ res[1][1] = mat1[1][0] * mat2[0][1] + mat1[1][1] * mat2[1][1] + mat1[1][2] * mat2[2][1];
+ res[1][2] = mat1[1][0] * mat2[0][2] + mat1[1][1] * mat2[1][2] + mat1[1][2] * mat2[2][2];
+
+ res[2][0] = mat1[2][0] * mat2[0][0] + mat1[2][1] * mat2[1][0] + mat1[2][2] * mat2[2][0];
+ res[2][1] = mat1[2][0] * mat2[0][1] + mat1[2][1] * mat2[1][1] + mat1[2][2] * mat2[2][1];
+ res[2][2] = mat1[2][0] * mat2[0][2] + mat1[2][1] * mat2[1][2] + mat1[2][2] * mat2[2][2];
+ }
+
+ // -------------------------------------------------------------------
+ double vecMatVec(const double mat[3][3], const double vec[3])
+ {
+ double tmp[3];
+ matVec(mat,vec,tmp);
+ return dotProd(vec,tmp);
+ }
+
+ // -------------------------------------------------------------------
+ double inverseMat(const double mat[3][3], double inv[3][3])
+ {
+ double det = detMat(mat);
+ if(det) {
+ double idet = 1. / det;
+ inv[0][0] = (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) * idet;
+ inv[1][0] = -(mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) * idet;
+ inv[2][0] = (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]) * idet;
+ inv[0][1] = -(mat[0][1] * mat[2][2] - mat[0][2] * mat[2][1]) * idet;
+ inv[1][1] = (mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0]) * idet;
+ inv[2][1] = -(mat[0][0] * mat[2][1] - mat[0][1] * mat[2][0]) * idet;
+ inv[0][2] = (mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1]) * idet;
+ inv[1][2] = -(mat[0][0] * mat[1][2] - mat[0][2] * mat[1][0]) * idet;
+ inv[2][2] = (mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]) * idet;
+ }
+ else{
+ printf("Error: Singular matrix\n");
+ for(int i=0; i<3; i++) for(int j=0; j<3; j++) inv[i][j] = 0.;
+ }
+ return det;
+ }
+
+ // -------------------------------------------------------------------
+ double invertMat(double mat[3][3])
+ {
+ double inv[3][3];
+ double det = inverseMat(mat,inv);
+ for (int i=0; i<3; i++) {
+ for (int j=0; j<3; j++) {
+ mat[i][j] = inv[i][j];
+ }
+ }
+ return det;
+ }
+
+ // -------------------------------------------------------------------
+ bool system(const double A[3][3], const double b[3], double res[3], double * det)
+ {
+ *det = detMat(A);
+ if(*det == 0.0) {
+ res[0] = res[1] = res[2] = 0.0;
+ return false;
+ }
+
+ res[0] = b[0] * (A[1][1] * A[2][2] - A[1][2] * A[2][1]) -
+ A[0][1] * (b[1] * A[2][2] - A[1][2] * b[2]) +
+ A[0][2] * (b[1] * A[2][1] - A[1][1] * b[2]);
+ res[1] = A[0][0] * (b[1] * A[2][2] - A[1][2] * b[2]) -
+ b[0] * (A[1][0] * A[2][2] - A[1][2] * A[2][0]) +
+ A[0][2] * (A[1][0] * b[2] - b[1] * A[2][0]);
+ res[2] = A[0][0] * (A[1][1] * b[2] - b[1] * A[2][1]) -
+ A[0][1] * (A[1][0] * b[2] - b[1] * A[2][0]) +
+ b[0] * (A[1][0] * A[2][1] - A[1][1] * A[2][0]);
+
+ double idet = 1. / (*det);
+ for(int i=0; i<3; i++) res[i] *= idet;
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ void printMat(const double mat[3][3], const char * name)
+ {
+ printf("\nPrinting matrix %s\n",name);
+ for (int i=0; i<3; i++) {
+ for (int j=0; j<3; j++) {
+ printf(" %g",mat[i][j]);
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+
+ // -------------------------------------------------------------------
+ void meanRow33(const double mat[3][3], double mean[3])
+ {
+ mean[0] = MAdTHIRD * ( mat[0][0] + mat[1][0] + mat[2][0] );
+ mean[1] = MAdTHIRD * ( mat[0][1] + mat[1][1] + mat[2][1] );
+ mean[2] = MAdTHIRD * ( mat[0][2] + mat[1][2] + mat[2][2] );
+ }
+
+ // -------------------------------------------------------------------
+ void meanRow43(const double mat[4][3], double mean[3])
+ {
+ mean[0] = 0.25 * ( mat[0][0] + mat[1][0] + mat[2][0] + mat[3][0] );
+ mean[1] = 0.25 * ( mat[0][1] + mat[1][1] + mat[2][1] + mat[3][1] );
+ mean[2] = 0.25 * ( mat[0][2] + mat[1][2] + mat[2][2] + mat[3][2] );
+ }
+
+ // -------------------------------------------------------------------
+ bool isNanMat (const double mat[3][3])
+ {
+ if ( isNanVec(mat[0]) || isNanVec(mat[1]) || isNanVec(mat[2]) ) return true;
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ // Miscellaneous
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ void sort(double lst[3])
+ {
+ for (int i=0; i<3; i++) {
+ int k = i;
+ double mx = lst[i];
+ for (int j=i+1; j<3; j++) if (lst[j] >= mx) { mx = lst[j]; k = j; }
+ if (k != i) { lst[k] = lst[i]; lst[i] = mx; }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void cubicRoots(const double coef[4], double real[3], double imag[3]) // GCTODO: to be rewritten
+ {
+ double a = coef[3];
+ double b = coef[2];
+ double c = coef[1];
+ double d = coef[0];
+
+ if(!a || !d){
+ printf("Error: Degenerate cubic: use a second degree solver!\n");
+ return;
+ }
+
+ b /= a;
+ c /= a;
+ d /= a;
+
+ double q = (3.0*c - (b*b))/9.0;
+ double r = -(27.0*d) + b*(9.0*c - 2.0*(b*b));
+ r /= 54.0;
+
+ double discrim = q*q*q + r*r;
+ imag[0] = 0.0; // The first root is always real.
+ double term1 = (b/3.0);
+
+ if (discrim > 0) { // one root is real, two are complex
+ double s = r + sqrt(discrim);
+ s = ((s < 0) ? -pow(-s, (1.0/3.0)) : pow(s, (1.0/3.0)));
+ double t = r - sqrt(discrim);
+ t = ((t < 0) ? -pow(-t, (1.0/3.0)) : pow(t, (1.0/3.0)));
+ real[0] = -term1 + s + t;
+ term1 += (s + t)/2.0;
+ real[1] = real[2] = -term1;
+ term1 = sqrt(3.0)*(-t + s)/2;
+ imag[1] = term1;
+ imag[2] = -term1;
+ return;
+ }
+
+ // The remaining options are all real
+ imag[1] = imag[2] = 0.0;
+
+ double r13;
+ if (discrim == 0){ // All roots real, at least two are equal.
+ r13 = ((r < 0) ? -pow(-r,(1.0/3.0)) : pow(r,(1.0/3.0)));
+ real[0] = -term1 + 2.0*r13;
+ real[1] = real[2] = -(r13 + term1);
+ return;
+ }
+
+ // Only option left is that all roots are real and unequal (to get
+ // here, q < 0)
+ q = -q;
+ double dum1 = q*q*q;
+ dum1 = acos(r/sqrt(dum1));
+ r13 = 2.0*sqrt(q);
+ real[0] = -term1 + r13*cos(dum1/3.0);
+ real[1] = -term1 + r13*cos((dum1 + 2.0*M_PI)/3.0);
+ real[2] = -term1 + r13*cos((dum1 + 4.0*M_PI)/3.0);
+ }
+
+
+ // -------------------------------------------------------------------
+ // solve x^2 + b x + c = 0
+ // x[2] is always set to be zero
+ // long FindQuadraticRoots(const double b, const double c, double x[3]) // GCTODO: to be rewritten
+ // {
+ // // printf("Quadratic roots\n");
+ // x[2]=0.0;
+ // double delt=b*b-4.*c;
+ // if( delt >=0 ) {
+ // delt=sqrt(delt);
+ // x[0]=(-b+delt)/2.0;
+ // x[1]=(-b-delt)/2.0;
+ // return 3;
+ // }
+
+ // printf("Imaginary roots, impossible, delt=%f\n",delt);
+ // return 1;
+ // }
+
+ // -------------------------------------------------------------------
+ // solve x^3 + a1 x^2 + a2 x + a3 = 0
+ // long FindCubicRoots(const double coeff[4], double x[3]) // GCTODO: to be rewritten
+ // {
+ // double a1 = coeff[2] / coeff[3];
+ // double a2 = coeff[1] / coeff[3];
+ // double a3 = coeff[0] / coeff[3];
+
+ // if( fabs(a3)<1.0e-8 )
+ // return FindQuadraticRoots(a1,a2,x);
+
+ // double Q = (a1 * a1 - 3 * a2) / 9.;
+ // double R = (2. * a1 * a1 * a1 - 9. * a1 * a2 + 27. * a3) / 54.;
+ // double Qcubed = Q * Q * Q;
+ // double d = Qcubed - R * R;
+
+ // // printf ("d = %22.15e Q = %12.5E R = %12.5E Qcubed %12.5E\n",d,Q,R,Qcubed);
+
+ // /// three roots, 2 equal
+ // if(Qcubed == 0.0 || fabs ( Qcubed - R * R ) < 1.e-8 * (fabs ( Qcubed) + fabs( R * R)) )
+ // {
+ // double theta;
+ // if (Qcubed <= 0.0)theta = acos(1.0);
+ // else if (R / sqrt(Qcubed) > 1.0)theta = acos(1.0);
+ // else if (R / sqrt(Qcubed) < -1.0)theta = acos(-1.0);
+ // else theta = acos(R / sqrt(Qcubed));
+ // double sqrtQ = sqrt(Q);
+ // // printf("sqrtQ = %12.5E teta=%12.5E a1=%12.5E\n",sqrt(Q),theta,a1);
+ // x[0] = -2 * sqrtQ * cos( theta / 3) - a1 / 3;
+ // x[1] = -2 * sqrtQ * cos((theta + 2 * M_PI) / 3) - a1 / 3;
+ // x[2] = -2 * sqrtQ * cos((theta + 4 * M_PI) / 3) - a1 / 3;
+ // return (3);
+ // }
+
+ // // Three real roots
+ // if (d >= 0.0) {
+ // double theta = acos(R / sqrt(Qcubed));
+ // double sqrtQ = sqrt(Q);
+ // x[0] = -2 * sqrtQ * cos( theta / 3) - a1 / 3;
+ // x[1] = -2 * sqrtQ * cos((theta + 2 * M_PI) / 3) - a1 / 3;
+ // x[2] = -2 * sqrtQ * cos((theta + 4 * M_PI) / 3) - a1 / 3;
+ // return (3);
+ // }
+
+ // // One real root
+ // else {
+ // printf("IMPOSSIBLE !!!\n");
+
+ // double e = pow(sqrt(-d) + fabs(R), 1. / 3.);
+ // if (R > 0)
+ // e = -e;
+ // x[0] = (e + Q / e) - a1 / 3.;
+ // return (1);
+ // }
+ // }
+
+ // -------------------------------------------------------------------
+ int indexOfMin(double v0, double v1, double v2)
+ {
+ double minV = v0;
+ int index = 0;
+ if ( v1 < minV ) { minV = v1; index = 1; }
+ if ( v2 < minV ) { minV = v2; index = 2; }
+ return index;
+ }
+
+ // -------------------------------------------------------------------
+ int indexOfMax(double v0, double v1, double v2)
+ {
+ double maxV = v0;
+ int index = 0;
+ if ( v1 > maxV ) { maxV = v1; index = 1; }
+ if ( v2 > maxV ) { maxV = v2; index = 2; }
+ return index;
+ }
+
+ // -------------------------------------------------------------------
+ double Tri_area(const double xyz[3][3])
+ {
+ double e0[3], e1[3];
+ diffVec(xyz[1],xyz[0],e0);
+ diffVec(xyz[2],xyz[0],e1);
+ double nor[3];
+ crossProd(e0,e1,nor);
+ return ( 0.5 * dotProd(nor,nor) );
+ }
+
+ // -------------------------------------------------------------------
+ double distToLineSq(const double p0[3], const double p1[3],
+ const double xyz[3], double proj2pt[3], bool * onSegment)
+ {
+ double v01[3]; diffVec(p1,p0,v01);
+ double v0x[3]; diffVec(xyz,p0,v0x);
+ double t = dotProd(v01,v0x) / dotProd(v01,v01);
+
+ if ( onSegment ) {
+ *onSegment = false;
+ if ( t >= 0. && t <= 1. ) *onSegment = true;
+ }
+
+ for (int i=0; i<3; i++) {
+ proj2pt[i] = xyz[i] - ( (1.-t) * p0[i] + t * p1[i] );
+ }
+
+ return dotProd(proj2pt,proj2pt);
+ }
+
+ // -------------------------------------------------------------------
+// double distToLineSq(const double p0[3], const double p1[3],
+// const double xyz[3], bool * onSegment)
+// {
+// double v01[3]; diffVec(p1,p0,v01);
+// double vx0[3]; diffVec(p0,xyz,vx0);
+// double d01Sq = dotProd(v01,v01);
+// double dx0Sq = dotProd(vx0,vx0);
+// double prod = dotProd(vx0,v01);
+
+// if ( onSegment ) {
+// *onSegment = false;
+// double vx1[3]; diffVec(p1,xyz,vx1);
+// if ( prod <= 0. && dotProd(vx1,v01) >= 0. ) *onSegment = true;
+// }
+
+// return std::max( ( dx0Sq * d01Sq - prod * prod ) / d01Sq, 0. );
+// }
+
+ // -------------------------------------------------------------------
+ //! Returns the coordinates (u,v) of the point in the parent element
+ void Tri_linearParams(const double tri[3][3], const double xyz[3],
+ double res[2])
+ {
+ double v0X[3], v01[3], v02[3];
+ diffVec(xyz,tri[0],v0X);
+ diffVec(tri[1],tri[0],v01);
+ diffVec(tri[2],tri[0],v02);
+
+ double n[3], nTmp[3];
+ crossProd(v01,v02,n);
+ double ASqInv = 1. / dotProd(n,n);
+
+ crossProd(v0X,v02,nTmp);
+ double A0X2Sq = dotProd(nTmp,nTmp);
+ res[0] = sqrt( A0X2Sq * ASqInv );
+ if ( dotProd(n,nTmp) < 0. ) res[0] = -res[0];
+
+ crossProd(v01,v0X,nTmp);
+ double A01XSq = dotProd(nTmp,nTmp);
+ res[1] = sqrt( A01XSq * ASqInv );
+ if ( dotProd(n,nTmp) < 0. ) res[1] = -res[1];
+
+// double n[3];
+// crossProd(v01,v02,n);
+// double A = sqrt ( dotProd(n,n) );
+// crossProd(v0X,v02,n);
+// double A1 = sqrt ( dotProd(n,n) );
+// crossProd(v01,v0X,n);
+// double A2 = sqrt ( dotProd(n,n) );
+
+// res[0] = A1/A;
+// res[1] = A2/A;
+ }
+
+ // -------------------------------------------------------------------
+ //! Gets the projection of a point on a plane defined by 3 points
+ //! and a bit representing the zone of the plane on wich the projection
+ //! falls given by:
+ //!
+ //! 010=2 | 011=3 / 001=1
+ //! | /
+ //! ------------+--e2--+-----------
+ //! v0| /v2
+ //! | 7 /
+ //! 110=6 e0 e1
+ //! | /
+ //! | / 101=5
+ //! |/
+ //! v1+
+ //! /|
+ //! / |
+ //! 4
+ //!
+ //! and 8, 9 or 10 if it falls on v0, v1 or v2 (respectively)
+ //!
+ //! Computes the square area of the faces of the tetrahedron defined by the
+ //! triangle and the point, projected on the plane of the triangle,
+ //! with the triangle being the first, and then
+ //! the 3 faces being ordered the same way as the edges e0, e1, e2 in
+ //! the triangle.
+ //!
+ void pointToTriangle(const double tri[3][3],
+ const double xyz[3],
+ double proj[3],
+ int * bit,
+ double area[4])
+ {
+ pointToPlane(tri,xyz,proj);
+
+ // find if the projection coincides with any of the 3 points
+ for(int i=0; i<3; i++) {
+ if( distanceSq(proj,tri[i]) < MAdTOL ) {
+ *bit=8+i;
+// area[0] = triArea(tri);
+// area[1] = area[2] = area[3] = 0.;
+//#warning "implement this"
+ return;
+ }
+ }
+
+ // find normal to the triangle
+ double v01[3], v02[3], norm[3];
+ diffVec(tri[1],tri[0],v01);
+ diffVec(tri[2],tri[0],v02);
+ crossProd(v01,v02,norm);
+
+ double ri[3], rj[3], rk[3];
+ diffVec(proj,tri[0],ri);
+ diffVec(proj,tri[1],rj);
+ diffVec(proj,tri[2],rk);
+
+ // determine on which side of the edges does the point lie.
+ // First get normal vectors
+ double temp[3];
+ double normi[3], normj[3], normk[3];
+ crossProd(v01,ri,normi);
+ diffVec(tri[2],tri[1],temp);
+ crossProd(temp,rj,normj);
+ diffVec(tri[0],tri[2],temp);
+ crossProd(temp,rk,normk);
+
+ double mag[3];
+ mag[0] = dotProd(normi,norm);
+ mag[1] = dotProd(normj,norm);
+ mag[2] = dotProd(normk,norm);
+
+ if (area) {
+ area[0] = 0.5 * dotProd(norm,norm);
+ area[1] = 0.5 * dotProd(normi,normi);
+ area[2] = 0.5 * dotProd(normj,normj);
+ area[3] = 0.5 * dotProd(normk,normk);
+ }
+
+ int filter[] = {1,2,4};
+ *bit=0;
+ for(int i=0; i<3; i++){
+ if( mag[i] > 0. ) {
+ *bit = *bit | filter[i];
+ }
+ }
+
+ }
+
+ // -------------------------------------------------------------------
+ //! Gets the distance from a point to a triangle. Consider the
+ //! projection of the point to the plane of the triangle and a bit
+ //! taking the following values according to the zone in which the
+ //! projection falls:
+ //!
+ //! 010=2 | 011=3|
+ //! | | 001=1
+ //! ------------+--e2--+v2
+ //! v0| / \
+ //! | 7 / \
+ //! 110=6 e0 e1 \
+ //! | / \
+ //! | / 101=5
+ //! v1|/
+ //! ------------+
+ //! \
+ //! 100=4 \
+ //! \
+ //!
+ //! and 8, 9 or 10 if it falls on v0, v1 or v2 (respectively).
+ //! The distance will be
+ //! * the distance to v0, v1, v2 if the bit = 2,4,1 resp.,
+ //! * the distance to e0, e1, e2 if the bit = 6,5,3 resp.,
+ //! * the distance to the projection point if the bit >= 7
+ //!
+ //! Computes the vector from the closest point on the tri to 'xyz'.
+ //!
+ double distToTriangleSq(const double tri[3][3],
+ const double xyz[3],
+ double vec[3])
+ {
+ double distSq = MAdBIG;
+
+ double proj[3];
+ pointToPlane(tri,xyz,proj);
+
+ double par[2];
+ Tri_linearParams(tri,proj,par);
+
+ // -- see if the closest point is inside the triangle ---
+ if ( par[0] >= 0. && par[1] >= 0. &&
+ par[0] + par[1] <= 1. )
+ {
+ diffVec(xyz,proj,vec);
+ distSq = dotProd(vec,vec);
+ }
+ // --- else ---
+ else
+ {
+ // --- see if the closest point is on an edge of the triangle ---
+ bool onSeg=false, onSegTest;
+ double testD;
+ double testVec[3];
+ for (int iE=0; iE<3; iE++) {
+ testD = distToLineSq(tri[iE],tri[(iE+1)%3],xyz,testVec,&onSegTest);
+ if ( onSegTest ) {
+ if ( testD < distSq ) {
+ distSq = testD;
+ vec[0] = testVec[0]; vec[1] = testVec[1]; vec[2] = testVec[2];
+ }
+ onSeg = true;
+ }
+ }
+
+ // --- otherwise it is a summit of the triangle
+ if ( !onSeg ) {
+ for (int iV=0; iV<3; iV++) {
+ diffVec(xyz,tri[iV],testVec);
+ testD = dotProd(testVec,testVec);
+ if ( testD < distSq ) {
+ distSq = testD;
+ vec[0] = testVec[0]; vec[1] = testVec[1]; vec[2] = testVec[2];
+ }
+ }
+ }
+ }
+
+ return distSq;
+ }
+
+ // -------------------------------------------------------------------
+ //! Gets the projection of a point on a plane defined by 3 points
+ void pointToPlane(const double plane[3][3],
+ const double xyz[3],
+ double proj[3])
+ {
+ double v01[3], v02[3];
+ diffVec(plane[1],plane[0],v01);
+ diffVec(plane[2],plane[0],v02);
+ double normal[3];
+ crossProd(v01,v02,normal);
+ double areaSq = dotProd(normal,normal);
+
+ double v0X[3];
+ diffVec(xyz,plane[0],v0X);
+ double ASqX = dotProd(v0X,normal);
+
+ double ratio = ASqX / areaSq;
+ for (int i=0; i<3; i++) proj[i] = xyz[i] - ratio * normal[i];
+ }
+
+ // -------------------------------------------------------------------
+ double distanceSq(const double xyz0[3], const double xyz1[3])
+ {
+ return ( ( xyz1[0] - xyz0[0] ) * ( xyz1[0] - xyz0[0] ) +
+ ( xyz1[1] - xyz0[1] ) * ( xyz1[1] - xyz0[1] ) +
+ ( xyz1[2] - xyz0[2] ) * ( xyz1[2] - xyz0[2] ) );
+ }
+
+ // -------------------------------------------------------------------
+
+} // End of namespace MAd
diff --git a/Common/MathUtils.h b/Common/MathUtils.h
new file mode 100644
index 0000000..8469b87
--- /dev/null
+++ b/Common/MathUtils.h
@@ -0,0 +1,69 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MATHUTILS
+#define _H_MATHUTILS
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // --- Vectors ---
+
+ void diffVec (const double [3], const double [3], double [3]);
+ double dotProd (const double [3], const double [3]);
+ void crossProd (const double [3], const double [3], double [3]);
+ void normalizeVec (const double [3], double[3]);
+ void printVec (const double [3], const char * name="");
+ bool isNanVec (const double [3]);
+
+ // -------------------------------------------------------------------
+ // --- Matrices ---
+
+ void transpose (double [3][3]);
+ void transpMat (const double [3][3], double [3][3]);
+ double detMat (const double [3][3]);
+ double traceMat (const double [3][3]);
+ double traceMatMat (const double [3][3]);
+ void vecMat (const double [3], const double [3][3], double [3]);
+ void matVec (const double [3][3], const double [3], double [3]);
+ double vecMatVec (const double [3][3], const double [3]);
+ void matMat (const double [3][3], const double [3][3], double [3][3]);
+ double inverseMat (const double [3][3], double [3][3]);
+ double invertMat (double [3][3]);
+ bool system (const double [3][3], const double [3], double [3], double *);
+ void printMat (const double [3][3], const char * name="");
+ void meanRow33 (const double [3][3], double [3]);
+ void meanRow43 (const double [4][3], double [3]);
+ bool isNanMat (const double [3][3]);
+
+ // -------------------------------------------------------------------
+
+ void sort(double [3]);
+ void cubicRoots(const double [4], double [3], double [3]);
+ int indexOfMin(double, double, double);
+ int indexOfMax(double, double, double);
+ double Tri_area(const double [3][3]);
+ void Tri_linearParams(const double tri[3][3], const double xyz[3], double res[2]);
+ double distToLineSq(const double p0[3], const double p1[3],
+ const double xyz[3], double proj2pt[3], bool *onSegment=0);
+ double distToTriangleSq(const double tri[3][3], const double xyz[3], double vec[3]);
+ void pointToTriangle(const double tri[3][3], const double xyz[3],
+ double proj[3], int * bit, double area[4]=0);
+ void pointToPlane(const double [3][3], const double [3], double[3]);
+ double distanceSq(const double[3], const double[3]);
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Contrib/ANN/Copyright.txt b/Contrib/ANN/Copyright.txt
new file mode 100755
index 0000000..201b616
--- /dev/null
+++ b/Contrib/ANN/Copyright.txt
@@ -0,0 +1,47 @@
+ANN: Approximate Nearest Neighbors
+Version: 1.1
+Release Date: May 3, 2005
+----------------------------------------------------------------------------
+Copyright (c) 1997-2006 University of Maryland and Sunil Arya and David
+Mount All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU Lesser Public License as published by the
+Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+This program 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 Public License for more details.
+
+A copy of the terms and conditions of the license can be found in
+License.txt or online at
+
+ http://www.gnu.org/copyleft/lesser.html
+
+To obtain a copy, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Disclaimer
+----------
+The University of Maryland and the authors make no representations about
+the suitability or fitness of this software for any purpose. It is
+provided "as is" without express or implied warranty.
+---------------------------------------------------------------------
+
+Authors
+-------
+David Mount
+Dept of Computer Science
+University of Maryland,
+College Park, MD 20742 USA
+mount at cs.umd.edu
+http://www.cs.umd.edu/~mount/
+
+Sunil Arya
+Dept of Computer Science
+Hong University of Science and Technology
+Clearwater Bay, HONG KONG
+arya at cs.ust.hk
+http://www.cs.ust.hk/faculty/arya/
diff --git a/Contrib/ANN/License.txt b/Contrib/ANN/License.txt
new file mode 100755
index 0000000..456ea97
--- /dev/null
+++ b/Contrib/ANN/License.txt
@@ -0,0 +1,450 @@
+----------------------------------------------------------------------
+The ANN Library (all versions) is provided under the terms and
+conditions of the GNU Lesser General Public Library, which is stated
+below. It can also be found at:
+
+ http://www.gnu.org/copyleft/lesser.html
+
+----------------------------------------------------------------------
+
+GNU LESSER GENERAL PUBLIC LICENSE
+
+Version 2.1, February 1999
+
+Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+as the successor of the GNU Library Public License, version 2, hence the
+version number 2.1.]
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public Licenses are
+intended to guarantee your freedom to share and change free software--to
+make sure the software is free for all its users.
+
+This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the Free
+Software Foundation and other authors who decide to use it. You can use
+it too, but we suggest you first think carefully about whether this
+license or the ordinary General Public License is the better strategy to
+use in any particular case, based on the explanations below.
+
+When we speak of free software, we are referring to freedom of use, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish); that you receive source code or can get it if
+you want it; that you can change the software and use pieces of it in
+new free programs; and that you are informed that you can do these
+things.
+
+To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for you
+if you distribute copies of the library or if you modify it.
+
+For example, if you distribute copies of the library, whether gratis or
+for a fee, you must give the recipients all the rights that we gave you.
+You must make sure that they, too, receive or can get the source code.
+If you link other code with the library, you must provide complete
+object files to the recipients, so that they can relink them with the
+library after making changes to the library and recompiling it. And you
+must show them these terms so they know their rights.
+
+We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+To protect each distributor, we want to make it very clear that there is
+no warranty for the free library. Also, if the library is modified by
+someone else and passed on, the recipients should know that what they
+have is not the original version, so that the original author's
+reputation will not be affected by problems that might be introduced by
+others.
+
+Finally, software patents pose a constant threat to the existence of any
+free program. We wish to make sure that a company cannot effectively
+restrict the users of a free program by obtaining a restrictive license
+from a patent holder. Therefore, we insist that any patent license
+obtained for a version of the library must be consistent with the full
+freedom of use specified in this license.
+
+Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License. This license, the GNU Lesser General Public
+License, applies to certain designated libraries, and is quite different
+from the ordinary General Public License. We use this license for
+certain libraries in order to permit linking those libraries into
+non-free programs.
+
+When a program is linked with a library, whether statically or using a
+shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the entire
+combination fits its criteria of freedom. The Lesser General Public
+License permits more lax criteria for linking other code with the
+library.
+
+We call this license the "Lesser" General Public License because it does
+Less to protect the user's freedom than the ordinary General Public
+License. It also provides other free software developers Less of an
+advantage over competing non-free programs. These disadvantages are the
+reason we use the ordinary General Public License for many libraries.
+However, the Lesser license provides advantages in certain special
+circumstances.
+
+For example, on rare occasions, there may be a special need to encourage
+the widest possible use of a certain library, so that it becomes a
+de-facto standard. To achieve this, non-free programs must be allowed to
+use the library. A more frequent case is that a free library does the
+same job as widely used non-free libraries. In this case, there is
+little to gain by limiting the free library to free software only, so we
+use the Lesser General Public License.
+
+In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of free
+software. For example, permission to use the GNU C Library in non-free
+programs enables many more people to use the whole GNU operating system,
+as well as its variant, the GNU/Linux operating system.
+
+Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is linked
+with the Library has the freedom and the wherewithal to run that program
+using a modified version of the Library.
+
+The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or other
+authorized party saying it may be distributed under the terms of this
+Lesser General Public License (also called "this License"). Each
+licensee is addressed as "you".
+
+A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+The "Library", below, refers to any such software library or work which
+has been distributed under these terms. A "work based on the Library"
+means either the Library or any derivative work under copyright law:
+that is to say, a work containing the Library or a portion of it, either
+verbatim or with modifications and/or translated straightforwardly into
+another language. (Hereinafter, translation is included without
+limitation in the term "modification".)
+
+"Source code" for a work means the preferred form of the work for making
+modifications to it. For a library, complete source code means all the
+source code for all modules it contains, plus any associated interface
+definition files, plus the scripts used to control compilation and
+installation of the library.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of running
+a program using the Library is not restricted, and output from such a
+program is covered only if its contents constitute a work based on the
+Library (independent of the use of the Library in a tool for writing
+it). Whether that is true depends on what the Library does and what the
+program that uses the Library does.
+
+1. You may copy and distribute verbatim copies of the Library's complete
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the notices
+that refer to this License and to the absence of any warranty; and
+distribute a copy of this License along with the Library.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Library or any portion of
+it, thus forming a work based on the Library, and copy and distribute
+such modifications or work under the terms of Section 1 above, provided
+that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+a purpose that is entirely well-defined independent of the application.
+Therefore, Subsection 2d requires that any application-supplied function
+or table used by this function must be optional: if the application does
+not supply it, the square root function must still compute square
+roots.)
+
+ These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library, and
+can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based on
+the Library, the distribution of the whole must be on the terms of this
+License, whose permissions for other licensees extend to the entire
+whole, and thus to each and every part regardless of who wrote it.
+
+ Thus, it is not the intent of this section to claim rights or
+contest your rights to work written entirely by you; rather, the intent
+is to exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+ In addition, mere aggregation of another work not based on the
+Library with the Library (or with a work based on the Library) on a
+volume of a storage or distribution medium does not bring the other work
+under the scope of this License.
+
+3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so that
+they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in these
+notices.
+
+Once this change is made in a given copy, it is irreversible for that
+copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+This option is useful when you wish to copy part of the code of the
+Library into a program that is not a library.
+
+4. You may copy and distribute the Library (or a portion or derivative
+of it, under Section 2) in object code or executable form under the
+terms of Sections 1 and 2 above provided that you accompany it with the
+complete corresponding machine-readable source code, which must be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange.
+
+If distribution of object code is made by offering access to copy from a
+designated place, then offering equivalent access to copy the source
+code from the same place satisfies the requirement to distribute the
+source code, even though third parties are not compelled to copy the
+source along with the object code.
+
+5. A program that contains no derivative of any portion of the Library,
+but is designed to work with the Library by being compiled or linked
+with it, is called a "work that uses the Library". Such a work, in
+isolation, is not a derivative work of the Library, and therefore falls
+outside the scope of this License.
+
+However, linking a "work that uses the Library" with the Library creates
+an executable that is a derivative of the Library (because it contains
+portions of the Library), rather than a "work that uses the library".
+The executable is therefore covered by this License. Section 6 states
+terms for distribution of such executables.
+
+When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be linked
+without the Library, or if the work is itself a library. The threshold
+for this to be true is not precisely defined by law.
+
+If such an object file uses only numerical parameters, data structure
+layouts and accessors, and small macros and small inline functions (ten
+lines or less in length), then the use of the object file is
+unrestricted, regardless of whether it is legally a derivative work.
+(Executables containing this object code plus portions of the Library
+will still fall under Section 6.)
+
+Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6, whether
+or not they are linked directly with the Library itself.
+
+6. As an exception to the Sections above, you may also combine or link a
+"work that uses the Library" with the Library to produce a work
+containing portions of the Library, and distribute that work under terms
+of your choice, provided that the terms permit modification of the work
+for the customer's own use and reverse engineering for debugging such
+modifications.
+
+You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work during
+execution displays copyright notices, you must include the copyright
+notice for the Library among them, as well as a reference directing the
+user to the copy of this License. Also, you must do one of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood that
+ the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+ c) Accompany the work with a written offer, valid for at least
+ three years, to give the same user the materials specified in
+ Subsection 6a, above, for a charge no more than the cost of
+ performing this distribution.
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+For an executable, the required form of the "work that uses the Library"
+must include any data and utility programs needed for reproducing the
+executable from it. However, as a special exception, the materials to be
+distributed need not include anything that is normally distributed (in
+either source or binary form) with the major components (compiler,
+kernel, and so on) of the operating system on which the executable runs,
+unless that component itself accompanies the executable.
+
+It may happen that this requirement contradicts the license restrictions
+of other proprietary libraries that do not normally accompany the
+operating system. Such a contradiction means you cannot use both them
+and the Library together in an executable that you distribute.
+
+7. You may place library facilities that are a work based on the Library
+side-by-side in a single library together with other library facilities
+not covered by this License, and distribute such a combined library,
+provided that the separate distribution of the work based on the Library
+and of the other library facilities is otherwise permitted, and provided
+that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+8. You may not copy, modify, sublicense, link with, or distribute the
+Library except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense, link with, or distribute the
+Library is void, and will automatically terminate your rights under this
+License. However, parties who have received copies, or rights, from you
+under this License will not have their licenses terminated so long as
+such parties remain in full compliance.
+
+9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and all
+its terms and conditions for copying, distributing or modifying the
+Library or works based on it.
+
+10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot distribute
+so as to satisfy simultaneously your obligations under this License and
+any other pertinent obligations, then as a consequence you may not
+distribute the Library at all. For example, if a patent license would
+not permit royalty-free redistribution of the Library by all those who
+receive copies directly or indirectly through you, then the only way you
+could satisfy both it and this License would be to refrain entirely from
+distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is implemented
+by public license practices. Many people have made generous
+contributions to the wide range of software distributed through that
+system in reliance on consistent application of that system; it is up to
+the author/donor to decide if he or she is willing to distribute
+software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be
+a consequence of the rest of this License.
+
+12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may
+add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among countries
+not thus excluded. In such case, this License incorporates the
+limitation as if written in the body of this License.
+
+13. The Free Software Foundation may publish revised and/or new versions
+of the Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a license
+version number, you may choose any version ever published by the Free
+Software Foundation.
+
+14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free Software
+Foundation; we sometimes make exceptions for this. Our decision will be
+guided by the two goals of preserving the free status of all derivatives
+of our free software and of promoting the sharing and reuse of software
+generally.
+
+NO WARRANTY
+
+15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH
+YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
+DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
+DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY
+(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
+THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR
+OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
diff --git a/Contrib/ANN/Makefile b/Contrib/ANN/Makefile
new file mode 100755
index 0000000..4451f2e
--- /dev/null
+++ b/Contrib/ANN/Makefile
@@ -0,0 +1,25 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../../variables
+
+default:
+ @cd src && ${MAKE}
+
+cpobj:
+ @cd src && ${MAKE} cpobj
+
+clean:
+ @cd src && ${MAKE} clean
+
+depend:
+ @cd src && ${MAKE} depend
diff --git a/Contrib/ANN/README b/Contrib/ANN/README
new file mode 100755
index 0000000..e55716c
--- /dev/null
+++ b/Contrib/ANN/README
@@ -0,0 +1,2 @@
+See the Copyright.txt and License.txt files for copyright and license
+information.
diff --git a/Contrib/ANN/include/ANN/ANN.h b/Contrib/ANN/include/ANN/ANN.h
new file mode 100755
index 0000000..ca8146a
--- /dev/null
+++ b/Contrib/ANN/include/ANN/ANN.h
@@ -0,0 +1,829 @@
+//----------------------------------------------------------------------
+// File: ANN.h
+// Programmer: Sunil Arya and David Mount
+// Last modified: 05/03/05 (Release 1.1)
+// Description: Basic include file for approximate nearest
+// neighbor searching.
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the
+// Approximate Nearest Neighbor Library (ANN).
+//
+// Permission to use, copy, and distribute this software and its
+// documentation is hereby granted free of charge, provided that
+// (1) it is not a component of a commercial product, and
+// (2) this notice appears in all copies of the software and
+// related documentation.
+//
+// The University of Maryland (U.M.) and the authors make no representations
+// about the suitability or fitness of this software for any purpose. It is
+// provided "as is" without express or implied warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.0 04/01/05
+// Added copyright and revision information
+// Added ANNcoordPrec for coordinate precision.
+// Added methods theDim, nPoints, maxPoints, thePoints to ANNpointSet.
+// Cleaned up C++ structure for modern compilers
+// Revision 1.1 05/03/05
+// Added fixed-radius k-NN searching
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// ANN - approximate nearest neighbor searching
+// ANN is a library for approximate nearest neighbor searching,
+// based on the use of standard and priority search in kd-trees
+// and balanced box-decomposition (bbd) trees. Here are some
+// references to the main algorithmic techniques used here:
+//
+// kd-trees:
+// Friedman, Bentley, and Finkel, ``An algorithm for finding
+// best matches in logarithmic expected time,'' ACM
+// Transactions on Mathematical Software, 3(3):209-226, 1977.
+//
+// Priority search in kd-trees:
+// Arya and Mount, ``Algorithms for fast vector quantization,''
+// Proc. of DCC '93: Data Compression Conference, eds. J. A.
+// Storer and M. Cohn, IEEE Press, 1993, 381-390.
+//
+// Approximate nearest neighbor search and bbd-trees:
+// Arya, Mount, Netanyahu, Silverman, and Wu, ``An optimal
+// algorithm for approximate nearest neighbor searching,''
+// 5th Ann. ACM-SIAM Symposium on Discrete Algorithms,
+// 1994, 573-582.
+//----------------------------------------------------------------------
+
+#ifndef ANN_H
+#define ANN_H
+
+#ifdef WIN33
+ //----------------------------------------------------------------------
+ // For Microsoft Visual C++, externally accessible symbols must be
+ // explicitly indicated with DLL_API, which is somewhat like "extern."
+ //
+ // The following ifdef block is the standard way of creating macros
+ // which make exporting from a DLL simpler. All files within this DLL
+ // are compiled with the DLL_EXPORTS preprocessor symbol defined on the
+ // command line. In contrast, projects that use (or import) the DLL
+ // objects do not define the DLL_EXPORTS symbol. This way any other
+ // project whose source files include this file see DLL_API functions as
+ // being imported from a DLL, wheras this DLL sees symbols defined with
+ // this macro as being exported.
+ //----------------------------------------------------------------------
+ #ifdef DLL_EXPORTS
+ #define DLL_API __declspec(dllexport)
+ #else
+ #define DLL_API __declspec(dllimport)
+ #endif
+ //----------------------------------------------------------------------
+ // DLL_API is ignored for all other systems
+ //----------------------------------------------------------------------
+#else
+ #define DLL_API
+#endif
+
+//----------------------------------------------------------------------
+// basic includes
+//----------------------------------------------------------------------
+
+#include <cmath> // math includes
+#include <iostream> // I/O streams
+
+//----------------------------------------------------------------------
+// Limits
+// There are a number of places where we use the maximum double value as
+// default initializers (and others may be used, depending on the
+// data/distance representation). These can usually be found in limits.h
+// (as LONG_MAX, INT_MAX) or in float.h (as DBL_MAX, FLT_MAX).
+//
+// Not all systems have these files. If you are using such a system,
+// you should set the preprocessor symbol ANN_NO_LIMITS_H when
+// compiling, and modify the statements below to generate the
+// appropriate value. For practical purposes, this does not need to be
+// the maximum double value. It is sufficient that it be at least as
+// large than the maximum squared distance between between any two
+// points.
+//----------------------------------------------------------------------
+#ifdef ANN_NO_LIMITS_H // limits.h unavailable
+ #include <cvalues> // replacement for limits.h
+ const double ANN_DBL_MAX = MAXDOUBLE; // insert maximum double
+#else
+ #include <climits>
+ #include <cfloat>
+ const double ANN_DBL_MAX = DBL_MAX;
+#endif
+
+#define ANNversion "1.0" // ANN version and information
+#define ANNversionCmt ""
+#define ANNcopyright "David M. Mount and Sunil Arya"
+#define ANNlatestRev "Mar 1, 2005"
+
+//----------------------------------------------------------------------
+// ANNbool
+// This is a simple boolean type. Although ANSI C++ is supposed
+// to support the type bool, some compilers do not have it.
+//----------------------------------------------------------------------
+
+enum ANNbool {ANNfalse = 0, ANNtrue = 1}; // ANN boolean type (non ANSI C++)
+
+//----------------------------------------------------------------------
+// ANNcoord, ANNdist
+// ANNcoord and ANNdist are the types used for representing
+// point coordinates and distances. They can be modified by the
+// user, with some care. It is assumed that they are both numeric
+// types, and that ANNdist is generally of an equal or higher type
+// from ANNcoord. A variable of type ANNdist should be large
+// enough to store the sum of squared components of a variable
+// of type ANNcoord for the number of dimensions needed in the
+// application. For example, the following combinations are
+// legal:
+//
+// ANNcoord ANNdist
+// --------- -------------------------------
+// short short, int, long, float, double
+// int int, long, float, double
+// long long, float, double
+// float float, double
+// double double
+//
+// It is the user's responsibility to make sure that overflow does
+// not occur in distance calculation.
+//----------------------------------------------------------------------
+
+typedef double ANNcoord; // coordinate data type
+typedef double ANNdist; // distance data type
+
+//----------------------------------------------------------------------
+// ANNidx
+// ANNidx is a point index. When the data structure is built, the
+// points are given as an array. Nearest neighbor results are
+// returned as an integer index into this array. To make it
+// clearer when this is happening, we define the integer type
+// ANNidx. Indexing starts from 0.
+//
+// For fixed-radius near neighbor searching, it is possible that
+// there are not k nearest neighbors within the search radius. To
+// indicate this, the algorithm returns ANN_NULL_IDX as its result.
+// It should be distinguishable from any valid array index.
+//----------------------------------------------------------------------
+
+typedef int ANNidx; // point index
+const ANNidx ANN_NULL_IDX = -1; // a NULL point index
+
+//----------------------------------------------------------------------
+// Infinite distance:
+// The code assumes that there is an "infinite distance" which it
+// uses to initialize distances before performing nearest neighbor
+// searches. It should be as larger or larger than any legitimate
+// nearest neighbor distance.
+//
+// On most systems, these should be found in the standard include
+// file <limits.h> or possibly <float.h>. If you do not have these
+// file, some suggested values are listed below, assuming 64-bit
+// long, 32-bit int and 16-bit short.
+//
+// ANNdist ANN_DIST_INF Values (see <limits.h> or <float.h>)
+// ------- ------------ ------------------------------------
+// double DBL_MAX 1.79769313486231570e+308
+// float FLT_MAX 3.40282346638528860e+38
+// long LONG_MAX 0x7fffffffffffffff
+// int INT_MAX 0x7fffffff
+// short SHRT_MAX 0x7fff
+//----------------------------------------------------------------------
+
+const ANNdist ANN_DIST_INF = ANN_DBL_MAX;
+
+//----------------------------------------------------------------------
+// Significant digits for tree dumps:
+// When floating point coordinates are used, the routine that dumps
+// a tree needs to know roughly how many significant digits there
+// are in a ANNcoord, so it can output points to full precision.
+// This is defined to be ANNcoordPrec. On most systems these
+// values can be found in the standard include files <limits.h> or
+// <float.h>. For integer types, the value is essentially ignored.
+//
+// ANNcoord ANNcoordPrec Values (see <limits.h> or <float.h>)
+// -------- ------------ ------------------------------------
+// double DBL_DIG 15
+// float FLT_DIG 6
+// long doesn't matter 19
+// int doesn't matter 10
+// short doesn't matter 5
+//----------------------------------------------------------------------
+
+#ifdef DBL_DIG // number of sig. bits in ANNcoord
+ const int ANNcoordPrec = DBL_DIG;
+#else
+ const int ANNcoordPrec = 15; // default precision
+#endif
+
+//----------------------------------------------------------------------
+// Self match?
+// In some applications, the nearest neighbor of a point is not
+// allowed to be the point itself. This occurs, for example, when
+// computing all nearest neighbors in a set. By setting the
+// parameter ANN_ALLOW_SELF_MATCH to ANNfalse, the nearest neighbor
+// is the closest point whose distance from the query point is
+// strictly positive.
+//----------------------------------------------------------------------
+
+const ANNbool ANN_ALLOW_SELF_MATCH = ANNtrue;
+
+//----------------------------------------------------------------------
+// Norms and metrics:
+// ANN supports any Minkowski norm for defining distance. In
+// particular, for any p >= 1, the L_p Minkowski norm defines the
+// length of a d-vector (v0, v1, ..., v(d-1)) to be
+//
+// (|v0|^p + |v1|^p + ... + |v(d-1)|^p)^(1/p),
+//
+// (where ^ denotes exponentiation, and |.| denotes absolute
+// value). The distance between two points is defined to be the
+// norm of the vector joining them. Some common distance metrics
+// include
+//
+// Euclidean metric p = 2
+// Manhattan metric p = 1
+// Max metric p = infinity
+//
+// In the case of the max metric, the norm is computed by taking
+// the maxima of the absolute values of the components. ANN is
+// highly "coordinate-based" and does not support general distances
+// functions (e.g. those obeying just the triangle inequality). It
+// also does not support distance functions based on
+// inner-products.
+//
+// For the purpose of computing nearest neighbors, it is not
+// necessary to compute the final power (1/p). Thus the only
+// component that is used by the program is |v(i)|^p.
+//
+// ANN parameterizes the distance computation through the following
+// macros. (Macros are used rather than procedures for
+// efficiency.) Recall that the distance between two points is
+// given by the length of the vector joining them, and the length
+// or norm of a vector v is given by formula:
+//
+// |v| = ROOT(POW(v0) # POW(v1) # ... # POW(v(d-1)))
+//
+// where ROOT, POW are unary functions and # is an associative and
+// commutative binary operator mapping the following types:
+//
+// ** POW: ANNcoord --> ANNdist
+// ** #: ANNdist x ANNdist --> ANNdist
+// ** ROOT: ANNdist (>0) --> double
+//
+// For early termination in distance calculation (partial distance
+// calculation) we assume that POW and # together are monotonically
+// increasing on sequences of arguments, meaning that for all
+// v0..vk and y:
+//
+// POW(v0) #...# POW(vk) <= (POW(v0) #...# POW(vk)) # POW(y).
+//
+// Incremental Distance Calculation:
+// The program uses an optimized method of computing distances for
+// kd-trees and bd-trees, called incremental distance calculation.
+// It is used when distances are to be updated when only a single
+// coordinate of a point has been changed. In order to use this,
+// we assume that there is an incremental update function DIFF(x,y)
+// for #, such that if:
+//
+// s = x0 # ... # xi # ... # xk
+//
+// then if s' is equal to s but with xi replaced by y, that is,
+//
+// s' = x0 # ... # y # ... # xk
+//
+// then the length of s' can be computed by:
+//
+// |s'| = |s| # DIFF(xi,y).
+//
+// Thus, if # is + then DIFF(xi,y) is (yi-x). For the L_infinity
+// norm we make use of the fact that in the program this function
+// is only invoked when y > xi, and hence DIFF(xi,y)=y.
+//
+// Finally, for approximate nearest neighbor queries we assume
+// that POW and ROOT are related such that
+//
+// v*ROOT(x) = ROOT(POW(v)*x)
+//
+// Here are the values for the various Minkowski norms:
+//
+// L_p: p even: p odd:
+// ------------------------- ------------------------
+// POW(v) = v^p POW(v) = |v|^p
+// ROOT(x) = x^(1/p) ROOT(x) = x^(1/p)
+// # = + # = +
+// DIFF(x,y) = y - x DIFF(x,y) = y - x
+//
+// L_inf:
+// POW(v) = |v|
+// ROOT(x) = x
+// # = max
+// DIFF(x,y) = y
+//
+// By default the Euclidean norm is assumed. To change the norm,
+// uncomment the appropriate set of macros below.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// Use the following for the Euclidean norm
+//----------------------------------------------------------------------
+#define ANN_POW(v) ((v)*(v))
+#define ANN_ROOT(x) sqrt(x)
+#define ANN_SUM(x,y) ((x) + (y))
+#define ANN_DIFF(x,y) ((y) - (x))
+
+//----------------------------------------------------------------------
+// Use the following for the L_1 (Manhattan) norm
+//----------------------------------------------------------------------
+// #define ANN_POW(v) fabs(v)
+// #define ANN_ROOT(x) (x)
+// #define ANN_SUM(x,y) ((x) + (y))
+// #define ANN_DIFF(x,y) ((y) - (x))
+
+//----------------------------------------------------------------------
+// Use the following for a general L_p norm
+//----------------------------------------------------------------------
+// #define ANN_POW(v) pow(fabs(v),p)
+// #define ANN_ROOT(x) pow(fabs(x),1/p)
+// #define ANN_SUM(x,y) ((x) + (y))
+// #define ANN_DIFF(x,y) ((y) - (x))
+
+//----------------------------------------------------------------------
+// Use the following for the L_infinity (Max) norm
+//----------------------------------------------------------------------
+// #define ANN_POW(v) fabs(v)
+// #define ANN_ROOT(x) (x)
+// #define ANN_SUM(x,y) ((x) > (y) ? (x) : (y))
+// #define ANN_DIFF(x,y) (y)
+
+//----------------------------------------------------------------------
+// Array types
+// The following array types are of basic interest. A point is
+// just a dimensionless array of coordinates, a point array is a
+// dimensionless array of points. A distance array is a
+// dimensionless array of distances and an index array is a
+// dimensionless array of point indices. The latter two are used
+// when returning the results of k-nearest neighbor queries.
+//----------------------------------------------------------------------
+
+typedef ANNcoord* ANNpoint; // a point
+typedef ANNpoint* ANNpointArray; // an array of points
+typedef ANNdist* ANNdistArray; // an array of distances
+typedef ANNidx* ANNidxArray; // an array of point indices
+
+//----------------------------------------------------------------------
+// Basic point and array utilities:
+// The following procedures are useful supplements to ANN's nearest
+// neighbor capabilities.
+//
+// annDist():
+// Computes the (squared) distance between a pair of points.
+// Note that this routine is not used internally by ANN for
+// computing distance calculations. For reasons of efficiency
+// this is done using incremental distance calculation. Thus,
+// this routine cannot be modified as a method of changing the
+// metric.
+//
+// Because points (somewhat like strings in C) are stored as
+// pointers. Consequently, creating and destroying copies of
+// points may require storage allocation. These procedures do
+// this.
+//
+// annAllocPt() and annDeallocPt():
+// Allocate a deallocate storage for a single point, and
+// return a pointer to it. The argument to AllocPt() is
+// used to initialize all components.
+//
+// annAllocPts() and annDeallocPts():
+// Allocate and deallocate an array of points as well a
+// place to store their coordinates, and initializes the
+// points to point to their respective coordinates. It
+// allocates point storage in a contiguous block large
+// enough to store all the points. It performs no
+// initialization.
+//
+// annCopyPt():
+// Creates a copy of a given point, allocating space for
+// the new point. It returns a pointer to the newly
+// allocated copy.
+//----------------------------------------------------------------------
+
+DLL_API ANNdist annDist(
+ int dim, // dimension of space
+ ANNpoint p, // points
+ ANNpoint q);
+
+DLL_API ANNpoint annAllocPt(
+ int dim, // dimension
+ ANNcoord c = 0); // coordinate value (all equal)
+
+DLL_API ANNpointArray annAllocPts(
+ int n, // number of points
+ int dim); // dimension
+
+DLL_API void annDeallocPt(
+ ANNpoint &p); // deallocate 1 point
+
+DLL_API void annDeallocPts(
+ ANNpointArray &pa); // point array
+
+DLL_API ANNpoint annCopyPt(
+ int dim, // dimension
+ ANNpoint source); // point to copy
+
+//----------------------------------------------------------------------
+//Overall structure: ANN supports a number of different data structures
+//for approximate and exact nearest neighbor searching. These are:
+//
+// ANNbruteForce A simple brute-force search structure.
+// ANNkd_tree A kd-tree tree search structure. ANNbd_tree
+// A bd-tree tree search structure (a kd-tree with shrink
+// capabilities).
+//
+// At a minimum, each of these data structures support k-nearest
+// neighbor queries. The nearest neighbor query, annkSearch,
+// returns an integer identifier and the distance to the nearest
+// neighbor(s) and annRangeSearch returns the nearest points that
+// lie within a given query ball.
+//
+// Each structure is built by invoking the appropriate constructor
+// and passing it (at a minimum) the array of points, the total
+// number of points and the dimension of the space. Each structure
+// is also assumed to support a destructor and member functions
+// that return basic information about the point set.
+//
+// Note that the array of points is not copied by the data
+// structure (for reasons of space efficiency), and it is assumed
+// to be constant throughout the lifetime of the search structure.
+//
+// The search algorithm, annkSearch, is given the query point (q),
+// and the desired number of nearest neighbors to report (k), and
+// the error bound (eps) (whose default value is 0, implying exact
+// nearest neighbors). It returns two arrays which are assumed to
+// contain at least k elements: one (nn_idx) contains the indices
+// (within the point array) of the nearest neighbors and the other
+// (dd) contains the squared distances to these nearest neighbors.
+//
+// The search algorithm, annkFRSearch, is a fixed-radius kNN
+// search. In addition to a query point, it is given a (squared)
+// radius bound. (This is done for consistency, because the search
+// returns distances as squared quantities.) It does two things.
+// First, it computes the k nearest neighbors within the radius
+// bound, and second, it returns the total number of points lying
+// within the radius bound. It is permitted to set k = 0, in which
+// case it effectively answers a range counting query. If the
+// error bound epsilon is positive, then the search is approximate
+// in the sense that it is free to ignore any point that lies
+// outside a ball of radius r/(1+epsilon), where r is the given
+// (unsquared) radius bound.
+//
+// The generic object from which all the search structures are
+// dervied is given below. It is a virtual object, and is useless
+// by itself.
+//----------------------------------------------------------------------
+
+class DLL_API ANNpointSet {
+public:
+ virtual ~ANNpointSet() {} // virtual distructor
+
+ virtual void annkSearch( // approx k near neighbor search
+ ANNpoint q, // query point
+ int k, // number of near neighbors to return
+ ANNidxArray nn_idx, // nearest neighbor array (modified)
+ ANNdistArray dd, // dist to near neighbors (modified)
+ double eps=0.0 // error bound
+ ) = 0; // pure virtual (defined elsewhere)
+
+ virtual int annkFRSearch( // approx fixed-radius kNN search
+ ANNpoint q, // query point
+ ANNdist sqRad, // squared radius
+ int k = 0, // number of near neighbors to return
+ ANNidxArray nn_idx = NULL, // nearest neighbor array (modified)
+ ANNdistArray dd = NULL, // dist to near neighbors (modified)
+ double eps=0.0 // error bound
+ ) = 0; // pure virtual (defined elsewhere)
+
+ virtual int theDim() = 0; // return dimension of space
+ virtual int nPoints() = 0; // return number of points
+ // return pointer to points
+ virtual ANNpointArray thePoints() = 0;
+};
+
+//----------------------------------------------------------------------
+// Brute-force nearest neighbor search:
+// The brute-force search structure is very simple but inefficient.
+// It has been provided primarily for the sake of comparison with
+// and validation of the more complex search structures.
+//
+// Query processing is the same as described above, but the value
+// of epsilon is ignored, since all distance calculations are
+// performed exactly.
+//
+// WARNING: This data structure is very slow, and should not be
+// used unless the number of points is very small.
+//
+// Internal information:
+// ---------------------
+// This data structure bascially consists of the array of points
+// (each a pointer to an array of coordinates). The search is
+// performed by a simple linear scan of all the points.
+//----------------------------------------------------------------------
+
+class DLL_API ANNbruteForce: public ANNpointSet {
+ int dim; // dimension
+ int n_pts; // number of points
+ ANNpointArray pts; // point array
+public:
+ ANNbruteForce( // constructor from point array
+ ANNpointArray pa, // point array
+ int n, // number of points
+ int dd); // dimension
+
+ ~ANNbruteForce(); // destructor
+
+ void annkSearch( // approx k near neighbor search
+ ANNpoint q, // query point
+ int k, // number of near neighbors to return
+ ANNidxArray nn_idx, // nearest neighbor array (modified)
+ ANNdistArray dd, // dist to near neighbors (modified)
+ double eps=0.0); // error bound
+
+ int annkFRSearch( // approx fixed-radius kNN search
+ ANNpoint q, // query point
+ ANNdist sqRad, // squared radius
+ int k = 0, // number of near neighbors to return
+ ANNidxArray nn_idx = NULL, // nearest neighbor array (modified)
+ ANNdistArray dd = NULL, // dist to near neighbors (modified)
+ double eps=0.0); // error bound
+
+ int theDim() // return dimension of space
+ { return dim; }
+
+ int nPoints() // return number of points
+ { return n_pts; }
+
+ ANNpointArray thePoints() // return pointer to points
+ { return pts; }
+};
+
+//----------------------------------------------------------------------
+// kd- and bd-tree splitting and shrinking rules
+// kd-trees supports a collection of different splitting rules.
+// In addition to the standard kd-tree splitting rule proposed
+// by Friedman, Bentley, and Finkel, we have introduced a
+// number of other splitting rules, which seem to perform
+// as well or better (for the distributions we have tested).
+//
+// The splitting methods given below allow the user to tailor
+// the data structure to the particular data set. They are
+// are described in greater details in the kd_split.cc source
+// file. The method ANN_KD_SUGGEST is the method chosen (rather
+// subjectively) by the implementors as the one giving the
+// fastest performance, and is the default splitting method.
+//
+// As with splitting rules, there are a number of different
+// shrinking rules. The shrinking rule ANN_BD_NONE does no
+// shrinking (and hence produces a kd-tree tree). The rule
+// ANN_BD_SUGGEST uses the implementors favorite rule.
+//----------------------------------------------------------------------
+
+enum ANNsplitRule {
+ ANN_KD_STD = 0, // the optimized kd-splitting rule
+ ANN_KD_MIDPT = 1, // midpoint split
+ ANN_KD_FAIR = 2, // fair split
+ ANN_KD_SL_MIDPT = 3, // sliding midpoint splitting method
+ ANN_KD_SL_FAIR = 4, // sliding fair split method
+ ANN_KD_SUGGEST = 5}; // the authors' suggestion for best
+const int ANN_N_SPLIT_RULES = 6; // number of split rules
+
+enum ANNshrinkRule {
+ ANN_BD_NONE = 0, // no shrinking at all (just kd-tree)
+ ANN_BD_SIMPLE = 1, // simple splitting
+ ANN_BD_CENTROID = 2, // centroid splitting
+ ANN_BD_SUGGEST = 3}; // the authors' suggested choice
+const int ANN_N_SHRINK_RULES = 4; // number of shrink rules
+
+//----------------------------------------------------------------------
+// kd-tree:
+// The main search data structure supported by ANN is a kd-tree.
+// The main constructor is given a set of points and a choice of
+// splitting method to use in building the tree.
+//
+// Construction:
+// -------------
+// The constructor is given the point array, number of points,
+// dimension, bucket size (default = 1), and the splitting rule
+// (default = ANN_KD_SUGGEST). The point array is not copied, and
+// is assumed to be kept constant throughout the lifetime of the
+// search structure. There is also a "load" constructor that
+// builds a tree from a file description that was created by the
+// Dump operation.
+//
+// Search:
+// -------
+// There are two search methods:
+//
+// Standard search (annkSearch()):
+// Searches nodes in tree-traversal order, always visiting
+// the closer child first.
+// Priority search (annkPriSearch()):
+// Searches nodes in order of increasing distance of the
+// associated cell from the query point. For many
+// distributions the standard search seems to work just
+// fine, but priority search is safer for worst-case
+// performance.
+//
+// Printing:
+// ---------
+// There are two methods provided for printing the tree. Print()
+// is used to produce a "human-readable" display of the tree, with
+// indenation, which is handy for debugging. Dump() produces a
+// format that is suitable reading by another program. There is a
+// "load" constructor, which constructs a tree which is assumed to
+// have been saved by the Dump() procedure.
+//
+// Performance and Structure Statistics:
+// -------------------------------------
+// The procedure getStats() collects statistics information on the
+// tree (its size, height, etc.) See ANNperf.h for information on
+// the stats structure it returns.
+//
+// Internal information:
+// ---------------------
+// The data structure consists of three major chunks of storage.
+// The first (implicit) storage are the points themselves (pts),
+// which have been provided by the users as an argument to the
+// constructor, or are allocated dynamically if the tree is built
+// using the load constructor). These should not be changed during
+// the lifetime of the search structure. It is the user's
+// responsibility to delete these after the tree is destroyed.
+//
+// The second is the tree itself (which is dynamically allocated in
+// the constructor) and is given as a pointer to its root node
+// (root). These nodes are automatically deallocated when the tree
+// is deleted. See the file src/kd_tree.h for further information
+// on the structure of the tree nodes.
+//
+// Each leaf of the tree does not contain a pointer directly to a
+// point, but rather contains a pointer to a "bucket", which is an
+// array consisting of point indices. The third major chunk of
+// storage is an array (pidx), which is a large array in which all
+// these bucket subarrays reside. (The reason for storing them
+// separately is the buckets are typically small, but of varying
+// sizes. This was done to avoid fragmentation.) This array is
+// also deallocated when the tree is deleted.
+//
+// In addition to this, the tree consists of a number of other
+// pieces of information which are used in searching and for
+// subsequent tree operations. These consist of the following:
+//
+// dim Dimension of space
+// n_pts Number of points currently in the tree
+// n_max Maximum number of points that are allowed
+// in the tree
+// bkt_size Maximum bucket size (no. of points per leaf)
+// bnd_box_lo Bounding box low point
+// bnd_box_hi Bounding box high point
+// splitRule Splitting method used
+//
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// Some types and objects used by kd-tree functions
+// See src/kd_tree.h and src/kd_tree.cpp for definitions
+//----------------------------------------------------------------------
+class ANNkdStats; // stats on kd-tree
+class ANNkd_node; // generic node in a kd-tree
+typedef ANNkd_node* ANNkd_ptr; // pointer to a kd-tree node
+
+class DLL_API ANNkd_tree: public ANNpointSet {
+protected:
+ int dim; // dimension of space
+ int n_pts; // number of points in tree
+ int bkt_size; // bucket size
+ ANNpointArray pts; // the points
+ ANNidxArray pidx; // point indices (to pts array)
+ ANNkd_ptr root; // root of kd-tree
+ ANNpoint bnd_box_lo; // bounding box low point
+ ANNpoint bnd_box_hi; // bounding box high point
+
+ void SkeletonTree( // construct skeleton tree
+ int n, // number of points
+ int dd, // dimension
+ int bs, // bucket size
+ ANNpointArray pa = NULL, // point array (optional)
+ ANNidxArray pi = NULL); // point indices (optional)
+
+public:
+ ANNkd_tree( // build skeleton tree
+ int n = 0, // number of points
+ int dd = 0, // dimension
+ int bs = 1); // bucket size
+
+ ANNkd_tree( // build from point array
+ ANNpointArray pa, // point array
+ int n, // number of points
+ int dd, // dimension
+ int bs = 1, // bucket size
+ ANNsplitRule split = ANN_KD_SUGGEST); // splitting method
+
+ ANNkd_tree( // build from dump file
+ std::istream& in); // input stream for dump file
+
+ ~ANNkd_tree(); // tree destructor
+
+ void annkSearch( // approx k near neighbor search
+ ANNpoint q, // query point
+ int k, // number of near neighbors to return
+ ANNidxArray nn_idx, // nearest neighbor array (modified)
+ ANNdistArray dd, // dist to near neighbors (modified)
+ double eps=0.0); // error bound
+
+ void annkPriSearch( // priority k near neighbor search
+ ANNpoint q, // query point
+ int k, // number of near neighbors to return
+ ANNidxArray nn_idx, // nearest neighbor array (modified)
+ ANNdistArray dd, // dist to near neighbors (modified)
+ double eps=0.0); // error bound
+
+ int annkFRSearch( // approx fixed-radius kNN search
+ ANNpoint q, // the query point
+ ANNdist sqRad, // squared radius of query ball
+ int k, // number of neighbors to return
+ ANNidxArray nn_idx = NULL, // nearest neighbor array (modified)
+ ANNdistArray dd = NULL, // dist to near neighbors (modified)
+ double eps=0.0); // error bound
+
+ int theDim() // return dimension of space
+ { return dim; }
+
+ int nPoints() // return number of points
+ { return n_pts; }
+
+ ANNpointArray thePoints() // return pointer to points
+ { return pts; }
+
+ virtual void Print( // print the tree (for debugging)
+ ANNbool with_pts, // print points as well?
+ std::ostream& out); // output stream
+
+ virtual void Dump( // dump entire tree
+ ANNbool with_pts, // print points as well?
+ std::ostream& out); // output stream
+
+ virtual void getStats( // compute tree statistics
+ ANNkdStats& st); // the statistics (modified)
+};
+
+//----------------------------------------------------------------------
+// Box decomposition tree (bd-tree)
+// The bd-tree is inherited from a kd-tree. The main difference
+// in the bd-tree and the kd-tree is a new type of internal node
+// called a shrinking node (in the kd-tree there is only one type
+// of internal node, a splitting node). The shrinking node
+// makes it possible to generate balanced trees in which the
+// cells have bounded aspect ratio, by allowing the decomposition
+// to zoom in on regions of dense point concentration. Although
+// this is a nice idea in theory, few point distributions are so
+// densely clustered that this is really needed.
+//----------------------------------------------------------------------
+
+class DLL_API ANNbd_tree: public ANNkd_tree {
+public:
+ ANNbd_tree( // build skeleton tree
+ int n, // number of points
+ int dd, // dimension
+ int bs = 1) // bucket size
+ : ANNkd_tree(n, dd, bs) {} // build base kd-tree
+
+ ANNbd_tree( // build from point array
+ ANNpointArray pa, // point array
+ int n, // number of points
+ int dd, // dimension
+ int bs = 1, // bucket size
+ ANNsplitRule split = ANN_KD_SUGGEST, // splitting rule
+ ANNshrinkRule shrink = ANN_BD_SUGGEST); // shrinking rule
+
+ ANNbd_tree( // build from dump file
+ std::istream& in); // input stream for dump file
+};
+
+//----------------------------------------------------------------------
+// Other functions
+// annMaxPtsVisit Sets a limit on the maximum number of points
+// to visit in the search.
+// annClose Can be called when all use of ANN is finished.
+// It clears up a minor memory leak.
+//----------------------------------------------------------------------
+
+DLL_API void annMaxPtsVisit( // max. pts to visit in search
+ int maxPts); // the limit
+
+DLL_API void annClose(); // called to end use of ANN
+
+#endif
diff --git a/Contrib/ANN/include/ANN/ANNperf.h b/Contrib/ANN/include/ANN/ANNperf.h
new file mode 100755
index 0000000..b18c816
--- /dev/null
+++ b/Contrib/ANN/include/ANN/ANNperf.h
@@ -0,0 +1,226 @@
+//----------------------------------------------------------------------
+// File: ANNperf.h
+// Programmer: Sunil Arya and David Mount
+// Last modified: 03/04/98 (Release 0.1)
+// Description: Include file for ANN performance stats
+//
+// Some of the code for statistics gathering has been adapted
+// from the SmplStat.h package in the g++ library.
+//----------------------------------------------------------------------
+// Copyright (c) 1997-1998 University of Maryland and Sunil Arya and David
+// Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the
+// Approximate Nearest Neighbor Library (ANN).
+//
+// Permission to use, copy, and distribute this software and its
+// documentation is hereby granted free of charge, provided that
+// (1) it is not a component of a commercial product, and
+// (2) this notice appears in all copies of the software and
+// related documentation.
+//
+// The University of Maryland (U.M.) and the authors make no representations
+// about the suitability or fitness of this software for any purpose. It is
+// provided "as is" without express or implied warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.0 04/01/05
+// Added ANN_ prefix to avoid name conflicts.
+//----------------------------------------------------------------------
+
+#ifndef ANNperf_H
+#define ANNperf_H
+
+//----------------------------------------------------------------------
+// basic includes
+//----------------------------------------------------------------------
+
+#include <ANN/ANN.h> // basic ANN includes
+
+//----------------------------------------------------------------------
+// kd-tree stats object
+// This object is used for collecting information about a kd-tree
+// or bd-tree.
+//----------------------------------------------------------------------
+
+class ANNkdStats { // stats on kd-tree
+public:
+ int dim; // dimension of space
+ int n_pts; // no. of points
+ int bkt_size; // bucket size
+ int n_lf; // no. of leaves (including trivial)
+ int n_tl; // no. of trivial leaves (no points)
+ int n_spl; // no. of splitting nodes
+ int n_shr; // no. of shrinking nodes (for bd-trees)
+ int depth; // depth of tree
+ float sum_ar; // sum of leaf aspect ratios
+ float avg_ar; // average leaf aspect ratio
+ //
+ // reset stats
+ void reset(int d=0, int n=0, int bs=0)
+ {
+ dim = d; n_pts = n; bkt_size = bs;
+ n_lf = n_tl = n_spl = n_shr = depth = 0;
+ sum_ar = avg_ar = 0.0;
+ }
+
+ ANNkdStats() // basic constructor
+ { reset(); }
+
+ void merge(const ANNkdStats &st); // merge stats from child
+};
+
+//----------------------------------------------------------------------
+// ANNsampStat
+// A sample stat collects numeric (double) samples and returns some
+// simple statistics. Its main functions are:
+//
+// reset() Reset to no samples.
+// += x Include sample x.
+// samples() Return number of samples.
+// mean() Return mean of samples.
+// stdDev() Return standard deviation
+// min() Return minimum of samples.
+// max() Return maximum of samples.
+//----------------------------------------------------------------------
+class DLL_API ANNsampStat {
+ int n; // number of samples
+ double sum; // sum
+ double sum2; // sum of squares
+ double minVal, maxVal; // min and max
+public :
+ void reset() // reset everything
+ {
+ n = 0;
+ sum = sum2 = 0;
+ minVal = ANN_DBL_MAX;
+ maxVal = -ANN_DBL_MAX;
+ }
+
+ ANNsampStat() { reset(); } // constructor
+
+ void operator+=(double x) // add sample
+ {
+ n++; sum += x; sum2 += x*x;
+ if (x < minVal) minVal = x;
+ if (x > maxVal) maxVal = x;
+ }
+
+ int samples() { return n; } // number of samples
+
+ double mean() { return sum/n; } // mean
+
+ // standard deviation
+ double stdDev() { return sqrt((sum2 - (sum*sum)/n)/(n-1));}
+
+ double min() { return minVal; } // minimum
+ double max() { return maxVal; } // maximum
+};
+
+//----------------------------------------------------------------------
+// Operation count updates
+//----------------------------------------------------------------------
+
+#ifdef ANN_PERF
+ #define ANN_FLOP(n) {ann_Nfloat_ops += (n);}
+ #define ANN_LEAF(n) {ann_Nvisit_lfs += (n);}
+ #define ANN_SPL(n) {ann_Nvisit_spl += (n);}
+ #define ANN_SHR(n) {ann_Nvisit_shr += (n);}
+ #define ANN_PTS(n) {ann_Nvisit_pts += (n);}
+ #define ANN_COORD(n) {ann_Ncoord_hts += (n);}
+#else
+ #define ANN_FLOP(n)
+ #define ANN_LEAF(n)
+ #define ANN_SPL(n)
+ #define ANN_SHR(n)
+ #define ANN_PTS(n)
+ #define ANN_COORD(n)
+#endif
+
+//----------------------------------------------------------------------
+// Performance statistics
+// The following data and routines are used for computing performance
+// statistics for nearest neighbor searching. Because these routines
+// can slow the code down, they can be activated and deactiviated by
+// defining the ANN_PERF variable, by compiling with the option:
+// -DANN_PERF
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// Global counters for performance measurement
+//
+// visit_lfs The number of leaf nodes visited in the
+// tree.
+//
+// visit_spl The number of splitting nodes visited in the
+// tree.
+//
+// visit_shr The number of shrinking nodes visited in the
+// tree.
+//
+// visit_pts The number of points visited in all the
+// leaf nodes visited. Equivalently, this
+// is the number of points for which distance
+// calculations are performed.
+//
+// coord_hts The number of times a coordinate of a
+// data point is accessed. This is generally
+// less than visit_pts*d if partial distance
+// calculation is used. This count is low
+// in the sense that if a coordinate is hit
+// many times in the same routine we may
+// count it only once.
+//
+// float_ops The number of floating point operations.
+// This includes all operations in the heap
+// as well as distance calculations to boxes.
+//
+// average_err The average error of each query (the
+// error of the reported point to the true
+// nearest neighbor). For k nearest neighbors
+// the error is computed k times.
+//
+// rank_err The rank error of each query (the difference
+// in the rank of the reported point and its
+// true rank).
+//
+// data_pts The number of data points. This is not
+// a counter, but used in stats computation.
+//----------------------------------------------------------------------
+
+extern int ann_Ndata_pts; // number of data points
+extern int ann_Nvisit_lfs; // number of leaf nodes visited
+extern int ann_Nvisit_spl; // number of splitting nodes visited
+extern int ann_Nvisit_shr; // number of shrinking nodes visited
+extern int ann_Nvisit_pts; // visited points for one query
+extern int ann_Ncoord_hts; // coordinate hits for one query
+extern int ann_Nfloat_ops; // floating ops for one query
+extern ANNsampStat ann_visit_lfs; // stats on leaf nodes visits
+extern ANNsampStat ann_visit_spl; // stats on splitting nodes visits
+extern ANNsampStat ann_visit_shr; // stats on shrinking nodes visits
+extern ANNsampStat ann_visit_nds; // stats on total nodes visits
+extern ANNsampStat ann_visit_pts; // stats on points visited
+extern ANNsampStat ann_coord_hts; // stats on coordinate hits
+extern ANNsampStat ann_float_ops; // stats on floating ops
+//----------------------------------------------------------------------
+// The following need to be part of the public interface, because
+// they are accessed outside the DLL in ann_test.cpp.
+//----------------------------------------------------------------------
+DLL_API extern ANNsampStat ann_average_err; // average error
+DLL_API extern ANNsampStat ann_rank_err; // rank error
+
+//----------------------------------------------------------------------
+// Declaration of externally accessible routines for statistics
+//----------------------------------------------------------------------
+
+DLL_API void annResetStats(int data_size); // reset stats for a set of queries
+
+DLL_API void annResetCounts(); // reset counts for one queries
+
+DLL_API void annUpdateStats(); // update stats with current counts
+
+DLL_API void annPrintStats(ANNbool validate); // print statistics for a run
+
+#endif
diff --git a/Contrib/ANN/include/ANN/ANNx.h b/Contrib/ANN/include/ANN/ANNx.h
new file mode 100755
index 0000000..38b07b7
--- /dev/null
+++ b/Contrib/ANN/include/ANN/ANNx.h
@@ -0,0 +1,170 @@
+//----------------------------------------------------------------------
+// File: ANNx.h
+// Programmer: Sunil Arya and David Mount
+// Last modified: 03/04/98 (Release 0.1)
+// Description: Internal include file for ANN
+//
+// These declarations are of use in manipulating some of
+// the internal data objects appearing in ANN, but are not
+// needed for applications just using the nearest neighbor
+// search.
+//
+// Typical users of ANN should not need to access this file.
+//----------------------------------------------------------------------
+// Copyright (c) 1997-1998 University of Maryland and Sunil Arya and David
+// Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the
+// Approximate Nearest Neighbor Library (ANN).
+//
+// Permission to use, copy, and distribute this software and its
+// documentation is hereby granted free of charge, provided that
+// (1) it is not a component of a commercial product, and
+// (2) this notice appears in all copies of the software and
+// related documentation.
+//
+// The University of Maryland (U.M.) and the authors make no representations
+// about the suitability or fitness of this software for any purpose. It is
+// provided "as is" without express or implied warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.0 04/01/05
+// Changed LO, HI, IN, OUT to ANN_LO, ANN_HI, etc.
+//----------------------------------------------------------------------
+
+#ifndef ANNx_H
+#define ANNx_H
+
+#include <iomanip> // I/O manipulators
+#include <ANN/ANN.h> // ANN includes
+
+//----------------------------------------------------------------------
+// Global constants and types
+//----------------------------------------------------------------------
+enum {ANN_LO=0, ANN_HI=1}; // splitting indices
+enum {ANN_IN=0, ANN_OUT=1}; // shrinking indices
+ // what to do in case of error
+enum ANNerr {ANNwarn = 0, ANNabort = 1};
+
+//----------------------------------------------------------------------
+// Maximum number of points to visit
+// We have an option for terminating the search early if the
+// number of points visited exceeds some threshold. If the
+// threshold is 0 (its default) this means there is no limit
+// and the algorithm applies its normal termination condition.
+//----------------------------------------------------------------------
+
+extern int ANNmaxPtsVisited; // maximum number of pts visited
+extern int ANNptsVisited; // number of pts visited in search
+
+//----------------------------------------------------------------------
+// Global function declarations
+//----------------------------------------------------------------------
+
+void annError( // ANN error routine
+ char *msg, // error message
+ ANNerr level); // level of error
+
+void annPrintPt( // print a point
+ ANNpoint pt, // the point
+ int dim, // the dimension
+ std::ostream &out); // output stream
+
+//----------------------------------------------------------------------
+// Orthogonal (axis aligned) rectangle
+// Orthogonal rectangles are represented by two points, one
+// for the lower left corner (min coordinates) and the other
+// for the upper right corner (max coordinates).
+//
+// The constructor initializes from either a pair of coordinates,
+// pair of points, or another rectangle. Note that all constructors
+// allocate new point storage. The destructor deallocates this
+// storage.
+//
+// BEWARE: Orthogonal rectangles should be passed ONLY BY REFERENCE.
+// (C++'s default copy constructor will not allocate new point
+// storage, then on return the destructor free's storage, and then
+// you get into big trouble in the calling procedure.)
+//----------------------------------------------------------------------
+
+class ANNorthRect {
+public:
+ ANNpoint lo; // rectangle lower bounds
+ ANNpoint hi; // rectangle upper bounds
+//
+ ANNorthRect( // basic constructor
+ int dd, // dimension of space
+ ANNcoord l=0, // default is empty
+ ANNcoord h=0)
+ { lo = annAllocPt(dd, l); hi = annAllocPt(dd, h); }
+
+ ANNorthRect( // (almost a) copy constructor
+ int dd, // dimension
+ const ANNorthRect &r) // rectangle to copy
+ { lo = annCopyPt(dd, r.lo); hi = annCopyPt(dd, r.hi); }
+
+ ANNorthRect( // construct from points
+ int dd, // dimension
+ ANNpoint l, // low point
+ ANNpoint h) // hight point
+ { lo = annCopyPt(dd, l); hi = annCopyPt(dd, h); }
+
+ ~ANNorthRect() // destructor
+ { annDeallocPt(lo); annDeallocPt(hi); }
+
+ ANNbool inside(int dim, ANNpoint p);// is point p inside rectangle?
+};
+
+void annAssignRect( // assign one rect to another
+ int dim, // dimension (both must be same)
+ ANNorthRect &dest, // destination (modified)
+ const ANNorthRect &source); // source
+
+//----------------------------------------------------------------------
+// Orthogonal (axis aligned) halfspace
+// An orthogonal halfspace is represented by an integer cutting
+// dimension cd, coordinate cutting value, cv, and side, sd, which is
+// either +1 or -1. Our convention is that point q lies in the (closed)
+// halfspace if (q[cd] - cv)*sd >= 0.
+//----------------------------------------------------------------------
+
+class ANNorthHalfSpace {
+public:
+ int cd; // cutting dimension
+ ANNcoord cv; // cutting value
+ int sd; // which side
+//
+ ANNorthHalfSpace() // default constructor
+ { cd = 0; cv = 0; sd = 0; }
+
+ ANNorthHalfSpace( // basic constructor
+ int cdd, // dimension of space
+ ANNcoord cvv, // cutting value
+ int sdd) // side
+ { cd = cdd; cv = cvv; sd = sdd; }
+
+ ANNbool in(ANNpoint q) const // is q inside halfspace?
+ { return (ANNbool) ((q[cd] - cv)*sd >= 0); }
+
+ ANNbool out(ANNpoint q) const // is q outside halfspace?
+ { return (ANNbool) ((q[cd] - cv)*sd < 0); }
+
+ ANNdist dist(ANNpoint q) const // (squared) distance from q
+ { return (ANNdist) ANN_POW(q[cd] - cv); }
+
+ void setLowerBound(int d, ANNpoint p)// set to lower bound at p[i]
+ { cd = d; cv = p[d]; sd = +1; }
+
+ void setUpperBound(int d, ANNpoint p)// set to upper bound at p[i]
+ { cd = d; cv = p[d]; sd = -1; }
+
+ void project(ANNpoint &q) // project q (modified) onto halfspace
+ { if (out(q)) q[cd] = cv; }
+};
+
+ // array of halfspaces
+typedef ANNorthHalfSpace *ANNorthHSArray;
+
+#endif
diff --git a/Contrib/ANN/src/ANN.cpp b/Contrib/ANN/src/ANN.cpp
new file mode 100755
index 0000000..79d1215
--- /dev/null
+++ b/Contrib/ANN/src/ANN.cpp
@@ -0,0 +1,199 @@
+//----------------------------------------------------------------------
+// File: ANN.cpp
+// Programmer: Sunil Arya and David Mount
+// Description: Methods for ANN.h and ANNx.h
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.0 04/01/05
+// Added performance counting to annDist()
+//----------------------------------------------------------------------
+
+#include <ANN/ANNx.h> // all ANN includes
+#include <ANN/ANNperf.h> // ANN performance
+#include <stdlib.h> // for gmsh
+
+using namespace std; // make std:: accessible
+
+//----------------------------------------------------------------------
+// Point methods
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// Distance utility.
+// (Note: In the nearest neighbor search, most distances are
+// computed using partial distance calculations, not this
+// procedure.)
+//----------------------------------------------------------------------
+
+ANNdist annDist( // interpoint squared distance
+ int dim,
+ ANNpoint p,
+ ANNpoint q)
+{
+ register int d;
+ register ANNcoord diff;
+ register ANNcoord dist;
+
+ dist = 0;
+ for (d = 0; d < dim; d++) {
+ diff = p[d] - q[d];
+ dist = ANN_SUM(dist, ANN_POW(diff));
+ }
+ ANN_FLOP(3*dim) // performance counts
+ ANN_PTS(1)
+ ANN_COORD(dim)
+ return dist;
+}
+
+//----------------------------------------------------------------------
+// annPrintPoint() prints a point to a given output stream.
+//----------------------------------------------------------------------
+
+void annPrintPt( // print a point
+ ANNpoint pt, // the point
+ int dim, // the dimension
+ std::ostream &out) // output stream
+{
+ for (int j = 0; j < dim; j++) {
+ out << pt[j];
+ if (j < dim-1) out << " ";
+ }
+}
+
+//----------------------------------------------------------------------
+// Point allocation/deallocation:
+//
+// Because points (somewhat like strings in C) are stored
+// as pointers. Consequently, creating and destroying
+// copies of points may require storage allocation. These
+// procedures do this.
+//
+// annAllocPt() and annDeallocPt() allocate a deallocate
+// storage for a single point, and return a pointer to it.
+//
+// annAllocPts() allocates an array of points as well a place
+// to store their coordinates, and initializes the points to
+// point to their respective coordinates. It allocates point
+// storage in a contiguous block large enough to store all the
+// points. It performs no initialization.
+//
+// annDeallocPts() should only be used on point arrays allocated
+// by annAllocPts since it assumes that points are allocated in
+// a block.
+//
+// annCopyPt() copies a point taking care to allocate storage
+// for the new point.
+//
+// annAssignRect() assigns the coordinates of one rectangle to
+// another. The two rectangles must have the same dimension
+// (and it is not possible to test this here).
+//----------------------------------------------------------------------
+
+ANNpoint annAllocPt(int dim, ANNcoord c) // allocate 1 point
+{
+ ANNpoint p = new ANNcoord[dim];
+ for (int i = 0; i < dim; i++) p[i] = c;
+ return p;
+}
+
+ANNpointArray annAllocPts(int n, int dim) // allocate n pts in dim
+{
+ ANNpointArray pa = new ANNpoint[n]; // allocate points
+ ANNpoint p = new ANNcoord[n*dim]; // allocate space for coords
+ for (int i = 0; i < n; i++) {
+ pa[i] = &(p[i*dim]);
+ }
+ return pa;
+}
+
+void annDeallocPt(ANNpoint &p) // deallocate 1 point
+{
+ delete [] p;
+ p = NULL;
+}
+
+void annDeallocPts(ANNpointArray &pa) // deallocate points
+{
+ delete [] pa[0]; // dealloc coordinate storage
+ delete [] pa; // dealloc points
+ pa = NULL;
+}
+
+ANNpoint annCopyPt(int dim, ANNpoint source) // copy point
+{
+ ANNpoint p = new ANNcoord[dim];
+ for (int i = 0; i < dim; i++) p[i] = source[i];
+ return p;
+}
+
+ // assign one rect to another
+void annAssignRect(int dim, ANNorthRect &dest, const ANNorthRect &source)
+{
+ for (int i = 0; i < dim; i++) {
+ dest.lo[i] = source.lo[i];
+ dest.hi[i] = source.hi[i];
+ }
+}
+
+ // is point inside rectangle?
+ANNbool ANNorthRect::inside(int dim, ANNpoint p)
+{
+ for (int i = 0; i < dim; i++) {
+ if (p[i] < lo[i] || p[i] > hi[i]) return ANNfalse;
+ }
+ return ANNtrue;
+}
+
+//----------------------------------------------------------------------
+// Error handler
+//----------------------------------------------------------------------
+
+void annError(char *msg, ANNerr level)
+{
+ if (level == ANNabort) {
+ cerr << "ANN: ERROR------->" << msg << "<-------------ERROR\n";
+ exit(1);
+ }
+ else {
+ cerr << "ANN: WARNING----->" << msg << "<-------------WARNING\n";
+ }
+}
+
+//----------------------------------------------------------------------
+// Limit on number of points visited
+// We have an option for terminating the search early if the
+// number of points visited exceeds some threshold. If the
+// threshold is 0 (its default) this means there is no limit
+// and the algorithm applies its normal termination condition.
+// This is for applications where there are real time constraints
+// on the running time of the algorithm.
+//----------------------------------------------------------------------
+
+int ANNmaxPtsVisited = 0; // maximum number of pts visited
+int ANNptsVisited; // number of pts visited in search
+
+//----------------------------------------------------------------------
+// Global function declarations
+//----------------------------------------------------------------------
+
+void annMaxPtsVisit( // set limit on max. pts to visit in search
+ int maxPts) // the limit
+{
+ ANNmaxPtsVisited = maxPts;
+}
diff --git a/Contrib/ANN/src/Makefile b/Contrib/ANN/src/Makefile
new file mode 100755
index 0000000..78c86a4
--- /dev/null
+++ b/Contrib/ANN/src/Makefile
@@ -0,0 +1,60 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../../../variables
+
+LIB = ../../../lib/libMAdANN${LIBEXT}
+
+INC = ${DASH}I../../../Common ${DASH}I../include
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = ANN.cpp\
+ bd_fix_rad_search.cpp\
+ bd_pr_search.cpp\
+ bd_search.cpp\
+ bd_tree.cpp\
+ brute.cpp\
+ kd_dump.cpp\
+ kd_fix_rad_search.cpp\
+ kd_pr_search.cpp\
+ kd_search.cpp\
+ kd_split.cpp\
+ kd_tree.cpp\
+ kd_util.cpp\
+ perf.cpp
+
+OBJ = ${SRC:.cpp=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cpp
+
+${LIB}: ${OBJ}
+ ${AR} ${ARFLAGS}${LIB} ${OBJ}
+ ${RANLIB} ${LIB}
+
+cpobj: ${OBJ}
+ cp -f ${OBJ} ../../../lib/
+
+.cpp${OBJEXT}:
+ ${CXX} ${ALLFLAGS} ${DASH}c $<
+
+clean:
+ ${RM} *.o *.obj
+
+depend:
+ (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+ ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+ ) > Makefile.new
+ cp Makefile Makefile.bak
+ cp Makefile.new Makefile
+ rm -f Makefile.new
+
diff --git a/Contrib/ANN/src/bd_fix_rad_search.cpp b/Contrib/ANN/src/bd_fix_rad_search.cpp
new file mode 100755
index 0000000..dea3f6b
--- /dev/null
+++ b/Contrib/ANN/src/bd_fix_rad_search.cpp
@@ -0,0 +1,61 @@
+//----------------------------------------------------------------------
+// File: bd_fix_rad_search.cpp
+// Programmer: David Mount
+// Description: Standard bd-tree search
+// Last modified: 05/03/05 (Version 1.1)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 1.1 05/03/05
+// Initial release
+//----------------------------------------------------------------------
+
+#include "bd_tree.h" // bd-tree declarations
+#include "kd_fix_rad_search.h" // kd-tree FR search declarations
+
+//----------------------------------------------------------------------
+// Approximate searching for bd-trees.
+// See the file kd_FR_search.cpp for general information on the
+// approximate nearest neighbor search algorithm. Here we
+// include the extensions for shrinking nodes.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// bd_shrink::ann_FR_search - search a shrinking node
+//----------------------------------------------------------------------
+
+void ANNbd_shrink::ann_FR_search(ANNdist box_dist)
+{
+ // check dist calc term cond.
+ if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
+
+ ANNdist inner_dist = 0; // distance to inner box
+ for (int i = 0; i < n_bnds; i++) { // is query point in the box?
+ if (bnds[i].out(ANNkdFRQ)) { // outside this bounding side?
+ // add to inner distance
+ inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdFRQ));
+ }
+ }
+ if (inner_dist <= box_dist) { // if inner box is closer
+ child[ANN_IN]->ann_FR_search(inner_dist);// search inner child first
+ child[ANN_OUT]->ann_FR_search(box_dist);// ...then outer child
+ }
+ else { // if outer box is closer
+ child[ANN_OUT]->ann_FR_search(box_dist);// search outer child first
+ child[ANN_IN]->ann_FR_search(inner_dist);// ...then outer child
+ }
+ ANN_FLOP(3*n_bnds) // increment floating ops
+ ANN_SHR(1) // one more shrinking node
+}
diff --git a/Contrib/ANN/src/bd_pr_search.cpp b/Contrib/ANN/src/bd_pr_search.cpp
new file mode 100755
index 0000000..d16d632
--- /dev/null
+++ b/Contrib/ANN/src/bd_pr_search.cpp
@@ -0,0 +1,62 @@
+//----------------------------------------------------------------------
+// File: bd_pr_search.cpp
+// Programmer: David Mount
+// Description: Priority search for bd-trees
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+//History:
+// Revision 0.1 03/04/98
+// Initial release
+//----------------------------------------------------------------------
+
+#include "bd_tree.h" // bd-tree declarations
+#include "kd_pr_search.h" // kd priority search declarations
+
+//----------------------------------------------------------------------
+// Approximate priority searching for bd-trees.
+// See the file kd_pr_search.cc for general information on the
+// approximate nearest neighbor priority search algorithm. Here
+// we include the extensions for shrinking nodes.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// bd_shrink::ann_search - search a shrinking node
+//----------------------------------------------------------------------
+
+void ANNbd_shrink::ann_pri_search(ANNdist box_dist)
+{
+ ANNdist inner_dist = 0; // distance to inner box
+ for (int i = 0; i < n_bnds; i++) { // is query point in the box?
+ if (bnds[i].out(ANNprQ)) { // outside this bounding side?
+ // add to inner distance
+ inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNprQ));
+ }
+ }
+ if (inner_dist <= box_dist) { // if inner box is closer
+ if (child[ANN_OUT] != KD_TRIVIAL) // enqueue outer if not trivial
+ ANNprBoxPQ->insert(box_dist,child[ANN_OUT]);
+ // continue with inner child
+ child[ANN_IN]->ann_pri_search(inner_dist);
+ }
+ else { // if outer box is closer
+ if (child[ANN_IN] != KD_TRIVIAL) // enqueue inner if not trivial
+ ANNprBoxPQ->insert(inner_dist,child[ANN_IN]);
+ // continue with outer child
+ child[ANN_OUT]->ann_pri_search(box_dist);
+ }
+ ANN_FLOP(3*n_bnds) // increment floating ops
+ ANN_SHR(1) // one more shrinking node
+}
diff --git a/Contrib/ANN/src/bd_search.cpp b/Contrib/ANN/src/bd_search.cpp
new file mode 100755
index 0000000..f057018
--- /dev/null
+++ b/Contrib/ANN/src/bd_search.cpp
@@ -0,0 +1,61 @@
+//----------------------------------------------------------------------
+// File: bd_search.cpp
+// Programmer: David Mount
+// Description: Standard bd-tree search
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+//----------------------------------------------------------------------
+
+#include "bd_tree.h" // bd-tree declarations
+#include "kd_search.h" // kd-tree search declarations
+
+//----------------------------------------------------------------------
+// Approximate searching for bd-trees.
+// See the file kd_search.cpp for general information on the
+// approximate nearest neighbor search algorithm. Here we
+// include the extensions for shrinking nodes.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// bd_shrink::ann_search - search a shrinking node
+//----------------------------------------------------------------------
+
+void ANNbd_shrink::ann_search(ANNdist box_dist)
+{
+ // check dist calc term cond.
+ if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
+
+ ANNdist inner_dist = 0; // distance to inner box
+ for (int i = 0; i < n_bnds; i++) { // is query point in the box?
+ if (bnds[i].out(ANNkdQ)) { // outside this bounding side?
+ // add to inner distance
+ inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdQ));
+ }
+ }
+ if (inner_dist <= box_dist) { // if inner box is closer
+ child[ANN_IN]->ann_search(inner_dist); // search inner child first
+ child[ANN_OUT]->ann_search(box_dist); // ...then outer child
+ }
+ else { // if outer box is closer
+ child[ANN_OUT]->ann_search(box_dist); // search outer child first
+ child[ANN_IN]->ann_search(inner_dist); // ...then outer child
+ }
+ ANN_FLOP(3*n_bnds) // increment floating ops
+ ANN_SHR(1) // one more shrinking node
+}
diff --git a/Contrib/ANN/src/bd_tree.cpp b/Contrib/ANN/src/bd_tree.cpp
new file mode 100755
index 0000000..0977dea
--- /dev/null
+++ b/Contrib/ANN/src/bd_tree.cpp
@@ -0,0 +1,417 @@
+//----------------------------------------------------------------------
+// File: bd_tree.cpp
+// Programmer: David Mount
+// Description: Basic methods for bd-trees.
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision l.0 04/01/05
+// Fixed centroid shrink threshold condition to depend on the
+// dimension.
+// Moved dump routine to kd_dump.cpp.
+//----------------------------------------------------------------------
+
+#include "bd_tree.h" // bd-tree declarations
+#include "kd_util.h" // kd-tree utilities
+#include "kd_split.h" // kd-tree splitting rules
+
+#include <ANN/ANNperf.h> // performance evaluation
+
+//----------------------------------------------------------------------
+// Printing a bd-tree
+// These routines print a bd-tree. See the analogous procedure
+// in kd_tree.cpp for more information.
+//----------------------------------------------------------------------
+
+void ANNbd_shrink::print( // print shrinking node
+ int level, // depth of node in tree
+ ostream &out) // output stream
+{
+ child[ANN_OUT]->print(level+1, out); // print out-child
+
+ out << " ";
+ for (int i = 0; i < level; i++) // print indentation
+ out << "..";
+ out << "Shrink";
+ for (int j = 0; j < n_bnds; j++) { // print sides, 2 per line
+ if (j % 2 == 0) {
+ out << "\n"; // newline and indentation
+ for (int i = 0; i < level+2; i++) out << " ";
+ }
+ out << " ([" << bnds[j].cd << "]"
+ << (bnds[j].sd > 0 ? ">=" : "< ")
+ << bnds[j].cv << ")";
+ }
+ out << "\n";
+
+ child[ANN_IN]->print(level+1, out); // print in-child
+}
+
+//----------------------------------------------------------------------
+// kd_tree statistics utility (for performance evaluation)
+// This routine computes various statistics information for
+// shrinking nodes. See file kd_tree.cpp for more information.
+//----------------------------------------------------------------------
+
+void ANNbd_shrink::getStats( // get subtree statistics
+ int dim, // dimension of space
+ ANNkdStats &st, // stats (modified)
+ ANNorthRect &bnd_box) // bounding box
+{
+ ANNkdStats ch_stats; // stats for children
+ ANNorthRect inner_box(dim); // inner box of shrink
+
+ annBnds2Box(bnd_box, // enclosing box
+ dim, // dimension
+ n_bnds, // number of bounds
+ bnds, // bounds array
+ inner_box); // inner box (modified)
+ // get stats for inner child
+ ch_stats.reset(); // reset
+ child[ANN_IN]->getStats(dim, ch_stats, inner_box);
+ st.merge(ch_stats); // merge them
+ // get stats for outer child
+ ch_stats.reset(); // reset
+ child[ANN_OUT]->getStats(dim, ch_stats, bnd_box);
+ st.merge(ch_stats); // merge them
+
+ st.depth++; // increment depth
+ st.n_shr++; // increment number of shrinks
+}
+
+//----------------------------------------------------------------------
+// bd-tree constructor
+// This is the main constructor for bd-trees given a set of points.
+// It first builds a skeleton kd-tree as a basis, then computes the
+// bounding box of the data points, and then invokes rbd_tree() to
+// actually build the tree, passing it the appropriate splitting
+// and shrinking information.
+//----------------------------------------------------------------------
+
+ANNkd_ptr rbd_tree( // recursive construction of bd-tree
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices to store in subtree
+ int n, // number of points
+ int dim, // dimension of space
+ int bsp, // bucket space
+ ANNorthRect &bnd_box, // bounding box for current node
+ ANNkd_splitter splitter, // splitting routine
+ ANNshrinkRule shrink); // shrinking rule
+
+ANNbd_tree::ANNbd_tree( // construct from point array
+ ANNpointArray pa, // point array (with at least n pts)
+ int n, // number of points
+ int dd, // dimension
+ int bs, // bucket size
+ ANNsplitRule split, // splitting rule
+ ANNshrinkRule shrink) // shrinking rule
+ : ANNkd_tree(n, dd, bs) // build skeleton base tree
+{
+ pts = pa; // where the points are
+ if (n == 0) return; // no points--no sweat
+
+ ANNorthRect bnd_box(dd); // bounding box for points
+ // construct bounding rectangle
+ annEnclRect(pa, pidx, n, dd, bnd_box);
+ // copy to tree structure
+ bnd_box_lo = annCopyPt(dd, bnd_box.lo);
+ bnd_box_hi = annCopyPt(dd, bnd_box.hi);
+
+ switch (split) { // build by rule
+ case ANN_KD_STD: // standard kd-splitting rule
+ root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split, shrink);
+ break;
+ case ANN_KD_MIDPT: // midpoint split
+ root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split, shrink);
+ break;
+ case ANN_KD_SUGGEST: // best (in our opinion)
+ case ANN_KD_SL_MIDPT: // sliding midpoint split
+ root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split, shrink);
+ break;
+ case ANN_KD_FAIR: // fair split
+ root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split, shrink);
+ break;
+ case ANN_KD_SL_FAIR: // sliding fair split
+ root = rbd_tree(pa, pidx, n, dd, bs,
+ bnd_box, sl_fair_split, shrink);
+ break;
+ default:
+ annError("Illegal splitting method", ANNabort);
+ }
+}
+
+//----------------------------------------------------------------------
+// Shrinking rules
+//----------------------------------------------------------------------
+
+enum ANNdecomp {SPLIT, SHRINK}; // decomposition methods
+
+//----------------------------------------------------------------------
+// trySimpleShrink - Attempt a simple shrink
+//
+// We compute the tight bounding box of the points, and compute
+// the 2*dim ``gaps'' between the sides of the tight box and the
+// bounding box. If any of the gaps is large enough relative to
+// the longest side of the tight bounding box, then we shrink
+// all sides whose gaps are large enough. (The reason for
+// comparing against the tight bounding box, is that after
+// shrinking the longest box size will decrease, and if we use
+// the standard bounding box, we may decide to shrink twice in
+// a row. Since the tight box is fixed, we cannot shrink twice
+// consecutively.)
+//----------------------------------------------------------------------
+const float BD_GAP_THRESH = 0.5; // gap threshold (must be < 1)
+const int BD_CT_THRESH = 2; // min number of shrink sides
+
+ANNdecomp trySimpleShrink( // try a simple shrink
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices to store in subtree
+ int n, // number of points
+ int dim, // dimension of space
+ const ANNorthRect &bnd_box, // current bounding box
+ ANNorthRect &inner_box) // inner box if shrinking (returned)
+{
+ int i;
+ // compute tight bounding box
+ annEnclRect(pa, pidx, n, dim, inner_box);
+
+ ANNcoord max_length = 0; // find longest box side
+ for (i = 0; i < dim; i++) {
+ ANNcoord length = inner_box.hi[i] - inner_box.lo[i];
+ if (length > max_length) {
+ max_length = length;
+ }
+ }
+
+ int shrink_ct = 0; // number of sides we shrunk
+ for (i = 0; i < dim; i++) { // select which sides to shrink
+ // gap between boxes
+ ANNcoord gap_hi = bnd_box.hi[i] - inner_box.hi[i];
+ // big enough gap to shrink?
+ if (gap_hi < max_length*BD_GAP_THRESH)
+ inner_box.hi[i] = bnd_box.hi[i]; // no - expand
+ else shrink_ct++; // yes - shrink this side
+
+ // repeat for high side
+ ANNcoord gap_lo = inner_box.lo[i] - bnd_box.lo[i];
+ if (gap_lo < max_length*BD_GAP_THRESH)
+ inner_box.lo[i] = bnd_box.lo[i]; // no - expand
+ else shrink_ct++; // yes - shrink this side
+ }
+
+ if (shrink_ct >= BD_CT_THRESH) // did we shrink enough sides?
+ return SHRINK;
+ else return SPLIT;
+}
+
+//----------------------------------------------------------------------
+// tryCentroidShrink - Attempt a centroid shrink
+//
+// We repeatedly apply the splitting rule, always to the larger subset
+// of points, until the number of points decreases by the constant
+// fraction BD_FRACTION. If this takes more than dim*BD_MAX_SPLIT_FAC
+// splits for this to happen, then we shrink to the final inner box
+// Otherwise we split.
+//----------------------------------------------------------------------
+
+const float BD_MAX_SPLIT_FAC = 0.5; // maximum number of splits allowed
+const float BD_FRACTION = 0.5; // ...to reduce points by this fraction
+ // ...This must be < 1.
+
+ANNdecomp tryCentroidShrink( // try a centroid shrink
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices to store in subtree
+ int n, // number of points
+ int dim, // dimension of space
+ const ANNorthRect &bnd_box, // current bounding box
+ ANNkd_splitter splitter, // splitting procedure
+ ANNorthRect &inner_box) // inner box if shrinking (returned)
+{
+ int n_sub = n; // number of points in subset
+ int n_goal = (int) (n*BD_FRACTION); // number of point in goal
+ int n_splits = 0; // number of splits needed
+ // initialize inner box to bounding box
+ annAssignRect(dim, inner_box, bnd_box);
+
+ while (n_sub > n_goal) { // keep splitting until goal reached
+ int cd; // cut dim from splitter (ignored)
+ ANNcoord cv; // cut value from splitter (ignored)
+ int n_lo; // number of points on low side
+ // invoke splitting procedure
+ (*splitter)(pa, pidx, inner_box, n_sub, dim, cd, cv, n_lo);
+ n_splits++; // increment split count
+
+ if (n_lo >= n_sub/2) { // most points on low side
+ inner_box.hi[cd] = cv; // collapse high side
+ n_sub = n_lo; // recurse on lower points
+ }
+ else { // most points on high side
+ inner_box.lo[cd] = cv; // collapse low side
+ pidx += n_lo; // recurse on higher points
+ n_sub -= n_lo;
+ }
+ }
+ if (n_splits > dim*BD_MAX_SPLIT_FAC)// took too many splits
+ return SHRINK; // shrink to final subset
+ else
+ return SPLIT;
+}
+
+//----------------------------------------------------------------------
+// selectDecomp - select which decomposition to use
+//----------------------------------------------------------------------
+
+ANNdecomp selectDecomp( // select decomposition method
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices to store in subtree
+ int n, // number of points
+ int dim, // dimension of space
+ const ANNorthRect &bnd_box, // current bounding box
+ ANNkd_splitter splitter, // splitting procedure
+ ANNshrinkRule shrink, // shrinking rule
+ ANNorthRect &inner_box) // inner box if shrinking (returned)
+{
+ ANNdecomp decomp = SPLIT; // decomposition
+
+ switch (shrink) { // check shrinking rule
+ case ANN_BD_NONE: // no shrinking allowed
+ decomp = SPLIT;
+ break;
+ case ANN_BD_SUGGEST: // author's suggestion
+ case ANN_BD_SIMPLE: // simple shrink
+ decomp = trySimpleShrink(
+ pa, pidx, // points and indices
+ n, dim, // number of points and dimension
+ bnd_box, // current bounding box
+ inner_box); // inner box if shrinking (returned)
+ break;
+ case ANN_BD_CENTROID: // centroid shrink
+ decomp = tryCentroidShrink(
+ pa, pidx, // points and indices
+ n, dim, // number of points and dimension
+ bnd_box, // current bounding box
+ splitter, // splitting procedure
+ inner_box); // inner box if shrinking (returned)
+ break;
+ default:
+ annError("Illegal shrinking rule", ANNabort);
+ }
+ return decomp;
+}
+
+//----------------------------------------------------------------------
+// rbd_tree - recursive procedure to build a bd-tree
+//
+// This is analogous to rkd_tree, but for bd-trees. See the
+// procedure rkd_tree() in kd_split.cpp for more information.
+//
+// If the number of points falls below the bucket size, then a
+// leaf node is created for the points. Otherwise we invoke the
+// procedure selectDecomp() which determines whether we are to
+// split or shrink. If splitting is chosen, then we essentially
+// do exactly as rkd_tree() would, and invoke the specified
+// splitting procedure to the points. Otherwise, the selection
+// procedure returns a bounding box, from which we extract the
+// appropriate shrinking bounds, and create a shrinking node.
+// Finally the points are subdivided, and the procedure is
+// invoked recursively on the two subsets to form the children.
+//----------------------------------------------------------------------
+
+ANNkd_ptr rbd_tree( // recursive construction of bd-tree
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices to store in subtree
+ int n, // number of points
+ int dim, // dimension of space
+ int bsp, // bucket space
+ ANNorthRect &bnd_box, // bounding box for current node
+ ANNkd_splitter splitter, // splitting routine
+ ANNshrinkRule shrink) // shrinking rule
+{
+ ANNdecomp decomp; // decomposition method
+
+ ANNorthRect inner_box(dim); // inner box (if shrinking)
+
+ if (n <= bsp) { // n small, make a leaf node
+ if (n == 0) // empty leaf node
+ return KD_TRIVIAL; // return (canonical) empty leaf
+ else // construct the node and return
+ return new ANNkd_leaf(n, pidx);
+ }
+
+ decomp = selectDecomp( // select decomposition method
+ pa, pidx, // points and indices
+ n, dim, // number of points and dimension
+ bnd_box, // current bounding box
+ splitter, shrink, // splitting/shrinking methods
+ inner_box); // inner box if shrinking (returned)
+
+ if (decomp == SPLIT) { // split selected
+ int cd; // cutting dimension
+ ANNcoord cv; // cutting value
+ int n_lo; // number on low side of cut
+ // invoke splitting procedure
+ (*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo);
+
+ ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension
+ ANNcoord hv = bnd_box.hi[cd];
+
+ bnd_box.hi[cd] = cv; // modify bounds for left subtree
+ ANNkd_ptr lo = rbd_tree( // build left subtree
+ pa, pidx, n_lo, // ...from pidx[0..n_lo-1]
+ dim, bsp, bnd_box, splitter, shrink);
+ bnd_box.hi[cd] = hv; // restore bounds
+
+ bnd_box.lo[cd] = cv; // modify bounds for right subtree
+ ANNkd_ptr hi = rbd_tree( // build right subtree
+ pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1]
+ dim, bsp, bnd_box, splitter, shrink);
+ bnd_box.lo[cd] = lv; // restore bounds
+ // create the splitting node
+ return new ANNkd_split(cd, cv, lv, hv, lo, hi);
+ }
+ else { // shrink selected
+ int n_in; // number of points in box
+ int n_bnds; // number of bounding sides
+
+ annBoxSplit( // split points around inner box
+ pa, // points to split
+ pidx, // point indices
+ n, // number of points
+ dim, // dimension
+ inner_box, // inner box
+ n_in); // number of points inside (returned)
+
+ ANNkd_ptr in = rbd_tree( // build inner subtree pidx[0..n_in-1]
+ pa, pidx, n_in, dim, bsp, inner_box, splitter, shrink);
+ ANNkd_ptr out = rbd_tree( // build outer subtree pidx[n_in..n]
+ pa, pidx+n_in, n - n_in, dim, bsp, bnd_box, splitter, shrink);
+
+ ANNorthHSArray bnds = NULL; // bounds (alloc in Box2Bnds and
+ // ...freed in bd_shrink destroyer)
+
+ annBox2Bnds( // convert inner box to bounds
+ inner_box, // inner box
+ bnd_box, // enclosing box
+ dim, // dimension
+ n_bnds, // number of bounds (returned)
+ bnds); // bounds array (modified)
+
+ // return shrinking node
+ return new ANNbd_shrink(n_bnds, bnds, in, out);
+ }
+}
diff --git a/Contrib/ANN/src/bd_tree.h b/Contrib/ANN/src/bd_tree.h
new file mode 100755
index 0000000..408889a
--- /dev/null
+++ b/Contrib/ANN/src/bd_tree.h
@@ -0,0 +1,100 @@
+//----------------------------------------------------------------------
+// File: bd_tree.h
+// Programmer: David Mount
+// Description: Declarations for standard bd-tree routines
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.0 04/01/05
+// Changed IN, OUT to ANN_IN, ANN_OUT
+//----------------------------------------------------------------------
+
+#ifndef ANN_bd_tree_H
+#define ANN_bd_tree_H
+
+#include <ANN/ANNx.h> // all ANN includes
+#include "kd_tree.h" // kd-tree includes
+
+//----------------------------------------------------------------------
+// bd-tree shrinking node.
+// The main addition in the bd-tree is the shrinking node, which
+// is declared here.
+//
+// Shrinking nodes are defined by list of orthogonal halfspaces.
+// These halfspaces define a (possibly unbounded) orthogonal
+// rectangle. There are two children, in and out. Points that
+// lie within this rectangle are stored in the in-child, and the
+// other points are stored in the out-child.
+//
+// We use a list of orthogonal halfspaces rather than an
+// orthogonal rectangle object because typically the number of
+// sides of the shrinking box will be much smaller than the
+// worst case bound of 2*dim.
+//
+// BEWARE: Note that constructor just copies the pointer to the
+// bounding array, but the destructor deallocates it. This is
+// rather poor practice, but happens to be convenient. The list
+// is allocated in the bd-tree building procedure rbd_tree() just
+// prior to construction, and is used for no other purposes.
+//
+// WARNING: In the near neighbor searching code it is assumed that
+// the list of bounding halfspaces is irredundant, meaning that there
+// are no two distinct halfspaces in the list with the same outward
+// pointing normals.
+//----------------------------------------------------------------------
+
+class ANNbd_shrink : public ANNkd_node // splitting node of a kd-tree
+{
+ int n_bnds; // number of bounding halfspaces
+ ANNorthHSArray bnds; // list of bounding halfspaces
+ ANNkd_ptr child[2]; // in and out children
+public:
+ ANNbd_shrink( // constructor
+ int nb, // number of bounding halfspaces
+ ANNorthHSArray bds, // list of bounding halfspaces
+ ANNkd_ptr ic=NULL, ANNkd_ptr oc=NULL) // children
+ {
+ n_bnds = nb; // cutting dimension
+ bnds = bds; // assign bounds
+ child[ANN_IN] = ic; // set children
+ child[ANN_OUT] = oc;
+ }
+
+ ~ANNbd_shrink() // destructor
+ {
+ if (child[ANN_IN]!= NULL && child[ANN_IN]!= KD_TRIVIAL)
+ delete child[ANN_IN];
+ if (child[ANN_OUT]!= NULL&& child[ANN_OUT]!= KD_TRIVIAL)
+ delete child[ANN_OUT];
+ if (bnds != NULL)
+ delete [] bnds; // delete bounds
+ }
+
+ virtual void getStats( // get tree statistics
+ int dim, // dimension of space
+ ANNkdStats &st, // statistics
+ ANNorthRect &bnd_box); // bounding box
+ virtual void print(int level, ostream &out);// print node
+ virtual void dump(ostream &out); // dump node
+
+ virtual void ann_search(ANNdist); // standard search
+ virtual void ann_pri_search(ANNdist); // priority search
+ virtual void ann_FR_search(ANNdist); // fixed-radius search
+};
+
+#endif
diff --git a/Contrib/ANN/src/brute.cpp b/Contrib/ANN/src/brute.cpp
new file mode 100755
index 0000000..d7cba2c
--- /dev/null
+++ b/Contrib/ANN/src/brute.cpp
@@ -0,0 +1,109 @@
+//----------------------------------------------------------------------
+// File: brute.cpp
+// Programmer: Sunil Arya and David Mount
+// Description: Brute-force nearest neighbors
+// Last modified: 05/03/05 (Version 1.1)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.1 05/03/05
+// Added fixed-radius kNN search
+//----------------------------------------------------------------------
+
+#include <ANN/ANNx.h> // all ANN includes
+#include "pr_queue_k.h" // k element priority queue
+
+//----------------------------------------------------------------------
+// Brute-force search simply stores a pointer to the list of
+// data points and searches linearly for the nearest neighbor.
+// The k nearest neighbors are stored in a k-element priority
+// queue (which is implemented in a pretty dumb way as well).
+//
+// If ANN_ALLOW_SELF_MATCH is ANNfalse then data points at distance
+// zero are not considered.
+//
+// Note that the error bound eps is passed in, but it is ignored.
+// These routines compute exact nearest neighbors (which is needed
+// for validation purposes in ann_test.cpp).
+//----------------------------------------------------------------------
+
+ANNbruteForce::ANNbruteForce( // constructor from point array
+ ANNpointArray pa, // point array
+ int n, // number of points
+ int dd) // dimension
+{
+ dim = dd; n_pts = n; pts = pa;
+}
+
+ANNbruteForce::~ANNbruteForce() { } // destructor (empty)
+
+void ANNbruteForce::annkSearch( // approx k near neighbor search
+ ANNpoint q, // query point
+ int k, // number of near neighbors to return
+ ANNidxArray nn_idx, // nearest neighbor indices (returned)
+ ANNdistArray dd, // dist to near neighbors (returned)
+ double eps) // error bound (ignored)
+{
+ ANNmin_k mk(k); // construct a k-limited priority queue
+ int i;
+
+ if (k > n_pts) { // too many near neighbors?
+ annError("Requesting more near neighbors than data points", ANNabort);
+ }
+ // run every point through queue
+ for (i = 0; i < n_pts; i++) {
+ // compute distance to point
+ ANNdist sqDist = annDist(dim, pts[i], q);
+ if (ANN_ALLOW_SELF_MATCH || sqDist != 0)
+ mk.insert(sqDist, i);
+ }
+ for (i = 0; i < k; i++) { // extract the k closest points
+ dd[i] = mk.ith_smallest_key(i);
+ nn_idx[i] = mk.ith_smallest_info(i);
+ }
+}
+
+int ANNbruteForce::annkFRSearch( // approx fixed-radius kNN search
+ ANNpoint q, // query point
+ ANNdist sqRad, // squared radius
+ int k, // number of near neighbors to return
+ ANNidxArray nn_idx, // nearest neighbor array (returned)
+ ANNdistArray dd, // dist to near neighbors (returned)
+ double eps) // error bound
+{
+ ANNmin_k mk(k); // construct a k-limited priority queue
+ int i;
+ int pts_in_range = 0; // number of points in query range
+ // run every point through queue
+ for (i = 0; i < n_pts; i++) {
+ // compute distance to point
+ ANNdist sqDist = annDist(dim, pts[i], q);
+ if (sqDist <= sqRad && // within radius bound
+ (ANN_ALLOW_SELF_MATCH || sqDist != 0)) { // ...and no self match
+ mk.insert(sqDist, i);
+ pts_in_range++;
+ }
+ }
+ for (i = 0; i < k; i++) { // extract the k closest points
+ if (dd != NULL)
+ dd[i] = mk.ith_smallest_key(i);
+ if (nn_idx != NULL)
+ nn_idx[i] = mk.ith_smallest_info(i);
+ }
+
+ return pts_in_range;
+}
diff --git a/Contrib/ANN/src/kd_dump.cpp b/Contrib/ANN/src/kd_dump.cpp
new file mode 100755
index 0000000..361e639
--- /dev/null
+++ b/Contrib/ANN/src/kd_dump.cpp
@@ -0,0 +1,446 @@
+//----------------------------------------------------------------------
+// File: kd_dump.cc
+// Programmer: David Mount
+// Description: Dump and Load for kd- and bd-trees
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.0 04/01/05
+// Moved dump out of kd_tree.cc into this file.
+// Added kd-tree load constructor.
+//----------------------------------------------------------------------
+// This file contains routines for dumping kd-trees and bd-trees and
+// reloading them. (It is an abuse of policy to include both kd- and
+// bd-tree routines in the same file, sorry. There should be no problem
+// in deleting the bd- versions of the routines if they are not
+// desired.)
+//----------------------------------------------------------------------
+
+#include "kd_tree.h" // kd-tree declarations
+#include "bd_tree.h" // bd-tree declarations
+#include <string.h> // for gmsh
+#include <stdlib.h> // for gmsh
+
+using namespace std; // make std:: available
+
+//----------------------------------------------------------------------
+// Constants
+//----------------------------------------------------------------------
+
+const int STRING_LEN = 500; // maximum string length
+const double EPSILON = 1E-5; // small number for float comparison
+
+enum ANNtreeType {KD_TREE, BD_TREE}; // tree types (used in loading)
+
+//----------------------------------------------------------------------
+// Procedure declarations
+//----------------------------------------------------------------------
+
+static ANNkd_ptr annReadDump( // read dump file
+ istream &in, // input stream
+ ANNtreeType tree_type, // type of tree expected
+ ANNpointArray &the_pts, // new points (if applic)
+ ANNidxArray &the_pidx, // point indices (returned)
+ int &the_dim, // dimension (returned)
+ int &the_n_pts, // number of points (returned)
+ int &the_bkt_size, // bucket size (returned)
+ ANNpoint &the_bnd_box_lo, // low bounding point
+ ANNpoint &the_bnd_box_hi); // high bounding point
+
+static ANNkd_ptr annReadTree( // read tree-part of dump file
+ istream &in, // input stream
+ ANNtreeType tree_type, // type of tree expected
+ ANNidxArray the_pidx, // point indices (modified)
+ int &next_idx); // next index (modified)
+
+//----------------------------------------------------------------------
+// ANN kd- and bd-tree Dump Format
+// The dump file begins with a header containing the version of
+// ANN, an optional section containing the points, followed by
+// a description of the tree. The tree is printed in preorder.
+//
+// Format:
+// #ANN <version number> <comments> [END_OF_LINE]
+// points <dim> <n_pts> (point coordinates: this is optional)
+// 0 <xxx> <xxx> ... <xxx> (point indices and coordinates)
+// 1 <xxx> <xxx> ... <xxx>
+// ...
+// tree <dim> <n_pts> <bkt_size>
+// <xxx> <xxx> ... <xxx> (lower end of bounding box)
+// <xxx> <xxx> ... <xxx> (upper end of bounding box)
+// If the tree is null, then a single line "null" is
+// output. Otherwise the nodes of the tree are printed
+// one per line in preorder. Leaves and splitting nodes
+// have the following formats:
+// Leaf node:
+// leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
+// Splitting nodes:
+// split <cut_dim> <cut_val> <lo_bound> <hi_bound>
+//
+// For bd-trees:
+//
+// Shrinking nodes:
+// shrink <n_bnds>
+// <cut_dim> <cut_val> <side>
+// <cut_dim> <cut_val> <side>
+// ... (repeated n_bnds times)
+//----------------------------------------------------------------------
+
+void ANNkd_tree::Dump( // dump entire tree
+ ANNbool with_pts, // print points as well?
+ ostream &out) // output stream
+{
+ out << "#ANN " << ANNversion << "\n";
+ out.precision(ANNcoordPrec); // use full precision in dumping
+ if (with_pts) { // print point coordinates
+ out << "points " << dim << " " << n_pts << "\n";
+ for (int i = 0; i < n_pts; i++) {
+ out << i << " ";
+ annPrintPt(pts[i], dim, out);
+ out << "\n";
+ }
+ }
+ out << "tree " // print tree elements
+ << dim << " "
+ << n_pts << " "
+ << bkt_size << "\n";
+
+ annPrintPt(bnd_box_lo, dim, out); // print lower bound
+ out << "\n";
+ annPrintPt(bnd_box_hi, dim, out); // print upper bound
+ out << "\n";
+
+ if (root == NULL) // empty tree?
+ out << "null\n";
+ else {
+ root->dump(out); // invoke printing at root
+ }
+ out.precision(0); // restore default precision
+}
+
+void ANNkd_split::dump( // dump a splitting node
+ ostream &out) // output stream
+{
+ out << "split " << cut_dim << " " << cut_val << " ";
+ out << cd_bnds[ANN_LO] << " " << cd_bnds[ANN_HI] << "\n";
+
+ child[ANN_LO]->dump(out); // print low child
+ child[ANN_HI]->dump(out); // print high child
+}
+
+void ANNkd_leaf::dump( // dump a leaf node
+ ostream &out) // output stream
+{
+ if (this == KD_TRIVIAL) { // canonical trivial leaf node
+ out << "leaf 0\n"; // leaf no points
+ }
+ else{
+ out << "leaf " << n_pts;
+ for (int j = 0; j < n_pts; j++) {
+ out << " " << bkt[j];
+ }
+ out << "\n";
+ }
+}
+
+void ANNbd_shrink::dump( // dump a shrinking node
+ ostream &out) // output stream
+{
+ out << "shrink " << n_bnds << "\n";
+ for (int j = 0; j < n_bnds; j++) {
+ out << bnds[j].cd << " " << bnds[j].cv << " " << bnds[j].sd << "\n";
+ }
+ child[ANN_IN]->dump(out); // print in-child
+ child[ANN_OUT]->dump(out); // print out-child
+}
+
+//----------------------------------------------------------------------
+// Load kd-tree from dump file
+// This rebuilds a kd-tree which was dumped to a file. The dump
+// file contains all the basic tree information according to a
+// preorder traversal. We assume that the dump file also contains
+// point data. (This is to guarantee the consistency of the tree.)
+// If not, then an error is generated.
+//
+// Indirectly, this procedure allocates space for points, point
+// indices, all nodes in the tree, and the bounding box for the
+// tree. When the tree is destroyed, all but the points are
+// deallocated.
+//
+// This routine calls annReadDump to do all the work.
+//----------------------------------------------------------------------
+
+ANNkd_tree::ANNkd_tree( // build from dump file
+ istream &in) // input stream for dump file
+{
+ int the_dim; // local dimension
+ int the_n_pts; // local number of points
+ int the_bkt_size; // local number of points
+ ANNpoint the_bnd_box_lo; // low bounding point
+ ANNpoint the_bnd_box_hi; // high bounding point
+ ANNpointArray the_pts; // point storage
+ ANNidxArray the_pidx; // point index storage
+ ANNkd_ptr the_root; // root of the tree
+
+ the_root = annReadDump( // read the dump file
+ in, // input stream
+ KD_TREE, // expecting a kd-tree
+ the_pts, // point array (returned)
+ the_pidx, // point indices (returned)
+ the_dim, the_n_pts, the_bkt_size, // basic tree info (returned)
+ the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned)
+
+ // create a skeletal tree
+ SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx);
+
+ bnd_box_lo = the_bnd_box_lo;
+ bnd_box_hi = the_bnd_box_hi;
+
+ root = the_root; // set the root
+}
+
+ANNbd_tree::ANNbd_tree( // build bd-tree from dump file
+ istream &in) : ANNkd_tree() // input stream for dump file
+{
+ int the_dim; // local dimension
+ int the_n_pts; // local number of points
+ int the_bkt_size; // local number of points
+ ANNpoint the_bnd_box_lo; // low bounding point
+ ANNpoint the_bnd_box_hi; // high bounding point
+ ANNpointArray the_pts; // point storage
+ ANNidxArray the_pidx; // point index storage
+ ANNkd_ptr the_root; // root of the tree
+
+ the_root = annReadDump( // read the dump file
+ in, // input stream
+ BD_TREE, // expecting a bd-tree
+ the_pts, // point array (returned)
+ the_pidx, // point indices (returned)
+ the_dim, the_n_pts, the_bkt_size, // basic tree info (returned)
+ the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned)
+
+ // create a skeletal tree
+ SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx);
+ bnd_box_lo = the_bnd_box_lo;
+ bnd_box_hi = the_bnd_box_hi;
+
+ root = the_root; // set the root
+}
+
+//----------------------------------------------------------------------
+// annReadDump - read a dump file
+//
+// This procedure reads a dump file, constructs a kd-tree
+// and returns all the essential information needed to actually
+// construct the tree. Because this procedure is used for
+// constructing both kd-trees and bd-trees, the second argument
+// is used to indicate which type of tree we are expecting.
+//----------------------------------------------------------------------
+
+static ANNkd_ptr annReadDump(
+ istream &in, // input stream
+ ANNtreeType tree_type, // type of tree expected
+ ANNpointArray &the_pts, // new points (returned)
+ ANNidxArray &the_pidx, // point indices (returned)
+ int &the_dim, // dimension (returned)
+ int &the_n_pts, // number of points (returned)
+ int &the_bkt_size, // bucket size (returned)
+ ANNpoint &the_bnd_box_lo, // low bounding point (ret'd)
+ ANNpoint &the_bnd_box_hi) // high bounding point (ret'd)
+{
+ int j;
+ char str[STRING_LEN]; // storage for string
+ char version[STRING_LEN]; // ANN version number
+ ANNkd_ptr the_root = NULL;
+
+ //------------------------------------------------------------------
+ // Input file header
+ //------------------------------------------------------------------
+ in >> str; // input header
+ if (strcmp(str, "#ANN") != 0) { // incorrect header
+ annError("Incorrect header for dump file", ANNabort);
+ }
+ in.getline(version, STRING_LEN); // get version (ignore)
+
+ //------------------------------------------------------------------
+ // Input the points
+ // An array the_pts is allocated and points are read from
+ // the dump file.
+ //------------------------------------------------------------------
+ in >> str; // get major heading
+ if (strcmp(str, "points") == 0) { // points section
+ in >> the_dim; // input dimension
+ in >> the_n_pts; // number of points
+ // allocate point storage
+ the_pts = annAllocPts(the_n_pts, the_dim);
+ for (int i = 0; i < the_n_pts; i++) { // input point coordinates
+ ANNidx idx; // point index
+ in >> idx; // input point index
+ if (idx < 0 || idx >= the_n_pts) {
+ annError("Point index is out of range", ANNabort);
+ }
+ for (j = 0; j < the_dim; j++) {
+ in >> the_pts[idx][j]; // read point coordinates
+ }
+ }
+ in >> str; // get next major heading
+ }
+ else { // no points were input
+ annError("Points must be supplied in the dump file", ANNabort);
+ }
+
+ //------------------------------------------------------------------
+ // Input the tree
+ // After the basic header information, we invoke annReadTree
+ // to do all the heavy work. We create our own array of
+ // point indices (so we can pass them to annReadTree())
+ // but we do not deallocate them. They will be deallocated
+ // when the tree is destroyed.
+ //------------------------------------------------------------------
+ if (strcmp(str, "tree") == 0) { // tree section
+ in >> the_dim; // read dimension
+ in >> the_n_pts; // number of points
+ in >> the_bkt_size; // bucket size
+ the_bnd_box_lo = annAllocPt(the_dim); // allocate bounding box pts
+ the_bnd_box_hi = annAllocPt(the_dim);
+
+ for (j = 0; j < the_dim; j++) { // read bounding box low
+ in >> the_bnd_box_lo[j];
+ }
+ for (j = 0; j < the_dim; j++) { // read bounding box low
+ in >> the_bnd_box_hi[j];
+ }
+ the_pidx = new ANNidx[the_n_pts]; // allocate point index array
+ int next_idx = 0; // number of indices filled
+ // read the tree and indices
+ the_root = annReadTree(in, tree_type, the_pidx, next_idx);
+ if (next_idx != the_n_pts) { // didn't see all the points?
+ annError("Didn't see as many points as expected", ANNwarn);
+ }
+ }
+ else {
+ annError("Illegal dump format. Expecting section heading", ANNabort);
+ }
+ return the_root;
+}
+
+//----------------------------------------------------------------------
+// annReadTree - input tree and return pointer
+//
+// annReadTree reads in a node of the tree, makes any recursive
+// calls as needed to input the children of this node (if internal).
+// It returns a pointer to the node that was created. An array
+// of point indices is given along with a pointer to the next
+// available location in the array. As leaves are read, their
+// point indices are stored here, and the point buckets point
+// to the first entry in the array.
+//
+// Recall that these are the formats. The tree is given in
+// preorder.
+//
+// Leaf node:
+// leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
+// Splitting nodes:
+// split <cut_dim> <cut_val> <lo_bound> <hi_bound>
+//
+// For bd-trees:
+//
+// Shrinking nodes:
+// shrink <n_bnds>
+// <cut_dim> <cut_val> <side>
+// <cut_dim> <cut_val> <side>
+// ... (repeated n_bnds times)
+//----------------------------------------------------------------------
+
+static ANNkd_ptr annReadTree(
+ istream &in, // input stream
+ ANNtreeType tree_type, // type of tree expected
+ ANNidxArray the_pidx, // point indices (modified)
+ int &next_idx) // next index (modified)
+{
+ char tag[STRING_LEN]; // tag (leaf, split, shrink)
+ int n_pts; // number of points in leaf
+ int cd; // cut dimension
+ ANNcoord cv; // cut value
+ ANNcoord lb; // low bound
+ ANNcoord hb; // high bound
+ int n_bnds; // number of bounding sides
+ int sd; // which side
+
+ in >> tag; // input node tag
+
+ if (strcmp(tag, "null") == 0) { // null tree
+ return NULL;
+ }
+ //------------------------------------------------------------------
+ // Read a leaf
+ //------------------------------------------------------------------
+ if (strcmp(tag, "leaf") == 0) { // leaf node
+
+ in >> n_pts; // input number of points
+ int old_idx = next_idx; // save next_idx
+ if (n_pts == 0) { // trivial leaf
+ return KD_TRIVIAL;
+ }
+ else {
+ for (int i = 0; i < n_pts; i++) { // input point indices
+ in >> the_pidx[next_idx++]; // store in array of indices
+ }
+ }
+ return new ANNkd_leaf(n_pts, &the_pidx[old_idx]);
+ }
+ //------------------------------------------------------------------
+ // Read a splitting node
+ //------------------------------------------------------------------
+ else if (strcmp(tag, "split") == 0) { // splitting node
+
+ in >> cd >> cv >> lb >> hb;
+
+ // read low and high subtrees
+ ANNkd_ptr lc = annReadTree(in, tree_type, the_pidx, next_idx);
+ ANNkd_ptr hc = annReadTree(in, tree_type, the_pidx, next_idx);
+ // create new node and return
+ return new ANNkd_split(cd, cv, lb, hb, lc, hc);
+ }
+ //------------------------------------------------------------------
+ // Read a shrinking node (bd-tree only)
+ //------------------------------------------------------------------
+ else if (strcmp(tag, "shrink") == 0) { // shrinking node
+ if (tree_type != BD_TREE) {
+ annError("Shrinking node not allowed in kd-tree", ANNabort);
+ }
+
+ in >> n_bnds; // number of bounding sides
+ // allocate bounds array
+ ANNorthHSArray bds = new ANNorthHalfSpace[n_bnds];
+ for (int i = 0; i < n_bnds; i++) {
+ in >> cd >> cv >> sd; // input bounding halfspace
+ // copy to array
+ bds[i] = ANNorthHalfSpace(cd, cv, sd);
+ }
+ // read inner and outer subtrees
+ ANNkd_ptr ic = annReadTree(in, tree_type, the_pidx, next_idx);
+ ANNkd_ptr oc = annReadTree(in, tree_type, the_pidx, next_idx);
+ // create new node and return
+ return new ANNbd_shrink(n_bnds, bds, ic, oc);
+ }
+ else {
+ annError("Illegal node type in dump file", ANNabort);
+ exit(0); // to keep the compiler happy
+ }
+}
diff --git a/Contrib/ANN/src/kd_fix_rad_search.cpp b/Contrib/ANN/src/kd_fix_rad_search.cpp
new file mode 100755
index 0000000..87eb757
--- /dev/null
+++ b/Contrib/ANN/src/kd_fix_rad_search.cpp
@@ -0,0 +1,183 @@
+//----------------------------------------------------------------------
+// File: kd_fix_rad_search.cpp
+// Programmer: Sunil Arya and David Mount
+// Description: Standard kd-tree fixed-radius kNN search
+// Last modified: 05/03/05 (Version 1.1)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 1.1 05/03/05
+// Initial release
+//----------------------------------------------------------------------
+
+#include "kd_fix_rad_search.h" // kd fixed-radius search decls
+
+//----------------------------------------------------------------------
+// Approximate fixed-radius k nearest neighbor search
+// The squared radius is provided, and this procedure finds the
+// k nearest neighbors within the radius, and returns the total
+// number of points lying within the radius.
+//
+// The method used for searching the kd-tree is a variation of the
+// nearest neighbor search used in kd_search.cpp, except that the
+// radius of the search ball is known. We refer the reader to that
+// file for the explanation of the recursive search procedure.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// To keep argument lists short, a number of global variables
+// are maintained which are common to all the recursive calls.
+// These are given below.
+//----------------------------------------------------------------------
+
+int ANNkdFRDim; // dimension of space
+ANNpoint ANNkdFRQ; // query point
+ANNdist ANNkdFRSqRad; // squared radius search bound
+double ANNkdFRMaxErr; // max tolerable squared error
+ANNpointArray ANNkdFRPts; // the points
+ANNmin_k* ANNkdFRPointMK; // set of k closest points
+int ANNkdFRPtsVisited; // total points visited
+int ANNkdFRPtsInRange; // number of points in the range
+
+//----------------------------------------------------------------------
+// annkFRSearch - fixed radius search for k nearest neighbors
+//----------------------------------------------------------------------
+
+int ANNkd_tree::annkFRSearch(
+ ANNpoint q, // the query point
+ ANNdist sqRad, // squared radius search bound
+ int k, // number of near neighbors to return
+ ANNidxArray nn_idx, // nearest neighbor indices (returned)
+ ANNdistArray dd, // the approximate nearest neighbor
+ double eps) // the error bound
+{
+ ANNkdFRDim = dim; // copy arguments to static equivs
+ ANNkdFRQ = q;
+ ANNkdFRSqRad = sqRad;
+ ANNkdFRPts = pts;
+ ANNkdFRPtsVisited = 0; // initialize count of points visited
+ ANNkdFRPtsInRange = 0; // ...and points in the range
+
+ ANNkdFRMaxErr = ANN_POW(1.0 + eps);
+ ANN_FLOP(2) // increment floating op count
+
+ ANNkdFRPointMK = new ANNmin_k(k); // create set for closest k points
+ // search starting at the root
+ root->ann_FR_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim));
+
+ for (int i = 0; i < k; i++) { // extract the k-th closest points
+ if (dd != NULL)
+ dd[i] = ANNkdFRPointMK->ith_smallest_key(i);
+ if (nn_idx != NULL)
+ nn_idx[i] = ANNkdFRPointMK->ith_smallest_info(i);
+ }
+
+ delete ANNkdFRPointMK; // deallocate closest point set
+ return ANNkdFRPtsInRange; // return final point count
+}
+
+//----------------------------------------------------------------------
+// kd_split::ann_FR_search - search a splitting node
+// Note: This routine is similar in structure to the standard kNN
+// search. It visits the subtree that is closer to the query point
+// first. For fixed-radius search, there is no benefit in visiting
+// one subtree before the other, but we maintain the same basic
+// code structure for the sake of uniformity.
+//----------------------------------------------------------------------
+
+void ANNkd_split::ann_FR_search(ANNdist box_dist)
+{
+ // check dist calc term condition
+ if (ANNmaxPtsVisited != 0 && ANNkdFRPtsVisited > ANNmaxPtsVisited) return;
+
+ // distance to cutting plane
+ ANNcoord cut_diff = ANNkdFRQ[cut_dim] - cut_val;
+
+ if (cut_diff < 0) { // left of cutting plane
+ child[ANN_LO]->ann_FR_search(box_dist);// visit closer child first
+
+ ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdFRQ[cut_dim];
+ if (box_diff < 0) // within bounds - ignore
+ box_diff = 0;
+ // distance to further box
+ box_dist = (ANNdist) ANN_SUM(box_dist,
+ ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+ // visit further child if in range
+ if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad)
+ child[ANN_HI]->ann_FR_search(box_dist);
+
+ }
+ else { // right of cutting plane
+ child[ANN_HI]->ann_FR_search(box_dist);// visit closer child first
+
+ ANNcoord box_diff = ANNkdFRQ[cut_dim] - cd_bnds[ANN_HI];
+ if (box_diff < 0) // within bounds - ignore
+ box_diff = 0;
+ // distance to further box
+ box_dist = (ANNdist) ANN_SUM(box_dist,
+ ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+ // visit further child if close enough
+ if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad)
+ child[ANN_LO]->ann_FR_search(box_dist);
+
+ }
+ ANN_FLOP(13) // increment floating ops
+ ANN_SPL(1) // one more splitting node visited
+}
+
+//----------------------------------------------------------------------
+// kd_leaf::ann_FR_search - search points in a leaf node
+// Note: The unreadability of this code is the result of
+// some fine tuning to replace indexing by pointer operations.
+//----------------------------------------------------------------------
+
+void ANNkd_leaf::ann_FR_search(ANNdist box_dist)
+{
+ register ANNdist dist; // distance to data point
+ register ANNcoord* pp; // data coordinate pointer
+ register ANNcoord* qq; // query coordinate pointer
+ register ANNcoord t;
+ register int d;
+
+ for (int i = 0; i < n_pts; i++) { // check points in bucket
+
+ pp = ANNkdFRPts[bkt[i]]; // first coord of next data point
+ qq = ANNkdFRQ; // first coord of query point
+ dist = 0;
+
+ for(d = 0; d < ANNkdFRDim; d++) {
+ ANN_COORD(1) // one more coordinate hit
+ ANN_FLOP(5) // increment floating ops
+
+ t = *(qq++) - *(pp++); // compute length and adv coordinate
+ // exceeds dist to k-th smallest?
+ if( (dist = ANN_SUM(dist, ANN_POW(t))) > ANNkdFRSqRad) {
+ break;
+ }
+ }
+
+ if (d >= ANNkdFRDim && // among the k best?
+ (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
+ // add it to the list
+ ANNkdFRPointMK->insert(dist, bkt[i]);
+ ANNkdFRPtsInRange++; // increment point count
+ }
+ }
+ ANN_LEAF(1) // one more leaf node visited
+ ANN_PTS(n_pts) // increment points visited
+ ANNkdFRPtsVisited += n_pts; // increment number of points visited
+}
diff --git a/Contrib/ANN/src/kd_fix_rad_search.h b/Contrib/ANN/src/kd_fix_rad_search.h
new file mode 100755
index 0000000..7bae230
--- /dev/null
+++ b/Contrib/ANN/src/kd_fix_rad_search.h
@@ -0,0 +1,44 @@
+//----------------------------------------------------------------------
+// File: kd_fix_rad_search.h
+// Programmer: Sunil Arya and David Mount
+// Description: Standard kd-tree fixed-radius kNN search
+// Last modified: ??/??/?? (Version 1.1)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 1.1 ??/??/??
+// Initial release
+//----------------------------------------------------------------------
+
+#ifndef ANN_kd_fix_rad_search_H
+#define ANN_kd_fix_rad_search_H
+
+#include "kd_tree.h" // kd-tree declarations
+#include "kd_util.h" // kd-tree utilities
+#include "pr_queue_k.h" // k-element priority queue
+
+#include <ANN/ANNperf.h> // performance evaluation
+
+//----------------------------------------------------------------------
+// Global variables
+// These are active for the life of each call to
+// annRangeSearch(). They are set to save the number of
+// variables that need to be passed among the various search
+// procedures.
+//----------------------------------------------------------------------
+
+extern ANNpoint ANNkdFRQ; // query point (static copy)
+
+#endif
diff --git a/Contrib/ANN/src/kd_pr_search.cpp b/Contrib/ANN/src/kd_pr_search.cpp
new file mode 100755
index 0000000..edb0479
--- /dev/null
+++ b/Contrib/ANN/src/kd_pr_search.cpp
@@ -0,0 +1,219 @@
+//----------------------------------------------------------------------
+// File: kd_pr_search.cpp
+// Programmer: Sunil Arya and David Mount
+// Description: Priority search for kd-trees
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+//----------------------------------------------------------------------
+
+#include "kd_pr_search.h" // kd priority search declarations
+
+//----------------------------------------------------------------------
+// Approximate nearest neighbor searching by priority search.
+// The kd-tree is searched for an approximate nearest neighbor.
+// The point is returned through one of the arguments, and the
+// distance returned is the SQUARED distance to this point.
+//
+// The method used for searching the kd-tree is called priority
+// search. (It is described in Arya and Mount, ``Algorithms for
+// fast vector quantization,'' Proc. of DCC '93: Data Compression
+// Conference}, eds. J. A. Storer and M. Cohn, IEEE Press, 1993,
+// 381--390.)
+//
+// The cell of the kd-tree containing the query point is located,
+// and cells are visited in increasing order of distance from the
+// query point. This is done by placing each subtree which has
+// NOT been visited in a priority queue, according to the closest
+// distance of the corresponding enclosing rectangle from the
+// query point. The search stops when the distance to the nearest
+// remaining rectangle exceeds the distance to the nearest point
+// seen by a factor of more than 1/(1+eps). (Implying that any
+// point found subsequently in the search cannot be closer by more
+// than this factor.)
+//
+// The main entry point is annkPriSearch() which sets things up and
+// then call the recursive routine ann_pri_search(). This is a
+// recursive routine which performs the processing for one node in
+// the kd-tree. There are two versions of this virtual procedure,
+// one for splitting nodes and one for leaves. When a splitting node
+// is visited, we determine which child to continue the search on
+// (the closer one), and insert the other child into the priority
+// queue. When a leaf is visited, we compute the distances to the
+// points in the buckets, and update information on the closest
+// points.
+//
+// Some trickery is used to incrementally update the distance from
+// a kd-tree rectangle to the query point. This comes about from
+// the fact that which each successive split, only one component
+// (along the dimension that is split) of the squared distance to
+// the child rectangle is different from the squared distance to
+// the parent rectangle.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// To keep argument lists short, a number of global variables
+// are maintained which are common to all the recursive calls.
+// These are given below.
+//----------------------------------------------------------------------
+
+double ANNprEps; // the error bound
+int ANNprDim; // dimension of space
+ANNpoint ANNprQ; // query point
+double ANNprMaxErr; // max tolerable squared error
+ANNpointArray ANNprPts; // the points
+ANNpr_queue *ANNprBoxPQ; // priority queue for boxes
+ANNmin_k *ANNprPointMK; // set of k closest points
+
+//----------------------------------------------------------------------
+// annkPriSearch - priority search for k nearest neighbors
+//----------------------------------------------------------------------
+
+void ANNkd_tree::annkPriSearch(
+ ANNpoint q, // query point
+ int k, // number of near neighbors to return
+ ANNidxArray nn_idx, // nearest neighbor indices (returned)
+ ANNdistArray dd, // dist to near neighbors (returned)
+ double eps) // error bound (ignored)
+{
+ // max tolerable squared error
+ ANNprMaxErr = ANN_POW(1.0 + eps);
+ ANN_FLOP(2) // increment floating ops
+
+ ANNprDim = dim; // copy arguments to static equivs
+ ANNprQ = q;
+ ANNprPts = pts;
+ ANNptsVisited = 0; // initialize count of points visited
+
+ ANNprPointMK = new ANNmin_k(k); // create set for closest k points
+
+ // distance to root box
+ ANNdist box_dist = annBoxDistance(q,
+ bnd_box_lo, bnd_box_hi, dim);
+
+ ANNprBoxPQ = new ANNpr_queue(n_pts);// create priority queue for boxes
+ ANNprBoxPQ->insert(box_dist, root); // insert root in priority queue
+
+ while (ANNprBoxPQ->non_empty() &&
+ (!(ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited))) {
+ ANNkd_ptr np; // next box from prior queue
+
+ // extract closest box from queue
+ ANNprBoxPQ->extr_min(box_dist, (void *&) np);
+
+ ANN_FLOP(2) // increment floating ops
+ if (box_dist*ANNprMaxErr >= ANNprPointMK->max_key())
+ break;
+
+ np->ann_pri_search(box_dist); // search this subtree.
+ }
+
+ for (int i = 0; i < k; i++) { // extract the k-th closest points
+ dd[i] = ANNprPointMK->ith_smallest_key(i);
+ nn_idx[i] = ANNprPointMK->ith_smallest_info(i);
+ }
+
+ delete ANNprPointMK; // deallocate closest point set
+ delete ANNprBoxPQ; // deallocate priority queue
+}
+
+//----------------------------------------------------------------------
+// kd_split::ann_pri_search - search a splitting node
+//----------------------------------------------------------------------
+
+void ANNkd_split::ann_pri_search(ANNdist box_dist)
+{
+ ANNdist new_dist; // distance to child visited later
+ // distance to cutting plane
+ ANNcoord cut_diff = ANNprQ[cut_dim] - cut_val;
+
+ if (cut_diff < 0) { // left of cutting plane
+ ANNcoord box_diff = cd_bnds[ANN_LO] - ANNprQ[cut_dim];
+ if (box_diff < 0) // within bounds - ignore
+ box_diff = 0;
+ // distance to further box
+ new_dist = (ANNdist) ANN_SUM(box_dist,
+ ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+ if (child[ANN_HI] != KD_TRIVIAL)// enqueue if not trivial
+ ANNprBoxPQ->insert(new_dist, child[ANN_HI]);
+ // continue with closer child
+ child[ANN_LO]->ann_pri_search(box_dist);
+ }
+ else { // right of cutting plane
+ ANNcoord box_diff = ANNprQ[cut_dim] - cd_bnds[ANN_HI];
+ if (box_diff < 0) // within bounds - ignore
+ box_diff = 0;
+ // distance to further box
+ new_dist = (ANNdist) ANN_SUM(box_dist,
+ ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+ if (child[ANN_LO] != KD_TRIVIAL)// enqueue if not trivial
+ ANNprBoxPQ->insert(new_dist, child[ANN_LO]);
+ // continue with closer child
+ child[ANN_HI]->ann_pri_search(box_dist);
+ }
+ ANN_SPL(1) // one more splitting node visited
+ ANN_FLOP(8) // increment floating ops
+}
+
+//----------------------------------------------------------------------
+// kd_leaf::ann_pri_search - search points in a leaf node
+//
+// This is virtually identical to the ann_search for standard search.
+//----------------------------------------------------------------------
+
+void ANNkd_leaf::ann_pri_search(ANNdist box_dist)
+{
+ register ANNdist dist; // distance to data point
+ register ANNcoord* pp; // data coordinate pointer
+ register ANNcoord* qq; // query coordinate pointer
+ register ANNdist min_dist; // distance to k-th closest point
+ register ANNcoord t;
+ register int d;
+
+ min_dist = ANNprPointMK->max_key(); // k-th smallest distance so far
+
+ for (int i = 0; i < n_pts; i++) { // check points in bucket
+
+ pp = ANNprPts[bkt[i]]; // first coord of next data point
+ qq = ANNprQ; // first coord of query point
+ dist = 0;
+
+ for(d = 0; d < ANNprDim; d++) {
+ ANN_COORD(1) // one more coordinate hit
+ ANN_FLOP(4) // increment floating ops
+
+ t = *(qq++) - *(pp++); // compute length and adv coordinate
+ // exceeds dist to k-th smallest?
+ if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) {
+ break;
+ }
+ }
+
+ if (d >= ANNprDim && // among the k best?
+ (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
+ // add it to the list
+ ANNprPointMK->insert(dist, bkt[i]);
+ min_dist = ANNprPointMK->max_key();
+ }
+ }
+ ANN_LEAF(1) // one more leaf node visited
+ ANN_PTS(n_pts) // increment points visited
+ ANNptsVisited += n_pts; // increment number of points visited
+}
diff --git a/Contrib/ANN/src/kd_pr_search.h b/Contrib/ANN/src/kd_pr_search.h
new file mode 100755
index 0000000..39e0484
--- /dev/null
+++ b/Contrib/ANN/src/kd_pr_search.h
@@ -0,0 +1,49 @@
+//----------------------------------------------------------------------
+// File: kd_pr_search.h
+// Programmer: Sunil Arya and David Mount
+// Description: Priority kd-tree search
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+//----------------------------------------------------------------------
+
+#ifndef ANN_kd_pr_search_H
+#define ANN_kd_pr_search_H
+
+#include "kd_tree.h" // kd-tree declarations
+#include "kd_util.h" // kd-tree utilities
+#include "pr_queue.h" // priority queue declarations
+#include "pr_queue_k.h" // k-element priority queue
+
+#include <ANN/ANNperf.h> // performance evaluation
+
+//----------------------------------------------------------------------
+// Global variables
+// Active for the life of each call to Appx_Near_Neigh() or
+// Appx_k_Near_Neigh().
+//----------------------------------------------------------------------
+
+extern double ANNprEps; // the error bound
+extern int ANNprDim; // dimension of space
+extern ANNpoint ANNprQ; // query point
+extern double ANNprMaxErr; // max tolerable squared error
+extern ANNpointArray ANNprPts; // the points
+extern ANNpr_queue *ANNprBoxPQ; // priority queue for boxes
+extern ANNmin_k *ANNprPointMK; // set of k closest points
+
+#endif
diff --git a/Contrib/ANN/src/kd_search.cpp b/Contrib/ANN/src/kd_search.cpp
new file mode 100755
index 0000000..5004ef7
--- /dev/null
+++ b/Contrib/ANN/src/kd_search.cpp
@@ -0,0 +1,210 @@
+//----------------------------------------------------------------------
+// File: kd_search.cpp
+// Programmer: Sunil Arya and David Mount
+// Description: Standard kd-tree search
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.0 04/01/05
+// Changed names LO, HI to ANN_LO, ANN_HI
+//----------------------------------------------------------------------
+
+#include "kd_search.h" // kd-search declarations
+
+//----------------------------------------------------------------------
+// Approximate nearest neighbor searching by kd-tree search
+// The kd-tree is searched for an approximate nearest neighbor.
+// The point is returned through one of the arguments, and the
+// distance returned is the squared distance to this point.
+//
+// The method used for searching the kd-tree is an approximate
+// adaptation of the search algorithm described by Friedman,
+// Bentley, and Finkel, ``An algorithm for finding best matches
+// in logarithmic expected time,'' ACM Transactions on Mathematical
+// Software, 3(3):209-226, 1977).
+//
+// The algorithm operates recursively. When first encountering a
+// node of the kd-tree we first visit the child which is closest to
+// the query point. On return, we decide whether we want to visit
+// the other child. If the box containing the other child exceeds
+// 1/(1+eps) times the current best distance, then we skip it (since
+// any point found in this child cannot be closer to the query point
+// by more than this factor.) Otherwise, we visit it recursively.
+// The distance between a box and the query point is computed exactly
+// (not approximated as is often done in kd-tree), using incremental
+// distance updates, as described by Arya and Mount in ``Algorithms
+// for fast vector quantization,'' Proc. of DCC '93: Data Compression
+// Conference, eds. J. A. Storer and M. Cohn, IEEE Press, 1993,
+// 381-390.
+//
+// The main entry points is annkSearch() which sets things up and
+// then call the recursive routine ann_search(). This is a recursive
+// routine which performs the processing for one node in the kd-tree.
+// There are two versions of this virtual procedure, one for splitting
+// nodes and one for leaves. When a splitting node is visited, we
+// determine which child to visit first (the closer one), and visit
+// the other child on return. When a leaf is visited, we compute
+// the distances to the points in the buckets, and update information
+// on the closest points.
+//
+// Some trickery is used to incrementally update the distance from
+// a kd-tree rectangle to the query point. This comes about from
+// the fact that which each successive split, only one component
+// (along the dimension that is split) of the squared distance to
+// the child rectangle is different from the squared distance to
+// the parent rectangle.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// To keep argument lists short, a number of global variables
+// are maintained which are common to all the recursive calls.
+// These are given below.
+//----------------------------------------------------------------------
+
+int ANNkdDim; // dimension of space
+ANNpoint ANNkdQ; // query point
+double ANNkdMaxErr; // max tolerable squared error
+ANNpointArray ANNkdPts; // the points
+ANNmin_k *ANNkdPointMK; // set of k closest points
+
+//----------------------------------------------------------------------
+// annkSearch - search for the k nearest neighbors
+//----------------------------------------------------------------------
+
+void ANNkd_tree::annkSearch(
+ ANNpoint q, // the query point
+ int k, // number of near neighbors to return
+ ANNidxArray nn_idx, // nearest neighbor indices (returned)
+ ANNdistArray dd, // the approximate nearest neighbor
+ double eps) // the error bound
+{
+
+ ANNkdDim = dim; // copy arguments to static equivs
+ ANNkdQ = q;
+ ANNkdPts = pts;
+ ANNptsVisited = 0; // initialize count of points visited
+
+ if (k > n_pts) { // too many near neighbors?
+ annError("Requesting more near neighbors than data points", ANNabort);
+ }
+
+ ANNkdMaxErr = ANN_POW(1.0 + eps);
+ ANN_FLOP(2) // increment floating op count
+
+ ANNkdPointMK = new ANNmin_k(k); // create set for closest k points
+ // search starting at the root
+ root->ann_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim));
+
+ for (int i = 0; i < k; i++) { // extract the k-th closest points
+ dd[i] = ANNkdPointMK->ith_smallest_key(i);
+ nn_idx[i] = ANNkdPointMK->ith_smallest_info(i);
+ }
+ delete ANNkdPointMK; // deallocate closest point set
+}
+
+//----------------------------------------------------------------------
+// kd_split::ann_search - search a splitting node
+//----------------------------------------------------------------------
+
+void ANNkd_split::ann_search(ANNdist box_dist)
+{
+ // check dist calc term condition
+ if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
+
+ // distance to cutting plane
+ ANNcoord cut_diff = ANNkdQ[cut_dim] - cut_val;
+
+ if (cut_diff < 0) { // left of cutting plane
+ child[ANN_LO]->ann_search(box_dist);// visit closer child first
+
+ ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdQ[cut_dim];
+ if (box_diff < 0) // within bounds - ignore
+ box_diff = 0;
+ // distance to further box
+ box_dist = (ANNdist) ANN_SUM(box_dist,
+ ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+ // visit further child if close enough
+ if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key())
+ child[ANN_HI]->ann_search(box_dist);
+
+ }
+ else { // right of cutting plane
+ child[ANN_HI]->ann_search(box_dist);// visit closer child first
+
+ ANNcoord box_diff = ANNkdQ[cut_dim] - cd_bnds[ANN_HI];
+ if (box_diff < 0) // within bounds - ignore
+ box_diff = 0;
+ // distance to further box
+ box_dist = (ANNdist) ANN_SUM(box_dist,
+ ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+ // visit further child if close enough
+ if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key())
+ child[ANN_LO]->ann_search(box_dist);
+
+ }
+ ANN_FLOP(10) // increment floating ops
+ ANN_SPL(1) // one more splitting node visited
+}
+
+//----------------------------------------------------------------------
+// kd_leaf::ann_search - search points in a leaf node
+// Note: The unreadability of this code is the result of
+// some fine tuning to replace indexing by pointer operations.
+//----------------------------------------------------------------------
+
+void ANNkd_leaf::ann_search(ANNdist box_dist)
+{
+ register ANNdist dist; // distance to data point
+ register ANNcoord* pp; // data coordinate pointer
+ register ANNcoord* qq; // query coordinate pointer
+ register ANNdist min_dist; // distance to k-th closest point
+ register ANNcoord t;
+ register int d;
+
+ min_dist = ANNkdPointMK->max_key(); // k-th smallest distance so far
+
+ for (int i = 0; i < n_pts; i++) { // check points in bucket
+
+ pp = ANNkdPts[bkt[i]]; // first coord of next data point
+ qq = ANNkdQ; // first coord of query point
+ dist = 0;
+
+ for(d = 0; d < ANNkdDim; d++) {
+ ANN_COORD(1) // one more coordinate hit
+ ANN_FLOP(4) // increment floating ops
+
+ t = *(qq++) - *(pp++); // compute length and adv coordinate
+ // exceeds dist to k-th smallest?
+ if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) {
+ break;
+ }
+ }
+
+ if (d >= ANNkdDim && // among the k best?
+ (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
+ // add it to the list
+ ANNkdPointMK->insert(dist, bkt[i]);
+ min_dist = ANNkdPointMK->max_key();
+ }
+ }
+ ANN_LEAF(1) // one more leaf node visited
+ ANN_PTS(n_pts) // increment points visited
+ ANNptsVisited += n_pts; // increment number of points visited
+}
diff --git a/Contrib/ANN/src/kd_search.h b/Contrib/ANN/src/kd_search.h
new file mode 100755
index 0000000..1adcdd4
--- /dev/null
+++ b/Contrib/ANN/src/kd_search.h
@@ -0,0 +1,48 @@
+//----------------------------------------------------------------------
+// File: kd_search.h
+// Programmer: Sunil Arya and David Mount
+// Description: Standard kd-tree search
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+//----------------------------------------------------------------------
+
+#ifndef ANN_kd_search_H
+#define ANN_kd_search_H
+
+#include "kd_tree.h" // kd-tree declarations
+#include "kd_util.h" // kd-tree utilities
+#include "pr_queue_k.h" // k-element priority queue
+
+#include <ANN/ANNperf.h> // performance evaluation
+
+//----------------------------------------------------------------------
+// More global variables
+// These are active for the life of each call to annkSearch(). They
+// are set to save the number of variables that need to be passed
+// among the various search procedures.
+//----------------------------------------------------------------------
+
+extern int ANNkdDim; // dimension of space (static copy)
+extern ANNpoint ANNkdQ; // query point (static copy)
+extern double ANNkdMaxErr; // max tolerable squared error
+extern ANNpointArray ANNkdPts; // the points (static copy)
+extern ANNmin_k *ANNkdPointMK; // set of k closest points
+extern int ANNptsVisited; // number of points visited
+
+#endif
diff --git a/Contrib/ANN/src/kd_split.cpp b/Contrib/ANN/src/kd_split.cpp
new file mode 100755
index 0000000..8d5b3d8
--- /dev/null
+++ b/Contrib/ANN/src/kd_split.cpp
@@ -0,0 +1,428 @@
+//----------------------------------------------------------------------
+// File: kd_split.cpp
+// Programmer: Sunil Arya and David Mount
+// Description: Methods for splitting kd-trees
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.0 04/01/05
+//----------------------------------------------------------------------
+
+#include "kd_tree.h" // kd-tree definitions
+#include "kd_util.h" // kd-tree utilities
+#include "kd_split.h" // splitting functions
+
+//----------------------------------------------------------------------
+// Constants
+//----------------------------------------------------------------------
+
+const double ERR = 0.001; // a small value
+const double FS_ASPECT_RATIO = 3.0; // maximum allowed aspect ratio
+ // in fair split. Must be >= 2.
+
+//----------------------------------------------------------------------
+// kd_split - Bentley's standard splitting routine for kd-trees
+// Find the dimension of the greatest spread, and split
+// just before the median point along this dimension.
+//----------------------------------------------------------------------
+
+void kd_split(
+ ANNpointArray pa, // point array (permuted on return)
+ ANNidxArray pidx, // point indices
+ const ANNorthRect &bnds, // bounding rectangle for cell
+ int n, // number of points
+ int dim, // dimension of space
+ int &cut_dim, // cutting dimension (returned)
+ ANNcoord &cut_val, // cutting value (returned)
+ int &n_lo) // num of points on low side (returned)
+{
+ // find dimension of maximum spread
+ cut_dim = annMaxSpread(pa, pidx, n, dim);
+ n_lo = n/2; // median rank
+ // split about median
+ annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
+}
+
+//----------------------------------------------------------------------
+// midpt_split - midpoint splitting rule for box-decomposition trees
+//
+// This is the simplest splitting rule that guarantees boxes
+// of bounded aspect ratio. It simply cuts the box with the
+// longest side through its midpoint. If there are ties, it
+// selects the dimension with the maximum point spread.
+//
+// WARNING: This routine (while simple) doesn't seem to work
+// well in practice in high dimensions, because it tends to
+// generate a large number of trivial and/or unbalanced splits.
+// Either kd_split(), sl_midpt_split(), or fair_split() are
+// recommended, instead.
+//----------------------------------------------------------------------
+
+void midpt_split(
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices (permuted on return)
+ const ANNorthRect &bnds, // bounding rectangle for cell
+ int n, // number of points
+ int dim, // dimension of space
+ int &cut_dim, // cutting dimension (returned)
+ ANNcoord &cut_val, // cutting value (returned)
+ int &n_lo) // num of points on low side (returned)
+{
+ int d;
+
+ ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
+ for (d = 1; d < dim; d++) { // find length of longest box side
+ ANNcoord length = bnds.hi[d] - bnds.lo[d];
+ if (length > max_length) {
+ max_length = length;
+ }
+ }
+ ANNcoord max_spread = -1; // find long side with most spread
+ for (d = 0; d < dim; d++) {
+ // is it among longest?
+ if (double(bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) {
+ // compute its spread
+ ANNcoord spr = annSpread(pa, pidx, n, d);
+ if (spr > max_spread) { // is it max so far?
+ max_spread = spr;
+ cut_dim = d;
+ }
+ }
+ }
+ // split along cut_dim at midpoint
+ cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim]) / 2;
+ // permute points accordingly
+ int br1, br2;
+ annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+ //------------------------------------------------------------------
+ // On return: pa[0..br1-1] < cut_val
+ // pa[br1..br2-1] == cut_val
+ // pa[br2..n-1] > cut_val
+ //
+ // We can set n_lo to any value in the range [br1..br2].
+ // We choose split so that points are most evenly divided.
+ //------------------------------------------------------------------
+ if (br1 > n/2) n_lo = br1;
+ else if (br2 < n/2) n_lo = br2;
+ else n_lo = n/2;
+}
+
+//----------------------------------------------------------------------
+// sl_midpt_split - sliding midpoint splitting rule
+//
+// This is a modification of midpt_split, which has the nonsensical
+// name "sliding midpoint". The idea is that we try to use the
+// midpoint rule, by bisecting the longest side. If there are
+// ties, the dimension with the maximum spread is selected. If,
+// however, the midpoint split produces a trivial split (no points
+// on one side of the splitting plane) then we slide the splitting
+// (maintaining its orientation) until it produces a nontrivial
+// split. For example, if the splitting plane is along the x-axis,
+// and all the data points have x-coordinate less than the x-bisector,
+// then the split is taken along the maximum x-coordinate of the
+// data points.
+//
+// Intuitively, this rule cannot generate trivial splits, and
+// hence avoids midpt_split's tendency to produce trees with
+// a very large number of nodes.
+//
+//----------------------------------------------------------------------
+
+void sl_midpt_split(
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices (permuted on return)
+ const ANNorthRect &bnds, // bounding rectangle for cell
+ int n, // number of points
+ int dim, // dimension of space
+ int &cut_dim, // cutting dimension (returned)
+ ANNcoord &cut_val, // cutting value (returned)
+ int &n_lo) // num of points on low side (returned)
+{
+ int d;
+
+ ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
+ for (d = 1; d < dim; d++) { // find length of longest box side
+ ANNcoord length = bnds.hi[d] - bnds.lo[d];
+ if (length > max_length) {
+ max_length = length;
+ }
+ }
+ ANNcoord max_spread = -1; // find long side with most spread
+ for (d = 0; d < dim; d++) {
+ // is it among longest?
+ if ((bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) {
+ // compute its spread
+ ANNcoord spr = annSpread(pa, pidx, n, d);
+ if (spr > max_spread) { // is it max so far?
+ max_spread = spr;
+ cut_dim = d;
+ }
+ }
+ }
+ // ideal split at midpoint
+ ANNcoord ideal_cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim])/2;
+
+ ANNcoord min, max;
+ annMinMax(pa, pidx, n, cut_dim, min, max); // find min/max coordinates
+
+ if (ideal_cut_val < min) // slide to min or max as needed
+ cut_val = min;
+ else if (ideal_cut_val > max)
+ cut_val = max;
+ else
+ cut_val = ideal_cut_val;
+
+ // permute points accordingly
+ int br1, br2;
+ annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+ //------------------------------------------------------------------
+ // On return: pa[0..br1-1] < cut_val
+ // pa[br1..br2-1] == cut_val
+ // pa[br2..n-1] > cut_val
+ //
+ // We can set n_lo to any value in the range [br1..br2] to satisfy
+ // the exit conditions of the procedure.
+ //
+ // if ideal_cut_val < min (implying br2 >= 1),
+ // then we select n_lo = 1 (so there is one point on left) and
+ // if ideal_cut_val > max (implying br1 <= n-1),
+ // then we select n_lo = n-1 (so there is one point on right).
+ // Otherwise, we select n_lo as close to n/2 as possible within
+ // [br1..br2].
+ //------------------------------------------------------------------
+ if (ideal_cut_val < min) n_lo = 1;
+ else if (ideal_cut_val > max) n_lo = n-1;
+ else if (br1 > n/2) n_lo = br1;
+ else if (br2 < n/2) n_lo = br2;
+ else n_lo = n/2;
+}
+
+//----------------------------------------------------------------------
+// fair_split - fair-split splitting rule
+//
+// This is a compromise between the kd-tree splitting rule (which
+// always splits data points at their median) and the midpoint
+// splitting rule (which always splits a box through its center.
+// The goal of this procedure is to achieve both nicely balanced
+// splits, and boxes of bounded aspect ratio.
+//
+// A constant FS_ASPECT_RATIO is defined. Given a box, those sides
+// which can be split so that the ratio of the longest to shortest
+// side does not exceed ASPECT_RATIO are identified. Among these
+// sides, we select the one in which the points have the largest
+// spread. We then split the points in a manner which most evenly
+// distributes the points on either side of the splitting plane,
+// subject to maintaining the bound on the ratio of long to short
+// sides. To determine that the aspect ratio will be preserved,
+// we determine the longest side (other than this side), and
+// determine how narrowly we can cut this side, without causing the
+// aspect ratio bound to be exceeded (small_piece).
+//
+// This procedure is more robust than either kd_split or midpt_split,
+// but is more complicated as well. When point distribution is
+// extremely skewed, this degenerates to midpt_split (actually
+// 1/3 point split), and when the points are most evenly distributed,
+// this degenerates to kd-split.
+//----------------------------------------------------------------------
+
+void fair_split(
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices (permuted on return)
+ const ANNorthRect &bnds, // bounding rectangle for cell
+ int n, // number of points
+ int dim, // dimension of space
+ int &cut_dim, // cutting dimension (returned)
+ ANNcoord &cut_val, // cutting value (returned)
+ int &n_lo) // num of points on low side (returned)
+{
+ int d;
+ ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
+ cut_dim = 0;
+ for (d = 1; d < dim; d++) { // find length of longest box side
+ ANNcoord length = bnds.hi[d] - bnds.lo[d];
+ if (length > max_length) {
+ max_length = length;
+ cut_dim = d;
+ }
+ }
+
+ ANNcoord max_spread = 0; // find legal cut with max spread
+ cut_dim = 0;
+ for (d = 0; d < dim; d++) {
+ ANNcoord length = bnds.hi[d] - bnds.lo[d];
+ // is this side midpoint splitable
+ // without violating aspect ratio?
+ if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) {
+ // compute spread along this dim
+ ANNcoord spr = annSpread(pa, pidx, n, d);
+ if (spr > max_spread) { // best spread so far
+ max_spread = spr;
+ cut_dim = d; // this is dimension to cut
+ }
+ }
+ }
+
+ max_length = 0; // find longest side other than cut_dim
+ for (d = 0; d < dim; d++) {
+ ANNcoord length = bnds.hi[d] - bnds.lo[d];
+ if (d != cut_dim && length > max_length)
+ max_length = length;
+ }
+ // consider most extreme splits
+ ANNcoord small_piece = max_length / FS_ASPECT_RATIO;
+ ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut
+ ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut
+
+ int br1, br2;
+ // is median below lo_cut ?
+ if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) {
+ cut_val = lo_cut; // cut at lo_cut
+ annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+ n_lo = br1;
+ }
+ // is median above hi_cut?
+ else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) {
+ cut_val = hi_cut; // cut at hi_cut
+ annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+ n_lo = br2;
+ }
+ else { // median cut preserves asp ratio
+ n_lo = n/2; // split about median
+ annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
+ }
+}
+
+//----------------------------------------------------------------------
+// sl_fair_split - sliding fair split splitting rule
+//
+// Sliding fair split is a splitting rule that combines the
+// strengths of both fair split with sliding midpoint split.
+// Fair split tends to produce balanced splits when the points
+// are roughly uniformly distributed, but it can produce many
+// trivial splits when points are highly clustered. Sliding
+// midpoint never produces trivial splits, and shrinks boxes
+// nicely if points are highly clustered, but it may produce
+// rather unbalanced splits when points are unclustered but not
+// quite uniform.
+//
+// Sliding fair split is based on the theory that there are two
+// types of splits that are "good": balanced splits that produce
+// fat boxes, and unbalanced splits provided the cell with fewer
+// points is fat.
+//
+// This splitting rule operates by first computing the longest
+// side of the current bounding box. Then it asks which sides
+// could be split (at the midpoint) and still satisfy the aspect
+// ratio bound with respect to this side. Among these, it selects
+// the side with the largest spread (as fair split would). It
+// then considers the most extreme cuts that would be allowed by
+// the aspect ratio bound. This is done by dividing the longest
+// side of the box by the aspect ratio bound. If the median cut
+// lies between these extreme cuts, then we use the median cut.
+// If not, then consider the extreme cut that is closer to the
+// median. If all the points lie to one side of this cut, then
+// we slide the cut until it hits the first point. This may
+// violate the aspect ratio bound, but will never generate empty
+// cells. However the sibling of every such skinny cell is fat,
+// and hence packing arguments still apply.
+//
+//----------------------------------------------------------------------
+
+void sl_fair_split(
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices (permuted on return)
+ const ANNorthRect &bnds, // bounding rectangle for cell
+ int n, // number of points
+ int dim, // dimension of space
+ int &cut_dim, // cutting dimension (returned)
+ ANNcoord &cut_val, // cutting value (returned)
+ int &n_lo) // num of points on low side (returned)
+{
+ int d;
+ ANNcoord min, max; // min/max coordinates
+ int br1, br2; // split break points
+
+ ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
+ cut_dim = 0;
+ for (d = 1; d < dim; d++) { // find length of longest box side
+ ANNcoord length = bnds.hi[d] - bnds.lo[d];
+ if (length > max_length) {
+ max_length = length;
+ cut_dim = d;
+ }
+ }
+
+ ANNcoord max_spread = 0; // find legal cut with max spread
+ cut_dim = 0;
+ for (d = 0; d < dim; d++) {
+ ANNcoord length = bnds.hi[d] - bnds.lo[d];
+ // is this side midpoint splitable
+ // without violating aspect ratio?
+ if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) {
+ // compute spread along this dim
+ ANNcoord spr = annSpread(pa, pidx, n, d);
+ if (spr > max_spread) { // best spread so far
+ max_spread = spr;
+ cut_dim = d; // this is dimension to cut
+ }
+ }
+ }
+
+ max_length = 0; // find longest side other than cut_dim
+ for (d = 0; d < dim; d++) {
+ ANNcoord length = bnds.hi[d] - bnds.lo[d];
+ if (d != cut_dim && length > max_length)
+ max_length = length;
+ }
+ // consider most extreme splits
+ ANNcoord small_piece = max_length / FS_ASPECT_RATIO;
+ ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut
+ ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut
+ // find min and max along cut_dim
+ annMinMax(pa, pidx, n, cut_dim, min, max);
+ // is median below lo_cut?
+ if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) {
+ if (max > lo_cut) { // are any points above lo_cut?
+ cut_val = lo_cut; // cut at lo_cut
+ annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+ n_lo = br1; // balance if there are ties
+ }
+ else { // all points below lo_cut
+ cut_val = max; // cut at max value
+ annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+ n_lo = n-1;
+ }
+ }
+ // is median above hi_cut?
+ else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) {
+ if (min < hi_cut) { // are any points below hi_cut?
+ cut_val = hi_cut; // cut at hi_cut
+ annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+ n_lo = br2; // balance if there are ties
+ }
+ else { // all points above hi_cut
+ cut_val = min; // cut at min value
+ annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+ n_lo = 1;
+ }
+ }
+ else { // median cut is good enough
+ n_lo = n/2; // split about median
+ annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
+ }
+}
diff --git a/Contrib/ANN/src/kd_split.h b/Contrib/ANN/src/kd_split.h
new file mode 100755
index 0000000..ef80461
--- /dev/null
+++ b/Contrib/ANN/src/kd_split.h
@@ -0,0 +1,85 @@
+//----------------------------------------------------------------------
+// File: kd_split.h
+// Programmer: Sunil Arya and David Mount
+// Description: Methods for splitting kd-trees
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+//----------------------------------------------------------------------
+
+#ifndef ANN_KD_SPLIT_H
+#define ANN_KD_SPLIT_H
+
+#include "kd_tree.h" // kd-tree definitions
+
+//----------------------------------------------------------------------
+// External entry points
+// These are all splitting procedures for kd-trees.
+//----------------------------------------------------------------------
+
+void kd_split( // standard (optimized) kd-splitter
+ ANNpointArray pa, // point array (unaltered)
+ ANNidxArray pidx, // point indices (permuted on return)
+ const ANNorthRect &bnds, // bounding rectangle for cell
+ int n, // number of points
+ int dim, // dimension of space
+ int &cut_dim, // cutting dimension (returned)
+ ANNcoord &cut_val, // cutting value (returned)
+ int &n_lo); // num of points on low side (returned)
+
+void midpt_split( // midpoint kd-splitter
+ ANNpointArray pa, // point array (unaltered)
+ ANNidxArray pidx, // point indices (permuted on return)
+ const ANNorthRect &bnds, // bounding rectangle for cell
+ int n, // number of points
+ int dim, // dimension of space
+ int &cut_dim, // cutting dimension (returned)
+ ANNcoord &cut_val, // cutting value (returned)
+ int &n_lo); // num of points on low side (returned)
+
+void sl_midpt_split( // sliding midpoint kd-splitter
+ ANNpointArray pa, // point array (unaltered)
+ ANNidxArray pidx, // point indices (permuted on return)
+ const ANNorthRect &bnds, // bounding rectangle for cell
+ int n, // number of points
+ int dim, // dimension of space
+ int &cut_dim, // cutting dimension (returned)
+ ANNcoord &cut_val, // cutting value (returned)
+ int &n_lo); // num of points on low side (returned)
+
+void fair_split( // fair-split kd-splitter
+ ANNpointArray pa, // point array (unaltered)
+ ANNidxArray pidx, // point indices (permuted on return)
+ const ANNorthRect &bnds, // bounding rectangle for cell
+ int n, // number of points
+ int dim, // dimension of space
+ int &cut_dim, // cutting dimension (returned)
+ ANNcoord &cut_val, // cutting value (returned)
+ int &n_lo); // num of points on low side (returned)
+
+void sl_fair_split( // sliding fair-split kd-splitter
+ ANNpointArray pa, // point array (unaltered)
+ ANNidxArray pidx, // point indices (permuted on return)
+ const ANNorthRect &bnds, // bounding rectangle for cell
+ int n, // number of points
+ int dim, // dimension of space
+ int &cut_dim, // cutting dimension (returned)
+ ANNcoord &cut_val, // cutting value (returned)
+ int &n_lo); // num of points on low side (returned)
+
+#endif
diff --git a/Contrib/ANN/src/kd_tree.cpp b/Contrib/ANN/src/kd_tree.cpp
new file mode 100755
index 0000000..2828fd2
--- /dev/null
+++ b/Contrib/ANN/src/kd_tree.cpp
@@ -0,0 +1,405 @@
+//----------------------------------------------------------------------
+// File: kd_tree.cpp
+// Programmer: Sunil Arya and David Mount
+// Description: Basic methods for kd-trees.
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.0 04/01/05
+// Increased aspect ratio bound (ANN_AR_TOOBIG) from 100 to 1000.
+// Fixed leaf counts to count trivial leaves.
+// Added optional pa, pi arguments to Skeleton kd_tree constructor
+// for use in load constructor.
+// Added annClose() to eliminate KD_TRIVIAL memory leak.
+//----------------------------------------------------------------------
+
+#include "kd_tree.h" // kd-tree declarations
+#include "kd_split.h" // kd-tree splitting rules
+#include "kd_util.h" // kd-tree utilities
+#include <ANN/ANNperf.h> // performance evaluation
+
+//----------------------------------------------------------------------
+// Global data
+//
+// For some splitting rules, especially with small bucket sizes,
+// it is possible to generate a large number of empty leaf nodes.
+// To save storage we allocate a single trivial leaf node which
+// contains no points. For messy coding reasons it is convenient
+// to have it reference a trivial point index.
+//
+// KD_TRIVIAL is allocated when the first kd-tree is created. It
+// must *never* deallocated (since it may be shared by more than
+// one tree).
+//----------------------------------------------------------------------
+static int IDX_TRIVIAL[] = {0}; // trivial point index
+ANNkd_leaf *KD_TRIVIAL = NULL; // trivial leaf node
+
+//----------------------------------------------------------------------
+// Printing the kd-tree
+// These routines print a kd-tree in reverse inorder (high then
+// root then low). (This is so that if you look at the output
+// from the right side it appear from left to right in standard
+// inorder.) When outputting leaves we output only the point
+// indices rather than the point coordinates. There is an option
+// to print the point coordinates separately.
+//
+// The tree printing routine calls the printing routines on the
+// individual nodes of the tree, passing in the level or depth
+// in the tree. The level in the tree is used to print indentation
+// for readability.
+//----------------------------------------------------------------------
+
+void ANNkd_split::print( // print splitting node
+ int level, // depth of node in tree
+ ostream &out) // output stream
+{
+ child[ANN_HI]->print(level+1, out); // print high child
+ out << " ";
+ for (int i = 0; i < level; i++) // print indentation
+ out << "..";
+ out << "Split cd=" << cut_dim << " cv=" << cut_val;
+ out << " lbnd=" << cd_bnds[ANN_LO];
+ out << " hbnd=" << cd_bnds[ANN_HI];
+ out << "\n";
+ child[ANN_LO]->print(level+1, out); // print low child
+}
+
+void ANNkd_leaf::print( // print leaf node
+ int level, // depth of node in tree
+ ostream &out) // output stream
+{
+
+ out << " ";
+ for (int i = 0; i < level; i++) // print indentation
+ out << "..";
+
+ if (this == KD_TRIVIAL) { // canonical trivial leaf node
+ out << "Leaf (trivial)\n";
+ }
+ else{
+ out << "Leaf n=" << n_pts << " <";
+ for (int j = 0; j < n_pts; j++) {
+ out << bkt[j];
+ if (j < n_pts-1) out << ",";
+ }
+ out << ">\n";
+ }
+}
+
+void ANNkd_tree::Print( // print entire tree
+ ANNbool with_pts, // print points as well?
+ ostream &out) // output stream
+{
+ out << "ANN Version " << ANNversion << "\n";
+ if (with_pts) { // print point coordinates
+ out << " Points:\n";
+ for (int i = 0; i < n_pts; i++) {
+ out << "\t" << i << ": ";
+ annPrintPt(pts[i], dim, out);
+ out << "\n";
+ }
+ }
+ if (root == NULL) // empty tree?
+ out << " Null tree.\n";
+ else {
+ root->print(0, out); // invoke printing at root
+ }
+}
+
+//----------------------------------------------------------------------
+// kd_tree statistics (for performance evaluation)
+// This routine compute various statistics information for
+// a kd-tree. It is used by the implementors for performance
+// evaluation of the data structure.
+//----------------------------------------------------------------------
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+void ANNkdStats::merge(const ANNkdStats &st) // merge stats from child
+{
+ n_lf += st.n_lf; n_tl += st.n_tl;
+ n_spl += st.n_spl; n_shr += st.n_shr;
+ depth = MAX(depth, st.depth);
+ sum_ar += st.sum_ar;
+}
+
+//----------------------------------------------------------------------
+// Update statistics for nodes
+//----------------------------------------------------------------------
+
+const double ANN_AR_TOOBIG = 1000; // too big an aspect ratio
+
+void ANNkd_leaf::getStats( // get subtree statistics
+ int dim, // dimension of space
+ ANNkdStats &st, // stats (modified)
+ ANNorthRect &bnd_box) // bounding box
+{
+ st.reset();
+ st.n_lf = 1; // count this leaf
+ if (this == KD_TRIVIAL) st.n_tl = 1; // count trivial leaf
+ double ar = annAspectRatio(dim, bnd_box); // aspect ratio of leaf
+ // incr sum (ignore outliers)
+ st.sum_ar += float(ar < ANN_AR_TOOBIG ? ar : ANN_AR_TOOBIG);
+}
+
+void ANNkd_split::getStats( // get subtree statistics
+ int dim, // dimension of space
+ ANNkdStats &st, // stats (modified)
+ ANNorthRect &bnd_box) // bounding box
+{
+ ANNkdStats ch_stats; // stats for children
+ // get stats for low child
+ ANNcoord hv = bnd_box.hi[cut_dim]; // save box bounds
+ bnd_box.hi[cut_dim] = cut_val; // upper bound for low child
+ ch_stats.reset(); // reset
+ child[ANN_LO]->getStats(dim, ch_stats, bnd_box);
+ st.merge(ch_stats); // merge them
+ bnd_box.hi[cut_dim] = hv; // restore bound
+ // get stats for high child
+ ANNcoord lv = bnd_box.lo[cut_dim]; // save box bounds
+ bnd_box.lo[cut_dim] = cut_val; // lower bound for high child
+ ch_stats.reset(); // reset
+ child[ANN_HI]->getStats(dim, ch_stats, bnd_box);
+ st.merge(ch_stats); // merge them
+ bnd_box.lo[cut_dim] = lv; // restore bound
+
+ st.depth++; // increment depth
+ st.n_spl++; // increment number of splits
+}
+
+//----------------------------------------------------------------------
+// getStats
+// Collects a number of statistics related to kd_tree or
+// bd_tree.
+//----------------------------------------------------------------------
+
+void ANNkd_tree::getStats( // get tree statistics
+ ANNkdStats &st) // stats (modified)
+{
+ st.reset(dim, n_pts, bkt_size); // reset stats
+ // create bounding box
+ ANNorthRect bnd_box(dim, bnd_box_lo, bnd_box_hi);
+ if (root != NULL) { // if nonempty tree
+ root->getStats(dim, st, bnd_box); // get statistics
+ st.avg_ar = st.sum_ar / st.n_lf; // average leaf asp ratio
+ }
+}
+
+//----------------------------------------------------------------------
+// kd_tree destructor
+// The destructor just frees the various elements that were
+// allocated in the construction process.
+//----------------------------------------------------------------------
+
+ANNkd_tree::~ANNkd_tree() // tree destructor
+{
+ if (root != NULL) delete root;
+ if (pidx != NULL) delete [] pidx;
+ if (bnd_box_lo != NULL) annDeallocPt(bnd_box_lo);
+ if (bnd_box_hi != NULL) annDeallocPt(bnd_box_hi);
+}
+
+//----------------------------------------------------------------------
+// This is called with all use of ANN is finished. It eliminates the
+// minor memory leak caused by the allocation of KD_TRIVIAL.
+//----------------------------------------------------------------------
+void annClose() // close use of ANN
+{
+ if (KD_TRIVIAL != NULL) {
+ delete KD_TRIVIAL;
+ KD_TRIVIAL = NULL;
+ }
+}
+
+//----------------------------------------------------------------------
+// kd_tree constructors
+// There is a skeleton kd-tree constructor which sets up a
+// trivial empty tree. The last optional argument allows
+// the routine to be passed a point index array which is
+// assumed to be of the proper size (n). Otherwise, one is
+// allocated and initialized to the identity. Warning: In
+// either case the destructor will deallocate this array.
+//
+// As a kludge, we need to allocate KD_TRIVIAL if one has not
+// already been allocated. (This is because I'm too dumb to
+// figure out how to cause a pointer to be allocated at load
+// time.)
+//----------------------------------------------------------------------
+
+void ANNkd_tree::SkeletonTree( // construct skeleton tree
+ int n, // number of points
+ int dd, // dimension
+ int bs, // bucket size
+ ANNpointArray pa, // point array
+ ANNidxArray pi) // point indices
+{
+ dim = dd; // initialize basic elements
+ n_pts = n;
+ bkt_size = bs;
+ pts = pa; // initialize points array
+
+ root = NULL; // no associated tree yet
+
+ if (pi == NULL) { // point indices provided?
+ pidx = new ANNidx[n]; // no, allocate space for point indices
+ for (int i = 0; i < n; i++) {
+ pidx[i] = i; // initially identity
+ }
+ }
+ else {
+ pidx = pi; // yes, use them
+ }
+
+ bnd_box_lo = bnd_box_hi = NULL; // bounding box is nonexistent
+ if (KD_TRIVIAL == NULL) // no trivial leaf node yet?
+ KD_TRIVIAL = new ANNkd_leaf(0, IDX_TRIVIAL); // allocate it
+}
+
+ANNkd_tree::ANNkd_tree( // basic constructor
+ int n, // number of points
+ int dd, // dimension
+ int bs) // bucket size
+{ SkeletonTree(n, dd, bs); } // construct skeleton tree
+
+//----------------------------------------------------------------------
+// rkd_tree - recursive procedure to build a kd-tree
+//
+// Builds a kd-tree for points in pa as indexed through the
+// array pidx[0..n-1] (typically a subarray of the array used in
+// the top-level call). This routine permutes the array pidx,
+// but does not alter pa[].
+//
+// The construction is based on a standard algorithm for constructing
+// the kd-tree (see Friedman, Bentley, and Finkel, ``An algorithm for
+// finding best matches in logarithmic expected time,'' ACM Transactions
+// on Mathematical Software, 3(3):209-226, 1977). The procedure
+// operates by a simple divide-and-conquer strategy, which determines
+// an appropriate orthogonal cutting plane (see below), and splits
+// the points. When the number of points falls below the bucket size,
+// we simply store the points in a leaf node's bucket.
+//
+// One of the arguments is a pointer to a splitting routine,
+// whose prototype is:
+//
+// void split(
+// ANNpointArray pa, // complete point array
+// ANNidxArray pidx, // point array (permuted on return)
+// ANNorthRect &bnds, // bounds of current cell
+// int n, // number of points
+// int dim, // dimension of space
+// int &cut_dim, // cutting dimension
+// ANNcoord &cut_val, // cutting value
+// int &n_lo) // no. of points on low side of cut
+//
+// This procedure selects a cutting dimension and cutting value,
+// partitions pa about these values, and returns the number of
+// points on the low side of the cut.
+//----------------------------------------------------------------------
+
+ANNkd_ptr rkd_tree( // recursive construction of kd-tree
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices to store in subtree
+ int n, // number of points
+ int dim, // dimension of space
+ int bsp, // bucket space
+ ANNorthRect &bnd_box, // bounding box for current node
+ ANNkd_splitter splitter) // splitting routine
+{
+ if (n <= bsp) { // n small, make a leaf node
+ if (n == 0) // empty leaf node
+ return KD_TRIVIAL; // return (canonical) empty leaf
+ else // construct the node and return
+ return new ANNkd_leaf(n, pidx);
+ }
+ else { // n large, make a splitting node
+ int cd; // cutting dimension
+ ANNcoord cv; // cutting value
+ int n_lo; // number on low side of cut
+ ANNkd_node *lo, *hi; // low and high children
+
+ // invoke splitting procedure
+ (*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo);
+
+ ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension
+ ANNcoord hv = bnd_box.hi[cd];
+
+ bnd_box.hi[cd] = cv; // modify bounds for left subtree
+ lo = rkd_tree( // build left subtree
+ pa, pidx, n_lo, // ...from pidx[0..n_lo-1]
+ dim, bsp, bnd_box, splitter);
+ bnd_box.hi[cd] = hv; // restore bounds
+
+ bnd_box.lo[cd] = cv; // modify bounds for right subtree
+ hi = rkd_tree( // build right subtree
+ pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1]
+ dim, bsp, bnd_box, splitter);
+ bnd_box.lo[cd] = lv; // restore bounds
+
+ // create the splitting node
+ ANNkd_split *ptr = new ANNkd_split(cd, cv, lv, hv, lo, hi);
+
+ return ptr; // return pointer to this node
+ }
+}
+
+//----------------------------------------------------------------------
+// kd-tree constructor
+// This is the main constructor for kd-trees given a set of points.
+// It first builds a skeleton tree, then computes the bounding box
+// of the data points, and then invokes rkd_tree() to actually
+// build the tree, passing it the appropriate splitting routine.
+//----------------------------------------------------------------------
+
+ANNkd_tree::ANNkd_tree( // construct from point array
+ ANNpointArray pa, // point array (with at least n pts)
+ int n, // number of points
+ int dd, // dimension
+ int bs, // bucket size
+ ANNsplitRule split) // splitting method
+{
+ SkeletonTree(n, dd, bs); // set up the basic stuff
+ pts = pa; // where the points are
+ if (n == 0) return; // no points--no sweat
+
+ ANNorthRect bnd_box(dd); // bounding box for points
+ annEnclRect(pa, pidx, n, dd, bnd_box);// construct bounding rectangle
+ // copy to tree structure
+ bnd_box_lo = annCopyPt(dd, bnd_box.lo);
+ bnd_box_hi = annCopyPt(dd, bnd_box.hi);
+
+ switch (split) { // build by rule
+ case ANN_KD_STD: // standard kd-splitting rule
+ root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split);
+ break;
+ case ANN_KD_MIDPT: // midpoint split
+ root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split);
+ break;
+ case ANN_KD_FAIR: // fair split
+ root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split);
+ break;
+ case ANN_KD_SUGGEST: // best (in our opinion)
+ case ANN_KD_SL_MIDPT: // sliding midpoint split
+ root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split);
+ break;
+ case ANN_KD_SL_FAIR: // sliding fair split
+ root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_fair_split);
+ break;
+ default:
+ annError("Illegal splitting method", ANNabort);
+ }
+}
diff --git a/Contrib/ANN/src/kd_tree.h b/Contrib/ANN/src/kd_tree.h
new file mode 100755
index 0000000..81284b6
--- /dev/null
+++ b/Contrib/ANN/src/kd_tree.h
@@ -0,0 +1,197 @@
+//----------------------------------------------------------------------
+// File: kd_tree.h
+// Programmer: Sunil Arya and David Mount
+// Description: Declarations for standard kd-tree routines
+// Last modified: 05/03/05 (Version 1.1)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.1 05/03/05
+// Added fixed radius kNN search
+//----------------------------------------------------------------------
+
+#ifndef ANN_kd_tree_H
+#define ANN_kd_tree_H
+
+#include <ANN/ANNx.h> // all ANN includes
+
+using namespace std; // make std:: available
+
+//----------------------------------------------------------------------
+// Generic kd-tree node
+//
+// Nodes in kd-trees are of two types, splitting nodes which contain
+// splitting information (a splitting hyperplane orthogonal to one
+// of the coordinate axes) and leaf nodes which contain point
+// information (an array of points stored in a bucket). This is
+// handled by making a generic class kd_node, which is essentially an
+// empty shell, and then deriving the leaf and splitting nodes from
+// this.
+//----------------------------------------------------------------------
+
+class ANNkd_node{ // generic kd-tree node (empty shell)
+public:
+ virtual ~ANNkd_node() {} // virtual distroyer
+
+ virtual void ann_search(ANNdist) = 0; // tree search
+ virtual void ann_pri_search(ANNdist) = 0; // priority search
+ virtual void ann_FR_search(ANNdist) = 0; // fixed-radius search
+
+ virtual void getStats( // get tree statistics
+ int dim, // dimension of space
+ ANNkdStats &st, // statistics
+ ANNorthRect &bnd_box) = 0; // bounding box
+ // print node
+ virtual void print(int level, ostream &out) = 0;
+ virtual void dump(ostream &out) = 0; // dump node
+
+ friend class ANNkd_tree; // allow kd-tree to access us
+};
+
+//----------------------------------------------------------------------
+// kd-splitting function:
+// kd_splitter is a pointer to a splitting routine for preprocessing.
+// Different splitting procedures result in different strategies
+// for building the tree.
+//----------------------------------------------------------------------
+
+typedef void (*ANNkd_splitter)( // splitting routine for kd-trees
+ ANNpointArray pa, // point array (unaltered)
+ ANNidxArray pidx, // point indices (permuted on return)
+ const ANNorthRect &bnds, // bounding rectangle for cell
+ int n, // number of points
+ int dim, // dimension of space
+ int &cut_dim, // cutting dimension (returned)
+ ANNcoord &cut_val, // cutting value (returned)
+ int &n_lo); // num of points on low side (returned)
+
+//----------------------------------------------------------------------
+// Leaf kd-tree node
+// Leaf nodes of the kd-tree store the set of points associated
+// with this bucket, stored as an array of point indices. These
+// are indices in the array points, which resides with the
+// root of the kd-tree. We also store the number of points
+// that reside in this bucket.
+//----------------------------------------------------------------------
+
+class ANNkd_leaf: public ANNkd_node // leaf node for kd-tree
+{
+ int n_pts; // no. points in bucket
+ ANNidxArray bkt; // bucket of points
+public:
+ ANNkd_leaf( // constructor
+ int n, // number of points
+ ANNidxArray b) // bucket
+ {
+ n_pts = n; // number of points in bucket
+ bkt = b; // the bucket
+ }
+
+ ~ANNkd_leaf() { } // destructor (none)
+
+ virtual void getStats( // get tree statistics
+ int dim, // dimension of space
+ ANNkdStats &st, // statistics
+ ANNorthRect &bnd_box); // bounding box
+ virtual void print(int level, ostream &out);// print node
+ virtual void dump(ostream &out); // dump node
+
+ virtual void ann_search(ANNdist); // standard search
+ virtual void ann_pri_search(ANNdist); // priority search
+ virtual void ann_FR_search(ANNdist); // fixed-radius search
+};
+
+//----------------------------------------------------------------------
+// KD_TRIVIAL is a special pointer to an empty leaf node. Since
+// some splitting rules generate many (more than 50%) trivial
+// leaves, we use this one shared node to save space.
+//
+// The pointer is initialized to NULL, but whenever a kd-tree is
+// created, we allocate this node, if it has not already been
+// allocated. This node is *never* deallocated, so it produces
+// a small memory leak.
+//----------------------------------------------------------------------
+
+extern ANNkd_leaf *KD_TRIVIAL; // trivial (empty) leaf node
+
+//----------------------------------------------------------------------
+// kd-tree splitting node.
+// Splitting nodes contain a cutting dimension and a cutting value.
+// These indicate the axis-parellel plane which subdivide the
+// box for this node. The extent of the bounding box along the
+// cutting dimension is maintained (this is used to speed up point
+// to box distance calculations) [we do not store the entire bounding
+// box since this may be wasteful of space in high dimensions].
+// We also store pointers to the 2 children.
+//----------------------------------------------------------------------
+
+class ANNkd_split : public ANNkd_node // splitting node of a kd-tree
+{
+ int cut_dim; // dim orthogonal to cutting plane
+ ANNcoord cut_val; // location of cutting plane
+ ANNcoord cd_bnds[2]; // lower and upper bounds of
+ // rectangle along cut_dim
+ ANNkd_ptr child[2]; // left and right children
+public:
+ ANNkd_split( // constructor
+ int cd, // cutting dimension
+ ANNcoord cv, // cutting value
+ ANNcoord lv, ANNcoord hv, // low and high values
+ ANNkd_ptr lc=NULL, ANNkd_ptr hc=NULL) // children
+ {
+ cut_dim = cd; // cutting dimension
+ cut_val = cv; // cutting value
+ cd_bnds[ANN_LO] = lv; // lower bound for rectangle
+ cd_bnds[ANN_HI] = hv; // upper bound for rectangle
+ child[ANN_LO] = lc; // left child
+ child[ANN_HI] = hc; // right child
+ }
+
+ ~ANNkd_split() // destructor
+ {
+ if (child[ANN_LO]!= NULL && child[ANN_LO]!= KD_TRIVIAL)
+ delete child[ANN_LO];
+ if (child[ANN_HI]!= NULL && child[ANN_HI]!= KD_TRIVIAL)
+ delete child[ANN_HI];
+ }
+
+ virtual void getStats( // get tree statistics
+ int dim, // dimension of space
+ ANNkdStats &st, // statistics
+ ANNorthRect &bnd_box); // bounding box
+ virtual void print(int level, ostream &out);// print node
+ virtual void dump(ostream &out); // dump node
+
+ virtual void ann_search(ANNdist); // standard search
+ virtual void ann_pri_search(ANNdist); // priority search
+ virtual void ann_FR_search(ANNdist); // fixed-radius search
+};
+
+//----------------------------------------------------------------------
+// External entry points
+//----------------------------------------------------------------------
+
+ANNkd_ptr rkd_tree( // recursive construction of kd-tree
+ ANNpointArray pa, // point array (unaltered)
+ ANNidxArray pidx, // point indices to store in subtree
+ int n, // number of points
+ int dim, // dimension of space
+ int bsp, // bucket space
+ ANNorthRect &bnd_box, // bounding box for current node
+ ANNkd_splitter splitter); // splitting routine
+
+#endif
diff --git a/Contrib/ANN/src/kd_util.cpp b/Contrib/ANN/src/kd_util.cpp
new file mode 100755
index 0000000..06d65b8
--- /dev/null
+++ b/Contrib/ANN/src/kd_util.cpp
@@ -0,0 +1,439 @@
+//----------------------------------------------------------------------
+// File: kd_util.cpp
+// Programmer: Sunil Arya and David Mount
+// Description: Common utilities for kd-trees
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+//----------------------------------------------------------------------
+
+#include "kd_util.h" // kd-utility declarations
+
+#include <ANN/ANNperf.h> // performance evaluation
+
+//----------------------------------------------------------------------
+// The following routines are utility functions for manipulating
+// points sets, used in determining splitting planes for kd-tree
+// construction.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// NOTE: Virtually all point indexing is done through an index (i.e.
+// permutation) array pidx. Consequently, a reference to the d-th
+// coordinate of the i-th point is pa[pidx[i]][d]. The macro PA(i,d)
+// is a shorthand for this.
+//----------------------------------------------------------------------
+ // standard 2-d indirect indexing
+#define PA(i,d) (pa[pidx[(i)]][(d)])
+ // accessing a single point
+#define PP(i) (pa[pidx[(i)]])
+
+//----------------------------------------------------------------------
+// annAspectRatio
+// Compute the aspect ratio (ratio of longest to shortest side)
+// of a rectangle.
+//----------------------------------------------------------------------
+
+double annAspectRatio(
+ int dim, // dimension
+ const ANNorthRect &bnd_box) // bounding cube
+{
+ ANNcoord length = bnd_box.hi[0] - bnd_box.lo[0];
+ ANNcoord min_length = length; // min side length
+ ANNcoord max_length = length; // max side length
+ for (int d = 0; d < dim; d++) {
+ length = bnd_box.hi[d] - bnd_box.lo[d];
+ if (length < min_length) min_length = length;
+ if (length > max_length) max_length = length;
+ }
+ return max_length/min_length;
+}
+
+//----------------------------------------------------------------------
+// annEnclRect, annEnclCube
+// These utilities compute the smallest rectangle and cube enclosing
+// a set of points, respectively.
+//----------------------------------------------------------------------
+
+void annEnclRect(
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int dim, // dimension
+ ANNorthRect &bnds) // bounding cube (returned)
+{
+ for (int d = 0; d < dim; d++) { // find smallest enclosing rectangle
+ ANNcoord lo_bnd = PA(0,d); // lower bound on dimension d
+ ANNcoord hi_bnd = PA(0,d); // upper bound on dimension d
+ for (int i = 0; i < n; i++) {
+ if (PA(i,d) < lo_bnd) lo_bnd = PA(i,d);
+ else if (PA(i,d) > hi_bnd) hi_bnd = PA(i,d);
+ }
+ bnds.lo[d] = lo_bnd;
+ bnds.hi[d] = hi_bnd;
+ }
+}
+
+void annEnclCube( // compute smallest enclosing cube
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int dim, // dimension
+ ANNorthRect &bnds) // bounding cube (returned)
+{
+ int d;
+ // compute smallest enclosing rect
+ annEnclRect(pa, pidx, n, dim, bnds);
+
+ ANNcoord max_len = 0; // max length of any side
+ for (d = 0; d < dim; d++) { // determine max side length
+ ANNcoord len = bnds.hi[d] - bnds.lo[d];
+ if (len > max_len) { // update max_len if longest
+ max_len = len;
+ }
+ }
+ for (d = 0; d < dim; d++) { // grow sides to match max
+ ANNcoord len = bnds.hi[d] - bnds.lo[d];
+ ANNcoord half_diff = (max_len - len) / 2;
+ bnds.lo[d] -= half_diff;
+ bnds.hi[d] += half_diff;
+ }
+}
+
+//----------------------------------------------------------------------
+// annBoxDistance - utility routine which computes distance from point to
+// box (Note: most distances to boxes are computed using incremental
+// distance updates, not this function.)
+//----------------------------------------------------------------------
+
+ANNdist annBoxDistance( // compute distance from point to box
+ const ANNpoint q, // the point
+ const ANNpoint lo, // low point of box
+ const ANNpoint hi, // high point of box
+ int dim) // dimension of space
+{
+ register ANNdist dist = 0.0; // sum of squared distances
+ register ANNdist t;
+
+ for (register int d = 0; d < dim; d++) {
+ if (q[d] < lo[d]) { // q is left of box
+ t = ANNdist(lo[d]) - ANNdist(q[d]);
+ dist = ANN_SUM(dist, ANN_POW(t));
+ }
+ else if (q[d] > hi[d]) { // q is right of box
+ t = ANNdist(q[d]) - ANNdist(hi[d]);
+ dist = ANN_SUM(dist, ANN_POW(t));
+ }
+ }
+ ANN_FLOP(4*dim) // increment floating op count
+
+ return dist;
+}
+
+//----------------------------------------------------------------------
+// annSpread - find spread along given dimension
+// annMinMax - find min and max coordinates along given dimension
+// annMaxSpread - find dimension of max spread
+//----------------------------------------------------------------------
+
+ANNcoord annSpread( // compute point spread along dimension
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int d) // dimension to check
+{
+ ANNcoord min = PA(0,d); // compute max and min coords
+ ANNcoord max = PA(0,d);
+ for (int i = 1; i < n; i++) {
+ ANNcoord c = PA(i,d);
+ if (c < min) min = c;
+ else if (c > max) max = c;
+ }
+ return (max - min); // total spread is difference
+}
+
+void annMinMax( // compute min and max coordinates along dim
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int d, // dimension to check
+ ANNcoord &min, // minimum value (returned)
+ ANNcoord &max) // maximum value (returned)
+{
+ min = PA(0,d); // compute max and min coords
+ max = PA(0,d);
+ for (int i = 1; i < n; i++) {
+ ANNcoord c = PA(i,d);
+ if (c < min) min = c;
+ else if (c > max) max = c;
+ }
+}
+
+int annMaxSpread( // compute dimension of max spread
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int dim) // dimension of space
+{
+ int max_dim = 0; // dimension of max spread
+ ANNcoord max_spr = 0; // amount of max spread
+
+ if (n == 0) return max_dim; // no points, who cares?
+
+ for (int d = 0; d < dim; d++) { // compute spread along each dim
+ ANNcoord spr = annSpread(pa, pidx, n, d);
+ if (spr > max_spr) { // bigger than current max
+ max_spr = spr;
+ max_dim = d;
+ }
+ }
+ return max_dim;
+}
+
+//----------------------------------------------------------------------
+// annMedianSplit - split point array about its median
+// Splits a subarray of points pa[0..n] about an element of given
+// rank (median: n_lo = n/2) with respect to dimension d. It places
+// the element of rank n_lo-1 correctly (because our splitting rule
+// takes the mean of these two). On exit, the array is permuted so
+// that:
+//
+// pa[0..n_lo-2][d] <= pa[n_lo-1][d] <= pa[n_lo][d] <= pa[n_lo+1..n-1][d].
+//
+// The mean of pa[n_lo-1][d] and pa[n_lo][d] is returned as the
+// splitting value.
+//
+// All indexing is done indirectly through the index array pidx.
+//
+// This function uses the well known selection algorithm due to
+// C.A.R. Hoare.
+//----------------------------------------------------------------------
+
+ // swap two points in pa array
+#define PASWAP(a,b) { int tmp = pidx[a]; pidx[a] = pidx[b]; pidx[b] = tmp; }
+
+void annMedianSplit(
+ ANNpointArray pa, // points to split
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int d, // dimension along which to split
+ ANNcoord &cv, // cutting value
+ int n_lo) // split into n_lo and n-n_lo
+{
+ int l = 0; // left end of current subarray
+ int r = n-1; // right end of current subarray
+ while (l < r) {
+ register int i = (r+l)/2; // select middle as pivot
+ register int k;
+
+ if (PA(i,d) > PA(r,d)) // make sure last > pivot
+ PASWAP(i,r)
+ PASWAP(l,i); // move pivot to first position
+
+ ANNcoord c = PA(l,d); // pivot value
+ i = l;
+ k = r;
+ for(;;) { // pivot about c
+ while (PA(++i,d) < c) ;
+ while (PA(--k,d) > c) ;
+ if (i < k) PASWAP(i,k) else break;
+ }
+ PASWAP(l,k); // pivot winds up in location k
+
+ if (k > n_lo) r = k-1; // recurse on proper subarray
+ else if (k < n_lo) l = k+1;
+ else break; // got the median exactly
+ }
+ if (n_lo > 0) { // search for next smaller item
+ ANNcoord c = PA(0,d); // candidate for max
+ int k = 0; // candidate's index
+ for (int i = 1; i < n_lo; i++) {
+ if (PA(i,d) > c) {
+ c = PA(i,d);
+ k = i;
+ }
+ }
+ PASWAP(n_lo-1, k); // max among pa[0..n_lo-1] to pa[n_lo-1]
+ }
+ // cut value is midpoint value
+ cv = (PA(n_lo-1,d) + PA(n_lo,d))/2.0;
+}
+
+//----------------------------------------------------------------------
+// annPlaneSplit - split point array about a cutting plane
+// Split the points in an array about a given plane along a
+// given cutting dimension. On exit, br1 and br2 are set so
+// that:
+//
+// pa[ 0 ..br1-1] < cv
+// pa[br1..br2-1] == cv
+// pa[br2.. n -1] > cv
+//
+// All indexing is done indirectly through the index array pidx.
+//
+//----------------------------------------------------------------------
+
+void annPlaneSplit( // split points by a plane
+ ANNpointArray pa, // points to split
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int d, // dimension along which to split
+ ANNcoord cv, // cutting value
+ int &br1, // first break (values < cv)
+ int &br2) // second break (values == cv)
+{
+ int l = 0;
+ int r = n-1;
+ for(;;) { // partition pa[0..n-1] about cv
+ while (l < n && PA(l,d) < cv) l++;
+ while (r >= 0 && PA(r,d) >= cv) r--;
+ if (l > r) break;
+ PASWAP(l,r);
+ l++; r--;
+ }
+ br1 = l; // now: pa[0..br1-1] < cv <= pa[br1..n-1]
+ r = n-1;
+ for(;;) { // partition pa[br1..n-1] about cv
+ while (l < n && PA(l,d) <= cv) l++;
+ while (r >= br1 && PA(r,d) > cv) r--;
+ if (l > r) break;
+ PASWAP(l,r);
+ l++; r--;
+ }
+ br2 = l; // now: pa[br1..br2-1] == cv < pa[br2..n-1]
+}
+
+
+//----------------------------------------------------------------------
+// annBoxSplit - split point array about a orthogonal rectangle
+// Split the points in an array about a given orthogonal
+// rectangle. On exit, n_in is set to the number of points
+// that are inside (or on the boundary of) the rectangle.
+//
+// All indexing is done indirectly through the index array pidx.
+//
+//----------------------------------------------------------------------
+
+void annBoxSplit( // split points by a box
+ ANNpointArray pa, // points to split
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int dim, // dimension of space
+ ANNorthRect &box, // the box
+ int &n_in) // number of points inside (returned)
+{
+ int l = 0;
+ int r = n-1;
+ for(;;) { // partition pa[0..n-1] about box
+ while (l < n && box.inside(dim, PP(l))) l++;
+ while (r >= 0 && !box.inside(dim, PP(r))) r--;
+ if (l > r) break;
+ PASWAP(l,r);
+ l++; r--;
+ }
+ n_in = l; // now: pa[0..n_in-1] inside and rest outside
+}
+
+//----------------------------------------------------------------------
+// annSplitBalance - compute balance factor for a given plane split
+// Balance factor is defined as the number of points lying
+// below the splitting value minus n/2 (median). Thus, a
+// median split has balance 0, left of this is negative and
+// right of this is positive. (The points are unchanged.)
+//----------------------------------------------------------------------
+
+int annSplitBalance( // determine balance factor of a split
+ ANNpointArray pa, // points to split
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int d, // dimension along which to split
+ ANNcoord cv) // cutting value
+{
+ int n_lo = 0;
+ for(int i = 0; i < n; i++) { // count number less than cv
+ if (PA(i,d) < cv) n_lo++;
+ }
+ return n_lo - n/2;
+}
+
+//----------------------------------------------------------------------
+// annBox2Bnds - convert bounding box to list of bounds
+// Given two boxes, an inner box enclosed within a bounding
+// box, this routine determines all the sides for which the
+// inner box is strictly contained with the bounding box,
+// and adds an appropriate entry to a list of bounds. Then
+// we allocate storage for the final list of bounds, and return
+// the resulting list and its size.
+//----------------------------------------------------------------------
+
+void annBox2Bnds( // convert inner box to bounds
+ const ANNorthRect &inner_box, // inner box
+ const ANNorthRect &bnd_box, // enclosing box
+ int dim, // dimension of space
+ int &n_bnds, // number of bounds (returned)
+ ANNorthHSArray &bnds) // bounds array (returned)
+{
+ int i;
+ n_bnds = 0; // count number of bounds
+ for (i = 0; i < dim; i++) {
+ if (inner_box.lo[i] > bnd_box.lo[i]) // low bound is inside
+ n_bnds++;
+ if (inner_box.hi[i] < bnd_box.hi[i]) // high bound is inside
+ n_bnds++;
+ }
+
+ bnds = new ANNorthHalfSpace[n_bnds]; // allocate appropriate size
+
+ int j = 0;
+ for (i = 0; i < dim; i++) { // fill the array
+ if (inner_box.lo[i] > bnd_box.lo[i]) {
+ bnds[j].cd = i;
+ bnds[j].cv = inner_box.lo[i];
+ bnds[j].sd = +1;
+ j++;
+ }
+ if (inner_box.hi[i] < bnd_box.hi[i]) {
+ bnds[j].cd = i;
+ bnds[j].cv = inner_box.hi[i];
+ bnds[j].sd = -1;
+ j++;
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// annBnds2Box - convert list of bounds to bounding box
+// Given an enclosing box and a list of bounds, this routine
+// computes the corresponding inner box. It is assumed that
+// the box points have been allocated already.
+//----------------------------------------------------------------------
+
+void annBnds2Box(
+ const ANNorthRect &bnd_box, // enclosing box
+ int dim, // dimension of space
+ int n_bnds, // number of bounds
+ ANNorthHSArray bnds, // bounds array
+ ANNorthRect &inner_box) // inner box (returned)
+{
+ annAssignRect(dim, inner_box, bnd_box); // copy bounding box to inner
+
+ for (int i = 0; i < n_bnds; i++) {
+ bnds[i].project(inner_box.lo); // project each endpoint
+ bnds[i].project(inner_box.hi);
+ }
+}
diff --git a/Contrib/ANN/src/kd_util.h b/Contrib/ANN/src/kd_util.h
new file mode 100755
index 0000000..6b43430
--- /dev/null
+++ b/Contrib/ANN/src/kd_util.h
@@ -0,0 +1,124 @@
+//----------------------------------------------------------------------
+// File: kd_util.h
+// Programmer: Sunil Arya and David Mount
+// Description: Common utilities for kd- trees
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+//----------------------------------------------------------------------
+
+#ifndef ANN_kd_util_H
+#define ANN_kd_util_H
+
+#include "kd_tree.h" // kd-tree declarations
+
+//----------------------------------------------------------------------
+// externally accessible functions
+//----------------------------------------------------------------------
+
+double annAspectRatio( // compute aspect ratio of box
+ int dim, // dimension
+ const ANNorthRect &bnd_box); // bounding cube
+
+void annEnclRect( // compute smallest enclosing rectangle
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int dim, // dimension
+ ANNorthRect &bnds); // bounding cube (returned)
+
+void annEnclCube( // compute smallest enclosing cube
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int dim, // dimension
+ ANNorthRect &bnds); // bounding cube (returned)
+
+ANNdist annBoxDistance( // compute distance from point to box
+ const ANNpoint q, // the point
+ const ANNpoint lo, // low point of box
+ const ANNpoint hi, // high point of box
+ int dim); // dimension of space
+
+ANNcoord annSpread( // compute point spread along dimension
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int d); // dimension to check
+
+void annMinMax( // compute min and max coordinates along dim
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int d, // dimension to check
+ ANNcoord& min, // minimum value (returned)
+ ANNcoord& max); // maximum value (returned)
+
+int annMaxSpread( // compute dimension of max spread
+ ANNpointArray pa, // point array
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int dim); // dimension of space
+
+void annMedianSplit( // split points along median value
+ ANNpointArray pa, // points to split
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int d, // dimension along which to split
+ ANNcoord &cv, // cutting value
+ int n_lo); // split into n_lo and n-n_lo
+
+void annPlaneSplit( // split points by a plane
+ ANNpointArray pa, // points to split
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int d, // dimension along which to split
+ ANNcoord cv, // cutting value
+ int &br1, // first break (values < cv)
+ int &br2); // second break (values == cv)
+
+void annBoxSplit( // split points by a box
+ ANNpointArray pa, // points to split
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int dim, // dimension of space
+ ANNorthRect &box, // the box
+ int &n_in); // number of points inside (returned)
+
+int annSplitBalance( // determine balance factor of a split
+ ANNpointArray pa, // points to split
+ ANNidxArray pidx, // point indices
+ int n, // number of points
+ int d, // dimension along which to split
+ ANNcoord cv); // cutting value
+
+void annBox2Bnds( // convert inner box to bounds
+ const ANNorthRect &inner_box, // inner box
+ const ANNorthRect &bnd_box, // enclosing box
+ int dim, // dimension of space
+ int &n_bnds, // number of bounds (returned)
+ ANNorthHSArray &bnds); // bounds array (returned)
+
+void annBnds2Box( // convert bounds to inner box
+ const ANNorthRect &bnd_box, // enclosing box
+ int dim, // dimension of space
+ int n_bnds, // number of bounds
+ ANNorthHSArray bnds, // bounds array
+ ANNorthRect &inner_box); // inner box (returned)
+
+#endif
diff --git a/Contrib/ANN/src/perf.cpp b/Contrib/ANN/src/perf.cpp
new file mode 100755
index 0000000..91bb044
--- /dev/null
+++ b/Contrib/ANN/src/perf.cpp
@@ -0,0 +1,134 @@
+//----------------------------------------------------------------------
+// File: perf.cpp
+// Programmer: Sunil Arya and David Mount
+// Description: Methods for performance stats
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+// Revision 1.0 04/01/05
+// Changed names to avoid namespace conflicts.
+// Added flush after printing performance stats to fix bug
+// in Microsoft Windows version.
+//----------------------------------------------------------------------
+
+#include <ANN/ANN.h> // basic ANN includes
+#include <ANN/ANNperf.h> // performance includes
+
+using namespace std; // make std:: available
+
+//----------------------------------------------------------------------
+// Performance statistics
+// The following data and routines are used for computing
+// performance statistics for nearest neighbor searching.
+// Because these routines can slow the code down, they can be
+// activated and deactiviated by defining the PERF variable,
+// by compiling with the option: -DPERF
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// Global counters for performance measurement
+//----------------------------------------------------------------------
+
+int ann_Ndata_pts = 0; // number of data points
+int ann_Nvisit_lfs = 0; // number of leaf nodes visited
+int ann_Nvisit_spl = 0; // number of splitting nodes visited
+int ann_Nvisit_shr = 0; // number of shrinking nodes visited
+int ann_Nvisit_pts = 0; // visited points for one query
+int ann_Ncoord_hts = 0; // coordinate hits for one query
+int ann_Nfloat_ops = 0; // floating ops for one query
+ANNsampStat ann_visit_lfs; // stats on leaf nodes visits
+ANNsampStat ann_visit_spl; // stats on splitting nodes visits
+ANNsampStat ann_visit_shr; // stats on shrinking nodes visits
+ANNsampStat ann_visit_nds; // stats on total nodes visits
+ANNsampStat ann_visit_pts; // stats on points visited
+ANNsampStat ann_coord_hts; // stats on coordinate hits
+ANNsampStat ann_float_ops; // stats on floating ops
+//
+ANNsampStat ann_average_err; // average error
+ANNsampStat ann_rank_err; // rank error
+
+//----------------------------------------------------------------------
+// Routines for statistics.
+//----------------------------------------------------------------------
+
+DLL_API void annResetStats(int data_size) // reset stats for a set of queries
+{
+ ann_Ndata_pts = data_size;
+ ann_visit_lfs.reset();
+ ann_visit_spl.reset();
+ ann_visit_shr.reset();
+ ann_visit_nds.reset();
+ ann_visit_pts.reset();
+ ann_coord_hts.reset();
+ ann_float_ops.reset();
+ ann_average_err.reset();
+ ann_rank_err.reset();
+}
+
+DLL_API void annResetCounts() // reset counts for one query
+{
+ ann_Nvisit_lfs = 0;
+ ann_Nvisit_spl = 0;
+ ann_Nvisit_shr = 0;
+ ann_Nvisit_pts = 0;
+ ann_Ncoord_hts = 0;
+ ann_Nfloat_ops = 0;
+}
+
+DLL_API void annUpdateStats() // update stats with current counts
+{
+ ann_visit_lfs += ann_Nvisit_lfs;
+ ann_visit_nds += ann_Nvisit_spl + ann_Nvisit_lfs;
+ ann_visit_spl += ann_Nvisit_spl;
+ ann_visit_shr += ann_Nvisit_shr;
+ ann_visit_pts += ann_Nvisit_pts;
+ ann_coord_hts += ann_Ncoord_hts;
+ ann_float_ops += ann_Nfloat_ops;
+}
+
+ // print a single statistic
+void print_one_stat(char *title, ANNsampStat s, double div)
+{
+ cout << title << "= [ ";
+ cout.width(9); cout << s.mean()/div << " : ";
+ cout.width(9); cout << s.stdDev()/div << " ]<";
+ cout.width(9); cout << s.min()/div << " , ";
+ cout.width(9); cout << s.max()/div << " >\n";
+}
+
+DLL_API void annPrintStats( // print statistics for a run
+ ANNbool validate) // true if average errors desired
+{
+ cout.precision(4); // set floating precision
+ cout << " (Performance stats: "
+ << " [ mean : stddev ]< min , max >\n";
+ print_one_stat(" leaf_nodes ", ann_visit_lfs, 1);
+ print_one_stat(" splitting_nodes ", ann_visit_spl, 1);
+ print_one_stat(" shrinking_nodes ", ann_visit_shr, 1);
+ print_one_stat(" total_nodes ", ann_visit_nds, 1);
+ print_one_stat(" points_visited ", ann_visit_pts, 1);
+ print_one_stat(" coord_hits/pt ", ann_coord_hts, ann_Ndata_pts);
+ print_one_stat(" floating_ops_(K) ", ann_float_ops, 1000);
+ if (validate) {
+ print_one_stat(" average_error ", ann_average_err, 1);
+ print_one_stat(" rank_error ", ann_rank_err, 1);
+ }
+ cout.precision(0); // restore the default
+ cout << " )\n";
+ cout.flush();
+}
diff --git a/Contrib/ANN/src/pr_queue.h b/Contrib/ANN/src/pr_queue.h
new file mode 100755
index 0000000..3f4b75c
--- /dev/null
+++ b/Contrib/ANN/src/pr_queue.h
@@ -0,0 +1,125 @@
+//----------------------------------------------------------------------
+// File: pr_queue.h
+// Programmer: Sunil Arya and David Mount
+// Description: Include file for priority queue and related
+// structures.
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+//----------------------------------------------------------------------
+
+#ifndef PR_QUEUE_H
+#define PR_QUEUE_H
+
+#include <ANN/ANNx.h> // all ANN includes
+#include <ANN/ANNperf.h> // performance evaluation
+
+//----------------------------------------------------------------------
+// Basic types.
+//----------------------------------------------------------------------
+typedef void *PQinfo; // info field is generic pointer
+typedef ANNdist PQkey; // key field is distance
+
+//----------------------------------------------------------------------
+// Priority queue
+// A priority queue is a list of items, along with associated
+// priorities. The basic operations are insert and extract_minimum.
+//
+// The priority queue is maintained using a standard binary heap.
+// (Implementation note: Indexing is performed from [1..max] rather
+// than the C standard of [0..max-1]. This simplifies parent/child
+// computations.) User information consists of a void pointer,
+// and the user is responsible for casting this quantity into whatever
+// useful form is desired.
+//
+// Because the priority queue is so central to the efficiency of
+// query processing, all the code is inline.
+//----------------------------------------------------------------------
+
+class ANNpr_queue {
+
+ struct pq_node { // node in priority queue
+ PQkey key; // key value
+ PQinfo info; // info field
+ };
+ int n; // number of items in queue
+ int max_size; // maximum queue size
+ pq_node *pq; // the priority queue (array of nodes)
+
+public:
+ ANNpr_queue(int max) // constructor (given max size)
+ {
+ n = 0; // initially empty
+ max_size = max; // maximum number of items
+ pq = new pq_node[max+1]; // queue is array [1..max] of nodes
+ }
+
+ ~ANNpr_queue() // destructor
+ { delete [] pq; }
+
+ ANNbool empty() // is queue empty?
+ { if (n==0) return ANNtrue; else return ANNfalse; }
+
+ ANNbool non_empty() // is queue nonempty?
+ { if (n==0) return ANNfalse; else return ANNtrue; }
+
+ void reset() // make existing queue empty
+ { n = 0; }
+
+ inline void insert( // insert item (inlined for speed)
+ PQkey kv, // key value
+ PQinfo inf) // item info
+ {
+ if (++n > max_size) annError("Priority queue overflow.", ANNabort);
+ register int r = n;
+ while (r > 1) { // sift up new item
+ register int p = r/2;
+ ANN_FLOP(1) // increment floating ops
+ if (pq[p].key <= kv) // in proper order
+ break;
+ pq[r] = pq[p]; // else swap with parent
+ r = p;
+ }
+ pq[r].key = kv; // insert new item at final location
+ pq[r].info = inf;
+ }
+
+ inline void extr_min( // extract minimum (inlined for speed)
+ PQkey &kv, // key (returned)
+ PQinfo &inf) // item info (returned)
+ {
+ kv = pq[1].key; // key of min item
+ inf = pq[1].info; // information of min item
+ register PQkey kn = pq[n--].key;// last item in queue
+ register int p = 1; // p points to item out of position
+ register int r = p<<1; // left child of p
+ while (r <= n) { // while r is still within the heap
+ ANN_FLOP(2) // increment floating ops
+ // set r to smaller child of p
+ if (r < n && pq[r].key > pq[r+1].key) r++;
+ if (kn <= pq[r].key) // in proper order
+ break;
+ pq[p] = pq[r]; // else swap with child
+ p = r; // advance pointers
+ r = p<<1;
+ }
+ pq[p] = pq[n+1]; // insert last item in proper place
+ }
+};
+
+#endif
diff --git a/Contrib/ANN/src/pr_queue_k.h b/Contrib/ANN/src/pr_queue_k.h
new file mode 100755
index 0000000..c2f01c3
--- /dev/null
+++ b/Contrib/ANN/src/pr_queue_k.h
@@ -0,0 +1,118 @@
+//----------------------------------------------------------------------
+// File: pr_queue_k.h
+// Programmer: Sunil Arya and David Mount
+// Description: Include file for priority queue with k items.
+// Last modified: 01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount. All Rights Reserved.
+//
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN). This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL). See the
+// file ../ReadMe.txt for further information.
+//
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose. It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+// Revision 0.1 03/04/98
+// Initial release
+//----------------------------------------------------------------------
+
+#ifndef PR_QUEUE_K_H
+#define PR_QUEUE_K_H
+
+#include <ANN/ANNx.h> // all ANN includes
+#include <ANN/ANNperf.h> // performance evaluation
+
+//----------------------------------------------------------------------
+// Basic types
+//----------------------------------------------------------------------
+typedef ANNdist PQKkey; // key field is distance
+typedef int PQKinfo; // info field is int
+
+//----------------------------------------------------------------------
+// Constants
+// The NULL key value is used to initialize the priority queue, and
+// so it should be larger than any valid distance, so that it will
+// be replaced as legal distance values are inserted. The NULL
+// info value must be a nonvalid array index, we use ANN_NULL_IDX,
+// which is guaranteed to be negative.
+//----------------------------------------------------------------------
+
+const PQKkey PQ_NULL_KEY = ANN_DIST_INF; // nonexistent key value
+const PQKinfo PQ_NULL_INFO = ANN_NULL_IDX; // nonexistent info value
+
+//----------------------------------------------------------------------
+// ANNmin_k
+// An ANNmin_k structure is one which maintains the smallest
+// k values (of type PQKkey) and associated information (of type
+// PQKinfo). The special info and key values PQ_NULL_INFO and
+// PQ_NULL_KEY means that thise entry is empty.
+//
+// It is currently implemented using an array with k items.
+// Items are stored in increasing sorted order, and insertions
+// are made through standard insertion sort. (This is quite
+// inefficient, but current applications call for small values
+// of k and relatively few insertions.)
+//
+// Note that the list contains k+1 entries, but the last entry
+// is used as a simple placeholder and is otherwise ignored.
+//----------------------------------------------------------------------
+
+class ANNmin_k {
+ struct mk_node { // node in min_k structure
+ PQKkey key; // key value
+ PQKinfo info; // info field (user defined)
+ };
+
+ int k; // max number of keys to store
+ int n; // number of keys currently active
+ mk_node *mk; // the list itself
+
+public:
+ ANNmin_k(int max) // constructor (given max size)
+ {
+ n = 0; // initially no items
+ k = max; // maximum number of items
+ mk = new mk_node[max+1]; // sorted array of keys
+ }
+
+ ~ANNmin_k() // destructor
+ { delete [] mk; }
+
+ PQKkey ANNmin_key() // return minimum key
+ { return (n > 0 ? mk[0].key : PQ_NULL_KEY); }
+
+ PQKkey max_key() // return maximum key
+ { return (n == k ? mk[k-1].key : PQ_NULL_KEY); }
+
+ PQKkey ith_smallest_key(int i) // ith smallest key (i in [0..n-1])
+ { return (i < n ? mk[i].key : PQ_NULL_KEY); }
+
+ PQKinfo ith_smallest_info(int i) // info for ith smallest (i in [0..n-1])
+ { return (i < n ? mk[i].info : PQ_NULL_INFO); }
+
+ inline void insert( // insert item (inlined for speed)
+ PQKkey kv, // key value
+ PQKinfo inf) // item info
+ {
+ register int i;
+ // slide larger values up
+ for (i = n; i > 0; i--) {
+ if (mk[i-1].key > kv)
+ mk[i] = mk[i-1];
+ else
+ break;
+ }
+ mk[i].key = kv; // store element here
+ mk[i].info = inf;
+ if (n < k) n++; // increment number of items
+ ANN_FLOP(k-i+1) // increment floating ops
+ }
+};
+
+#endif
diff --git a/Contrib/gmm/gmm.h b/Contrib/gmm/gmm.h
new file mode 100755
index 0000000..c6bd391
--- /dev/null
+++ b/Contrib/gmm/gmm.h
@@ -0,0 +1,53 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief Include common gmm files.
+*/
+#ifndef GMM_H__
+#define GMM_H__
+
+#include "gmm_kernel.h"
+#include "gmm_dense_lu.h"
+#include "gmm_dense_qr.h"
+
+#include "gmm_iter_solvers.h"
+#include "gmm_condition_number.h"
+#include "gmm_inoutput.h"
+
+#include "gmm_lapack_interface.h"
+#include "gmm_superlu_interface.h"
+
+
+#include "gmm_domain_decomp.h"
+
+#endif // GMM_H__
diff --git a/Contrib/gmm/gmm_MUMPS_interface.h b/Contrib/gmm/gmm_MUMPS_interface.h
new file mode 100755
index 0000000..a7c1401
--- /dev/null
+++ b/Contrib/gmm/gmm_MUMPS_interface.h
@@ -0,0 +1,306 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_MUMPS_interface.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>,
+ @author Julien Pommier <Julien.Pommier at insa-toulouse.fr>
+ @date December 8, 2005.
+ @brief Interface with MUMPS (LU direct solver for sparse matrices).
+*/
+#if defined(GMM_USES_MUMPS)
+
+#ifndef GMM_MUMPS_INTERFACE_H
+#define GMM_MUMPS_INTERFACE_H
+
+#include "gmm_kernel.h"
+
+
+extern "C" {
+
+#include <smumps_c.h>
+#undef F_INT
+#undef F_DOUBLE
+#undef F_DOUBLE2
+#include <dmumps_c.h>
+#undef F_INT
+#undef F_DOUBLE
+#undef F_DOUBLE2
+#include <cmumps_c.h>
+#undef F_INT
+#undef F_DOUBLE
+#undef F_DOUBLE2
+#include <zmumps_c.h>
+#undef F_INT
+#undef F_DOUBLE
+#undef F_DOUBLE2
+
+}
+
+namespace gmm {
+
+ template <typename T> struct ij_sparse_matrix {
+ std::vector<int> irn;
+ std::vector<int> jcn;
+ std::vector<T> a;
+
+ template <typename L> void store(const L& l, size_type i) {
+ typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
+ ite = vect_const_end(l);
+ for (; it != ite; ++it)
+ { irn.push_back(i + 1); jcn.push_back(it.index() + 1); a.push_back(*it); }
+ }
+
+ template <typename L> void build_from(const L& l, row_major) {
+ for (size_type i = 0; i < mat_nrows(l); ++i)
+ store(mat_const_row(l, i), i);
+ }
+
+ template <typename L> void build_from(const L& l, col_major) {
+ for (size_type i = 0; i < mat_ncols(l); ++i)
+ store(mat_const_col(l, i), i);
+ irn.swap(jcn);
+ }
+
+ template <typename L> ij_sparse_matrix(const L& A) {
+ size_type nz = nnz(A);
+ irn.reserve(nz); jcn.reserve(nz); a.reserve(nz);
+ build_from(A, typename principal_orientation_type<typename
+ linalg_traits<L>::sub_orientation>::potype());
+ }
+ };
+
+ /* ********************************************************************* */
+ /* MUMPS solve interface */
+ /* ********************************************************************* */
+
+
+ template <typename T> struct mumps_interf {};
+
+ template <> struct mumps_interf<float> {
+ typedef SMUMPS_STRUC_C MUMPS_STRUC_C;
+ typedef float value_type;
+
+ static void mumps_c(MUMPS_STRUC_C &id) { smumps_c(&id); }
+ };
+
+ template <> struct mumps_interf<double> {
+ typedef DMUMPS_STRUC_C MUMPS_STRUC_C;
+ typedef double value_type;
+ static void mumps_c(MUMPS_STRUC_C &id) { dmumps_c(&id); }
+ };
+
+ template <> struct mumps_interf<std::complex<float> > {
+ typedef CMUMPS_STRUC_C MUMPS_STRUC_C;
+ typedef mumps_complex value_type;
+ static void mumps_c(MUMPS_STRUC_C &id) { cmumps_c(&id); }
+ };
+
+ template <> struct mumps_interf<std::complex<double> > {
+ typedef ZMUMPS_STRUC_C MUMPS_STRUC_C;
+ typedef mumps_double_complex value_type;
+ static void mumps_c(MUMPS_STRUC_C &id) { zmumps_c(&id); }
+ };
+
+
+ /** MUMPS solve interface
+ * Works only with sparse or skyline matrices
+ */
+ template <typename MAT, typename VECTX, typename VECTB>
+ void MUMPS_solve(const MAT &A, const VECTX &X_, const VECTB &B) {
+ VECTX &X = const_cast<VECTX &>(X_);
+
+ typedef typename linalg_traits<MAT>::value_type T;
+ typedef typename mumps_interf<T>::value_type MUMPS_T;
+ GMM_ASSERT2(gmm::mat_nrows(A) == gmm::mat_ncols(A), "Non square matrix");
+
+ std::vector<T> rhs(gmm::vect_size(B)); gmm::copy(B, rhs);
+
+ ij_sparse_matrix<T> AA(A);
+
+ const int JOB_INIT = -1;
+ const int JOB_END = -2;
+ const int USE_COMM_WORLD = -987654;
+
+ typename mumps_interf<T>::MUMPS_STRUC_C id;
+
+#ifdef GMM_USES_MPI
+ int rank;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+#endif
+
+ id.job = JOB_INIT;
+ id.par = 1;
+ id.sym = 0;
+ id.comm_fortran = USE_COMM_WORLD;
+ mumps_interf<T>::mumps_c(id);
+
+#ifdef GMM_USES_MPI
+ if (rank == 0) {
+#endif
+ id.n = gmm::mat_nrows(A);
+ id.nz = AA.irn.size();
+ id.irn = &(AA.irn[0]);
+ id.jcn = &(AA.jcn[0]);
+ id.a = (MUMPS_T*)(&(AA.a[0]));
+ id.rhs = (MUMPS_T*)(&(rhs[0]));
+#ifdef GMM_USES_MPI
+ }
+#endif
+
+#define ICNTL(I) icntl[(I)-1]
+#define INFO(I) info[(I)-1]
+ id.ICNTL(1) = -1; id.ICNTL(2) = -1; id.ICNTL(3) = -1; id.ICNTL(4) = 0;
+ id.job = 6;
+
+ id.ICNTL(14) += 40; /* small boost to the workspace size as we have encountered some problem
+ who did not fit in the default settings of mumps..
+ by default, ICNTL(14) = 15 or 20
+ */
+ //cout << "ICNTL(14): " << id.ICNTL(14) << "\n";
+
+ mumps_interf<T>::mumps_c(id);
+ if (id.INFO(1) < 0) {
+ switch (id.INFO(1)) {
+ case -6 : case -10 :
+ GMM_ASSERT1(false, "Solve with MUMPS failed: matrix is singular");
+ case -13 :
+ GMM_ASSERT1(false, "Solve with MUMPS failed: not enough memory");
+ case -9:
+ GMM_ASSERT1(false, "Solve with MUMPS failed: error " << id.INFO(1)
+ << ", increase ICNTL(14)");
+ default :
+ GMM_ASSERT1(false, "Solve with MUMPS failed with error "
+ << id.INFO(1));
+ }
+ }
+
+ id.job = JOB_END;
+ mumps_interf<T>::mumps_c(id);
+
+ gmm::copy(rhs, X);
+
+#undef ICNTL
+#undef INFO
+
+ }
+
+
+
+ /** MUMPS solve interface for distributed matrices
+ * Works only with sparse or skyline matrices
+ */
+ template <typename MAT, typename VECTX, typename VECTB>
+ void MUMPS_distributed_matrix_solve(const MAT &A, const VECTX &X_,
+ const VECTB &B) {
+ VECTX &X = const_cast<VECTX &>(X_);
+
+ typedef typename linalg_traits<MAT>::value_type T;
+ typedef typename mumps_interf<T>::value_type MUMPS_T;
+ GMM_ASSERT2(gmm::mat_nrows(A) == gmm::mat_ncols(A), "Non-square matrix");
+
+ std::vector<T> rhs(gmm::vect_size(B)); gmm::copy(B, rhs);
+
+ ij_sparse_matrix<T> AA(A);
+
+ const int JOB_INIT = -1;
+ const int JOB_END = -2;
+ const int USE_COMM_WORLD = -987654;
+
+ typename mumps_interf<T>::MUMPS_STRUC_C id;
+
+#ifdef GMM_USES_MPI
+ int rank;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+#endif
+
+ id.job = JOB_INIT;
+ id.par = 1;
+ id.sym = 0;
+ id.comm_fortran = USE_COMM_WORLD;
+ mumps_interf<T>::mumps_c(id);
+
+ id.n = gmm::mat_nrows(A);
+ id.nz_loc = AA.irn.size();
+ id.irn_loc = &(AA.irn[0]);
+ id.jcn_loc = &(AA.jcn[0]);
+ id.a_loc = (MUMPS_T*)(&(AA.a[0]));
+
+#ifdef GMM_USES_MPI
+ if (rank == 0) {
+#endif
+ id.rhs = (MUMPS_T*)(&(rhs[0]));
+#ifdef GMM_USES_MPI
+ }
+#endif
+
+#define ICNTL(I) icntl[(I)-1]
+#define INFO(I) info[(I)-1]
+ id.ICNTL(1) = -1; id.ICNTL(2) = 6; // id.ICNTL(2) = -1;
+ id.ICNTL(3) = 6;
+ // id.ICNTL(3) = -1;
+ id.ICNTL(4) = 2;
+ id.ICNTL(5)=0; id.ICNTL(18)=3;
+ id.job = 6;
+ mumps_interf<T>::mumps_c(id);
+ if (id.INFO(1) < 0) {
+ switch (id.INFO(1)) {
+ case -6 : case -10 :
+ GMM_ASSERT1(false, "Solve with MUMPS failed: matrix is singular");
+ case -13:
+ GMM_ASSERT1(false, "Solve with MUMPS failed: not enough memory");
+ case -9:
+ GMM_ASSERT1(false, "Solve with MUMPS failed: error " << id.INFO(1)
+ << ", increase ICNTL(14)");
+ default :
+ GMM_ASSERT1(false, "Solve with MUMPS failed with error " <<id.INFO(1));
+ }
+ }
+
+ id.job = JOB_END;
+ mumps_interf<T>::mumps_c(id);
+#ifdef GMM_USES_MPI
+ MPI_Bcast(&(rhs[0]),id.n,gmm::mpi_type(T()),0,MPI_COMM_WORLD);
+#endif
+ gmm::copy(rhs, X);
+
+#undef ICNTL
+#undef INFO
+
+ }
+
+
+
+
+}
+
+
+#endif // GMM_MUMPS_INTERFACE_H
+
+#endif // GMM_USES_MUMPS
diff --git a/Contrib/gmm/gmm_algobase.h b/Contrib/gmm/gmm_algobase.h
new file mode 100755
index 0000000..1b72ac2
--- /dev/null
+++ b/Contrib/gmm/gmm_algobase.h
@@ -0,0 +1,225 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2000-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/** @file gmm_algobase.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date September 28, 2000.
+ @brief Miscelleanous algorithms on containers.
+*/
+
+#ifndef GMM_ALGOBASE_H__
+#define GMM_ALGOBASE_H__
+#include "gmm_std.h"
+#include "gmm_except.h"
+#include <functional>
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* Definitition de classes de comparaison. */
+ /* retournant un int. */
+ /* ********************************************************************* */
+
+ template <class T>
+ struct less : public std::binary_function<T, T, int> {
+ inline int operator()(const T& x, const T& y) const
+ { return (x < y) ? -1 : ((y < x) ? 1 : 0); }
+ };
+
+ template<> struct less<int> : public std::binary_function<int, int, int>
+ { int operator()(int x, int y) const { return x-y; } };
+ template<> struct less<char> : public std::binary_function<char, char, int>
+ { int operator()(char x, char y) const { return int(x-y); } };
+ template<> struct less<short> : public std::binary_function<short,short,int>
+ { int operator()(short x, short y) const { return int(x-y); } };
+ template<> struct less<unsigned char>
+ : public std::binary_function<unsigned char, unsigned char, int> {
+ int operator()(unsigned char x, unsigned char y) const
+ { return int(x)-int(y); }
+ };
+
+
+ template <class T>
+ struct greater : public std::binary_function<T, T, int> {
+ inline int operator()(const T& x, const T& y) const
+ { return (y < x) ? -1 : ((x < y) ? 1 : 0); }
+ };
+
+ template<> struct greater<int> : public std::binary_function<int, int, int>
+ { int operator()(int x, int y) const { return y-x; } };
+ template<> struct greater<char> : public std::binary_function<char,char,int>
+ { int operator()(char x, char y) const { return int(y-x); } };
+ template<> struct greater<short>
+ : public std::binary_function<short, short, int>
+ { int operator()(short x, short y) const { return int(y-x); } };
+ template<> struct greater<unsigned char>
+ : public std::binary_function<unsigned char, unsigned char, int> {
+ int operator()(unsigned char x, unsigned char y) const
+ { return int(y)-int(x); }
+ };
+
+ template <typename T> inline T my_abs(T a) { return (a < T(0)) ? T(-a) : a; }
+
+ template <class T>
+ struct approx_less : public std::binary_function<T, T, int> {
+ double eps;
+ inline int operator()(const T &x, const T &y) const
+ { if (my_abs(x - y) <= eps) return 0; if (x < y) return -1; return 1; }
+ approx_less(double e = 1E-13) { eps = e; }
+ };
+
+ template <class T>
+ struct approx_greater : public std::binary_function<T, T, int> {
+ double eps;
+ inline int operator()(const T &x, const T &y) const
+ { if (my_abs(x - y) <= eps) return 0; if (x > y) return -1; return 1; }
+ approx_greater(double e = 1E-13) { eps = e; }
+ };
+
+ template<class ITER1, class ITER2, class COMP>
+ int lexicographical_compare(ITER1 b1, const ITER1 &e1,
+ ITER2 b2, const ITER2 &e2, const COMP &c) {
+ int i;
+ for ( ; b1 != e1 && b2 != e2; ++b1, ++b2)
+ if ((i = c(*b1, *b2)) != 0) return i;
+ if (b1 != e1) return 1; if (b2 != e2) return -1; return 0;
+ }
+
+ template<class CONT, class COMP = gmm::less<typename CONT::value_type> >
+ struct lexicographical_less : public std::binary_function<CONT, CONT, int>
+ {
+ COMP c;
+ int operator()(const CONT &x, const CONT &y) const {
+ return gmm::lexicographical_compare(x.begin(), x.end(),
+ y.begin(), y.end(), c);
+ }
+ lexicographical_less(const COMP &d = COMP()) { c = d; }
+ };
+
+ template<class CONT, class COMP = gmm::less<typename CONT::value_type> >
+ struct lexicographical_greater
+ : public std::binary_function<CONT, CONT, int> {
+ COMP c;
+ int operator()(const CONT &x, const CONT &y) const {
+ return -gmm::lexicographical_compare(x.begin(), x.end(),
+ y.begin(), y.end(), c);
+ }
+ lexicographical_greater(const COMP &d = COMP()) { c = d; }
+ };
+
+
+ /* ********************************************************************* */
+ /* "Virtual" iterators on sequences. */
+ /* The class T represent a class of sequence. */
+ /* ********************************************************************* */
+
+ template<class T> struct sequence_iterator {
+
+ typedef T value_type;
+ typedef value_type* pointer;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef std::forward_iterator_tag iterator_category;
+
+ T Un;
+
+ sequence_iterator(T U0 = T(0)) { Un = U0; }
+
+ sequence_iterator &operator ++()
+ { ++Un; return *this; }
+ sequence_iterator operator ++(int)
+ { sequence_iterator tmp = *this; (*this)++; return tmp; }
+
+ const_reference operator *() const { return Un; }
+ reference operator *() { return Un; }
+
+ bool operator ==(const sequence_iterator &i) const { return (i.Un==Un);}
+ bool operator !=(const sequence_iterator &i) const { return (i.Un!=Un);}
+ };
+
+ /* ********************************************************************* */
+ /* generic algorithms. */
+ /* ********************************************************************* */
+
+ template <class ITER1, class SIZE, class ITER2>
+ ITER2 copy_n(ITER1 first, SIZE count, ITER2 result) {
+ for ( ; count > 0; --count, ++first, ++result) *result = *first;
+ return result;
+ }
+
+ template<class ITER>
+ typename std::iterator_traits<ITER>::value_type
+ mean_value(ITER first, const ITER &last) {
+ GMM_ASSERT2(first != last, "mean value of empty container");
+ size_t n = 1;
+ typename std::iterator_traits<ITER>::value_type res = *first++;
+ while (first != last) { res += *first; ++first; ++n; }
+ res /= n;
+ return res;
+ }
+
+ template<class CONT>
+ typename CONT::value_type
+ mean_value(const CONT &c) { return mean_value(c.begin(), c.end()); }
+
+ template<class ITER> /* hum ... */
+ void minmax_box(typename std::iterator_traits<ITER>::value_type &pmin,
+ typename std::iterator_traits<ITER>::value_type &pmax,
+ ITER first, const ITER &last) {
+ typedef typename std::iterator_traits<ITER>::value_type PT;
+ if (first != last) { pmin = pmax = *first; ++first; }
+ while (first != last) {
+ typename PT::const_iterator b = (*first).begin(), e = (*first).end();
+ typename PT::iterator b1 = pmin.begin(), b2 = pmax.begin();
+ while (b != e)
+ { *b1 = std::min(*b1, *b); *b2 = std::max(*b2, *b); ++b; ++b1; ++b2; }
+ }
+ }
+
+ template<typename VEC> struct sorted_indexes_aux {
+ const VEC &v;
+ public:
+ sorted_indexes_aux(const VEC& v_) : v(v_) {}
+ template <typename IDX>
+ bool operator()(const IDX &ia, const IDX &ib) const
+ { return v[ia] < v[ib]; }
+ };
+
+ template<typename VEC, typename IVEC>
+ void sorted_indexes(const VEC &v, IVEC &iv) {
+ iv.clear(); iv.resize(v.size());
+ for (size_t i=0; i < v.size(); ++i) iv[i] = i;
+ std::sort(iv.begin(), iv.end(), sorted_indexes_aux<VEC>(v));
+ }
+
+}
+
+
+#endif /* GMM_ALGOBASE_H__ */
diff --git a/Contrib/gmm/gmm_blas.h b/Contrib/gmm/gmm_blas.h
new file mode 100755
index 0000000..31c76cc
--- /dev/null
+++ b/Contrib/gmm/gmm_blas.h
@@ -0,0 +1,2282 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_blas.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief Basic linear algebra functions.
+*/
+
+#ifndef GMM_BLAS_H__
+#define GMM_BLAS_H__
+
+#include "gmm_scaled.h"
+#include "gmm_transposed.h"
+#include "gmm_conjugated.h"
+
+namespace gmm {
+
+ /* ******************************************************************** */
+ /* */
+ /* Generic algorithms */
+ /* */
+ /* ******************************************************************** */
+
+
+ /* ******************************************************************** */
+ /* Miscellaneous */
+ /* ******************************************************************** */
+
+ /** clear (fill with zeros) a vector or matrix. */
+ template <typename L> inline void clear(L &l)
+ { linalg_traits<L>::do_clear(l); }
+ /** @cond DOXY_SHOW_ALL_FUNCTIONS
+ skip all these redundant definitions in doxygen documentation..
+ */
+ template <typename L> inline void clear(const L &l)
+ { linalg_traits<L>::do_clear(linalg_const_cast(l)); }
+
+ ///@endcond
+ /** count the number of non-zero entries of a vector or matrix. */ template <typename L> inline size_type nnz(const L& l)
+ { return nnz(l, typename linalg_traits<L>::linalg_type()); }
+
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+ template <typename L> inline size_type nnz(const L& l, abstract_vector) {
+ typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
+ ite = vect_const_end(l);
+ size_type res(0);
+ for (; it != ite; ++it) ++res;
+ return res;
+ }
+
+ template <typename L> inline size_type nnz(const L& l, abstract_matrix) {
+ return nnz(l, typename principal_orientation_type<typename
+ linalg_traits<L>::sub_orientation>::potype());
+ }
+
+ template <typename L> inline size_type nnz(const L& l, row_major) {
+ size_type res(0);
+ for (size_type i = 0; i < mat_nrows(l); ++i)
+ res += nnz(mat_const_row(l, i));
+ return res;
+ }
+
+ template <typename L> inline size_type nnz(const L& l, col_major) {
+ size_type res(0);
+ for (size_type i = 0; i < mat_ncols(l); ++i)
+ res += nnz(mat_const_col(l, i));
+ return res;
+ }
+
+ ///@endcond
+
+
+ /** fill a vector or matrix with x. */
+ template <typename L> inline
+ void fill(L& l, typename gmm::linalg_traits<L>::value_type x) {
+ typedef typename gmm::linalg_traits<L>::value_type T;
+ if (x == T(0)) gmm::clear(l);
+ fill(l, x, typename linalg_traits<L>::linalg_type());
+ }
+
+ template <typename L> inline
+ void fill(const L& l, typename gmm::linalg_traits<L>::value_type x) {
+ fill(linalg_const_cast(l), x);
+ }
+
+ template <typename L> inline // to be optimized for dense vectors ...
+ void fill(L& l, typename gmm::linalg_traits<L>::value_type x,
+ abstract_vector) {
+ for (size_type i = 0; i < vect_size(l); ++i) l[i] = x;
+ }
+
+ template <typename L> inline // to be optimized for dense matrices ...
+ void fill(L& l, typename gmm::linalg_traits<L>::value_type x,
+ abstract_matrix) {
+ for (size_type i = 0; i < mat_nrows(l); ++i)
+ for (size_type j = 0; j < mat_ncols(l); ++j)
+ l(i,j) = x;
+ }
+
+ /** fill a vector or matrix with random value (uniform [0,1]). */
+ template <typename L> inline void fill_random(L& l)
+ { fill_random(l, typename linalg_traits<L>::linalg_type()); }
+
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+ template <typename L> inline void fill_random(const L& l) {
+ fill_random(linalg_const_cast(l),
+ typename linalg_traits<L>::linalg_type());
+ }
+
+ template <typename L> inline void fill_random(L& l, abstract_vector) {
+ for (size_type i = 0; i < vect_size(l); ++i)
+ l[i] = gmm::random(typename linalg_traits<L>::value_type());
+ }
+
+ template <typename L> inline void fill_random(L& l, abstract_matrix) {
+ for (size_type i = 0; i < mat_nrows(l); ++i)
+ for (size_type j = 0; j < mat_ncols(l); ++j)
+ l(i,j) = gmm::random(typename linalg_traits<L>::value_type());
+ }
+
+ ///@endcond
+ /** fill a vector or matrix with random value.
+ @param l a vector or matrix.
+ @param cfill probability of a non-zero value.
+ */
+ template <typename L> inline void fill_random(L& l, double cfill)
+ { fill_random(l, cfill, typename linalg_traits<L>::linalg_type()); }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ template <typename L> inline void fill_random(const L& l, double cfill) {
+ fill_random(linalg_const_cast(l), cfill,
+ typename linalg_traits<L>::linalg_type());
+ }
+
+ template <typename L> inline
+ void fill_random(L& l, double cfill, abstract_vector) {
+ typedef typename linalg_traits<L>::value_type T;
+ size_type ntot = std::min(vect_size(l), size_type(vect_size(l)*cfill) + 1);
+ for (size_type nb = 0; nb < ntot;) {
+ size_type i = gmm::irandom(vect_size(l));
+ if (l[i] == T(0)) {
+ l[i] = gmm::random(typename linalg_traits<L>::value_type());
+ ++nb;
+ }
+ }
+ }
+
+ template <typename L> inline
+ void fill_random(L& l, double cfill, abstract_matrix) {
+ fill_random(l, cfill, typename principal_orientation_type<typename
+ linalg_traits<L>::sub_orientation>::potype());
+ }
+
+ template <typename L> inline
+ void fill_random(L& l, double cfill, row_major) {
+ for (size_type i=0; i < mat_nrows(l); ++i) fill_random(mat_row(l,i),cfill);
+ }
+
+ template <typename L> inline
+ void fill_random(L& l, double cfill, col_major) {
+ for (size_type j=0; j < mat_ncols(l); ++j) fill_random(mat_col(l,j),cfill);
+ }
+
+ /* resize a vector */
+ template <typename V> inline
+ void resize(V &v, size_type n, linalg_false)
+ { linalg_traits<V>::resize(v, n); }
+
+ template <typename V> inline
+ void resize(V &, size_type , linalg_modifiable)
+ { GMM_ASSERT1(false, "You cannot resize a reference"); }
+
+ template <typename V> inline
+ void resize(V &, size_type , linalg_const)
+ { GMM_ASSERT1(false, "You cannot resize a reference"); }
+
+ ///@endcond
+ /** resize a vector. */
+ template <typename V> inline
+ void resize(V &v, size_type n) {
+ resize(v, n, typename linalg_traits<V>::is_reference());
+ }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ /** resize a matrix **/
+ template <typename M> inline
+ void resize(M &v, size_type m, size_type n, linalg_false) {
+ linalg_traits<M>::resize(v, m, n);
+ }
+
+ template <typename M> inline
+ void resize(M &, size_type, size_type, linalg_modifiable)
+ { GMM_ASSERT1(false, "You cannot resize a reference"); }
+
+ template <typename M> inline
+ void resize(M &, size_type, size_type, linalg_const)
+ { GMM_ASSERT1(false, "You cannot resize a reference"); }
+
+ ///@endcond
+ /** resize a matrix */
+ template <typename M> inline
+ void resize(M &v, size_type m, size_type n)
+ { resize(v, m, n, typename linalg_traits<M>::is_reference()); }
+ ///@cond
+
+ template <typename M> inline
+ void reshape(M &v, size_type m, size_type n, linalg_false)
+ { linalg_traits<M>::reshape(v, m, n); }
+
+ template <typename M> inline
+ void reshape(M &, size_type, size_type, linalg_modifiable)
+ { GMM_ASSERT1(false, "You cannot reshape a reference"); }
+
+ template <typename M> inline
+ void reshape(M &, size_type, size_type, linalg_const)
+ { GMM_ASSERT1(false, "You cannot reshape a reference"); }
+
+ ///@endcond
+ /** reshape a matrix */
+ template <typename M> inline
+ void reshape(M &v, size_type m, size_type n)
+ { reshape(v, m, n, typename linalg_traits<M>::is_reference()); }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+
+ /* ******************************************************************** */
+ /* Scalar product */
+ /* ******************************************************************** */
+
+ ///@endcond
+ /** scalar product between two vectors */
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp(const V1 &v1, const V2 &v2) {
+ GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+ return vect_sp(v1, v2,
+ typename linalg_traits<V1>::storage_type(),
+ typename linalg_traits<V2>::storage_type());
+ }
+
+ /** scalar product between two vectors, using a matrix.
+ @param ps the matrix of the scalar product.
+ @param v1 the first vector
+ @param v2 the second vector
+ */
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp(const MATSP &ps, const V1 &v1, const V2 &v2) {
+ return vect_sp_with_mat(ps, v1, v2,
+ typename linalg_traits<MATSP>::sub_orientation());
+ }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp_with_mat(const MATSP &ps, const V1 &v1, const V2 &v2, row_major) {
+ return vect_sp_with_matr(ps, v1, v2,
+ typename linalg_traits<V2>::storage_type());
+ }
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp_with_matr(const MATSP &ps, const V1 &v1, const V2 &v2,
+ abstract_sparse) {
+ GMM_ASSERT2(vect_size(v1) == mat_ncols(ps) &&
+ vect_size(v2) == mat_nrows(ps), "dimensions mismatch");
+ size_type nr = mat_nrows(ps);
+ typename linalg_traits<V2>::const_iterator
+ it = vect_const_begin(v2), ite = vect_const_end(v2);
+ typename strongest_value_type3<V1,V2,MATSP>::value_type res(0);
+ for (; it != ite; ++it)
+ res += vect_sp(mat_const_row(ps, it.index()), v1)* (*it);
+ return res;
+ }
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp_with_matr(const MATSP &ps, const V1 &v1, const V2 &v2,
+ abstract_skyline)
+ { return vect_sp_with_matr(ps, v1, v2, abstract_sparse()); }
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp_with_matr(const MATSP &ps, const V1 &v1, const V2 &v2,
+ abstract_dense) {
+ GMM_ASSERT2(vect_size(v1) == mat_ncols(ps) &&
+ vect_size(v2) == mat_nrows(ps), "dimensions mismatch");
+ typename linalg_traits<V2>::const_iterator
+ it = vect_const_begin(v2), ite = vect_const_end(v2);
+ typename strongest_value_type3<V1,V2,MATSP>::value_type res(0);
+ for (size_type i = 0; it != ite; ++i, ++it)
+ res += vect_sp(mat_const_row(ps, i), v1) * (*it);
+ return res;
+ }
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp_with_mat(const MATSP &ps, const V1 &v1,const V2 &v2,row_and_col)
+ { return vect_sp_with_mat(ps, v1, v2, row_major()); }
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp_with_mat(const MATSP &ps, const V1 &v1, const V2 &v2,col_major){
+ return vect_sp_with_matc(ps, v1, v2,
+ typename linalg_traits<V1>::storage_type());
+ }
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp_with_matc(const MATSP &ps, const V1 &v1, const V2 &v2,
+ abstract_sparse) {
+ GMM_ASSERT2(vect_size(v1) == mat_ncols(ps) &&
+ vect_size(v2) == mat_nrows(ps),"dimensions mismatch");
+ typename linalg_traits<V1>::const_iterator
+ it = vect_const_begin(v1), ite = vect_const_end(v1);
+ typename strongest_value_type3<V1,V2,MATSP>::value_type res(0);
+ for (; it != ite; ++it)
+ res += vect_sp(mat_const_col(ps, it.index()), v2) * (*it);
+ return res;
+ }
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp_with_matc(const MATSP &ps, const V1 &v1, const V2 &v2,
+ abstract_skyline)
+ { return vect_sp_with_matc(ps, v1, v2, abstract_sparse()); }
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp_with_matc(const MATSP &ps, const V1 &v1, const V2 &v2,
+ abstract_dense) {
+ GMM_ASSERT2(vect_size(v1) == mat_ncols(ps) &&
+ vect_size(v2) == mat_nrows(ps), "dimensions mismatch");
+ typename linalg_traits<V1>::const_iterator
+ it = vect_const_begin(v1), ite = vect_const_end(v1);
+ typename strongest_value_type3<V1,V2,MATSP>::value_type res(0);
+ for (size_type i = 0; it != ite; ++i, ++it)
+ res += vect_sp(mat_const_col(ps, i), v2) * (*it);
+ return res;
+ }
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp_with_mat(const MATSP &ps, const V1 &v1,const V2 &v2,col_and_row)
+ { return vect_sp_with_mat(ps, v1, v2, col_major()); }
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp_with_mat(const MATSP &ps, const V1 &v1, const V2 &v2,
+ abstract_null_type) {
+ typename temporary_vector<V1>::vector_type w(mat_nrows(ps));
+ GMM_WARNING2("Warning, a temporary is used in scalar product\n");
+ mult(ps, v1, w);
+ return vect_sp(w, v2);
+ }
+
+ template <typename IT1, typename IT2> inline
+ typename strongest_numeric_type<typename std::iterator_traits<IT1>::value_type,
+ typename std::iterator_traits<IT2>::value_type>::T
+ vect_sp_dense_(IT1 it, IT1 ite, IT2 it2) {
+ typename strongest_numeric_type<typename std::iterator_traits<IT1>::value_type,
+ typename std::iterator_traits<IT2>::value_type>::T res(0);
+ for (; it != ite; ++it, ++it2) res += (*it) * (*it2);
+ return res;
+ }
+
+ template <typename IT1, typename V> inline
+ typename strongest_numeric_type<typename std::iterator_traits<IT1>::value_type,
+ typename linalg_traits<V>::value_type>::T
+ vect_sp_sparse_(IT1 it, IT1 ite, const V &v) {
+ typename strongest_numeric_type<typename std::iterator_traits<IT1>::value_type,
+ typename linalg_traits<V>::value_type>::T res(0);
+ for (; it != ite; ++it) res += (*it) * v[it.index()];
+ return res;
+ }
+
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp(const V1 &v1, const V2 &v2, abstract_dense, abstract_dense) {
+ return vect_sp_dense_(vect_const_begin(v1), vect_const_end(v1),
+ vect_const_begin(v2));
+ }
+
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp(const V1 &v1, const V2 &v2, abstract_skyline, abstract_dense) {
+ typename linalg_traits<V1>::const_iterator it1 = vect_const_begin(v1),
+ ite = vect_const_end(v1);
+ typename linalg_traits<V2>::const_iterator it2 = vect_const_begin(v2);
+ return vect_sp_dense_(it1, ite, it2 + it1.index());
+ }
+
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp(const V1 &v1, const V2 &v2, abstract_dense, abstract_skyline) {
+ typename linalg_traits<V2>::const_iterator it1 = vect_const_begin(v2),
+ ite = vect_const_end(v2);
+ typename linalg_traits<V1>::const_iterator it2 = vect_const_begin(v1);
+ return vect_sp_dense_(it1, ite, it2 + it1.index());
+ }
+
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp(const V1 &v1, const V2 &v2, abstract_skyline, abstract_skyline) {
+ typedef typename strongest_value_type<V1,V2>::value_type T;
+ typename linalg_traits<V1>::const_iterator it1 = vect_const_begin(v1),
+ ite1 = vect_const_end(v1);
+ typename linalg_traits<V2>::const_iterator it2 = vect_const_begin(v2),
+ ite2 = vect_const_end(v2);
+ size_type n = std::min(ite1.index(), ite2.index());
+ size_type l = std::max(it1.index(), it2.index());
+
+ if (l < n) {
+ size_type m = l - it1.index(), p = l - it2.index(), q = m + n - l;
+ return vect_sp_dense_(it1+m, it1+q, it2 + p);
+ }
+ return T(0);
+ }
+
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp(const V1 &v1, const V2 &v2,abstract_sparse,abstract_dense) {
+ return vect_sp_sparse_(vect_const_begin(v1), vect_const_end(v1), v2);
+ }
+
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp(const V1 &v1, const V2 &v2, abstract_sparse, abstract_skyline) {
+ return vect_sp_sparse_(vect_const_begin(v1), vect_const_end(v1), v2);
+ }
+
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp(const V1 &v1, const V2 &v2, abstract_skyline, abstract_sparse) {
+ return vect_sp_sparse_(vect_const_begin(v2), vect_const_end(v2), v1);
+ }
+
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp(const V1 &v1, const V2 &v2, abstract_dense,abstract_sparse) {
+ return vect_sp_sparse_(vect_const_begin(v2), vect_const_end(v2), v1);
+ }
+
+
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp_sparse_sparse(const V1 &v1, const V2 &v2, linalg_true) {
+ typename linalg_traits<V1>::const_iterator it1 = vect_const_begin(v1),
+ ite1 = vect_const_end(v1);
+ typename linalg_traits<V2>::const_iterator it2 = vect_const_begin(v2),
+ ite2 = vect_const_end(v2);
+ typename strongest_value_type<V1,V2>::value_type res(0);
+
+ while (it1 != ite1 && it2 != ite2) {
+ if (it1.index() == it2.index())
+ { res += (*it1) * *it2; ++it1; ++it2; }
+ else if (it1.index() < it2.index()) ++it1; else ++it2;
+ }
+ return res;
+ }
+
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp_sparse_sparse(const V1 &v1, const V2 &v2, linalg_false) {
+ return vect_sp_sparse_(vect_const_begin(v1), vect_const_end(v1), v2);
+ }
+
+ template <typename V1, typename V2> inline
+ typename strongest_value_type<V1,V2>::value_type
+ vect_sp(const V1 &v1, const V2 &v2,abstract_sparse,abstract_sparse) {
+ return vect_sp_sparse_sparse(v1, v2,
+ typename linalg_and<typename linalg_traits<V1>::index_sorted,
+ typename linalg_traits<V2>::index_sorted>::bool_type());
+ }
+
+ /* ******************************************************************** */
+ /* Hermitian product */
+ /* ******************************************************************** */
+ ///@endcond
+ /** Hermitian product. */
+ template <typename V1, typename V2>
+ inline typename strongest_value_type<V1,V2>::value_type
+ vect_hp(const V1 &v1, const V2 &v2)
+ { return vect_sp(v1, conjugated(v2)); }
+
+ /** Hermitian product with a matrix. */
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_hp(const MATSP &ps, const V1 &v1, const V2 &v2) {
+ return vect_sp(ps, v1, gmm::conjugated(v2));
+ }
+
+ /* ******************************************************************** */
+ /* Trace of a matrix */
+ /* ******************************************************************** */
+
+ /** Trace of a matrix */
+ template <typename M>
+ typename linalg_traits<M>::value_type
+ mat_trace(const M &m) {
+ typedef typename linalg_traits<M>::value_type T;
+ T res(0);
+ for (size_type i = 0; i < std::max(mat_nrows(m), mat_ncols(m)); ++i)
+ res += m(i,i);
+ return res;
+ }
+
+ /* ******************************************************************** */
+ /* Euclidean norm */
+ /* ******************************************************************** */
+
+ /** Euclidean norm of a vector. */
+ template <typename V>
+ typename number_traits<typename linalg_traits<V>::value_type>
+ ::magnitude_type
+ vect_norm2_sqr(const V &v) {
+ typedef typename linalg_traits<V>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ typename linalg_traits<V>::const_iterator
+ it = vect_const_begin(v), ite = vect_const_end(v);
+ R res(0);
+ for (; it != ite; ++it) res += gmm::abs_sqr(*it);
+ return res;
+ }
+
+ /** squared Euclidean norm of a vector. */
+ template <typename V> inline
+ typename number_traits<typename linalg_traits<V>::value_type>
+ ::magnitude_type
+ vect_norm2(const V &v)
+ { return sqrt(vect_norm2_sqr(v)); }
+
+
+ /** squared Euclidean distance between two vectors */
+ template <typename V1, typename V2> inline
+ typename number_traits<typename linalg_traits<V1>::value_type>
+ ::magnitude_type
+ vect_dist2_sqr(const V1 &v1, const V2 &v2) { // not fully optimized
+ typedef typename linalg_traits<V1>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ typename linalg_traits<V1>::const_iterator
+ it1 = vect_const_begin(v1), ite1 = vect_const_end(v1);
+ typename linalg_traits<V2>::const_iterator
+ it2 = vect_const_begin(v2), ite2 = vect_const_end(v2);
+ size_type k1(0), k2(0);
+ R res(0);
+ while (it1 != ite1 && it2 != ite2) {
+ size_type i1 = index_of_it(it1, k1,
+ typename linalg_traits<V1>::storage_type());
+ size_type i2 = index_of_it(it2, k2,
+ typename linalg_traits<V2>::storage_type());
+
+ if (i1 == i2) {
+ res += gmm::abs_sqr(*it2 - *it1); ++it1; ++k1; ++it2; ++k2;
+ }
+ else if (i1 < i2) {
+ res += gmm::abs_sqr(*it1); ++it1; ++k1;
+ }
+ else {
+ res += gmm::abs_sqr(*it2); ++it2; ++k2;
+ }
+ }
+ while (it1 != ite1) { res += gmm::abs_sqr(*it1); ++it1; }
+ while (it2 != ite2) { res += gmm::abs_sqr(*it2); ++it2; }
+ return res;
+ }
+
+ /** Euclidean distance between two vectors */
+ template <typename V1, typename V2> inline
+ typename number_traits<typename linalg_traits<V1>::value_type>
+ ::magnitude_type
+ vect_dist2(const V1 &v1, const V2 &v2)
+ { return sqrt(vect_dist2_sqr(v1, v2)); }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_euclidean_norm_sqr(const M &m, row_major) {
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type res(0);
+ for (size_type i = 0; i < mat_nrows(m); ++i)
+ res += vect_norm2_sqr(mat_const_row(m, i));
+ return res;
+ }
+
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_euclidean_norm_sqr(const M &m, col_major) {
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type res(0);
+ for (size_type i = 0; i < mat_ncols(m); ++i)
+ res += vect_norm2_sqr(mat_const_col(m, i));
+ return res;
+ }
+ ///@endcond
+ /** squared Euclidean norm of a matrix. */
+ template <typename M> inline
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_euclidean_norm_sqr(const M &m) {
+ return mat_euclidean_norm_sqr(m,
+ typename principal_orientation_type<typename
+ linalg_traits<M>::sub_orientation>::potype());
+ }
+
+ /** Euclidean norm of a matrix. */
+ template <typename M> inline
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_euclidean_norm(const M &m)
+ { return gmm::sqrt(mat_euclidean_norm_sqr(m)); }
+
+ /* ******************************************************************** */
+ /* vector norm1 */
+ /* ******************************************************************** */
+ /** 1-norm of a vector */
+ template <typename V>
+ typename number_traits<typename linalg_traits<V>::value_type>
+ ::magnitude_type
+ vect_norm1(const V &v) {
+ typename linalg_traits<V>::const_iterator
+ it = vect_const_begin(v), ite = vect_const_end(v);
+ typename number_traits<typename linalg_traits<V>::value_type>
+ ::magnitude_type res(0);
+ for (; it != ite; ++it) res += gmm::abs(*it);
+ return res;
+ }
+
+ /* ******************************************************************** */
+ /* vector Infinity norm */
+ /* ******************************************************************** */
+ /** Infinity norm of a vector. */
+ template <typename V>
+ typename number_traits<typename linalg_traits<V>::value_type>
+ ::magnitude_type
+ vect_norminf(const V &v) {
+ typename linalg_traits<V>::const_iterator
+ it = vect_const_begin(v), ite = vect_const_end(v);
+ typename number_traits<typename linalg_traits<V>::value_type>
+ ::magnitude_type res(0);
+ for (; it != ite; ++it) res = std::max(res, gmm::abs(*it));
+ return res;
+ }
+
+ /* ******************************************************************** */
+ /* matrix norm1 */
+ /* ******************************************************************** */
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_norm1(const M &m, col_major) {
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type res(0);
+ for (size_type i = 0; i < mat_ncols(m); ++i)
+ res = std::max(res, vect_norm1(mat_const_col(m,i)));
+ return res;
+ }
+
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_norm1(const M &m, row_major) {
+ typedef typename linalg_traits<M>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ typedef typename linalg_traits<M>::storage_type store_type;
+
+ std::vector<R> aux(mat_ncols(m));
+ for (size_type i = 0; i < mat_nrows(m); ++i) {
+ typedef typename linalg_traits<M>::const_sub_row_type row_type;
+ row_type row = mat_const_row(m, i);
+ typename linalg_traits<row_type>::const_iterator
+ it = vect_const_begin(row), ite = vect_const_end(row);
+ for (size_type k = 0; it != ite; ++it, ++k)
+ aux[index_of_it(it, k, store_type())] += gmm::abs(*it);
+ }
+ return vect_norminf(aux);
+ }
+
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_norm1(const M &m, col_and_row)
+ { return mat_norm1(m, col_major()); }
+
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_norm1(const M &m, row_and_col)
+ { return mat_norm1(m, col_major()); }
+ ///@endcond
+ /** 1-norm of a matrix */
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_norm1(const M &m) {
+ return mat_norm1(m, typename linalg_traits<M>::sub_orientation());
+ }
+
+
+ /* ******************************************************************** */
+ /* matrix Infinity norm */
+ /* ******************************************************************** */
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_norminf(const M &m, row_major) {
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type res(0);
+ for (size_type i = 0; i < mat_nrows(m); ++i)
+ res = std::max(res, vect_norm1(mat_const_row(m,i)));
+ return res;
+ }
+
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_norminf(const M &m, col_major) {
+ typedef typename linalg_traits<M>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ typedef typename linalg_traits<M>::storage_type store_type;
+
+ std::vector<R> aux(mat_nrows(m));
+ for (size_type i = 0; i < mat_ncols(m); ++i) {
+ typedef typename linalg_traits<M>::const_sub_col_type col_type;
+ col_type col = mat_const_col(m, i);
+ typename linalg_traits<col_type>::const_iterator
+ it = vect_const_begin(col), ite = vect_const_end(col);
+ for (size_type k = 0; it != ite; ++it, ++k)
+ aux[index_of_it(it, k, store_type())] += gmm::abs(*it);
+ }
+ return vect_norminf(aux);
+ }
+
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_norminf(const M &m, col_and_row)
+ { return mat_norminf(m, row_major()); }
+
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_norminf(const M &m, row_and_col)
+ { return mat_norminf(m, row_major()); }
+ ///@endcond
+ /** infinity-norm of a matrix.*/
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_norminf(const M &m) {
+ return mat_norminf(m, typename linalg_traits<M>::sub_orientation());
+ }
+
+ /* ******************************************************************** */
+ /* Max norm for matrices */
+ /* ******************************************************************** */
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_maxnorm(const M &m, row_major) {
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type res(0);
+ for (size_type i = 0; i < mat_nrows(m); ++i)
+ res = std::max(res, vect_norminf(mat_const_row(m,i)));
+ return res;
+ }
+
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_maxnorm(const M &m, col_major) {
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type res(0);
+ for (size_type i = 0; i < mat_ncols(m); ++i)
+ res = std::max(res, vect_norminf(mat_const_col(m,i)));
+ return res;
+ }
+ ///@endcond
+ /** max-norm of a matrix. */
+ template <typename M>
+ typename number_traits<typename linalg_traits<M>::value_type>
+ ::magnitude_type
+ mat_maxnorm(const M &m) {
+ return mat_maxnorm(m,
+ typename principal_orientation_type<typename
+ linalg_traits<M>::sub_orientation>::potype());
+ }
+
+ /* ******************************************************************** */
+ /* Clean */
+ /* ******************************************************************** */
+ /** Clean a vector or matrix (replace near-zero entries with zeroes). */
+
+ template <typename L> inline void clean(L &l, double threshold);
+
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ template <typename L, typename T>
+ void clean(L &l, double threshold, abstract_dense, T) {
+ typedef typename number_traits<T>::magnitude_type R;
+ typename linalg_traits<L>::iterator it = vect_begin(l), ite = vect_end(l);
+ for (; it != ite; ++it)
+ if (gmm::abs(*it) < R(threshold)) *it = T(0);
+ }
+
+ template <typename L, typename T>
+ void clean(L &l, double threshold, abstract_skyline, T)
+ { gmm::clean(l, threshold, abstract_dense(), T()); }
+
+ template <typename L, typename T>
+ void clean(L &l, double threshold, abstract_sparse, T) {
+ typedef typename number_traits<T>::magnitude_type R;
+ typename linalg_traits<L>::iterator it = vect_begin(l), ite = vect_end(l);
+ std::vector<size_type> ind;
+ for (; it != ite; ++it)
+ if (gmm::abs(*it) < R(threshold)) ind.push_back(it.index());
+ for (size_type i = 0; i < ind.size(); ++i) l[ind[i]] = T(0);
+ }
+
+ template <typename L, typename T>
+ void clean(L &l, double threshold, abstract_dense, std::complex<T>) {
+ typename linalg_traits<L>::iterator it = vect_begin(l), ite = vect_end(l);
+ for (; it != ite; ++it){
+ if (gmm::abs((*it).real()) < T(threshold))
+ *it = std::complex<T>(T(0), (*it).imag());
+ if (gmm::abs((*it).imag()) < T(threshold))
+ *it = std::complex<T>((*it).real(), T(0));
+ }
+ }
+
+ template <typename L, typename T>
+ void clean(L &l, double threshold, abstract_skyline, std::complex<T>)
+ { gmm::clean(l, threshold, abstract_dense(), std::complex<T>()); }
+
+ template <typename L, typename T>
+ void clean(L &l, double threshold, abstract_sparse, std::complex<T>) {
+ typename linalg_traits<L>::iterator it = vect_begin(l), ite = vect_end(l);
+ std::vector<size_type> ind;
+ for (; it != ite; ++it) {
+ bool r = (gmm::abs((*it).real()) < T(threshold));
+ bool i = (gmm::abs((*it).imag()) < T(threshold));
+ if (r && i) ind.push_back(it.index());
+ else if (r) (*it).real() = T(0);
+ else if (i) (*it).imag() = T(0);
+ }
+ for (size_type i = 0; i < ind.size(); ++i)
+ l[ind[i]] = std::complex<T>(T(0),T(0));
+ }
+
+ template <typename L> inline void clean(L &l, double threshold,
+ abstract_vector) {
+ gmm::clean(l, threshold, typename linalg_traits<L>::storage_type(),
+ typename linalg_traits<L>::value_type());
+ }
+
+ template <typename L> inline void clean(const L &l, double threshold);
+
+ template <typename L> void clean(L &l, double threshold, row_major) {
+ for (size_type i = 0; i < mat_nrows(l); ++i)
+ gmm::clean(mat_row(l, i), threshold);
+ }
+
+ template <typename L> void clean(L &l, double threshold, col_major) {
+ for (size_type i = 0; i < mat_ncols(l); ++i)
+ gmm::clean(mat_col(l, i), threshold);
+ }
+
+ template <typename L> inline void clean(L &l, double threshold,
+ abstract_matrix) {
+ gmm::clean(l, threshold,
+ typename principal_orientation_type<typename
+ linalg_traits<L>::sub_orientation>::potype());
+ }
+
+ template <typename L> inline void clean(L &l, double threshold)
+ { clean(l, threshold, typename linalg_traits<L>::linalg_type()); }
+
+ template <typename L> inline void clean(const L &l, double threshold)
+ { gmm::clean(linalg_const_cast(l), threshold); }
+
+ /* ******************************************************************** */
+ /* Copy */
+ /* ******************************************************************** */
+ ///@endcond
+ /** Copy vectors or matrices.
+ @param l1 source vector or matrix.
+ @param l2 destination.
+ */
+ template <typename L1, typename L2> inline
+ void copy(const L1& l1, L2& l2) {
+ if ((const void *)(&l1) != (const void *)(&l2)) {
+ if (same_origin(l1,l2))
+ GMM_WARNING2("Warning : a conflict is possible in copy\n");
+
+ copy(l1, l2, typename linalg_traits<L1>::linalg_type(),
+ typename linalg_traits<L2>::linalg_type());
+ }
+ }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ template <typename L1, typename L2> inline
+ void copy(const L1& l1, const L2& l2) { copy(l1, linalg_const_cast(l2)); }
+
+ template <typename L1, typename L2> inline
+ void copy(const L1& l1, L2& l2, abstract_vector, abstract_vector) {
+ GMM_ASSERT2(vect_size(l1) == vect_size(l2), "dimensions mismatch");
+ copy_vect(l1, l2, typename linalg_traits<L1>::storage_type(),
+ typename linalg_traits<L2>::storage_type());
+ }
+
+ template <typename L1, typename L2> inline
+ void copy(const L1& l1, L2& l2, abstract_matrix, abstract_matrix) {
+ size_type m = mat_nrows(l1), n = mat_ncols(l1);
+ if (!m || !n) return;
+ GMM_ASSERT2(n==mat_ncols(l2) && m==mat_nrows(l2), "dimensions mismatch");
+ copy_mat(l1, l2, typename linalg_traits<L1>::sub_orientation(),
+ typename linalg_traits<L2>::sub_orientation());
+ }
+
+ template <typename V1, typename V2, typename C1, typename C2> inline
+ void copy_vect(const V1 &v1, const V2 &v2, C1, C2)
+ { copy_vect(v1, const_cast<V2 &>(v2), C1(), C2()); }
+
+
+ template <typename L1, typename L2>
+ void copy_mat_by_row(const L1& l1, L2& l2) {
+ size_type nbr = mat_nrows(l1);
+ for (size_type i = 0; i < nbr; ++i)
+ copy_vect(mat_const_row(l1, i), mat_row(l2, i),
+ typename linalg_traits<L1>::storage_type(),
+ typename linalg_traits<L2>::storage_type());
+ }
+
+ template <typename L1, typename L2>
+ void copy_mat_by_col(const L1 &l1, L2 &l2) {
+ size_type nbc = mat_ncols(l1);
+ for (size_type i = 0; i < nbc; ++i) {
+ copy_vect(mat_const_col(l1, i), mat_col(l2, i),
+ typename linalg_traits<L1>::storage_type(),
+ typename linalg_traits<L2>::storage_type());
+ }
+ }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, row_major, row_major)
+ { copy_mat_by_row(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, row_major, row_and_col)
+ { copy_mat_by_row(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, row_and_col, row_and_col)
+ { copy_mat_by_row(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, row_and_col, row_major)
+ { copy_mat_by_row(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, col_and_row, row_major)
+ { copy_mat_by_row(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, row_major, col_and_row)
+ { copy_mat_by_row(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, col_and_row, row_and_col)
+ { copy_mat_by_row(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, row_and_col, col_and_row)
+ { copy_mat_by_row(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, col_major, col_major)
+ { copy_mat_by_col(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, col_major, col_and_row)
+ { copy_mat_by_col(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, col_major, row_and_col)
+ { copy_mat_by_col(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, row_and_col, col_major)
+ { copy_mat_by_col(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, col_and_row, col_major)
+ { copy_mat_by_col(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat(const L1& l1, L2& l2, col_and_row, col_and_row)
+ { copy_mat_by_col(l1, l2); }
+
+ template <typename L1, typename L2> inline
+ void copy_mat_mixed_rc(const L1& l1, L2& l2, size_type i) {
+ copy_mat_mixed_rc(l1, l2, i, typename linalg_traits<L1>::storage_type());
+ }
+
+ template <typename L1, typename L2>
+ void copy_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_sparse) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (; it != ite; ++it)
+ l2(i, it.index()) = *it;
+ }
+
+ template <typename L1, typename L2>
+ void copy_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_skyline) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (; it != ite; ++it)
+ l2(i, it.index()) = *it;
+ }
+
+ template <typename L1, typename L2>
+ void copy_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_dense) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (size_type j = 0; it != ite; ++it, ++j) l2(i, j) = *it;
+ }
+
+ template <typename L1, typename L2> inline
+ void copy_mat_mixed_cr(const L1& l1, L2& l2, size_type i) {
+ copy_mat_mixed_cr(l1, l2, i, typename linalg_traits<L1>::storage_type());
+ }
+
+ template <typename L1, typename L2>
+ void copy_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_sparse) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (; it != ite; ++it) l2(it.index(), i) = *it;
+ }
+
+ template <typename L1, typename L2>
+ void copy_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_skyline) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (; it != ite; ++it) l2(it.index(), i) = *it;
+ }
+
+ template <typename L1, typename L2>
+ void copy_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_dense) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (size_type j = 0; it != ite; ++it, ++j) l2(j, i) = *it;
+ }
+
+ template <typename L1, typename L2>
+ void copy_mat(const L1& l1, L2& l2, row_major, col_major) {
+ clear(l2);
+ size_type nbr = mat_nrows(l1);
+ for (size_type i = 0; i < nbr; ++i)
+ copy_mat_mixed_rc(mat_const_row(l1, i), l2, i);
+ }
+
+ template <typename L1, typename L2>
+ void copy_mat(const L1& l1, L2& l2, col_major, row_major) {
+ clear(l2);
+ size_type nbc = mat_ncols(l1);
+ for (size_type i = 0; i < nbc; ++i)
+ copy_mat_mixed_cr(mat_const_col(l1, i), l2, i);
+ }
+
+ template <typename L1, typename L2> inline
+ void copy_vect(const L1 &l1, L2 &l2, abstract_dense, abstract_dense) {
+ std::copy(vect_const_begin(l1), vect_const_end(l1), vect_begin(l2));
+ }
+
+ template <typename L1, typename L2> inline // to be optimised ?
+ void copy_vect(const L1 &l1, L2 &l2, abstract_skyline, abstract_skyline) {
+ typename linalg_traits<L1>::const_iterator it1 = vect_const_begin(l1),
+ ite1 = vect_const_end(l1);
+ while (it1 != ite1 && *it1 == typename linalg_traits<L1>::value_type(0))
+ ++it1;
+
+ if (ite1 - it1 > 0) {
+ clear(l2);
+ typename linalg_traits<L2>::iterator it2 = vect_begin(l2),
+ ite2 = vect_end(l2);
+ while (*(ite1-1) == typename linalg_traits<L1>::value_type(0)) ite1--;
+
+ if (it2 == ite2) {
+ l2[it1.index()] = *it1; ++it1;
+ l2[ite1.index()-1] = *(ite1-1); --ite1;
+ if (it1 < ite1)
+ { it2 = vect_begin(l2); ++it2; std::copy(it1, ite1, it2); }
+ }
+ else {
+ ptrdiff_t m = it1.index() - it2.index();
+ if (m >= 0 && ite1.index() <= ite2.index())
+ std::copy(it1, ite1, it2 + m);
+ else {
+ if (m < 0) l2[it1.index()] = *it1;
+ if (ite1.index() > ite2.index()) l2[ite1.index()-1] = *(ite1-1);
+ it2 = vect_begin(l2); ite2 = vect_end(l2);
+ m = it1.index() - it2.index();
+ std::copy(it1, ite1, it2 + m);
+ }
+ }
+ }
+ }
+
+ template <typename L1, typename L2>
+ void copy_vect(const L1& l1, L2& l2, abstract_sparse, abstract_dense) {
+ clear(l2);
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (; it != ite; ++it) { l2[it.index()] = *it; }
+ }
+
+ template <typename L1, typename L2>
+ void copy_vect(const L1& l1, L2& l2, abstract_sparse, abstract_skyline) {
+ clear(l2);
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (; it != ite; ++it) l2[it.index()] = *it;
+ }
+
+ template <typename L1, typename L2>
+ void copy_vect(const L1& l1, L2& l2, abstract_skyline, abstract_dense) {
+ typedef typename linalg_traits<L1>::value_type T;
+ typedef typename linalg_traits<L1>::const_iterator l1_const_iterator;
+ typedef typename linalg_traits<L2>::iterator l2_iterator;
+ l1_const_iterator it = vect_const_begin(l1), ite = vect_const_end(l1);
+ if (it == ite)
+ gmm::clear(l2);
+ else {
+ l2_iterator it2 = vect_begin(l2), ite2 = vect_end(l2);
+
+ size_type i = it.index(), j;
+ for (j = 0; j < i; ++j, ++it2) *it2 = T(0);
+ for (; it != ite; ++it, ++it2) *it2 = *it;
+ for (; it2 != ite2; ++it2) *it2 = T(0);
+ }
+ }
+
+ template <typename L1, typename L2>
+ void copy_vect(const L1& l1, L2& l2, abstract_sparse, abstract_sparse) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ clear(l2);
+ for (; it != ite; ++it)
+ if (*it != (typename linalg_traits<L1>::value_type)(0))
+ l2[it.index()] = *it;
+ }
+
+ template <typename L1, typename L2>
+ void copy_vect(const L1& l1, L2& l2, abstract_dense, abstract_sparse) {
+ clear(l2);
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (size_type i = 0; it != ite; ++it, ++i)
+ if (*it != (typename linalg_traits<L1>::value_type)(0))
+ l2[i] = *it;
+ }
+
+ template <typename L1, typename L2> // to be optimised ...
+ void copy_vect(const L1& l1, L2& l2, abstract_dense, abstract_skyline) {
+ clear(l2);
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (size_type i = 0; it != ite; ++it, ++i)
+ if (*it != (typename linalg_traits<L1>::value_type)(0))
+ l2[i] = *it;
+ }
+
+
+ template <typename L1, typename L2>
+ void copy_vect(const L1& l1, L2& l2, abstract_skyline, abstract_sparse) {
+ clear(l2);
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (; it != ite; ++it)
+ if (*it != (typename linalg_traits<L1>::value_type)(0))
+ l2[it.index()] = *it;
+ }
+
+ /* ******************************************************************** */
+ /* Matrix and vector addition */
+ /* algorithms are built in order to avoid some conflicts whith */
+ /* repeated arguments or with overlapping part of a same object. */
+ /* In the latter case, conflicts are still possible. */
+ /* ******************************************************************** */
+ ///@endcond
+ /** Add two vectors or matrices
+ @param l1
+ @param l2 contains on output, l2+l1.
+ */
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2) {
+ add_spec(l1, l2, typename linalg_traits<L2>::linalg_type());
+ }
+ ///@cond
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, const L2& l2) { add(l1, linalg_const_cast(l2)); }
+
+ template <typename L1, typename L2> inline
+ void add_spec(const L1& l1, L2& l2, abstract_vector) {
+ GMM_ASSERT2(vect_size(l1) == vect_size(l2), "dimensions mismatch");
+ add(l1, l2, typename linalg_traits<L1>::storage_type(),
+ typename linalg_traits<L2>::storage_type());
+ }
+
+ template <typename L1, typename L2> inline
+ void add_spec(const L1& l1, L2& l2, abstract_matrix) {
+ size_type m = mat_nrows(l1), n = mat_ncols(l1);
+ GMM_ASSERT2(m==mat_nrows(l2) && n==mat_ncols(l2), "dimensions mismatch");
+ add(l1, l2, typename linalg_traits<L1>::sub_orientation(),
+ typename linalg_traits<L2>::sub_orientation());
+ }
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, row_major, row_major) {
+ typename linalg_traits<L1>::const_row_iterator it1 = mat_row_begin(l1),
+ ite = mat_row_end(l1);
+ typename linalg_traits<L2>::row_iterator it2 = mat_row_begin(l2);
+ for ( ; it1 != ite; ++it1, ++it2)
+ add(linalg_traits<L1>::row(it1), linalg_traits<L2>::row(it2));
+ }
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, col_major, col_major) {
+ typename linalg_traits<L1>::const_col_iterator
+ it1 = mat_col_const_begin(l1),
+ ite = mat_col_const_end(l1);
+ typename linalg_traits<L2>::col_iterator it2 = mat_col_begin(l2);
+ for ( ; it1 != ite; ++it1, ++it2)
+ add(linalg_traits<L1>::col(it1), linalg_traits<L2>::col(it2));
+ }
+
+ template <typename L1, typename L2> inline
+ void add_mat_mixed_rc(const L1& l1, L2& l2, size_type i) {
+ add_mat_mixed_rc(l1, l2, i, typename linalg_traits<L1>::storage_type());
+ }
+
+ template <typename L1, typename L2>
+ void add_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_sparse) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (; it != ite; ++it) l2(i, it.index()) += *it;
+ }
+
+ template <typename L1, typename L2>
+ void add_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_skyline) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (; it != ite; ++it) l2(i, it.index()) += *it;
+ }
+
+ template <typename L1, typename L2>
+ void add_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_dense) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (size_type j = 0; it != ite; ++it, ++j) l2(i, j) += *it;
+ }
+
+ template <typename L1, typename L2> inline
+ void add_mat_mixed_cr(const L1& l1, L2& l2, size_type i) {
+ add_mat_mixed_cr(l1, l2, i, typename linalg_traits<L1>::storage_type());
+ }
+
+ template <typename L1, typename L2>
+ void add_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_sparse) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (; it != ite; ++it) l2(it.index(), i) += *it;
+ }
+
+ template <typename L1, typename L2>
+ void add_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_skyline) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (; it != ite; ++it) l2(it.index(), i) += *it;
+ }
+
+ template <typename L1, typename L2>
+ void add_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_dense) {
+ typename linalg_traits<L1>::const_iterator
+ it = vect_const_begin(l1), ite = vect_const_end(l1);
+ for (size_type j = 0; it != ite; ++it, ++j) l2(j, i) += *it;
+ }
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, row_major, col_major) {
+ size_type nbr = mat_nrows(l1);
+ for (size_type i = 0; i < nbr; ++i)
+ add_mat_mixed_rc(mat_const_row(l1, i), l2, i);
+ }
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, col_major, row_major) {
+ size_type nbc = mat_ncols(l1);
+ for (size_type i = 0; i < nbc; ++i)
+ add_mat_mixed_cr(mat_const_col(l1, i), l2, i);
+ }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, row_and_col, row_major)
+ { add(l1, l2, row_major(), row_major()); }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, row_and_col, row_and_col)
+ { add(l1, l2, row_major(), row_major()); }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, row_and_col, col_and_row)
+ { add(l1, l2, row_major(), row_major()); }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, col_and_row, row_and_col)
+ { add(l1, l2, row_major(), row_major()); }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, row_major, row_and_col)
+ { add(l1, l2, row_major(), row_major()); }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, col_and_row, row_major)
+ { add(l1, l2, row_major(), row_major()); }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, row_major, col_and_row)
+ { add(l1, l2, row_major(), row_major()); }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, row_and_col, col_major)
+ { add(l1, l2, col_major(), col_major()); }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, col_major, row_and_col)
+ { add(l1, l2, col_major(), col_major()); }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, col_and_row, col_major)
+ { add(l1, l2, col_major(), col_major()); }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, col_and_row, col_and_row)
+ { add(l1, l2, col_major(), col_major()); }
+
+ template <typename L1, typename L2> inline
+ void add(const L1& l1, L2& l2, col_major, col_and_row)
+ { add(l1, l2, col_major(), col_major()); }
+
+ ///@endcond
+ /** Addition of two vectors/matrices
+ @param l1
+ @param l2
+ @param l3 contains l1+l2 on output
+ */
+ template <typename L1, typename L2, typename L3> inline
+ void add(const L1& l1, const L2& l2, L3& l3) {
+ add_spec(l1, l2, l3, typename linalg_traits<L2>::linalg_type());
+ }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ template <typename L1, typename L2, typename L3> inline
+ void add(const L1& l1, const L2& l2, const L3& l3)
+ { add(l1, l2, linalg_const_cast(l3)); }
+
+ template <typename L1, typename L2, typename L3> inline
+ void add_spec(const L1& l1, const L2& l2, L3& l3, abstract_matrix)
+ { copy(l2, l3); add(l1, l3); }
+
+ template <typename L1, typename L2, typename L3> inline
+ void add_spec(const L1& l1, const L2& l2, L3& l3, abstract_vector) {
+ GMM_ASSERT2(vect_size(l1) == vect_size(l2) &&
+ vect_size(l1) == vect_size(l3), "dimensions mismatch");
+ if ((const void *)(&l1) == (const void *)(&l3))
+ add(l2, l3);
+ else if ((const void *)(&l2) == (const void *)(&l3))
+ add(l1, l3);
+ else
+ add(l1, l2, l3, typename linalg_traits<L1>::storage_type(),
+ typename linalg_traits<L2>::storage_type(),
+ typename linalg_traits<L3>::storage_type());
+ }
+
+ template <typename IT1, typename IT2, typename IT3>
+ void add_full_(IT1 it1, IT2 it2, IT3 it3, IT3 ite) {
+ for (; it3 != ite; ++it3, ++it2, ++it1) *it3 = *it1 + *it2;
+ }
+
+ template <typename IT1, typename IT2, typename IT3>
+ void add_almost_full_(IT1 it1, IT1 ite1, IT2 it2, IT3 it3, IT3 ite3) {
+ IT3 it = it3;
+ for (; it != ite3; ++it, ++it2) *it = *it2;
+ for (; it1 != ite1; ++it1)
+ *(it3 + it1.index()) += *it1;
+ }
+
+ template <typename IT1, typename IT2, typename IT3>
+ void add_to_full_(IT1 it1, IT1 ite1, IT2 it2, IT2 ite2,
+ IT3 it3, IT3 ite3) {
+ typedef typename std::iterator_traits<IT3>::value_type T;
+ IT3 it = it3;
+ for (; it != ite3; ++it) *it = T(0);
+ for (; it1 != ite1; ++it1) *(it3 + it1.index()) = *it1;
+ for (; it2 != ite2; ++it2) *(it3 + it2.index()) += *it2;
+ }
+
+ template <typename L1, typename L2, typename L3> inline
+ void add(const L1& l1, const L2& l2, L3& l3,
+ abstract_dense, abstract_dense, abstract_dense) {
+ add_full_(vect_const_begin(l1), vect_const_begin(l2),
+ vect_begin(l3), vect_end(l3));
+ }
+
+ // generic function for add(v1, v2, v3).
+ // Need to be specialized to optimize particular additions.
+ template <typename L1, typename L2, typename L3,
+ typename ST1, typename ST2, typename ST3>
+ inline void add(const L1& l1, const L2& l2, L3& l3, ST1, ST2, ST3)
+ { copy(l2, l3); add(l1, l3, ST1(), ST3()); }
+
+ template <typename L1, typename L2, typename L3> inline
+ void add(const L1& l1, const L2& l2, L3& l3,
+ abstract_sparse, abstract_dense, abstract_dense) {
+ add_almost_full_(vect_const_begin(l1), vect_const_end(l1),
+ vect_const_begin(l2), vect_begin(l3), vect_end(l3));
+ }
+
+ template <typename L1, typename L2, typename L3> inline
+ void add(const L1& l1, const L2& l2, L3& l3,
+ abstract_dense, abstract_sparse, abstract_dense)
+ { add(l2, l1, l3, abstract_sparse(), abstract_dense(), abstract_dense()); }
+
+ template <typename L1, typename L2, typename L3> inline
+ void add(const L1& l1, const L2& l2, L3& l3,
+ abstract_sparse, abstract_sparse, abstract_dense) {
+ add_to_full_(vect_const_begin(l1), vect_const_end(l1),
+ vect_const_begin(l2), vect_const_end(l2),
+ vect_begin(l3), vect_end(l3));
+ }
+
+
+ template <typename L1, typename L2, typename L3>
+ void add_spspsp(const L1& l1, const L2& l2, L3& l3, linalg_true) {
+ typename linalg_traits<L1>::const_iterator
+ it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+ typename linalg_traits<L2>::const_iterator
+ it2 = vect_const_begin(l2), ite2 = vect_const_end(l2);
+ clear(l3);
+ while (it1 != ite1 && it2 != ite2) {
+ ptrdiff_t d = it1.index() - it2.index();
+ if (d < 0)
+ { l3[it1.index()] += *it1; ++it1; }
+ else if (d > 0)
+ { l3[it2.index()] += *it2; ++it2; }
+ else
+ { l3[it1.index()] = *it1 + *it2; ++it1; ++it2; }
+ }
+ for (; it1 != ite1; ++it1) l3[it1.index()] += *it1;
+ for (; it2 != ite2; ++it2) l3[it2.index()] += *it2;
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void add_spspsp(const L1& l1, const L2& l2, L3& l3, linalg_false)
+ { copy(l2, l3); add(l2, l3); }
+
+ template <typename L1, typename L2, typename L3>
+ void add(const L1& l1, const L2& l2, L3& l3,
+ abstract_sparse, abstract_sparse, abstract_sparse) {
+ add_spspsp(l1, l2, l3, typename linalg_and<typename
+ linalg_traits<L1>::index_sorted,
+ typename linalg_traits<L2>::index_sorted>::bool_type());
+ }
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, abstract_dense, abstract_dense) {
+ typename linalg_traits<L1>::const_iterator it1 = vect_const_begin(l1);
+ typename linalg_traits<L2>::iterator
+ it2 = vect_begin(l2), ite = vect_end(l2);
+ for (; it2 != ite; ++it2, ++it1) *it2 += *it1;
+ }
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, abstract_dense, abstract_skyline) {
+ typedef typename linalg_traits<L1>::const_iterator const_l1_iterator;
+ typedef typename linalg_traits<L2>::iterator l2_iterator;
+ typedef typename linalg_traits<L1>::value_type T;
+
+ const_l1_iterator it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+ size_type i1 = 0, ie1 = vect_size(l1);
+ while (it1 != ite1 && *it1 == T(0)) { ++it1; ++i1; }
+ if (it1 != ite1) {
+ l2_iterator it2 = vect_begin(l2), ite2 = vect_end(l2);
+ while (ie1 && *(ite1-1) == T(0)) { ite1--; --ie1; }
+
+ if (it2 == ite2 || i1 < it2.index()) {
+ l2[i1] = *it1; ++i1; ++it1;
+ if (it1 == ite1) return;
+ it2 = vect_begin(l2); ite2 = vect_end(l2);
+ }
+ if (ie1 > ite2.index()) {
+ --ite1; l2[ie1 - 1] = *ite1;
+ it2 = vect_begin(l2);
+ }
+ it2 += i1 - it2.index();
+ for (; it1 != ite1; ++it1, ++it2) { *it2 += *it1; }
+ }
+ }
+
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, abstract_skyline, abstract_dense) {
+ typename linalg_traits<L1>::const_iterator it1 = vect_const_begin(l1),
+ ite1 = vect_const_end(l1);
+ if (it1 != ite1) {
+ typename linalg_traits<L2>::iterator it2 = vect_begin(l2);
+ it2 += it1.index();
+ for (; it1 != ite1; ++it2, ++it1) *it2 += *it1;
+ }
+ }
+
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, abstract_sparse, abstract_dense) {
+ typename linalg_traits<L1>::const_iterator
+ it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+ for (; it1 != ite1; ++it1) l2[it1.index()] += *it1;
+ }
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, abstract_sparse, abstract_sparse) {
+ typename linalg_traits<L1>::const_iterator
+ it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+ for (; it1 != ite1; ++it1) l2[it1.index()] += *it1;
+ }
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, abstract_sparse, abstract_skyline) {
+ typename linalg_traits<L1>::const_iterator
+ it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+ for (; it1 != ite1; ++it1) l2[it1.index()] += *it1;
+ }
+
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, abstract_skyline, abstract_sparse) {
+ typename linalg_traits<L1>::const_iterator
+ it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+ for (; it1 != ite1; ++it1)
+ if (*it1 != typename linalg_traits<L1>::value_type(0))
+ l2[it1.index()] += *it1;
+ }
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, abstract_skyline, abstract_skyline) {
+ typedef typename linalg_traits<L1>::const_iterator const_l1_iterator;
+ typedef typename linalg_traits<L2>::iterator l2_iterator;
+ typedef typename linalg_traits<L1>::value_type T1;
+ typedef typename linalg_traits<L2>::value_type T2;
+
+ const_l1_iterator it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+
+ while (it1 != ite1 && *it1 == T1(0)) ++it1;
+ if (ite1 != it1) {
+ l2_iterator it2 = vect_begin(l2), ite2 = vect_end(l2);
+ while (*(ite1-1) == T1(0)) ite1--;
+ if (it2 == ite2 || it1.index() < it2.index()) {
+ l2[it1.index()] = T2(0);
+ it2 = vect_begin(l2); ite2 = vect_end(l2);
+ }
+ if (ite1.index() > ite2.index()) {
+ l2[ite1.index() - 1] = T2(0);
+ it2 = vect_begin(l2);
+ }
+ it2 += it1.index() - it2.index();
+ for (; it1 != ite1; ++it1, ++it2) *it2 += *it1;
+ }
+ }
+
+ template <typename L1, typename L2>
+ void add(const L1& l1, L2& l2, abstract_dense, abstract_sparse) {
+ typename linalg_traits<L1>::const_iterator
+ it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+ for (size_type i = 0; it1 != ite1; ++it1, ++i)
+ if (*it1 != typename linalg_traits<L1>::value_type(0)) l2[i] += *it1;
+ }
+
+ /* ******************************************************************** */
+ /* Matrix-vector mult */
+ /* ******************************************************************** */
+ ///@endcond
+ /** matrix-vector or matrix-matrix product.
+ @param l1 a matrix.
+ @param l2 a vector or matrix.
+ @param l3 the product l1*l2.
+ */
+ template <typename L1, typename L2, typename L3> inline
+ void mult(const L1& l1, const L2& l2, L3& l3) {
+ mult_dispatch(l1, l2, l3, typename linalg_traits<L2>::linalg_type());
+ }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult(const L1& l1, const L2& l2, const L3& l3)
+ { mult(l1, l2, linalg_const_cast(l3)); }
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_dispatch(const L1& l1, const L2& l2, L3& l3, abstract_vector) {
+ size_type m = mat_nrows(l1), n = mat_ncols(l1);
+ if (!m || !n) { gmm::clear(l3); return; }
+ GMM_ASSERT2(n==vect_size(l2) && m==vect_size(l3), "dimensions mismatch");
+ if (!same_origin(l2, l3))
+ mult_spec(l1, l2, l3, typename principal_orientation_type<typename
+ linalg_traits<L1>::sub_orientation>::potype());
+ else {
+ GMM_WARNING2("Warning, A temporary is used for mult\n");
+ typename temporary_vector<L3>::vector_type temp(vect_size(l3));
+ mult_spec(l1, l2, temp, typename principal_orientation_type<typename
+ linalg_traits<L1>::sub_orientation>::potype());
+ copy(temp, l3);
+ }
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_by_row(const L1& l1, const L2& l2, L3& l3, abstract_sparse) {
+ typedef typename linalg_traits<L3>::value_type T;
+ clear(l3);
+ size_type nr = mat_nrows(l1);
+ for (size_type i = 0; i < nr; ++i) {
+ T aux = vect_sp(mat_const_row(l1, i), l2);
+ if (aux != T(0)) l3[i] = aux;
+ }
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_by_row(const L1& l1, const L2& l2, L3& l3, abstract_skyline) {
+ typedef typename linalg_traits<L3>::value_type T;
+ clear(l3);
+ size_type nr = mat_nrows(l1);
+ for (size_type i = 0; i < nr; ++i) {
+ T aux = vect_sp(mat_const_row(l1, i), l2);
+ if (aux != T(0)) l3[i] = aux;
+ }
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_by_row(const L1& l1, const L2& l2, L3& l3, abstract_dense) {
+ typename linalg_traits<L3>::iterator it=vect_begin(l3), ite=vect_end(l3);
+ typename linalg_traits<L1>::const_row_iterator
+ itr = mat_row_const_begin(l1);
+ for (; it != ite; ++it, ++itr)
+ *it = vect_sp(linalg_traits<L1>::row(itr), l2,
+ typename linalg_traits<L1>::storage_type(),
+ typename linalg_traits<L2>::storage_type());
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_by_col(const L1& l1, const L2& l2, L3& l3, abstract_dense) {
+ clear(l3);
+ size_type nc = mat_ncols(l1);
+ for (size_type i = 0; i < nc; ++i)
+ add(scaled(mat_const_col(l1, i), l2[i]), l3);
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_by_col(const L1& l1, const L2& l2, L3& l3, abstract_sparse) {
+ typedef typename linalg_traits<L2>::value_type T;
+ clear(l3);
+ typename linalg_traits<L2>::const_iterator it = vect_const_begin(l2),
+ ite = vect_const_end(l2);
+ for (; it != ite; ++it)
+ if (*it != T(0)) add(scaled(mat_const_col(l1, it.index()), *it), l3);
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_by_col(const L1& l1, const L2& l2, L3& l3, abstract_skyline) {
+ typedef typename linalg_traits<L2>::value_type T;
+ clear(l3);
+ typename linalg_traits<L2>::const_iterator it = vect_const_begin(l2),
+ ite = vect_const_end(l2);
+ for (; it != ite; ++it)
+ if (*it != T(0)) add(scaled(mat_const_col(l1, it.index()), *it), l3);
+ }
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, row_major)
+ { mult_by_row(l1, l2, l3, typename linalg_traits<L3>::storage_type()); }
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, col_major)
+ { mult_by_col(l1, l2, l3, typename linalg_traits<L2>::storage_type()); }
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, abstract_null_type)
+ { mult_ind(l1, l2, l3, typename linalg_traits<L1>::storage_type()); }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_ind(const L1& l1, const L2& l2, L3& l3, abstract_indirect) {
+ GMM_ASSERT1(false, "gmm::mult(m, ., .) undefined for this kind of matrix");
+ }
+
+ template <typename L1, typename L2, typename L3, typename L4> inline
+ void mult(const L1& l1, const L2& l2, const L3& l3, L4& l4) {
+ size_type m = mat_nrows(l1), n = mat_ncols(l1);
+ copy(l3, l4);
+ if (!m || !n) { gmm::copy(l3, l4); return; }
+ GMM_ASSERT2(n==vect_size(l2) && m==vect_size(l4), "dimensions mismatch");
+ if (!same_origin(l2, l4)) {
+ mult_add_spec(l1, l2, l4, typename principal_orientation_type<typename
+ linalg_traits<L1>::sub_orientation>::potype());
+ }
+ else {
+ GMM_WARNING2("Warning, A temporary is used for mult\n");
+ typename temporary_vector<L2>::vector_type temp(vect_size(l2));
+ copy(l2, temp);
+ mult_add_spec(l1,temp, l4, typename principal_orientation_type<typename
+ linalg_traits<L1>::sub_orientation>::potype());
+ }
+ }
+
+ template <typename L1, typename L2, typename L3, typename L4> inline
+ void mult(const L1& l1, const L2& l2, const L3& l3, const L4& l4)
+ { mult(l1, l2, l3, linalg_const_cast(l4)); }
+
+ ///@endcond
+ /** Multiply-accumulate. l3 += l1*l2; */
+ template <typename L1, typename L2, typename L3> inline
+ void mult_add(const L1& l1, const L2& l2, L3& l3) {
+ size_type m = mat_nrows(l1), n = mat_ncols(l1);
+ if (!m || !n) return;
+ GMM_ASSERT2(n==vect_size(l2) && m==vect_size(l3), "dimensions mismatch");
+ if (!same_origin(l2, l3)) {
+ mult_add_spec(l1, l2, l3, typename principal_orientation_type<typename
+ linalg_traits<L1>::sub_orientation>::potype());
+ }
+ else {
+ GMM_WARNING2("Warning, A temporary is used for mult\n");
+ typename temporary_vector<L3>::vector_type temp(vect_size(l2));
+ copy(l2, temp);
+ mult_add_spec(l1,temp, l3, typename principal_orientation_type<typename
+ linalg_traits<L1>::sub_orientation>::potype());
+ }
+ }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_add(const L1& l1, const L2& l2, const L3& l3)
+ { mult_add(l1, l2, linalg_const_cast(l3)); }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_add_by_row(const L1& l1, const L2& l2, L3& l3, abstract_sparse) {
+ typedef typename linalg_traits<L3>::value_type T;
+ size_type nr = mat_nrows(l1);
+ for (size_type i = 0; i < nr; ++i) {
+ T aux = vect_sp(mat_const_row(l1, i), l2);
+ if (aux != T(0)) l3[i] += aux;
+ }
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_add_by_row(const L1& l1, const L2& l2, L3& l3, abstract_skyline) {
+ typedef typename linalg_traits<L3>::value_type T;
+ size_type nr = mat_nrows(l1);
+ for (size_type i = 0; i < nr; ++i) {
+ T aux = vect_sp(mat_const_row(l1, i), l2);
+ if (aux != T(0)) l3[i] += aux;
+ }
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_add_by_row(const L1& l1, const L2& l2, L3& l3, abstract_dense) {
+ typename linalg_traits<L3>::iterator it=vect_begin(l3), ite=vect_end(l3);
+ typename linalg_traits<L1>::const_row_iterator
+ itr = mat_row_const_begin(l1);
+ for (; it != ite; ++it, ++itr)
+ *it += vect_sp(linalg_traits<L1>::row(itr), l2);
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_add_by_col(const L1& l1, const L2& l2, L3& l3, abstract_dense) {
+ size_type nc = mat_ncols(l1);
+ for (size_type i = 0; i < nc; ++i)
+ add(scaled(mat_const_col(l1, i), l2[i]), l3);
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_add_by_col(const L1& l1, const L2& l2, L3& l3, abstract_sparse) {
+ typename linalg_traits<L2>::const_iterator it = vect_const_begin(l2),
+ ite = vect_const_end(l2);
+ for (; it != ite; ++it)
+ if (*it != typename linalg_traits<L2>::value_type(0))
+ add(scaled(mat_const_col(l1, it.index()), *it), l3);
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_add_by_col(const L1& l1, const L2& l2, L3& l3, abstract_skyline) {
+ typename linalg_traits<L2>::const_iterator it = vect_const_begin(l2),
+ ite = vect_const_end(l2);
+ for (; it != ite; ++it)
+ if (*it != typename linalg_traits<L2>::value_type(0))
+ add(scaled(mat_const_col(l1, it.index()), *it), l3);
+ }
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_add_spec(const L1& l1, const L2& l2, L3& l3, row_major)
+ { mult_add_by_row(l1, l2, l3, typename linalg_traits<L3>::storage_type()); }
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_add_spec(const L1& l1, const L2& l2, L3& l3, col_major)
+ { mult_add_by_col(l1, l2, l3, typename linalg_traits<L2>::storage_type()); }
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_add_spec(const L1& l1, const L2& l2, L3& l3, abstract_null_type)
+ { mult_ind(l1, l2, l3, typename linalg_traits<L1>::storage_type()); }
+
+ template <typename L1, typename L2, typename L3>
+ void transposed_mult(const L1& l1, const L2& l2, const L3& l3)
+ { mult(gmm::transposed(l1), l2, l3); }
+
+
+ /* ******************************************************************** */
+ /* Matrix-matrix mult */
+ /* ******************************************************************** */
+
+
+ struct g_mult {}; // generic mult, less optimized
+ struct c_mult {}; // col x col -> col mult
+ struct r_mult {}; // row x row -> row mult
+ struct rcmult {}; // row x col -> col mult
+ struct crmult {}; // col x row -> row mult
+
+
+ template<typename SO1, typename SO2, typename SO3> struct mult_t;
+ #define DEFMU__ template<> struct mult_t
+ DEFMU__<row_major , row_major , row_major > { typedef r_mult t; };
+ DEFMU__<row_major , row_major , col_major > { typedef g_mult t; };
+ DEFMU__<row_major , row_major , col_and_row> { typedef r_mult t; };
+ DEFMU__<row_major , row_major , row_and_col> { typedef r_mult t; };
+ DEFMU__<row_major , col_major , row_major > { typedef rcmult t; };
+ DEFMU__<row_major , col_major , col_major > { typedef rcmult t; };
+ DEFMU__<row_major , col_major , col_and_row> { typedef rcmult t; };
+ DEFMU__<row_major , col_major , row_and_col> { typedef rcmult t; };
+ DEFMU__<row_major , col_and_row, row_major > { typedef r_mult t; };
+ DEFMU__<row_major , col_and_row, col_major > { typedef rcmult t; };
+ DEFMU__<row_major , col_and_row, col_and_row> { typedef rcmult t; };
+ DEFMU__<row_major , col_and_row, row_and_col> { typedef rcmult t; };
+ DEFMU__<row_major , row_and_col, row_major > { typedef r_mult t; };
+ DEFMU__<row_major , row_and_col, col_major > { typedef rcmult t; };
+ DEFMU__<row_major , row_and_col, col_and_row> { typedef r_mult t; };
+ DEFMU__<row_major , row_and_col, row_and_col> { typedef r_mult t; };
+ DEFMU__<col_major , row_major , row_major > { typedef crmult t; };
+ DEFMU__<col_major , row_major , col_major > { typedef g_mult t; };
+ DEFMU__<col_major , row_major , col_and_row> { typedef crmult t; };
+ DEFMU__<col_major , row_major , row_and_col> { typedef crmult t; };
+ DEFMU__<col_major , col_major , row_major > { typedef g_mult t; };
+ DEFMU__<col_major , col_major , col_major > { typedef c_mult t; };
+ DEFMU__<col_major , col_major , col_and_row> { typedef c_mult t; };
+ DEFMU__<col_major , col_major , row_and_col> { typedef c_mult t; };
+ DEFMU__<col_major , col_and_row, row_major > { typedef crmult t; };
+ DEFMU__<col_major , col_and_row, col_major > { typedef c_mult t; };
+ DEFMU__<col_major , col_and_row, col_and_row> { typedef c_mult t; };
+ DEFMU__<col_major , col_and_row, row_and_col> { typedef c_mult t; };
+ DEFMU__<col_major , row_and_col, row_major > { typedef crmult t; };
+ DEFMU__<col_major , row_and_col, col_major > { typedef c_mult t; };
+ DEFMU__<col_major , row_and_col, col_and_row> { typedef c_mult t; };
+ DEFMU__<col_major , row_and_col, row_and_col> { typedef c_mult t; };
+ DEFMU__<col_and_row, row_major , row_major > { typedef r_mult t; };
+ DEFMU__<col_and_row, row_major , col_major > { typedef c_mult t; };
+ DEFMU__<col_and_row, row_major , col_and_row> { typedef r_mult t; };
+ DEFMU__<col_and_row, row_major , row_and_col> { typedef r_mult t; };
+ DEFMU__<col_and_row, col_major , row_major > { typedef rcmult t; };
+ DEFMU__<col_and_row, col_major , col_major > { typedef c_mult t; };
+ DEFMU__<col_and_row, col_major , col_and_row> { typedef c_mult t; };
+ DEFMU__<col_and_row, col_major , row_and_col> { typedef c_mult t; };
+ DEFMU__<col_and_row, col_and_row, row_major > { typedef r_mult t; };
+ DEFMU__<col_and_row, col_and_row, col_major > { typedef c_mult t; };
+ DEFMU__<col_and_row, col_and_row, col_and_row> { typedef c_mult t; };
+ DEFMU__<col_and_row, col_and_row, row_and_col> { typedef c_mult t; };
+ DEFMU__<col_and_row, row_and_col, row_major > { typedef r_mult t; };
+ DEFMU__<col_and_row, row_and_col, col_major > { typedef c_mult t; };
+ DEFMU__<col_and_row, row_and_col, col_and_row> { typedef c_mult t; };
+ DEFMU__<col_and_row, row_and_col, row_and_col> { typedef r_mult t; };
+ DEFMU__<row_and_col, row_major , row_major > { typedef r_mult t; };
+ DEFMU__<row_and_col, row_major , col_major > { typedef c_mult t; };
+ DEFMU__<row_and_col, row_major , col_and_row> { typedef r_mult t; };
+ DEFMU__<row_and_col, row_major , row_and_col> { typedef r_mult t; };
+ DEFMU__<row_and_col, col_major , row_major > { typedef rcmult t; };
+ DEFMU__<row_and_col, col_major , col_major > { typedef c_mult t; };
+ DEFMU__<row_and_col, col_major , col_and_row> { typedef c_mult t; };
+ DEFMU__<row_and_col, col_major , row_and_col> { typedef c_mult t; };
+ DEFMU__<row_and_col, col_and_row, row_major > { typedef rcmult t; };
+ DEFMU__<row_and_col, col_and_row, col_major > { typedef rcmult t; };
+ DEFMU__<row_and_col, col_and_row, col_and_row> { typedef rcmult t; };
+ DEFMU__<row_and_col, col_and_row, row_and_col> { typedef rcmult t; };
+ DEFMU__<row_and_col, row_and_col, row_major > { typedef r_mult t; };
+ DEFMU__<row_and_col, row_and_col, col_major > { typedef c_mult t; };
+ DEFMU__<row_and_col, row_and_col, col_and_row> { typedef r_mult t; };
+ DEFMU__<row_and_col, row_and_col, row_and_col> { typedef r_mult t; };
+
+ template <typename L1, typename L2, typename L3>
+ void mult_dispatch(const L1& l1, const L2& l2, L3& l3, abstract_matrix) {
+ typedef typename temporary_matrix<L3>::matrix_type temp_mat_type;
+ size_type m = mat_nrows(l1), n = mat_ncols(l1), k = mat_ncols(l2);
+ if (n == 0) { gmm::clear(l3); return; }
+ GMM_ASSERT2(n == mat_nrows(l2) && m == mat_nrows(l3) && k == mat_ncols(l3),
+ "dimensions mismatch");
+
+ if (same_origin(l2, l3) || same_origin(l1, l3)) {
+ GMM_WARNING2("A temporary is used for mult");
+ temp_mat_type temp(mat_nrows(l3), mat_ncols(l3));
+ mult_spec(l1, l2, temp, typename mult_t<
+ typename linalg_traits<L1>::sub_orientation,
+ typename linalg_traits<L2>::sub_orientation,
+ typename linalg_traits<temp_mat_type>::sub_orientation>::t());
+ copy(temp, l3);
+ }
+ else
+ mult_spec(l1, l2, l3, typename mult_t<
+ typename linalg_traits<L1>::sub_orientation,
+ typename linalg_traits<L2>::sub_orientation,
+ typename linalg_traits<L3>::sub_orientation>::t());
+ }
+
+ // Completely generic but inefficient
+
+ template <typename L1, typename L2, typename L3>
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, g_mult) {
+ typedef typename linalg_traits<L3>::value_type T;
+ GMM_WARNING2("Inefficient generic matrix-matrix mult is used");
+ for (size_type i = 0; i < mat_nrows(l3) ; ++i)
+ for (size_type j = 0; j < mat_ncols(l3) ; ++j) {
+ T a(0);
+ for (size_type k = 0; k < mat_nrows(l2) ; ++k) a += l1(i, k)*l2(k, j);
+ l3(i, j) = a;
+ }
+ }
+
+ // row x col matrix-matrix mult
+
+ template <typename L1, typename L2, typename L3>
+ void mult_row_col_with_temp(const L1& l1, const L2& l2, L3& l3, col_major) {
+ typedef typename temporary_col_matrix<L1>::matrix_type temp_col_mat;
+ temp_col_mat temp(mat_nrows(l1), mat_ncols(l1));
+ copy(l1, temp);
+ mult(temp, l2, l3);
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_row_col_with_temp(const L1& l1, const L2& l2, L3& l3, row_major) {
+ typedef typename temporary_row_matrix<L2>::matrix_type temp_row_mat;
+ temp_row_mat temp(mat_nrows(l2), mat_ncols(l2));
+ copy(l2, temp);
+ mult(l1, temp, l3);
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, rcmult) {
+ if (is_sparse(l1) && is_sparse(l2)) {
+ GMM_WARNING3("Inefficient row matrix - col matrix mult for "
+ "sparse matrices, using temporary");
+ mult_row_col_with_temp(l1, l2, l3,
+ typename principal_orientation_type<typename
+ linalg_traits<L3>::sub_orientation>::potype());
+ }
+ else {
+ typename linalg_traits<L2>::const_col_iterator
+ it2b = linalg_traits<L2>::col_begin(l2), it2,
+ ite = linalg_traits<L2>::col_end(l2);
+ size_type i,j, k = mat_nrows(l1);
+
+ for (i = 0; i < k; ++i) {
+ typename linalg_traits<L1>::const_sub_row_type r1=mat_const_row(l1, i);
+ for (it2 = it2b, j = 0; it2 != ite; ++it2, ++j)
+ l3(i,j) = vect_sp(r1, linalg_traits<L2>::col(it2));
+ }
+ }
+ }
+
+ // row - row matrix-matrix mult
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, r_mult) {
+ mult_spec(l1, l2, l3,r_mult(),typename linalg_traits<L1>::storage_type());
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, r_mult, abstract_dense) {
+ // optimizable
+ clear(l3);
+ size_type nn = mat_nrows(l3), mm = mat_nrows(l2);
+ for (size_type i = 0; i < nn; ++i) {
+ for (size_type j = 0; j < mm; ++j) {
+ add(scaled(mat_const_row(l2, j), l1(i, j)), mat_row(l3, i));
+ }
+ }
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, r_mult, abstract_sparse) {
+ // optimizable
+ clear(l3);
+ size_type nn = mat_nrows(l3);
+ for (size_type i = 0; i < nn; ++i) {
+ typename linalg_traits<L1>::const_sub_row_type rl1=mat_const_row(l1, i);
+ typename linalg_traits<typename linalg_traits<L1>::const_sub_row_type>::
+ const_iterator it = vect_const_begin(rl1), ite = vect_const_end(rl1);
+ for (; it != ite; ++it)
+ add(scaled(mat_const_row(l2, it.index()), *it), mat_row(l3, i));
+ }
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, r_mult, abstract_skyline)
+ { mult_spec(l1, l2, l3, r_mult(), abstract_sparse()); }
+
+ // col - col matrix-matrix mult
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, c_mult) {
+ mult_spec(l1, l2,l3,c_mult(),typename linalg_traits<L2>::storage_type(),
+ typename linalg_traits<L2>::sub_orientation());
+ }
+
+
+ template <typename L1, typename L2, typename L3, typename ORIEN>
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, c_mult,
+ abstract_dense, ORIEN) {
+ typedef typename linalg_traits<L2>::value_type T;
+ size_type nn = mat_ncols(l3), mm = mat_ncols(l1);
+
+ for (size_type i = 0; i < nn; ++i) {
+ clear(mat_col(l3, i));
+ for (size_type j = 0; j < mm; ++j) {
+ T b = l2(j, i);
+ if (b != T(0)) add(scaled(mat_const_col(l1, j), b), mat_col(l3, i));
+ }
+ }
+ }
+
+ template <typename L1, typename L2, typename L3, typename ORIEN>
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, c_mult,
+ abstract_sparse, ORIEN) {
+ // optimizable
+ clear(l3);
+ size_type nn = mat_ncols(l3);
+ for (size_type i = 0; i < nn; ++i) {
+ typename linalg_traits<L2>::const_sub_col_type rc2=mat_const_col(l2, i);
+ typename linalg_traits<typename linalg_traits<L2>::const_sub_col_type>::
+ const_iterator it = vect_const_begin(rc2), ite = vect_const_end(rc2);
+ for (; it != ite; ++it)
+ add(scaled(mat_const_col(l1, it.index()), *it), mat_col(l3, i));
+ }
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, c_mult,
+ abstract_sparse, row_major) {
+ typedef typename linalg_traits<L2>::value_type T;
+ GMM_WARNING3("Inefficient matrix-matrix mult for sparse matrices");
+ clear(l3);
+ size_type mm = mat_nrows(l2), nn = mat_ncols(l3);
+ for (size_type i = 0; i < nn; ++i)
+ for (size_type j = 0; j < mm; ++j) {
+ T a = l2(i,j);
+ if (a != T(0)) add(scaled(mat_const_col(l1, j), a), mat_col(l3, i));
+ }
+ }
+
+ template <typename L1, typename L2, typename L3, typename ORIEN> inline
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, c_mult,
+ abstract_skyline, ORIEN)
+ { mult_spec(l1, l2, l3, c_mult(), abstract_sparse(), ORIEN()); }
+
+
+ // col - row matrix-matrix mult
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, crmult)
+ { mult_spec(l1,l2,l3,crmult(), typename linalg_traits<L1>::storage_type()); }
+
+
+ template <typename L1, typename L2, typename L3>
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, crmult, abstract_dense) {
+ // optimizable
+ clear(l3);
+ size_type nn = mat_ncols(l1), mm = mat_nrows(l1);
+ for (size_type i = 0; i < nn; ++i) {
+ for (size_type j = 0; j < mm; ++j)
+ add(scaled(mat_const_row(l2, i), l1(j, i)), mat_row(l3, j));
+ }
+ }
+
+ template <typename L1, typename L2, typename L3>
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, crmult, abstract_sparse) {
+ // optimizable
+ clear(l3);
+ size_type nn = mat_ncols(l1);
+ for (size_type i = 0; i < nn; ++i) {
+ typename linalg_traits<L1>::const_sub_col_type rc1=mat_const_col(l1, i);
+ typename linalg_traits<typename linalg_traits<L1>::const_sub_col_type>::
+ const_iterator it = vect_const_begin(rc1), ite = vect_const_end(rc1);
+ for (; it != ite; ++it)
+ add(scaled(mat_const_row(l2, i), *it), mat_row(l3, it.index()));
+ }
+ }
+
+ template <typename L1, typename L2, typename L3> inline
+ void mult_spec(const L1& l1, const L2& l2, L3& l3, crmult, abstract_skyline)
+ { mult_spec(l1, l2, l3, crmult(), abstract_sparse()); }
+
+
+ /* ******************************************************************** */
+ /* Symmetry test. */
+ /* ******************************************************************** */
+
+ ///@endcond
+ /** test if A is symmetric.
+ @param A a matrix.
+ @param tol a threshold.
+ */
+ template <typename MAT> inline
+ bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol
+ = magnitude_of_linalg(MAT)(-1)) {
+ typedef magnitude_of_linalg(MAT) R;
+ if (tol < R(0)) tol = default_tol(R()) * mat_maxnorm(A);
+ if (mat_nrows(A) != mat_ncols(A)) return false;
+ return is_symmetric(A, tol, typename linalg_traits<MAT>::storage_type());
+ }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ template <typename MAT>
+ bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol,
+ abstract_dense) {
+ size_type m = mat_nrows(A);
+ for (size_type i = 1; i < m; ++i)
+ for (size_type j = 0; j < i; ++j)
+ if (gmm::abs(A(i, j)-A(j, i)) > tol) return false;
+ return true;
+ }
+
+ template <typename MAT>
+ bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol,
+ abstract_sparse) {
+ return is_symmetric(A, tol, typename principal_orientation_type<typename
+ linalg_traits<MAT>::sub_orientation>::potype());
+ }
+
+ template <typename MAT>
+ bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol,
+ row_major) {
+ for (size_type i = 0; i < mat_nrows(A); ++i) {
+ typedef typename linalg_traits<MAT>::const_sub_row_type row_type;
+ row_type row = mat_const_row(A, i);
+ typename linalg_traits<row_type>::const_iterator
+ it = vect_const_begin(row), ite = vect_const_end(row);
+ for (; it != ite; ++it)
+ if (gmm::abs(*it - A(it.index(), i)) > tol) return false;
+ }
+ return true;
+ }
+
+ template <typename MAT>
+ bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol,
+ col_major) {
+ for (size_type i = 0; i < mat_ncols(A); ++i) {
+ typedef typename linalg_traits<MAT>::const_sub_col_type col_type;
+ col_type col = mat_const_col(A, i);
+ typename linalg_traits<col_type>::const_iterator
+ it = vect_const_begin(col), ite = vect_const_end(col);
+ for (; it != ite; ++it)
+ if (gmm::abs(*it - A(i, it.index())) > tol) return false;
+ }
+ return true;
+ }
+
+ template <typename MAT>
+ bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol,
+ abstract_skyline)
+ { return is_symmetric(A, tol, abstract_sparse()); }
+
+ ///@endcond
+ /** test if A is Hermitian.
+ @param A a matrix.
+ @param tol a threshold.
+ */
+ template <typename MAT> inline
+ bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol
+ = magnitude_of_linalg(MAT)(-1)) {
+ typedef magnitude_of_linalg(MAT) R;
+ if (tol < R(0)) tol = default_tol(R()) * mat_maxnorm(A);
+ if (mat_nrows(A) != mat_ncols(A)) return false;
+ return is_hermitian(A, tol, typename linalg_traits<MAT>::storage_type());
+ }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ template <typename MAT>
+ bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol,
+ abstract_dense) {
+ size_type m = mat_nrows(A);
+ for (size_type i = 1; i < m; ++i)
+ for (size_type j = 0; j < i; ++j)
+ if (gmm::abs(A(i, j)-gmm::conj(A(j, i))) > tol) return false;
+ return true;
+ }
+
+ template <typename MAT>
+ bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol,
+ abstract_sparse) {
+ return is_hermitian(A, tol, typename principal_orientation_type<typename
+ linalg_traits<MAT>::sub_orientation>::potype());
+ }
+
+ template <typename MAT>
+ bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol,
+ row_major) {
+ for (size_type i = 0; i < mat_nrows(A); ++i) {
+ typedef typename linalg_traits<MAT>::const_sub_row_type row_type;
+ row_type row = mat_const_row(A, i);
+ typename linalg_traits<row_type>::const_iterator
+ it = vect_const_begin(row), ite = vect_const_end(row);
+ for (; it != ite; ++it)
+ if (gmm::abs(gmm::conj(*it) - A(it.index(), i)) > tol) return false;
+ }
+ return true;
+ }
+
+ template <typename MAT>
+ bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol,
+ col_major) {
+ for (size_type i = 0; i < mat_ncols(A); ++i) {
+ typedef typename linalg_traits<MAT>::const_sub_col_type col_type;
+ col_type col = mat_const_col(A, i);
+ typename linalg_traits<col_type>::const_iterator
+ it = vect_const_begin(col), ite = vect_const_end(col);
+ for (; it != ite; ++it)
+ if (gmm::abs(gmm::conj(*it) - A(i, it.index())) > tol) return false;
+ }
+ return true;
+ }
+
+ template <typename MAT>
+ bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol,
+ abstract_skyline)
+ { return is_hermitian(A, tol, abstract_sparse()); }
+ ///@endcond
+}
+
+
+#endif // GMM_BLAS_H__
diff --git a/Contrib/gmm/gmm_blas_interface.h b/Contrib/gmm/gmm_blas_interface.h
new file mode 100755
index 0000000..44e1dd8
--- /dev/null
+++ b/Contrib/gmm/gmm_blas_interface.h
@@ -0,0 +1,853 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_blas_interface.h
+ @author Caroline Lecalvez, Caroline.Lecalvez at gmm.insa-tlse.fr, Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 7, 2003.
+ @brief gmm interface for fortran BLAS.
+*/
+
+#if defined(GETFEM_USES_BLAS) || defined(GMM_USES_BLAS) \
+ || defined(GMM_USES_LAPACK) || defined(GMM_USES_ATLAS)
+
+#ifndef GMM_BLAS_INTERFACE_H
+#define GMM_BLAS_INTERFACE_H
+
+#include "gmm_blas.h"
+#include "gmm_interface.h"
+#include "gmm_matrix.h"
+
+namespace gmm {
+
+#define GMMLAPACK_TRACE(f)
+ // #define GMMLAPACK_TRACE(f) cout << "function " << f << " called" << endl;
+
+ /* ********************************************************************* */
+ /* Operations interfaced for T = float, double, std::complex<float> */
+ /* or std::complex<double> : */
+ /* */
+ /* vect_norm2(std::vector<T>) */
+ /* */
+ /* vect_sp(std::vector<T>, std::vector<T>) */
+ /* vect_sp(scaled(std::vector<T>), std::vector<T>) */
+ /* vect_sp(std::vector<T>, scaled(std::vector<T>)) */
+ /* vect_sp(scaled(std::vector<T>), scaled(std::vector<T>)) */
+ /* */
+ /* vect_hp(std::vector<T>, std::vector<T>) */
+ /* vect_hp(scaled(std::vector<T>), std::vector<T>) */
+ /* vect_hp(std::vector<T>, scaled(std::vector<T>)) */
+ /* vect_hp(scaled(std::vector<T>), scaled(std::vector<T>)) */
+ /* */
+ /* add(std::vector<T>, std::vector<T>) */
+ /* add(scaled(std::vector<T>, a), std::vector<T>) */
+ /* */
+ /* mult(dense_matrix<T>, dense_matrix<T>, dense_matrix<T>) */
+ /* mult(transposed(dense_matrix<T>), dense_matrix<T>, dense_matrix<T>) */
+ /* mult(dense_matrix<T>, transposed(dense_matrix<T>), dense_matrix<T>) */
+ /* mult(transposed(dense_matrix<T>), transposed(dense_matrix<T>), */
+ /* dense_matrix<T>) */
+ /* mult(conjugated(dense_matrix<T>), dense_matrix<T>, dense_matrix<T>) */
+ /* mult(dense_matrix<T>, conjugated(dense_matrix<T>), dense_matrix<T>) */
+ /* mult(conjugated(dense_matrix<T>), conjugated(dense_matrix<T>), */
+ /* dense_matrix<T>) */
+ /* */
+ /* mult(dense_matrix<T>, std::vector<T>, std::vector<T>) */
+ /* mult(transposed(dense_matrix<T>), std::vector<T>, std::vector<T>) */
+ /* mult(conjugated(dense_matrix<T>), std::vector<T>, std::vector<T>) */
+ /* mult(dense_matrix<T>, scaled(std::vector<T>), std::vector<T>) */
+ /* mult(transposed(dense_matrix<T>), scaled(std::vector<T>), */
+ /* std::vector<T>) */
+ /* mult(conjugated(dense_matrix<T>), scaled(std::vector<T>), */
+ /* std::vector<T>) */
+ /* */
+ /* mult_add(dense_matrix<T>, std::vector<T>, std::vector<T>) */
+ /* mult_add(transposed(dense_matrix<T>), std::vector<T>, std::vector<T>) */
+ /* mult_add(conjugated(dense_matrix<T>), std::vector<T>, std::vector<T>) */
+ /* mult_add(dense_matrix<T>, scaled(std::vector<T>), std::vector<T>) */
+ /* mult_add(transposed(dense_matrix<T>), scaled(std::vector<T>), */
+ /* std::vector<T>) */
+ /* mult_add(conjugated(dense_matrix<T>), scaled(std::vector<T>), */
+ /* std::vector<T>) */
+ /* */
+ /* mult(dense_matrix<T>, std::vector<T>, std::vector<T>, std::vector<T>) */
+ /* mult(transposed(dense_matrix<T>), std::vector<T>, std::vector<T>, */
+ /* std::vector<T>) */
+ /* mult(conjugated(dense_matrix<T>), std::vector<T>, std::vector<T>, */
+ /* std::vector<T>) */
+ /* mult(dense_matrix<T>, scaled(std::vector<T>), std::vector<T>, */
+ /* std::vector<T>) */
+ /* mult(transposed(dense_matrix<T>), scaled(std::vector<T>), */
+ /* std::vector<T>, std::vector<T>) */
+ /* mult(conjugated(dense_matrix<T>), scaled(std::vector<T>), */
+ /* std::vector<T>, std::vector<T>) */
+ /* mult(dense_matrix<T>, std::vector<T>, scaled(std::vector<T>), */
+ /* std::vector<T>) */
+ /* mult(transposed(dense_matrix<T>), std::vector<T>, */
+ /* scaled(std::vector<T>), std::vector<T>) */
+ /* mult(conjugated(dense_matrix<T>), std::vector<T>, */
+ /* scaled(std::vector<T>), std::vector<T>) */
+ /* mult(dense_matrix<T>, scaled(std::vector<T>), scaled(std::vector<T>), */
+ /* std::vector<T>) */
+ /* mult(transposed(dense_matrix<T>), scaled(std::vector<T>), */
+ /* scaled(std::vector<T>), std::vector<T>) */
+ /* mult(conjugated(dense_matrix<T>), scaled(std::vector<T>), */
+ /* scaled(std::vector<T>), std::vector<T>) */
+ /* */
+ /* lower_tri_solve(dense_matrix<T>, std::vector<T>, k, b) */
+ /* upper_tri_solve(dense_matrix<T>, std::vector<T>, k, b) */
+ /* lower_tri_solve(transposed(dense_matrix<T>), std::vector<T>, k, b) */
+ /* upper_tri_solve(transposed(dense_matrix<T>), std::vector<T>, k, b) */
+ /* lower_tri_solve(conjugated(dense_matrix<T>), std::vector<T>, k, b) */
+ /* upper_tri_solve(conjugated(dense_matrix<T>), std::vector<T>, k, b) */
+ /* */
+ /* ********************************************************************* */
+
+ /* ********************************************************************* */
+ /* Basic defines. */
+ /* ********************************************************************* */
+
+# define BLAS_S float
+# define BLAS_D double
+# define BLAS_C std::complex<float>
+# define BLAS_Z std::complex<double>
+
+ /* ********************************************************************* */
+ /* BLAS functions used. */
+ /* ********************************************************************* */
+ extern "C" void daxpy_(const int *n, const double *alpha, const double *x, const int *incx, double *y, const int *incy);
+ extern "C" {
+ void sgemm_(...); void dgemm_(...); void cgemm_(...); void zgemm_(...);
+ void sgemv_(...); void dgemv_(...); void cgemv_(...); void zgemv_(...);
+ void strsv_(...); void dtrsv_(...); void ctrsv_(...); void ztrsv_(...);
+ void saxpy_(...); /*void daxpy_(...); */void caxpy_(...); void zaxpy_(...);
+ BLAS_S sdot_ (...); BLAS_D ddot_ (...);
+ BLAS_C cdotu_(...); BLAS_Z zdotu_(...);
+ BLAS_C cdotc_(...); BLAS_Z zdotc_(...);
+ BLAS_S snrm2_(...); BLAS_D dnrm2_(...);
+ BLAS_S scnrm2_(...); BLAS_D dznrm2_(...);
+ }
+
+ /* ********************************************************************* */
+ /* vect_norm2(x). */
+ /* ********************************************************************* */
+
+ # define nrm2_interface(param1, trans1, blas_name, base_type) \
+ inline number_traits<base_type >::magnitude_type \
+ vect_norm2(param1(base_type)) { \
+ GMMLAPACK_TRACE("nrm2_interface"); \
+ int inc(1), n(vect_size(x)); trans1(base_type); \
+ return blas_name(&n, &x[0], &inc); \
+ }
+
+# define nrm2_p1(base_type) const std::vector<base_type > &x
+# define nrm2_trans1(base_type)
+
+ nrm2_interface(nrm2_p1, nrm2_trans1, snrm2_ , BLAS_S)
+ nrm2_interface(nrm2_p1, nrm2_trans1, dnrm2_ , BLAS_D)
+ nrm2_interface(nrm2_p1, nrm2_trans1, scnrm2_, BLAS_C)
+ nrm2_interface(nrm2_p1, nrm2_trans1, dznrm2_, BLAS_Z)
+
+ /* ********************************************************************* */
+ /* vect_sp(x, y). */
+ /* ********************************************************************* */
+
+ # define dot_interface(param1, trans1, mult1, param2, trans2, mult2, \
+ blas_name, base_type) \
+ inline base_type vect_sp(param1(base_type), param2(base_type)) { \
+ GMMLAPACK_TRACE("dot_interface"); \
+ trans1(base_type); trans2(base_type); int inc(1), n(vect_size(y)); \
+ return mult1 mult2 blas_name(&n, &x[0], &inc, &y[0], &inc); \
+ }
+
+# define dot_p1(base_type) const std::vector<base_type > &x
+# define dot_trans1(base_type)
+# define dot_p1_s(base_type) \
+ const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
+# define dot_trans1_s(base_type) \
+ std::vector<base_type > &x = \
+ const_cast<std::vector<base_type > &>(*(linalg_origin(x_))); \
+ base_type a(x_.r)
+
+# define dot_p2(base_type) const std::vector<base_type > &y
+# define dot_trans2(base_type)
+# define dot_p2_s(base_type) \
+ const scaled_vector_const_ref<std::vector<base_type >, base_type > &y_
+# define dot_trans2_s(base_type) \
+ std::vector<base_type > &y = \
+ const_cast<std::vector<base_type > &>(*(linalg_origin(y_))); \
+ base_type b(y_.r)
+
+ dot_interface(dot_p1, dot_trans1, , dot_p2, dot_trans2, , sdot_ , BLAS_S)
+ dot_interface(dot_p1, dot_trans1, , dot_p2, dot_trans2, , ddot_ , BLAS_D)
+ dot_interface(dot_p1, dot_trans1, , dot_p2, dot_trans2, , cdotu_, BLAS_C)
+ dot_interface(dot_p1, dot_trans1, , dot_p2, dot_trans2, , zdotu_, BLAS_Z)
+
+ dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, ,sdot_ ,BLAS_S)
+ dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, ,ddot_ ,BLAS_D)
+ dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, ,cdotu_,BLAS_C)
+ dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, ,zdotu_,BLAS_Z)
+
+ dot_interface(dot_p1, dot_trans1, , dot_p2_s, dot_trans2_s, b*,sdot_ ,BLAS_S)
+ dot_interface(dot_p1, dot_trans1, , dot_p2_s, dot_trans2_s, b*,ddot_ ,BLAS_D)
+ dot_interface(dot_p1, dot_trans1, , dot_p2_s, dot_trans2_s, b*,cdotu_,BLAS_C)
+ dot_interface(dot_p1, dot_trans1, , dot_p2_s, dot_trans2_s, b*,zdotu_,BLAS_Z)
+
+ dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,sdot_ ,
+ BLAS_S)
+ dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,ddot_ ,
+ BLAS_D)
+ dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,cdotu_,
+ BLAS_C)
+ dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,zdotu_,
+ BLAS_Z)
+
+
+ /* ********************************************************************* */
+ /* vect_hp(x, y). */
+ /* ********************************************************************* */
+
+ # define dotc_interface(param1, trans1, mult1, param2, trans2, mult2, \
+ blas_name, base_type) \
+ inline base_type vect_hp(param1(base_type), param2(base_type)) { \
+ GMMLAPACK_TRACE("dotc_interface"); \
+ trans1(base_type); trans2(base_type); int inc(1), n(vect_size(y)); \
+ return mult1 mult2 blas_name(&n, &x[0], &inc, &y[0], &inc); \
+ }
+
+# define dotc_p1(base_type) const std::vector<base_type > &x
+# define dotc_trans1(base_type)
+# define dotc_p1_s(base_type) \
+ const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
+# define dotc_trans1_s(base_type) \
+ std::vector<base_type > &x = \
+ const_cast<std::vector<base_type > &>(*(linalg_origin(x_))); \
+ base_type a(x_.r)
+
+# define dotc_p2(base_type) const std::vector<base_type > &y
+# define dotc_trans2(base_type)
+# define dotc_p2_s(base_type) \
+ const scaled_vector_const_ref<std::vector<base_type >, base_type > &y_
+# define dotc_trans2_s(base_type) \
+ std::vector<base_type > &y = \
+ const_cast<std::vector<base_type > &>(*(linalg_origin(y_))); \
+ base_type b(gmm::conj(y_.r))
+
+ dotc_interface(dotc_p1, dotc_trans1, , dotc_p2, dotc_trans2, ,sdot_ ,BLAS_S)
+ dotc_interface(dotc_p1, dotc_trans1, , dotc_p2, dotc_trans2, ,ddot_ ,BLAS_D)
+ dotc_interface(dotc_p1, dotc_trans1, , dotc_p2, dotc_trans2, ,cdotc_,BLAS_C)
+ dotc_interface(dotc_p1, dotc_trans1, , dotc_p2, dotc_trans2, ,zdotc_,BLAS_Z)
+
+ dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2, ,sdot_,
+ BLAS_S)
+ dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2, ,ddot_ ,
+ BLAS_D)
+ dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2, ,cdotc_,
+ BLAS_C)
+ dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2, ,zdotc_,
+ BLAS_Z)
+
+ dotc_interface(dotc_p1, dotc_trans1, , dotc_p2_s, dotc_trans2_s, b*,sdot_ ,
+ BLAS_S)
+ dotc_interface(dotc_p1, dotc_trans1, , dotc_p2_s, dotc_trans2_s, b*,ddot_ ,
+ BLAS_D)
+ dotc_interface(dotc_p1, dotc_trans1, , dotc_p2_s, dotc_trans2_s, b*,cdotc_,
+ BLAS_C)
+ dotc_interface(dotc_p1, dotc_trans1, , dotc_p2_s, dotc_trans2_s, b*,zdotc_,
+ BLAS_Z)
+
+ dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,sdot_ ,
+ BLAS_S)
+ dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,ddot_ ,
+ BLAS_D)
+ dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,cdotc_,
+ BLAS_C)
+ dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,zdotc_,
+ BLAS_Z)
+
+ /* ********************************************************************* */
+ /* add(x, y). */
+ /* ********************************************************************* */
+
+# define axpy_interface(param1, trans1, blas_name, base_type) \
+ inline void add(param1(base_type), std::vector<base_type > &y) { \
+ GMMLAPACK_TRACE("axpy_interface"); \
+ int inc(1), n(vect_size(y)); trans1(base_type); \
+ blas_name(&n, &a, &x[0], &inc, &y[0], &inc); \
+ }
+
+# define axpy_p1(base_type) const std::vector<base_type > &x
+# define axpy_trans1(base_type) base_type a(1)
+# define axpy_p1_s(base_type) \
+ const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
+# define axpy_trans1_s(base_type) \
+ std::vector<base_type > &x = \
+ const_cast<std::vector<base_type > &>(*(linalg_origin(x_))); \
+ base_type a(x_.r)
+
+ axpy_interface(axpy_p1, axpy_trans1, saxpy_, BLAS_S)
+ axpy_interface(axpy_p1, axpy_trans1, daxpy_, BLAS_D)
+ axpy_interface(axpy_p1, axpy_trans1, caxpy_, BLAS_C)
+ axpy_interface(axpy_p1, axpy_trans1, zaxpy_, BLAS_Z)
+
+ axpy_interface(axpy_p1_s, axpy_trans1_s, saxpy_, BLAS_S)
+ axpy_interface(axpy_p1_s, axpy_trans1_s, daxpy_, BLAS_D)
+ axpy_interface(axpy_p1_s, axpy_trans1_s, caxpy_, BLAS_C)
+ axpy_interface(axpy_p1_s, axpy_trans1_s, zaxpy_, BLAS_Z)
+
+
+ /* ********************************************************************* */
+ /* mult_add(A, x, z). */
+ /* ********************************************************************* */
+
+# define gemv_interface(param1, trans1, param2, trans2, blas_name, \
+ base_type, orien) \
+ inline void mult_add_spec(param1(base_type), param2(base_type), \
+ std::vector<base_type > &z, orien) { \
+ GMMLAPACK_TRACE("gemv_interface"); \
+ trans1(base_type); trans2(base_type); base_type beta(1); \
+ int m(mat_nrows(A)), lda(m), n(mat_ncols(A)), inc(1); \
+ if (m && n) blas_name(&t, &m, &n, &alpha, &A(0,0), &lda, &x[0], &inc, \
+ &beta, &z[0], &inc); \
+ else gmm::clear(z); \
+ }
+
+ // First parameter
+# define gem_p1_n(base_type) const dense_matrix<base_type > &A
+# define gem_trans1_n(base_type) const char t = 'N'
+# define gem_p1_t(base_type) \
+ const transposed_col_ref<dense_matrix<base_type > *> &A_
+# define gem_trans1_t(base_type) dense_matrix<base_type > &A = \
+ const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
+ const char t = 'T'
+# define gem_p1_tc(base_type) \
+ const transposed_col_ref<const dense_matrix<base_type > *> &A_
+# define gem_p1_c(base_type) \
+ const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &A_
+# define gem_trans1_c(base_type) dense_matrix<base_type > &A = \
+ const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
+ const char t = 'C'
+
+ // second parameter
+# define gemv_p2_n(base_type) const std::vector<base_type > &x
+# define gemv_trans2_n(base_type) base_type alpha(1)
+# define gemv_p2_s(base_type) \
+ const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
+# define gemv_trans2_s(base_type) std::vector<base_type > &x = \
+ const_cast<std::vector<base_type > &>(*(linalg_origin(x_))); \
+ base_type alpha(x_.r)
+
+ // Z <- AX + Z.
+ gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, sgemv_,
+ BLAS_S, col_major)
+ gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, dgemv_,
+ BLAS_D, col_major)
+ gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, cgemv_,
+ BLAS_C, col_major)
+ gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, zgemv_,
+ BLAS_Z, col_major)
+
+ // Z <- transposed(A)X + Z.
+ gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
+ BLAS_Z, row_major)
+
+ // Z <- transposed(const A)X + Z.
+ gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
+ BLAS_Z, row_major)
+
+ // Z <- conjugated(A)X + Z.
+ gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, zgemv_,
+ BLAS_Z, row_major)
+
+ // Z <- A scaled(X) + Z.
+ gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, sgemv_,
+ BLAS_S, col_major)
+ gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, dgemv_,
+ BLAS_D, col_major)
+ gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, cgemv_,
+ BLAS_C, col_major)
+ gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, zgemv_,
+ BLAS_Z, col_major)
+
+ // Z <- transposed(A) scaled(X) + Z.
+ gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
+ BLAS_Z, row_major)
+
+ // Z <- transposed(const A) scaled(X) + Z.
+ gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
+ BLAS_Z, row_major)
+
+ // Z <- conjugated(A) scaled(X) + Z.
+ gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, zgemv_,
+ BLAS_Z, row_major)
+
+
+ /* ********************************************************************* */
+ /* mult(A, x, y). */
+ /* ********************************************************************* */
+
+# define gemv_interface2(param1, trans1, param2, trans2, blas_name, \
+ base_type, orien) \
+ inline void mult_spec(param1(base_type), param2(base_type), \
+ std::vector<base_type > &z, orien) { \
+ GMMLAPACK_TRACE("gemv_interface2"); \
+ trans1(base_type); trans2(base_type); base_type beta(0); \
+ int m(mat_nrows(A)), lda(m), n(mat_ncols(A)), inc(1); \
+ if (m && n) \
+ blas_name(&t, &m, &n, &alpha, &A(0,0), &lda, &x[0], &inc, &beta, \
+ &z[0], &inc); \
+ else gmm::clear(z); \
+ }
+
+ // Y <- AX.
+ gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, sgemv_,
+ BLAS_S, col_major)
+ gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, dgemv_,
+ BLAS_D, col_major)
+ gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, cgemv_,
+ BLAS_C, col_major)
+ gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, zgemv_,
+ BLAS_Z, col_major)
+
+ // Y <- transposed(A)X.
+ gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
+ BLAS_Z, row_major)
+
+ // Y <- transposed(const A)X.
+ gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
+ BLAS_Z, row_major)
+
+ // Y <- conjugated(A)X.
+ gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, zgemv_,
+ BLAS_Z, row_major)
+
+ // Y <- A scaled(X).
+ gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, sgemv_,
+ BLAS_S, col_major)
+ gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, dgemv_,
+ BLAS_D, col_major)
+ gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, cgemv_,
+ BLAS_C, col_major)
+ gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, zgemv_,
+ BLAS_Z, col_major)
+
+ // Y <- transposed(A) scaled(X).
+ gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
+ BLAS_Z, row_major)
+
+ // Y <- transposed(const A) scaled(X).
+ gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
+ BLAS_Z, row_major)
+
+ // Y <- conjugated(A) scaled(X).
+ gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, sgemv_,
+ BLAS_S, row_major)
+ gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, dgemv_,
+ BLAS_D, row_major)
+ gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, cgemv_,
+ BLAS_C, row_major)
+ gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, zgemv_,
+ BLAS_Z, row_major)
+
+ /* ********************************************************************* */
+ /* dense matrix x dense matrix multiplication. */
+ /* ********************************************************************* */
+
+# define gemm_interface_nn(blas_name, base_type) \
+ inline void mult_spec(const dense_matrix<base_type > &A, \
+ const dense_matrix<base_type > &B, \
+ dense_matrix<base_type > &C, c_mult) { \
+ GMMLAPACK_TRACE("gemm_interface_nn"); \
+ const char t = 'N'; \
+ int m = mat_nrows(A), lda = m, k = mat_ncols(A), n = mat_ncols(B); \
+ int ldb = k, ldc = m; \
+ base_type alpha(1), beta(0); \
+ if (m && k && n) \
+ blas_name(&t, &t, &m, &n, &k, &alpha, \
+ &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
+ else gmm::clear(C); \
+ }
+
+ gemm_interface_nn(sgemm_, BLAS_S)
+ gemm_interface_nn(dgemm_, BLAS_D)
+ gemm_interface_nn(cgemm_, BLAS_C)
+ gemm_interface_nn(zgemm_, BLAS_Z)
+
+ /* ********************************************************************* */
+ /* transposed(dense matrix) x dense matrix multiplication. */
+ /* ********************************************************************* */
+
+# define gemm_interface_tn(blas_name, base_type, is_const) \
+ inline void mult_spec( \
+ const transposed_col_ref<is_const dense_matrix<base_type > *> &A_,\
+ const dense_matrix<base_type > &B, \
+ dense_matrix<base_type > &C, rcmult) { \
+ GMMLAPACK_TRACE("gemm_interface_tn"); \
+ dense_matrix<base_type > &A \
+ = const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
+ const char t = 'T', u = 'N'; \
+ int m = mat_ncols(A), k = mat_nrows(A), n = mat_ncols(B), lda = k; \
+ int ldb = k, ldc = m; \
+ base_type alpha(1), beta(0); \
+ if (m && k && n) \
+ blas_name(&t, &u, &m, &n, &k, &alpha, \
+ &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
+ else gmm::clear(C); \
+ }
+
+ gemm_interface_tn(sgemm_, BLAS_S,)
+ gemm_interface_tn(dgemm_, BLAS_D,)
+ gemm_interface_tn(cgemm_, BLAS_C,)
+ gemm_interface_tn(zgemm_, BLAS_Z,)
+ gemm_interface_tn(sgemm_, BLAS_S, const)
+ gemm_interface_tn(dgemm_, BLAS_D, const)
+ gemm_interface_tn(cgemm_, BLAS_C, const)
+ gemm_interface_tn(zgemm_, BLAS_Z, const)
+
+ /* ********************************************************************* */
+ /* dense matrix x transposed(dense matrix) multiplication. */
+ /* ********************************************************************* */
+
+# define gemm_interface_nt(blas_name, base_type, is_const) \
+ inline void mult_spec(const dense_matrix<base_type > &A, \
+ const transposed_col_ref<is_const dense_matrix<base_type > *> &B_,\
+ dense_matrix<base_type > &C, r_mult) { \
+ GMMLAPACK_TRACE("gemm_interface_nt"); \
+ dense_matrix<base_type > &B \
+ = const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_))); \
+ const char t = 'N', u = 'T'; \
+ int m = mat_nrows(A), lda = m, k = mat_ncols(A), n = mat_nrows(B); \
+ int ldb = n, ldc = m; \
+ base_type alpha(1), beta(0); \
+ if (m && k && n) \
+ blas_name(&t, &u, &m, &n, &k, &alpha, \
+ &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
+ else gmm::clear(C); \
+ }
+
+ gemm_interface_nt(sgemm_, BLAS_S,)
+ gemm_interface_nt(dgemm_, BLAS_D,)
+ gemm_interface_nt(cgemm_, BLAS_C,)
+ gemm_interface_nt(zgemm_, BLAS_Z,)
+ gemm_interface_nt(sgemm_, BLAS_S, const)
+ gemm_interface_nt(dgemm_, BLAS_D, const)
+ gemm_interface_nt(cgemm_, BLAS_C, const)
+ gemm_interface_nt(zgemm_, BLAS_Z, const)
+
+ /* ********************************************************************* */
+ /* transposed(dense matrix) x transposed(dense matrix) multiplication. */
+ /* ********************************************************************* */
+
+# define gemm_interface_tt(blas_name, base_type, isA_const, isB_const) \
+ inline void mult_spec( \
+ const transposed_col_ref<isA_const dense_matrix<base_type > *> &A_,\
+ const transposed_col_ref<isB_const dense_matrix<base_type > *> &B_,\
+ dense_matrix<base_type > &C, r_mult) { \
+ GMMLAPACK_TRACE("gemm_interface_tt"); \
+ dense_matrix<base_type > &A \
+ = const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
+ dense_matrix<base_type > &B \
+ = const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_))); \
+ const char t = 'T', u = 'T'; \
+ int m = mat_ncols(A), k = mat_nrows(A), n = mat_nrows(B), lda = k; \
+ int ldb = n, ldc = m; \
+ base_type alpha(1), beta(0); \
+ if (m && k && n) \
+ blas_name(&t, &u, &m, &n, &k, &alpha, \
+ &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
+ else gmm::clear(C); \
+ }
+
+ gemm_interface_tt(sgemm_, BLAS_S,,)
+ gemm_interface_tt(dgemm_, BLAS_D,,)
+ gemm_interface_tt(cgemm_, BLAS_C,,)
+ gemm_interface_tt(zgemm_, BLAS_Z,,)
+ gemm_interface_tt(sgemm_, BLAS_S, const,)
+ gemm_interface_tt(dgemm_, BLAS_D, const,)
+ gemm_interface_tt(cgemm_, BLAS_C, const,)
+ gemm_interface_tt(zgemm_, BLAS_Z, const,)
+ gemm_interface_tt(sgemm_, BLAS_S,, const)
+ gemm_interface_tt(dgemm_, BLAS_D,, const)
+ gemm_interface_tt(cgemm_, BLAS_C,, const)
+ gemm_interface_tt(zgemm_, BLAS_Z,, const)
+ gemm_interface_tt(sgemm_, BLAS_S, const, const)
+ gemm_interface_tt(dgemm_, BLAS_D, const, const)
+ gemm_interface_tt(cgemm_, BLAS_C, const, const)
+ gemm_interface_tt(zgemm_, BLAS_Z, const, const)
+
+
+ /* ********************************************************************* */
+ /* conjugated(dense matrix) x dense matrix multiplication. */
+ /* ********************************************************************* */
+
+# define gemm_interface_cn(blas_name, base_type) \
+ inline void mult_spec( \
+ const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &A_,\
+ const dense_matrix<base_type > &B, \
+ dense_matrix<base_type > &C, rcmult) { \
+ GMMLAPACK_TRACE("gemm_interface_cn"); \
+ dense_matrix<base_type > &A \
+ = const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
+ const char t = 'C', u = 'N'; \
+ int m = mat_ncols(A), k = mat_nrows(A), n = mat_ncols(B), lda = k; \
+ int ldb = k, ldc = m; \
+ base_type alpha(1), beta(0); \
+ if (m && k && n) \
+ blas_name(&t, &u, &m, &n, &k, &alpha, \
+ &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
+ else gmm::clear(C); \
+ }
+
+ gemm_interface_cn(sgemm_, BLAS_S)
+ gemm_interface_cn(dgemm_, BLAS_D)
+ gemm_interface_cn(cgemm_, BLAS_C)
+ gemm_interface_cn(zgemm_, BLAS_Z)
+
+ /* ********************************************************************* */
+ /* dense matrix x conjugated(dense matrix) multiplication. */
+ /* ********************************************************************* */
+
+# define gemm_interface_nc(blas_name, base_type) \
+ inline void mult_spec(const dense_matrix<base_type > &A, \
+ const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &B_,\
+ dense_matrix<base_type > &C, c_mult, row_major) { \
+ GMMLAPACK_TRACE("gemm_interface_nc"); \
+ dense_matrix<base_type > &B \
+ = const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_))); \
+ const char t = 'N', u = 'C'; \
+ int m = mat_nrows(A), lda = m, k = mat_ncols(A), n = mat_nrows(B); \
+ int ldb = n, ldc = m; \
+ base_type alpha(1), beta(0); \
+ if (m && k && n) \
+ blas_name(&t, &u, &m, &n, &k, &alpha, \
+ &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
+ else gmm::clear(C); \
+ }
+
+ gemm_interface_nc(sgemm_, BLAS_S)
+ gemm_interface_nc(dgemm_, BLAS_D)
+ gemm_interface_nc(cgemm_, BLAS_C)
+ gemm_interface_nc(zgemm_, BLAS_Z)
+
+ /* ********************************************************************* */
+ /* conjugated(dense matrix) x conjugated(dense matrix) multiplication. */
+ /* ********************************************************************* */
+
+# define gemm_interface_cc(blas_name, base_type) \
+ inline void mult_spec( \
+ const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &A_,\
+ const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &B_,\
+ dense_matrix<base_type > &C, r_mult) { \
+ GMMLAPACK_TRACE("gemm_interface_cc"); \
+ dense_matrix<base_type > &A \
+ = const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
+ dense_matrix<base_type > &B \
+ = const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_))); \
+ const char t = 'C', u = 'C'; \
+ int m = mat_ncols(A), k = mat_nrows(A), lda = k, n = mat_nrows(B); \
+ int ldb = n, ldc = m; \
+ base_type alpha(1), beta(0); \
+ if (m && k && n) \
+ blas_name(&t, &u, &m, &n, &k, &alpha, \
+ &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
+ else gmm::clear(C); \
+ }
+
+ gemm_interface_cc(sgemm_, BLAS_S)
+ gemm_interface_cc(dgemm_, BLAS_D)
+ gemm_interface_cc(cgemm_, BLAS_C)
+ gemm_interface_cc(zgemm_, BLAS_Z)
+
+ /* ********************************************************************* */
+ /* Tri solve. */
+ /* ********************************************************************* */
+
+# define trsv_interface(f_name, loru, param1, trans1, blas_name, base_type)\
+ inline void f_name(param1(base_type), std::vector<base_type > &x, \
+ size_type k, bool is_unit) { \
+ GMMLAPACK_TRACE("trsv_interface"); \
+ loru; trans1(base_type); char d = is_unit ? 'U' : 'N'; \
+ int lda(mat_nrows(A)), inc(1), n(k); \
+ if (lda) blas_name(&l, &t, &d, &n, &A(0,0), &lda, &x[0], &inc); \
+ }
+
+# define trsv_upper const char l = 'U'
+# define trsv_lower const char l = 'L'
+
+ // X <- LOWER(A)^{-1}X.
+ trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
+ strsv_, BLAS_S)
+ trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
+ dtrsv_, BLAS_D)
+ trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
+ ctrsv_, BLAS_C)
+ trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
+ ztrsv_, BLAS_Z)
+
+ // X <- UPPER(A)^{-1}X.
+ trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
+ strsv_, BLAS_S)
+ trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
+ dtrsv_, BLAS_D)
+ trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
+ ctrsv_, BLAS_C)
+ trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
+ ztrsv_, BLAS_Z)
+
+ // X <- LOWER(transposed(A))^{-1}X.
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
+ strsv_, BLAS_S)
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
+ dtrsv_, BLAS_D)
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
+ ctrsv_, BLAS_C)
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
+ ztrsv_, BLAS_Z)
+
+ // X <- UPPER(transposed(A))^{-1}X.
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
+ strsv_, BLAS_S)
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
+ dtrsv_, BLAS_D)
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
+ ctrsv_, BLAS_C)
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
+ ztrsv_, BLAS_Z)
+
+ // X <- LOWER(transposed(const A))^{-1}X.
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
+ strsv_, BLAS_S)
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
+ dtrsv_, BLAS_D)
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
+ ctrsv_, BLAS_C)
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
+ ztrsv_, BLAS_Z)
+
+ // X <- UPPER(transposed(const A))^{-1}X.
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
+ strsv_, BLAS_S)
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
+ dtrsv_, BLAS_D)
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
+ ctrsv_, BLAS_C)
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
+ ztrsv_, BLAS_Z)
+
+ // X <- LOWER(conjugated(A))^{-1}X.
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
+ strsv_, BLAS_S)
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
+ dtrsv_, BLAS_D)
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
+ ctrsv_, BLAS_C)
+ trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
+ ztrsv_, BLAS_Z)
+
+ // X <- UPPER(conjugated(A))^{-1}X.
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
+ strsv_, BLAS_S)
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
+ dtrsv_, BLAS_D)
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
+ ctrsv_, BLAS_C)
+ trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
+ ztrsv_, BLAS_Z)
+
+}
+
+#endif // GMM_BLAS_INTERFACE_H
+
+#endif // GMM_USES_BLAS
diff --git a/Contrib/gmm/gmm_condition_number.h b/Contrib/gmm/gmm_condition_number.h
new file mode 100755
index 0000000..4b9f250
--- /dev/null
+++ b/Contrib/gmm/gmm_condition_number.h
@@ -0,0 +1,142 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_condition_number.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>, Julien Pommier <Julien.Pommier at insa-toulouse.fr>
+ @date August 27, 2003.
+ @brief computation of the condition number of dense matrices.
+*/
+#ifndef GMM_CONDITION_NUMBER_H__
+#define GMM_CONDITION_NUMBER_H__
+
+#include "gmm_dense_qr.h"
+
+namespace gmm {
+
+ /** computation of the condition number of dense matrices using SVD.
+
+ Uses symmetric_qr_algorithm => dense matrices only.
+
+ @param M a matrix.
+ @param emin smallest (in magnitude) eigenvalue
+ @param emax largest eigenvalue.
+ */
+ template <typename MAT>
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type
+ condition_number(const MAT& M,
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type& emin,
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type& emax) {
+ typedef typename linalg_traits<MAT>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type m = mat_nrows(M), n = mat_ncols(M);
+ emax = emin = R(0);
+ std::vector<R> eig(m+n);
+
+ if (m+n == 0) return R(0);
+ if (is_hermitian(M)) {
+ eig.resize(m);
+ gmm::symmetric_qr_algorithm(M, eig);
+ }
+ else {
+ dense_matrix<T> B(m+n, m+n); // not very efficient ??
+ gmm::copy(conjugated(M), sub_matrix(B, sub_interval(m, n), sub_interval(0, m)));
+ gmm::copy(M, sub_matrix(B, sub_interval(0, m),
+ sub_interval(m, n)));
+ gmm::symmetric_qr_algorithm(B, eig);
+ }
+ emin = emax = gmm::abs(eig[0]);
+ for (size_type i = 1; i < eig.size(); ++i) {
+ R e = gmm::abs(eig[i]);
+ emin = std::min(emin, e);
+ emax = std::max(emax, e);
+ }
+ // cout << "emin = " << emin << " emax = " << emax << endl;
+ if (emin == R(0)) return gmm::default_max(R());
+ return emax / emin;
+ }
+
+ template <typename MAT>
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type
+ condition_number(const MAT& M) {
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type emax, emin;
+ return condition_number(M, emin, emax);
+ }
+
+ template <typename MAT>
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type
+ Frobenius_condition_number_sqr(const MAT& M) {
+ typedef typename linalg_traits<MAT>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ size_type m = mat_nrows(M), n = mat_ncols(M);
+ dense_matrix<T> B(std::min(m,n), std::min(m,n));
+ if (m < n) mult(M,gmm::conjugated(M),B);
+ else mult(gmm::conjugated(M),M,B);
+ R trB = abs(mat_trace(B));
+ lu_inverse(B);
+ return trB*abs(mat_trace(B));
+ }
+
+ template <typename MAT>
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type
+ Frobenius_condition_number(const MAT& M)
+ { return sqrt(Frobenius_condition_number_sqr(M)); }
+
+ /** estimation of the condition number (TO BE DONE...)
+ */
+ template <typename MAT>
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type
+ condest(const MAT& M,
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type& emin,
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type& emax) {
+ return condition_number(M, emin, emax);
+ }
+
+ template <typename MAT>
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type
+ condest(const MAT& M) {
+ typename number_traits<typename
+ linalg_traits<MAT>::value_type>::magnitude_type emax, emin;
+ return condest(M, emin, emax);
+ }
+}
+
+#endif
diff --git a/Contrib/gmm/gmm_conjugated.h b/Contrib/gmm/gmm_conjugated.h
new file mode 100755
index 0000000..2f18837
--- /dev/null
+++ b/Contrib/gmm/gmm_conjugated.h
@@ -0,0 +1,395 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_conjugated.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date September 18, 2003.
+ @brief handle conjugation of complex matrices/vectors.
+*/
+#ifndef GMM_CONJUGATED_H__
+#define GMM_CONJUGATED_H__
+
+#include "gmm_def.h"
+
+namespace gmm {
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ /* ********************************************************************* */
+ /* Conjugated references on vectors */
+ /* ********************************************************************* */
+
+ template <typename IT> struct conjugated_const_iterator {
+ typedef typename std::iterator_traits<IT>::value_type value_type;
+ typedef typename std::iterator_traits<IT>::pointer pointer;
+ typedef typename std::iterator_traits<IT>::reference reference;
+ typedef typename std::iterator_traits<IT>::difference_type difference_type;
+ typedef typename std::iterator_traits<IT>::iterator_category
+ iterator_category;
+
+ IT it;
+
+ conjugated_const_iterator(void) {}
+ conjugated_const_iterator(const IT &i) : it(i) {}
+
+ inline size_type index(void) const { return it.index(); }
+ conjugated_const_iterator operator ++(int)
+ { conjugated_const_iterator tmp = *this; ++it; return tmp; }
+ conjugated_const_iterator operator --(int)
+ { conjugated_const_iterator tmp = *this; --it; return tmp; }
+ conjugated_const_iterator &operator ++() { ++it; return *this; }
+ conjugated_const_iterator &operator --() { --it; return *this; }
+ conjugated_const_iterator &operator +=(difference_type i)
+ { it += i; return *this; }
+ conjugated_const_iterator &operator -=(difference_type i)
+ { it -= i; return *this; }
+ conjugated_const_iterator operator +(difference_type i) const
+ { conjugated_const_iterator itb = *this; return (itb += i); }
+ conjugated_const_iterator operator -(difference_type i) const
+ { conjugated_const_iterator itb = *this; return (itb -= i); }
+ difference_type operator -(const conjugated_const_iterator &i) const
+ { return difference_type(it - i.it); }
+
+ value_type operator *() const { return gmm::conj(*it); }
+ value_type operator [](size_type ii) const { return gmm::conj(it[ii]); }
+
+ bool operator ==(const conjugated_const_iterator &i) const
+ { return (i.it == it); }
+ bool operator !=(const conjugated_const_iterator &i) const
+ { return (i.it != it); }
+ bool operator < (const conjugated_const_iterator &i) const
+ { return (it < i.it); }
+ };
+
+ template <typename V> struct conjugated_vector_const_ref {
+ typedef conjugated_vector_const_ref<V> this_type;
+ typedef typename linalg_traits<V>::value_type value_type;
+ typedef typename linalg_traits<V>::const_iterator iterator;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+ iterator begin_, end_;
+ const origin_type *origin;
+ size_type size_;
+
+ conjugated_vector_const_ref(const V &v)
+ : begin_(vect_const_begin(v)), end_(vect_const_end(v)),
+ origin(linalg_origin(v)),
+ size_(vect_size(v)) {}
+
+ reference operator[](size_type i) const
+ { return gmm::conj(linalg_traits<V>::access(origin, begin_, end_, i)); }
+ };
+
+ template <typename V> struct linalg_traits<conjugated_vector_const_ref<V> > {
+ typedef conjugated_vector_const_ref<V> this_type;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef linalg_const is_reference;
+ typedef abstract_vector linalg_type;
+ typedef typename linalg_traits<V>::value_type value_type;
+ typedef value_type reference;
+ typedef abstract_null_type iterator;
+ typedef conjugated_const_iterator<typename
+ linalg_traits<V>::const_iterator> const_iterator;
+ typedef typename linalg_traits<V>::storage_type storage_type;
+ typedef typename linalg_traits<V>::index_sorted index_sorted;
+ static size_type size(const this_type &v) { return v.size_; }
+ static iterator begin(this_type &v) { return iterator(v.begin_); }
+ static const_iterator begin(const this_type &v)
+ { return const_iterator(v.begin_); }
+ static iterator end(this_type &v)
+ { return iterator(v.end_); }
+ static const_iterator end(const this_type &v)
+ { return const_iterator(v.end_); }
+ static value_type access(const origin_type *o, const const_iterator &it,
+ const const_iterator &ite, size_type i)
+ { return gmm::conj(linalg_traits<V>::access(o, it.it, ite.it, i)); }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ };
+
+ template<typename V> std::ostream &operator <<
+ (std::ostream &o, const conjugated_vector_const_ref<V>& m)
+ { gmm::write(o,m); return o; }
+
+ /* ********************************************************************* */
+ /* Conjugated references on matrices */
+ /* ********************************************************************* */
+
+ template <typename M> struct conjugated_row_const_iterator {
+ typedef conjugated_row_const_iterator<M> iterator;
+ typedef typename linalg_traits<M>::const_row_iterator ITER;
+ typedef typename linalg_traits<M>::value_type value_type;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+
+ ITER it;
+
+ iterator operator ++(int) { iterator tmp = *this; it++; return tmp; }
+ iterator operator --(int) { iterator tmp = *this; it--; return tmp; }
+ iterator &operator ++() { it++; return *this; }
+ iterator &operator --() { it--; return *this; }
+ iterator &operator +=(difference_type i) { it += i; return *this; }
+ iterator &operator -=(difference_type i) { it -= i; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator itt = *this; return (itt += i); }
+ iterator operator -(difference_type i) const
+ { iterator itt = *this; return (itt -= i); }
+ difference_type operator -(const iterator &i) const
+ { return it - i.it; }
+
+ ITER operator *() const { return it; }
+ ITER operator [](int i) { return it + i; }
+
+ bool operator ==(const iterator &i) const { return (it == i.it); }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+ bool operator < (const iterator &i) const { return (it < i.it); }
+
+ conjugated_row_const_iterator(void) {}
+ conjugated_row_const_iterator(const ITER &i) : it(i) { }
+
+ };
+
+ template <typename M> struct conjugated_row_matrix_const_ref {
+
+ typedef conjugated_row_matrix_const_ref<M> this_type;
+ typedef typename linalg_traits<M>::const_row_iterator iterator;
+ typedef typename linalg_traits<M>::value_type value_type;
+ typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+ iterator begin_, end_;
+ const origin_type *origin;
+ size_type nr, nc;
+
+ conjugated_row_matrix_const_ref(const M &m)
+ : begin_(mat_row_begin(m)), end_(mat_row_end(m)),
+ origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
+
+ value_type operator()(size_type i, size_type j) const
+ { return gmm::conj(linalg_traits<M>::access(begin_+j, i)); }
+ };
+
+ template <typename M>
+ struct linalg_traits<conjugated_row_matrix_const_ref<M> > {
+ typedef conjugated_row_matrix_const_ref<M> this_type;
+ typedef typename linalg_traits<M>::origin_type origin_type;
+ typedef linalg_const is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<M>::value_type value_type;
+ typedef value_type reference;
+ typedef typename linalg_traits<M>::storage_type storage_type;
+ typedef typename linalg_traits<M>::const_sub_row_type vector_type;
+ typedef conjugated_vector_const_ref<vector_type> sub_col_type;
+ typedef conjugated_vector_const_ref<vector_type> const_sub_col_type;
+ typedef conjugated_row_const_iterator<M> col_iterator;
+ typedef conjugated_row_const_iterator<M> const_col_iterator;
+ typedef abstract_null_type const_sub_row_type;
+ typedef abstract_null_type sub_row_type;
+ typedef abstract_null_type const_row_iterator;
+ typedef abstract_null_type row_iterator;
+ typedef col_major sub_orientation;
+ typedef typename linalg_traits<M>::index_sorted index_sorted;
+ static inline size_type ncols(const this_type &m) { return m.nc; }
+ static inline size_type nrows(const this_type &m) { return m.nr; }
+ static inline const_sub_col_type col(const const_col_iterator &it)
+ { return conjugated(linalg_traits<M>::row(it.it)); }
+ static inline const_col_iterator col_begin(const this_type &m)
+ { return const_col_iterator(m.begin_); }
+ static inline const_col_iterator col_end(const this_type &m)
+ { return const_col_iterator(m.end_); }
+ static inline const origin_type* origin(const this_type &m)
+ { return m.origin; }
+ static value_type access(const const_col_iterator &it, size_type i)
+ { return gmm::conj(linalg_traits<M>::access(it.it, i)); }
+ };
+
+ template<typename M> std::ostream &operator <<
+ (std::ostream &o, const conjugated_row_matrix_const_ref<M>& m)
+ { gmm::write(o,m); return o; }
+
+
+ template <typename M> struct conjugated_col_const_iterator {
+ typedef conjugated_col_const_iterator<M> iterator;
+ typedef typename linalg_traits<M>::const_col_iterator ITER;
+ typedef typename linalg_traits<M>::value_type value_type;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+
+ ITER it;
+
+ iterator operator ++(int) { iterator tmp = *this; it++; return tmp; }
+ iterator operator --(int) { iterator tmp = *this; it--; return tmp; }
+ iterator &operator ++() { it++; return *this; }
+ iterator &operator --() { it--; return *this; }
+ iterator &operator +=(difference_type i) { it += i; return *this; }
+ iterator &operator -=(difference_type i) { it -= i; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator itt = *this; return (itt += i); }
+ iterator operator -(difference_type i) const
+ { iterator itt = *this; return (itt -= i); }
+ difference_type operator -(const iterator &i) const
+ { return it - i.it; }
+
+ ITER operator *() const { return it; }
+ ITER operator [](int i) { return it + i; }
+
+ bool operator ==(const iterator &i) const { return (it == i.it); }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+ bool operator < (const iterator &i) const { return (it < i.it); }
+
+ conjugated_col_const_iterator(void) {}
+ conjugated_col_const_iterator(const ITER &i) : it(i) { }
+
+ };
+
+ template <typename M> struct conjugated_col_matrix_const_ref {
+
+ typedef conjugated_col_matrix_const_ref<M> this_type;
+ typedef typename linalg_traits<M>::const_col_iterator iterator;
+ typedef typename linalg_traits<M>::value_type value_type;
+ typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+ iterator begin_, end_;
+ const origin_type *origin;
+ size_type nr, nc;
+
+ conjugated_col_matrix_const_ref(const M &m)
+ : begin_(mat_col_begin(m)), end_(mat_col_end(m)),
+ origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
+
+ value_type operator()(size_type i, size_type j) const
+ { return gmm::conj(linalg_traits<M>::access(begin_+i, j)); }
+ };
+
+ template <typename M>
+ struct linalg_traits<conjugated_col_matrix_const_ref<M> > {
+ typedef conjugated_col_matrix_const_ref<M> this_type;
+ typedef typename linalg_traits<M>::origin_type origin_type;
+ typedef linalg_const is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<M>::value_type value_type;
+ typedef value_type reference;
+ typedef typename linalg_traits<M>::storage_type storage_type;
+ typedef typename linalg_traits<M>::const_sub_col_type vector_type;
+ typedef conjugated_vector_const_ref<vector_type> sub_row_type;
+ typedef conjugated_vector_const_ref<vector_type> const_sub_row_type;
+ typedef conjugated_col_const_iterator<M> row_iterator;
+ typedef conjugated_col_const_iterator<M> const_row_iterator;
+ typedef abstract_null_type const_sub_col_type;
+ typedef abstract_null_type sub_col_type;
+ typedef abstract_null_type const_col_iterator;
+ typedef abstract_null_type col_iterator;
+ typedef row_major sub_orientation;
+ typedef typename linalg_traits<M>::index_sorted index_sorted;
+ static inline size_type nrows(const this_type &m) { return m.nr; }
+ static inline size_type ncols(const this_type &m) { return m.nc; }
+ static inline const_sub_row_type row(const const_row_iterator &it)
+ { return conjugated(linalg_traits<M>::col(it.it)); }
+ static inline const_row_iterator row_begin(const this_type &m)
+ { return const_row_iterator(m.begin_); }
+ static inline const_row_iterator row_end(const this_type &m)
+ { return const_row_iterator(m.end_); }
+ static inline const origin_type* origin(const this_type &m)
+ { return m.origin; }
+ static value_type access(const const_row_iterator &it, size_type i)
+ { return gmm::conj(linalg_traits<M>::access(it.it, i)); }
+ };
+
+ template<typename M> std::ostream &operator <<
+ (std::ostream &o, const conjugated_col_matrix_const_ref<M>& m)
+ { gmm::write(o,m); return o; }
+
+
+ template <typename L, typename SO> struct conjugated_return__ {
+ typedef conjugated_row_matrix_const_ref<L> return_type;
+ };
+ template <typename L> struct conjugated_return__<L, col_major> {
+ typedef conjugated_col_matrix_const_ref<L> return_type;
+ };
+ template <typename L, typename T, typename LT> struct conjugated_return_ {
+ typedef const L & return_type;
+ };
+ template <typename L, typename T>
+ struct conjugated_return_<L, std::complex<T>, abstract_vector> {
+ typedef conjugated_vector_const_ref<L> return_type;
+ };
+ template <typename L, typename T>
+ struct conjugated_return_<L, T, abstract_matrix> {
+ typedef typename conjugated_return__<L,
+ typename principal_orientation_type<typename
+ linalg_traits<L>::sub_orientation>::potype
+ >::return_type return_type;
+ };
+ template <typename L> struct conjugated_return {
+ typedef typename
+ conjugated_return_<L, typename linalg_traits<L>::value_type,
+ typename linalg_traits<L>::linalg_type
+ >::return_type return_type;
+ };
+
+ ///@endcond
+ /** return a conjugated view of the input matrix or vector. */
+ template <typename L> inline
+ typename conjugated_return<L>::return_type
+ conjugated(const L &v) {
+ return conjugated(v, typename linalg_traits<L>::value_type(),
+ typename linalg_traits<L>::linalg_type());
+ }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ template <typename L, typename T, typename LT> inline
+ const L & conjugated(const L &v, T, LT) { return v; }
+
+ template <typename L, typename T> inline
+ conjugated_vector_const_ref<L> conjugated(const L &v, std::complex<T>,
+ abstract_vector)
+ { return conjugated_vector_const_ref<L>(v); }
+
+ template <typename L, typename T> inline
+ typename conjugated_return__<L,
+ typename principal_orientation_type<typename
+ linalg_traits<L>::sub_orientation>::potype>::return_type
+ conjugated(const L &v, T, abstract_matrix) {
+ return conjugated(v, typename principal_orientation_type<typename
+ linalg_traits<L>::sub_orientation>::potype());
+ }
+
+ template <typename L> inline
+ conjugated_row_matrix_const_ref<L> conjugated(const L &v, row_major)
+ { return conjugated_row_matrix_const_ref<L>(v); }
+
+ template <typename L> inline
+ conjugated_col_matrix_const_ref<L> conjugated(const L &v, col_major)
+ { return conjugated_col_matrix_const_ref<L>(v); }
+
+ ///@endcond
+
+
+}
+
+#endif // GMM_CONJUGATED_H__
diff --git a/Contrib/gmm/gmm_def.h b/Contrib/gmm/gmm_def.h
new file mode 100755
index 0000000..e71e33d
--- /dev/null
+++ b/Contrib/gmm/gmm_def.h
@@ -0,0 +1,1117 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_def.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief Basic definitions and tools of GMM.
+*/
+#ifndef GMM_DEF_H__
+#define GMM_DEF_H__
+
+#include "gmm_ref.h"
+#include <complex>
+
+#ifndef M_PI
+# define M_E 2.7182818284590452354 /* e */
+# define M_LOG2E 1.4426950408889634074 /* 1/ln(2) */
+# define M_LOG10E 0.43429448190325182765 /* 1/ln(10) */
+# define M_LN2 0.69314718055994530942 /* ln(2) */
+# define M_LN10 2.30258509299404568402 /* ln(10) */
+# define M_PI 3.14159265358979323846 /* pi */
+# define M_PI_2 1.57079632679489661923 /* pi/2 */
+# define M_PI_4 0.78539816339744830962 /* pi/4 */
+# define M_1_PI 0.31830988618379067154 /* 1/pi */
+# define M_2_PI 0.63661977236758134308 /* 2/pi */
+# define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
+# define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
+# define M_SQRT1_2 0.70710678118654752440 /* sqrt(2)/2 */
+#endif
+
+#ifndef M_PIl
+# define M_PIl 3.1415926535897932384626433832795029L /* pi */
+# define M_PI_2l 1.5707963267948966192313216916397514L /* pi/2 */
+# define M_PI_4l 0.7853981633974483096156608458198757L /* pi/4 */
+# define M_1_PIl 0.3183098861837906715377675267450287L /* 1/pi */
+# define M_2_PIl 0.6366197723675813430755350534900574L /* 2/pi */
+# define M_2_SQRTPIl 1.1283791670955125738961589031215452L /* 2/sqrt(pi) */
+#endif
+
+namespace gmm {
+
+ typedef size_t size_type;
+
+ /* ******************************************************************** */
+ /* Specifier types */
+ /* ******************************************************************** */
+ /* not perfectly null, required by aCC 3.33 */
+ struct abstract_null_type {
+ abstract_null_type(int=0) {}
+ template <typename A,typename B,typename C> void operator()(A,B,C) {}
+ }; // specify an information lake.
+
+ struct linalg_true {};
+ struct linalg_false {};
+
+ template <typename V, typename W> struct linalg_and
+ { typedef linalg_false bool_type; };
+ template <> struct linalg_and<linalg_true, linalg_true>
+ { typedef linalg_true bool_type; };
+ template <typename V, typename W> struct linalg_or
+ { typedef linalg_true bool_type; };
+ template <> struct linalg_and<linalg_false, linalg_false>
+ { typedef linalg_false bool_type; };
+
+ struct linalg_const {}; // A reference is either linalg_const,
+ struct linalg_modifiable {}; // linalg_modifiable or linalg_false.
+
+ struct abstract_vector {}; // The object is a vector
+ struct abstract_matrix {}; // The object is a matrix
+
+ struct abstract_sparse {}; // sparse matrix or vector
+ struct abstract_skyline {}; // 'sky-line' matrix or vector
+ struct abstract_dense {}; // dense matrix or vector
+ struct abstract_indirect {}; // matrix given by the product with a vector
+
+ struct row_major {}; // matrix with a row access.
+ struct col_major {}; // matrix with a column access
+ struct row_and_col {}; // both accesses but row preference
+ struct col_and_row {}; // both accesses but column preference
+
+ template <typename T> struct transposed_type;
+ template<> struct transposed_type<row_major> {typedef col_major t_type;};
+ template<> struct transposed_type<col_major> {typedef row_major t_type;};
+ template<> struct transposed_type<row_and_col> {typedef col_and_row t_type;};
+ template<> struct transposed_type<col_and_row> {typedef row_and_col t_type;};
+
+ template <typename T> struct principal_orientation_type
+ { typedef abstract_null_type potype; };
+ template<> struct principal_orientation_type<row_major>
+ { typedef row_major potype; };
+ template<> struct principal_orientation_type<col_major>
+ { typedef col_major potype; };
+ template<> struct principal_orientation_type<row_and_col>
+ { typedef row_major potype; };
+ template<> struct principal_orientation_type<col_and_row>
+ { typedef col_major potype; };
+
+ // template <typename V> struct linalg_traits;
+ template <typename V> struct linalg_traits {
+ typedef abstract_null_type this_type;
+ typedef abstract_null_type linalg_type;
+ typedef abstract_null_type value_type;
+ typedef abstract_null_type is_reference;
+ typedef abstract_null_type& reference;
+ typedef abstract_null_type* iterator;
+ typedef const abstract_null_type* const_iterator;
+ typedef abstract_null_type index_sorted;
+ typedef abstract_null_type storage_type;
+ typedef abstract_null_type origin_type;
+ typedef abstract_null_type const_sub_row_type;
+ typedef abstract_null_type sub_row_type;
+ typedef abstract_null_type const_row_iterator;
+ typedef abstract_null_type row_iterator;
+ typedef abstract_null_type const_sub_col_type;
+ typedef abstract_null_type sub_col_type;
+ typedef abstract_null_type const_col_iterator;
+ typedef abstract_null_type col_iterator;
+ typedef abstract_null_type sub_orientation;
+ };
+
+ template <typename PT, typename V> struct vect_ref_type;
+ template <typename P, typename V> struct vect_ref_type<P *, V> {
+ typedef typename linalg_traits<V>::reference access_type;
+ typedef typename linalg_traits<V>::iterator iterator;
+ };
+ template <typename P, typename V> struct vect_ref_type<const P *, V> {
+ typedef typename linalg_traits<V>::value_type access_type;
+ typedef typename linalg_traits<V>::const_iterator iterator;
+ };
+
+ template <typename PT> struct const_pointer;
+ template <typename P> struct const_pointer<P *>
+ { typedef const P* pointer; };
+ template <typename P> struct const_pointer<const P *>
+ { typedef const P* pointer; };
+
+ template <typename PT> struct modifiable_pointer;
+ template <typename P> struct modifiable_pointer<P *>
+ { typedef P* pointer; };
+ template <typename P> struct modifiable_pointer<const P *>
+ { typedef P* pointer; };
+
+ template <typename R> struct const_reference;
+ template <typename R> struct const_reference<R &>
+ { typedef const R &reference; };
+ template <typename R> struct const_reference<const R &>
+ { typedef const R &reference; };
+
+
+ inline bool is_sparse(abstract_sparse) { return true; }
+ inline bool is_sparse(abstract_dense) { return false; }
+ inline bool is_sparse(abstract_skyline) { return true; }
+ inline bool is_sparse(abstract_indirect) { return false; }
+
+ template <typename L> inline bool is_sparse(const L &)
+ { return is_sparse(typename linalg_traits<L>::storage_type()); }
+
+ inline bool is_row_matrix_(row_major) { return true; }
+ inline bool is_row_matrix_(col_major) { return false; }
+ inline bool is_row_matrix_(row_and_col) { return true; }
+ inline bool is_row_matrix_(col_and_row) { return true; }
+
+ template <typename L> inline bool is_row_matrix(const L &)
+ { return is_row_matrix_(typename linalg_traits<L>::sub_orientation()); }
+
+ inline bool is_col_matrix_(row_major) { return false; }
+ inline bool is_col_matrix_(col_major) { return true; }
+ inline bool is_col_matrix_(row_and_col) { return true; }
+ inline bool is_col_matrix_(col_and_row) { return true; }
+
+ template <typename L> inline bool is_col_matrix(const L &)
+ { return is_col_matrix_(typename linalg_traits<L>::sub_orientation()); }
+
+ inline bool is_col_matrix(row_major) { return false; }
+ inline bool is_col_matrix(col_major) { return true; }
+ inline bool is_row_matrix(row_major) { return true; }
+ inline bool is_row_matrix(col_major) { return false; }
+
+ template <typename L> inline bool is_const_reference(L) { return false; }
+ inline bool is_const_reference(linalg_const) { return true; }
+
+
+ template <typename T> struct is_gmm_interfaced_ {
+ typedef linalg_true result;
+ };
+
+ template<> struct is_gmm_interfaced_<abstract_null_type> {
+ typedef linalg_false result;
+ };
+
+ template <typename T> struct is_gmm_interfaced {
+ typedef typename is_gmm_interfaced_<typename gmm::linalg_traits<T>::this_type >::result result;
+ };
+
+ /* ******************************************************************** */
+ /* types to deal with const object representing a modifiable reference */
+ /* ******************************************************************** */
+
+ template <typename PT, typename R> struct mref_type_
+ { typedef abstract_null_type return_type; };
+ template <typename L, typename R> struct mref_type_<L *, R>
+ { typedef L & return_type; };
+ template <typename L, typename R> struct mref_type_<const L *, R>
+ { typedef const L & return_type; };
+ template <typename L> struct mref_type_<L *, linalg_const>
+ { typedef const L & return_type; };
+ template <typename L> struct mref_type_<const L *, linalg_const>
+ { typedef const L & return_type; };
+ template <typename L> struct mref_type_<const L *, linalg_modifiable>
+ { typedef L & return_type; };
+ template <typename L> struct mref_type_<L *, linalg_modifiable>
+ { typedef L & return_type; };
+
+ template <typename PT> struct mref_type {
+ typedef typename std::iterator_traits<PT>::value_type L;
+ typedef typename mref_type_<PT,
+ typename linalg_traits<L>::is_reference>::return_type return_type;
+ };
+
+ template <typename L> typename mref_type<const L *>::return_type
+ linalg_cast(const L &l)
+ { return const_cast<typename mref_type<const L *>::return_type>(l); }
+
+ template <typename L> typename mref_type<L *>::return_type linalg_cast(L &l)
+ { return const_cast<typename mref_type<L *>::return_type>(l); }
+
+ template <typename L, typename R> struct cref_type_
+ { typedef abstract_null_type return_type; };
+ template <typename L> struct cref_type_<L, linalg_modifiable>
+ { typedef L & return_type; };
+ template <typename L> struct cref_type {
+ typedef typename cref_type_<L,
+ typename linalg_traits<L>::is_reference>::return_type return_type;
+ };
+
+ template <typename L> typename cref_type<L>::return_type
+ linalg_const_cast(const L &l)
+ { return const_cast<typename cref_type<L>::return_type>(l); }
+
+
+ // To be used to select between a reference or a const refercence for
+ // the return type of a function
+ // select_return<C1, C2, L *> return C1 if L is a const reference,
+ // C2 otherwise.
+ // select_return<C1, C2, const L *> return C2 if L is a modifiable reference
+ // C1 otherwise.
+ template <typename C1, typename C2, typename REF> struct select_return_ {
+ typedef abstract_null_type return_type;
+ };
+ template <typename C1, typename C2, typename L>
+ struct select_return_<C1, C2, const L &> { typedef C1 return_type; };
+ template <typename C1, typename C2, typename L>
+ struct select_return_<C1, C2, L &> { typedef C2 return_type; };
+ template <typename C1, typename C2, typename PT> struct select_return {
+ typedef typename std::iterator_traits<PT>::value_type L;
+ typedef typename select_return_<C1, C2,
+ typename mref_type<PT>::return_type>::return_type return_type;
+ };
+
+
+ // To be used to select between a reference or a const refercence inside
+ // a structure or a linagl_traits
+ // select_ref<C1, C2, L *> return C1 if L is a const reference,
+ // C2 otherwise.
+ // select_ref<C1, C2, const L *> return C2 in any case.
+ template <typename C1, typename C2, typename REF> struct select_ref_
+ { typedef abstract_null_type ref_type; };
+ template <typename C1, typename C2, typename L>
+ struct select_ref_<C1, C2, const L &> { typedef C1 ref_type; };
+ template <typename C1, typename C2, typename L>
+ struct select_ref_<C1, C2, L &> { typedef C2 ref_type; };
+ template <typename C1, typename C2, typename PT> struct select_ref {
+ typedef typename std::iterator_traits<PT>::value_type L;
+ typedef typename select_ref_<C1, C2,
+ typename mref_type<PT>::return_type>::ref_type ref_type;
+ };
+ template <typename C1, typename C2, typename L>
+ struct select_ref<C1, C2, const L *>
+ { typedef C1 ref_type; };
+
+
+ template<typename R> struct is_a_reference_
+ { typedef linalg_true reference; };
+ template<> struct is_a_reference_<linalg_false>
+ { typedef linalg_false reference; };
+
+ template<typename L> struct is_a_reference {
+ typedef typename is_a_reference_<typename linalg_traits<L>::is_reference>
+ ::reference reference;
+ };
+
+
+ template <typename L> inline bool is_original_linalg(const L &)
+ { return is_original_linalg(typename is_a_reference<L>::reference()); }
+ inline bool is_original_linalg(linalg_false) { return true; }
+ inline bool is_original_linalg(linalg_true) { return false; }
+
+
+ template <typename PT> struct which_reference
+ { typedef abstract_null_type is_reference; };
+ template <typename PT> struct which_reference<PT *>
+ { typedef linalg_modifiable is_reference; };
+ template <typename PT> struct which_reference<const PT *>
+ { typedef linalg_const is_reference; };
+
+
+ template <typename C1, typename C2, typename R> struct select_orientation_
+ { typedef abstract_null_type return_type; };
+ template <typename C1, typename C2>
+ struct select_orientation_<C1, C2, row_major>
+ { typedef C1 return_type; };
+ template <typename C1, typename C2>
+ struct select_orientation_<C1, C2, col_major>
+ { typedef C2 return_type; };
+ template <typename C1, typename C2, typename L> struct select_orientation {
+ typedef typename select_orientation_<C1, C2,
+ typename principal_orientation_type<typename
+ linalg_traits<L>::sub_orientation>::potype>::return_type return_type;
+ };
+
+ /* ******************************************************************** */
+ /* Operations on scalars */
+ /* ******************************************************************** */
+
+ template <typename T> inline T sqr(T a) { return a * a; }
+ template <typename T> inline T abs(T a) { return (a < T(0)) ? T(-a) : a; }
+ template <typename T> inline T abs(std::complex<T> a)
+ { T x = a.real(), y = a.imag(); return ::sqrt(x*x+y*y); }
+ template <typename T> inline T abs_sqr(T a) { return a*a; }
+ template <typename T> inline T abs_sqr(std::complex<T> a)
+ { return gmm::sqr(a.real()) + gmm::sqr(a.imag()); }
+ template <typename T> inline T pos(T a) { return (a < T(0)) ? T(0) : a; }
+ template <typename T> inline T neg(T a) { return (a < T(0)) ? T(-a) : T(0); }
+ template <typename T> inline T sgn(T a) { return (a < T(0)) ? T(-1) : T(1); }
+ inline double random() { return double(rand())/(RAND_MAX+0.5); }
+ template <typename T> inline T random(T)
+ { return T(rand()*2.0)/(T(RAND_MAX)+T(1)/T(2)) - T(1); }
+ template <typename T> inline std::complex<T> random(std::complex<T>)
+ { return std::complex<T>(gmm::random(T()), gmm::random(T())); }
+ template <typename T> inline T irandom(T max)
+ { return T(gmm::random() * max); }
+ template <typename T> inline T conj(T a) { return a; }
+ template <typename T> inline std::complex<T> conj(std::complex<T> a)
+ { return std::conj(a); }
+ template <typename T> inline T real(T a) { return a; }
+ template <typename T> inline T real(std::complex<T> a) { return a.real(); }
+ template <typename T> inline T imag(T ) { return T(0); }
+ template <typename T> inline T imag(std::complex<T> a) { return a.imag(); }
+ template <typename T> inline T sqrt(T a) { return ::sqrt(a); }
+ template <typename T> inline std::complex<T> sqrt(std::complex<T> a) {
+ T x = a.real(), y = a.imag();
+ if (x == T(0)) {
+ T t = ::sqrt(gmm::abs(y) / T(2));
+ return std::complex<T>(t, y < T(0) ? -t : t);
+ }
+ T t = ::sqrt(T(2) * (gmm::abs(a) + gmm::abs(x))), u = t / T(2);
+ return x > T(0) ? std::complex<T>(u, y / t)
+ : std::complex<T>(gmm::abs(y) / t, y < T(0) ? -u : u);
+ }
+ using std::swap;
+
+
+ template <typename T> struct number_traits {
+ typedef T magnitude_type;
+ };
+
+ template <typename T> struct number_traits<std::complex<T> > {
+ typedef T magnitude_type;
+ };
+
+ template <typename T> inline T conj_product(T a, T b) { return a * b; }
+ template <typename T> inline
+ std::complex<T> conj_product(std::complex<T> a, std::complex<T> b)
+ { return std::conj(a) * b; } // to be optimized ?
+
+ template <typename T> inline bool is_complex(T) { return false; }
+ template <typename T> inline bool is_complex(std::complex<T> )
+ { return true; }
+
+# define magnitude_of_linalg(M) typename number_traits<typename \
+ linalg_traits<M>::value_type>::magnitude_type
+
+ template<typename T> inline std::complex<T> operator*(const std::complex<T>& a, int b) {
+ return a*T(b);
+ }
+ template<typename T> inline std::complex<T> operator*(int b, const std::complex<T>& a) {
+ return a*T(b);
+ }
+
+ /* ******************************************************************** */
+ /* types promotion */
+ /* ******************************************************************** */
+
+ /* should be completed for more specific cases <unsigned int, float> etc */
+ template <typename T1, typename T2, bool c>
+ struct strongest_numeric_type_aux {
+ typedef T1 T;
+ };
+ template <typename T1, typename T2>
+ struct strongest_numeric_type_aux<T1,T2,false> {
+ typedef T2 T;
+ };
+
+ template <typename T1, typename T2>
+ struct strongest_numeric_type {
+ typedef typename
+ strongest_numeric_type_aux<T1,T2,(sizeof(T1)>sizeof(T2))>::T T;
+ };
+ template <typename T1, typename T2>
+ struct strongest_numeric_type<T1,std::complex<T2> > {
+ typedef typename number_traits<T1>::magnitude_type R1;
+ typedef std::complex<typename strongest_numeric_type<R1,T2>::T > T;
+ };
+ template <typename T1, typename T2>
+ struct strongest_numeric_type<std::complex<T1>,T2 > {
+ typedef typename number_traits<T2>::magnitude_type R2;
+ typedef std::complex<typename strongest_numeric_type<T1,R2>::T > T;
+ };
+ template <typename T1, typename T2>
+ struct strongest_numeric_type<std::complex<T1>,std::complex<T2> > {
+ typedef std::complex<typename strongest_numeric_type<T1,T2>::T > T;
+ };
+
+ template<> struct strongest_numeric_type<int,float> { typedef float T; };
+ template<> struct strongest_numeric_type<float,int> { typedef float T; };
+ template<> struct strongest_numeric_type<long,float> { typedef float T; };
+ template<> struct strongest_numeric_type<float,long> { typedef float T; };
+ template<> struct strongest_numeric_type<long,double> { typedef double T; };
+ template<> struct strongest_numeric_type<double,long> { typedef double T; };
+
+ template <typename V1, typename V2>
+ struct strongest_value_type {
+ typedef typename
+ strongest_numeric_type<typename linalg_traits<V1>::value_type,
+ typename linalg_traits<V2>::value_type>::T
+ value_type;
+ };
+ template <typename V1, typename V2, typename V3>
+ struct strongest_value_type3 {
+ typedef typename
+ strongest_value_type<V1, typename
+ strongest_value_type<V2,V3>::value_type>::value_type
+ value_type;
+ };
+
+
+
+ /* ******************************************************************** */
+ /* Basic vectors used */
+ /* ******************************************************************** */
+
+ template<typename T> struct dense_vector_type
+ { typedef std::vector<T> vector_type; };
+
+ template <typename T> class wsvector;
+ template <typename T> class rsvector;
+ template<typename T> struct sparse_vector_type
+ { typedef wsvector<T> vector_type; };
+
+ template <typename T> class slvector;
+ template <typename T> class dense_matrix;
+ template <typename VECT> class row_matrix;
+ template <typename VECT> class col_matrix;
+
+
+ /* ******************************************************************** */
+ /* Selects a temporary vector type */
+ /* V if V is a valid vector type, */
+ /* wsvector if V is a reference on a sparse vector, */
+ /* std::vector if V is a reference on a dense vector. */
+ /* ******************************************************************** */
+
+
+ template <typename R, typename S, typename L, typename V>
+ struct temporary_vector_ {
+ typedef abstract_null_type vector_type;
+ };
+ template <typename V, typename L>
+ struct temporary_vector_<linalg_true, abstract_sparse, L, V>
+ { typedef wsvector<typename linalg_traits<V>::value_type> vector_type; };
+ template <typename V, typename L>
+ struct temporary_vector_<linalg_true, abstract_skyline, L, V>
+ { typedef slvector<typename linalg_traits<V>::value_type> vector_type; };
+ template <typename V, typename L>
+ struct temporary_vector_<linalg_true, abstract_dense, L, V>
+ { typedef std::vector<typename linalg_traits<V>::value_type> vector_type; };
+ template <typename S, typename V>
+ struct temporary_vector_<linalg_false, S, abstract_vector, V>
+ { typedef V vector_type; };
+ template <typename V>
+ struct temporary_vector_<linalg_false, abstract_dense, abstract_matrix, V>
+ { typedef std::vector<typename linalg_traits<V>::value_type> vector_type; };
+ template <typename V>
+ struct temporary_vector_<linalg_false, abstract_sparse, abstract_matrix, V>
+ { typedef wsvector<typename linalg_traits<V>::value_type> vector_type; };
+
+ template <typename V> struct temporary_vector {
+ typedef typename temporary_vector_<typename is_a_reference<V>::reference,
+ typename linalg_traits<V>::storage_type,
+ typename linalg_traits<V>::linalg_type,
+ V>::vector_type vector_type;
+ };
+
+ /* ******************************************************************** */
+ /* Selects a temporary matrix type */
+ /* M if M is a valid matrix type, */
+ /* row_matrix<wsvector> if M is a reference on a sparse matrix, */
+ /* dense_matrix if M is a reference on a dense matrix. */
+ /* ******************************************************************** */
+
+
+ template <typename R, typename S, typename L, typename V>
+ struct temporary_matrix_ { typedef abstract_null_type matrix_type; };
+ template <typename V, typename L>
+ struct temporary_matrix_<linalg_true, abstract_sparse, L, V> {
+ typedef typename linalg_traits<V>::value_type T;
+ typedef row_matrix<wsvector<T> > matrix_type;
+ };
+ template <typename V, typename L>
+ struct temporary_matrix_<linalg_true, abstract_skyline, L, V> {
+ typedef typename linalg_traits<V>::value_type T;
+ typedef row_matrix<slvector<T> > matrix_type;
+ };
+ template <typename V, typename L>
+ struct temporary_matrix_<linalg_true, abstract_dense, L, V>
+ { typedef dense_matrix<typename linalg_traits<V>::value_type> matrix_type; };
+ template <typename S, typename V>
+ struct temporary_matrix_<linalg_false, S, abstract_matrix, V>
+ { typedef V matrix_type; };
+
+ template <typename V> struct temporary_matrix {
+ typedef typename temporary_matrix_<typename is_a_reference<V>::reference,
+ typename linalg_traits<V>::storage_type,
+ typename linalg_traits<V>::linalg_type,
+ V>::matrix_type matrix_type;
+ };
+
+
+ template <typename S, typename L, typename V>
+ struct temporary_col_matrix_ { typedef abstract_null_type matrix_type; };
+ template <typename V, typename L>
+ struct temporary_col_matrix_<abstract_sparse, L, V> {
+ typedef typename linalg_traits<V>::value_type T;
+ typedef col_matrix<wsvector<T> > matrix_type;
+ };
+ template <typename V, typename L>
+ struct temporary_col_matrix_<abstract_skyline, L, V> {
+ typedef typename linalg_traits<V>::value_type T;
+ typedef col_matrix<slvector<T> > matrix_type;
+ };
+ template <typename V, typename L>
+ struct temporary_col_matrix_<abstract_dense, L, V>
+ { typedef dense_matrix<typename linalg_traits<V>::value_type> matrix_type; };
+
+ template <typename V> struct temporary_col_matrix {
+ typedef typename temporary_col_matrix_<
+ typename linalg_traits<V>::storage_type,
+ typename linalg_traits<V>::linalg_type,
+ V>::matrix_type matrix_type;
+ };
+
+
+
+
+ template <typename S, typename L, typename V>
+ struct temporary_row_matrix_ { typedef abstract_null_type matrix_type; };
+ template <typename V, typename L>
+ struct temporary_row_matrix_<abstract_sparse, L, V> {
+ typedef typename linalg_traits<V>::value_type T;
+ typedef row_matrix<wsvector<T> > matrix_type;
+ };
+ template <typename V, typename L>
+ struct temporary_row_matrix_<abstract_skyline, L, V> {
+ typedef typename linalg_traits<V>::value_type T;
+ typedef row_matrix<slvector<T> > matrix_type;
+ };
+ template <typename V, typename L>
+ struct temporary_row_matrix_<abstract_dense, L, V>
+ { typedef dense_matrix<typename linalg_traits<V>::value_type> matrix_type; };
+
+ template <typename V> struct temporary_row_matrix {
+ typedef typename temporary_row_matrix_<
+ typename linalg_traits<V>::storage_type,
+ typename linalg_traits<V>::linalg_type,
+ V>::matrix_type matrix_type;
+ };
+
+
+
+ /* ******************************************************************** */
+ /* Selects a temporary dense vector type */
+ /* V if V is a valid dense vector type, */
+ /* std::vector if V is a reference or another type of vector */
+ /* ******************************************************************** */
+
+ template <typename R, typename S, typename V>
+ struct temporary_dense_vector_ { typedef abstract_null_type vector_type; };
+ template <typename S, typename V>
+ struct temporary_dense_vector_<linalg_true, S, V>
+ { typedef std::vector<typename linalg_traits<V>::value_type> vector_type; };
+ template <typename V>
+ struct temporary_dense_vector_<linalg_false, abstract_sparse, V>
+ { typedef std::vector<typename linalg_traits<V>::value_type> vector_type; };
+ template <typename V>
+ struct temporary_dense_vector_<linalg_false, abstract_skyline, V>
+ { typedef std::vector<typename linalg_traits<V>::value_type> vector_type; };
+ template <typename V>
+ struct temporary_dense_vector_<linalg_false, abstract_dense, V>
+ { typedef V vector_type; };
+
+ template <typename V> struct temporary_dense_vector {
+ typedef typename temporary_dense_vector_<typename
+ is_a_reference<V>::reference,
+ typename linalg_traits<V>::storage_type, V>::vector_type vector_type;
+ };
+
+ /* ******************************************************************** */
+ /* Selects a temporary sparse vector type */
+ /* V if V is a valid sparse vector type, */
+ /* wsvector if V is a reference or another type of vector */
+ /* ******************************************************************** */
+
+ template <typename R, typename S, typename V>
+ struct temporary_sparse_vector_ { typedef abstract_null_type vector_type; };
+ template <typename S, typename V>
+ struct temporary_sparse_vector_<linalg_true, S, V>
+ { typedef wsvector<typename linalg_traits<V>::value_type> vector_type; };
+ template <typename V>
+ struct temporary_sparse_vector_<linalg_false, abstract_sparse, V>
+ { typedef V vector_type; };
+ template <typename V>
+ struct temporary_sparse_vector_<linalg_false, abstract_dense, V>
+ { typedef wsvector<typename linalg_traits<V>::value_type> vector_type; };
+ template <typename V>
+ struct temporary_sparse_vector_<linalg_false, abstract_skyline, V>
+ { typedef wsvector<typename linalg_traits<V>::value_type> vector_type; };
+
+ template <typename V> struct temporary_sparse_vector {
+ typedef typename temporary_sparse_vector_<typename
+ is_a_reference<V>::reference,
+ typename linalg_traits<V>::storage_type, V>::vector_type vector_type;
+ };
+
+ /* ******************************************************************** */
+ /* Selects a temporary sky-line vector type */
+ /* V if V is a valid sky-line vector type, */
+ /* slvector if V is a reference or another type of vector */
+ /* ******************************************************************** */
+
+ template <typename R, typename S, typename V>
+ struct temporary_skyline_vector_
+ { typedef abstract_null_type vector_type; };
+ template <typename S, typename V>
+ struct temporary_skyline_vector_<linalg_true, S, V>
+ { typedef slvector<typename linalg_traits<V>::value_type> vector_type; };
+ template <typename V>
+ struct temporary_skyline_vector_<linalg_false, abstract_skyline, V>
+ { typedef V vector_type; };
+ template <typename V>
+ struct temporary_skyline_vector_<linalg_false, abstract_dense, V>
+ { typedef slvector<typename linalg_traits<V>::value_type> vector_type; };
+ template <typename V>
+ struct temporary_skyline_vector_<linalg_false, abstract_sparse, V>
+ { typedef slvector<typename linalg_traits<V>::value_type> vector_type; };
+
+ template <typename V> struct temporary_skylines_vector {
+ typedef typename temporary_skyline_vector_<typename
+ is_a_reference<V>::reference,
+ typename linalg_traits<V>::storage_type, V>::vector_type vector_type;
+ };
+
+ /* ********************************************************************* */
+ /* Definition & Comparison of origins. */
+ /* ********************************************************************* */
+
+ template <typename L>
+ typename select_return<const typename linalg_traits<L>::origin_type *,
+ typename linalg_traits<L>::origin_type *,
+ L *>::return_type
+ linalg_origin(L &l)
+ { return linalg_traits<L>::origin(linalg_cast(l)); }
+
+ template <typename L>
+ typename select_return<const typename linalg_traits<L>::origin_type *,
+ typename linalg_traits<L>::origin_type *,
+ const L *>::return_type
+ linalg_origin(const L &l)
+ { return linalg_traits<L>::origin(linalg_cast(l)); }
+
+ template <typename PT1, typename PT2>
+ bool same_porigin(PT1, PT2) { return false; }
+
+ template <typename PT>
+ bool same_porigin(PT pt1, PT pt2) { return (pt1 == pt2); }
+
+ template <typename L1, typename L2>
+ bool same_origin(const L1 &l1, const L2 &l2)
+ { return same_porigin(linalg_origin(l1), linalg_origin(l2)); }
+
+
+ /* ******************************************************************** */
+ /* Miscellaneous */
+ /* ******************************************************************** */
+
+ template <typename V> inline size_type vect_size(const V &v)
+ { return linalg_traits<V>::size(v); }
+
+ template <typename MAT> inline size_type mat_nrows(const MAT &m)
+ { return linalg_traits<MAT>::nrows(m); }
+
+ template <typename MAT> inline size_type mat_ncols(const MAT &m)
+ { return linalg_traits<MAT>::ncols(m); }
+
+
+ template <typename V> inline
+ typename select_return<typename linalg_traits<V>::const_iterator,
+ typename linalg_traits<V>::iterator, V *>::return_type
+ vect_begin(V &v)
+ { return linalg_traits<V>::begin(linalg_cast(v)); }
+
+ template <typename V> inline
+ typename select_return<typename linalg_traits<V>::const_iterator,
+ typename linalg_traits<V>::iterator, const V *>::return_type
+ vect_begin(const V &v)
+ { return linalg_traits<V>::begin(linalg_cast(v)); }
+
+ template <typename V> inline
+ typename linalg_traits<V>::const_iterator
+ vect_const_begin(const V &v)
+ { return linalg_traits<V>::begin(v); }
+
+ template <typename V> inline
+ typename select_return<typename linalg_traits<V>::const_iterator,
+ typename linalg_traits<V>::iterator, V *>::return_type
+ vect_end(V &v)
+ { return linalg_traits<V>::end(linalg_cast(v)); }
+
+ template <typename V> inline
+ typename select_return<typename linalg_traits<V>::const_iterator,
+ typename linalg_traits<V>::iterator, const V *>::return_type
+ vect_end(const V &v)
+ { return linalg_traits<V>::end(linalg_cast(v)); }
+
+ template <typename V> inline
+ typename linalg_traits<V>::const_iterator
+ vect_const_end(const V &v)
+ { return linalg_traits<V>::end(v); }
+
+ template <typename M> inline
+ typename select_return<typename linalg_traits<M>::const_row_iterator,
+ typename linalg_traits<M>::row_iterator, M *>::return_type
+ mat_row_begin(M &m) { return linalg_traits<M>::row_begin(linalg_cast(m)); }
+
+ template <typename M> inline
+ typename select_return<typename linalg_traits<M>::const_row_iterator,
+ typename linalg_traits<M>::row_iterator, const M *>::return_type
+ mat_row_begin(const M &m)
+ { return linalg_traits<M>::row_begin(linalg_cast(m)); }
+
+ template <typename M> inline typename linalg_traits<M>::const_row_iterator
+ mat_row_const_begin(const M &m)
+ { return linalg_traits<M>::row_begin(m); }
+
+ template <typename M> inline
+ typename select_return<typename linalg_traits<M>::const_row_iterator,
+ typename linalg_traits<M>::row_iterator, M *>::return_type
+ mat_row_end(M &v) {
+ return linalg_traits<M>::row_end(linalg_cast(v));
+ }
+
+ template <typename M> inline
+ typename select_return<typename linalg_traits<M>::const_row_iterator,
+ typename linalg_traits<M>::row_iterator, const M *>::return_type
+ mat_row_end(const M &v) {
+ return linalg_traits<M>::row_end(linalg_cast(v));
+ }
+
+ template <typename M> inline
+ typename linalg_traits<M>::const_row_iterator
+ mat_row_const_end(const M &v)
+ { return linalg_traits<M>::row_end(v); }
+
+ template <typename M> inline
+ typename select_return<typename linalg_traits<M>::const_col_iterator,
+ typename linalg_traits<M>::col_iterator, M *>::return_type
+ mat_col_begin(M &v) {
+ return linalg_traits<M>::col_begin(linalg_cast(v));
+ }
+
+ template <typename M> inline
+ typename select_return<typename linalg_traits<M>::const_col_iterator,
+ typename linalg_traits<M>::col_iterator, const M *>::return_type
+ mat_col_begin(const M &v) {
+ return linalg_traits<M>::col_begin(linalg_cast(v));
+ }
+
+ template <typename M> inline
+ typename linalg_traits<M>::const_col_iterator
+ mat_col_const_begin(const M &v)
+ { return linalg_traits<M>::col_begin(v); }
+
+ template <typename M> inline
+ typename linalg_traits<M>::const_col_iterator
+ mat_col_const_end(const M &v)
+ { return linalg_traits<M>::col_end(v); }
+
+ template <typename M> inline
+ typename select_return<typename linalg_traits<M>::const_col_iterator,
+ typename linalg_traits<M>::col_iterator,
+ M *>::return_type
+ mat_col_end(M &m)
+ { return linalg_traits<M>::col_end(linalg_cast(m)); }
+
+ template <typename M> inline
+ typename select_return<typename linalg_traits<M>::const_col_iterator,
+ typename linalg_traits<M>::col_iterator,
+ const M *>::return_type
+ mat_col_end(const M &m)
+ { return linalg_traits<M>::col_end(linalg_cast(m)); }
+
+ template <typename MAT> inline
+ typename select_return<typename linalg_traits<MAT>::const_sub_row_type,
+ typename linalg_traits<MAT>::sub_row_type,
+ const MAT *>::return_type
+ mat_row(const MAT &m, size_type i)
+ { return linalg_traits<MAT>::row(mat_row_begin(m) + i); }
+
+ template <typename MAT> inline
+ typename select_return<typename linalg_traits<MAT>::const_sub_row_type,
+ typename linalg_traits<MAT>::sub_row_type,
+ MAT *>::return_type
+ mat_row(MAT &m, size_type i)
+ { return linalg_traits<MAT>::row(mat_row_begin(m) + i); }
+
+ template <typename MAT> inline
+ typename linalg_traits<MAT>::const_sub_row_type
+ mat_const_row(const MAT &m, size_type i)
+ { return linalg_traits<MAT>::row(mat_row_const_begin(m) + i); }
+
+ template <typename MAT> inline
+ typename select_return<typename linalg_traits<MAT>::const_sub_col_type,
+ typename linalg_traits<MAT>::sub_col_type,
+ const MAT *>::return_type
+ mat_col(const MAT &m, size_type i)
+ { return linalg_traits<MAT>::col(mat_col_begin(m) + i); }
+
+
+ template <typename MAT> inline
+ typename select_return<typename linalg_traits<MAT>::const_sub_col_type,
+ typename linalg_traits<MAT>::sub_col_type,
+ MAT *>::return_type
+ mat_col(MAT &m, size_type i)
+ { return linalg_traits<MAT>::col(mat_col_begin(m) + i); }
+
+ template <typename MAT> inline
+ typename linalg_traits<MAT>::const_sub_col_type
+ mat_const_col(const MAT &m, size_type i)
+ { return linalg_traits<MAT>::col(mat_col_const_begin(m) + i); }
+
+ /* ********************************************************************* */
+ /* Set to begin end set to end for iterators on non-const sparse vectors.*/
+ /* ********************************************************************* */
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_begin(IT &it, ORG o, VECT *, linalg_false)
+ { it = vect_begin(*o); }
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_begin(IT &it, ORG o, const VECT *, linalg_false)
+ { it = vect_const_begin(*o); }
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_end(IT &it, ORG o, VECT *, linalg_false)
+ { it = vect_end(*o); }
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_end(IT &it, ORG o, const VECT *, linalg_false)
+ { it = vect_const_end(*o); }
+
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_begin(IT &, ORG, VECT *, linalg_const) { }
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_begin(IT &, ORG, const VECT *, linalg_const) { }
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_end(IT &, ORG, VECT *, linalg_const) { }
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_end(IT &, ORG, const VECT *, linalg_const) { }
+
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_begin(IT &, ORG, VECT *v, linalg_modifiable)
+ { GMM_ASSERT3(!is_sparse(*v), "internal_error"); v = 0; }
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_begin(IT &, ORG, const VECT *v, linalg_modifiable)
+ { GMM_ASSERT3(!is_sparse(*v), "internal_error"); v = 0; }
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_end(IT &, ORG, VECT *v, linalg_modifiable)
+ { GMM_ASSERT3(!is_sparse(*v), "internal_error"); v = 0; }
+
+ template <typename IT, typename ORG, typename VECT> inline
+ void set_to_end(IT &, ORG, const VECT *v, linalg_modifiable)
+ { GMM_ASSERT3(!is_sparse(*v), "internal_error"); v = 0; }
+
+ /* ******************************************************************** */
+ /* General index for certain algorithms. */
+ /* ******************************************************************** */
+
+ template<class IT>
+ size_type index_of_it(const IT &it, size_type, abstract_sparse)
+ { return it.index(); }
+ template<class IT>
+ size_type index_of_it(const IT &it, size_type, abstract_skyline)
+ { return it.index(); }
+ template<class IT>
+ size_type index_of_it(const IT &, size_type k, abstract_dense)
+ { return k; }
+
+ /* ********************************************************************* */
+ /* Numeric limits. */
+ /* ********************************************************************* */
+
+ template<typename T> inline T default_tol(T) {
+ using namespace std;
+ static T tol(10);
+ if (tol == T(10)) {
+ if (numeric_limits<T>::is_specialized)
+ tol = numeric_limits<T>::epsilon();
+ else {
+ int i=sizeof(T)/4; while(i-- > 0) tol*=T(1E-8);
+ GMM_WARNING1("The numeric type " << typeid(T).name()
+ << " has no numeric_limits defined !!\n"
+ << "Taking " << tol << " as default tolerance");
+ }
+ }
+ return tol;
+ }
+ template<typename T> inline T default_tol(std::complex<T>)
+ { return default_tol(T()); }
+
+ template<typename T> inline T default_min(T) {
+ using namespace std;
+ static T mi(10);
+ if (mi == T(10)) {
+ if (numeric_limits<T>::is_specialized)
+ mi = std::numeric_limits<T>::min();
+ else {
+ mi = T(0);
+ GMM_WARNING1("The numeric type " << typeid(T).name()
+ << " has no numeric_limits defined !!\n"
+ << "Taking 0 as default minimum");
+ }
+ }
+ return mi;
+ }
+ template<typename T> inline T default_min(std::complex<T>)
+ { return default_min(T()); }
+
+ template<typename T> inline T default_max(T) {
+ using namespace std;
+ static T mi(10);
+ if (mi == T(10)) {
+ if (numeric_limits<T>::is_specialized)
+ mi = std::numeric_limits<T>::max();
+ else {
+ mi = T(1);
+ GMM_WARNING1("The numeric type " << typeid(T).name()
+ << " has no numeric_limits defined !!\n"
+ << "Taking 1 as default maximum !");
+ }
+ }
+ return mi;
+ }
+ template<typename T> inline T default_max(std::complex<T>)
+ { return default_max(T()); }
+
+
+ /*
+ use safe_divide to avoid NaNs when dividing very small complex
+ numbers, for example
+ std::complex<float>(1e-23,1e-30)/std::complex<float>(1e-23,1e-30)
+ */
+ template<typename T> inline T safe_divide(T a, T b) { return a/b; }
+ template<typename T> inline std::complex<T>
+ safe_divide(std::complex<T> a, std::complex<T> b) {
+ T m = std::max(gmm::abs(b.real()), gmm::abs(b.imag()));
+ a = std::complex<T>(a.real()/m, a.imag()/m);
+ b = std::complex<T>(b.real()/m, b.imag()/m);
+ return a / b;
+ }
+
+
+ /* ******************************************************************** */
+ /* Write */
+ /* ******************************************************************** */
+
+ template <typename T> struct cast_char_type { typedef T return_type; };
+ template <> struct cast_char_type<signed char> { typedef int return_type; };
+ template <> struct cast_char_type<unsigned char>
+ { typedef unsigned int return_type; };
+ template <typename T> inline typename cast_char_type<T>::return_type
+ cast_char(const T &c) { return typename cast_char_type<T>::return_type(c); }
+
+
+ template <typename L> inline void write(std::ostream &o, const L &l)
+ { write(o, l, typename linalg_traits<L>::linalg_type()); }
+
+ template <typename L> void write(std::ostream &o, const L &l,
+ abstract_vector) {
+ o << "vector(" << vect_size(l) << ") [";
+ write(o, l, typename linalg_traits<L>::storage_type());
+ o << " ]";
+ }
+
+ template <typename L> void write(std::ostream &o, const L &l,
+ abstract_sparse) {
+ typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
+ ite = vect_const_end(l);
+ for (; it != ite; ++it)
+ o << " (r" << it.index() << "," << cast_char(*it) << ")";
+ }
+
+ template <typename L> void write(std::ostream &o, const L &l,
+ abstract_dense) {
+ typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
+ ite = vect_const_end(l);
+ if (it != ite) o << " " << cast_char(*it++);
+ for (; it != ite; ++it) o << ", " << cast_char(*it);
+ }
+
+ template <typename L> void write(std::ostream &o, const L &l,
+ abstract_skyline) {
+ typedef typename linalg_traits<L>::const_iterator const_iterator;
+ const_iterator it = vect_const_begin(l), ite = vect_const_end(l);
+ if (it != ite) {
+ o << "<r+" << it.index() << ">";
+ if (it != ite) o << " " << cast_char(*it++);
+ for (; it != ite; ++it) { o << ", " << cast_char(*it); }
+ }
+ }
+
+ template <typename L> inline void write(std::ostream &o, const L &l,
+ abstract_matrix) {
+ write(o, l, typename linalg_traits<L>::sub_orientation());
+ }
+
+
+ template <typename L> void write(std::ostream &o, const L &l,
+ row_major) {
+ o << "matrix(" << mat_nrows(l) << ", " << mat_ncols(l) << ")" << endl;
+ for (size_type i = 0; i < mat_nrows(l); ++i) {
+ o << "(";
+ write(o, mat_const_row(l, i), typename linalg_traits<L>::storage_type());
+ o << " )\n";
+ }
+ }
+
+ template <typename L> inline
+ void write(std::ostream &o, const L &l, row_and_col)
+ { write(o, l, row_major()); }
+
+ template <typename L> inline
+ void write(std::ostream &o, const L &l, col_and_row)
+ { write(o, l, row_major()); }
+
+ template <typename L> void write(std::ostream &o, const L &l, col_major) {
+ o << "matrix(" << mat_nrows(l) << ", " << mat_ncols(l) << ")" << endl;
+ for (size_type i = 0; i < mat_nrows(l); ++i) {
+ o << "(";
+ if (is_sparse(l)) { // not optimized ...
+ for (size_type j = 0; j < mat_ncols(l); ++j)
+ if (l(i,j) != typename linalg_traits<L>::value_type(0))
+ o << " (r" << j << ", " << l(i,j) << ")";
+ }
+ else {
+ if (mat_ncols(l) != 0) o << ' ' << l(i, 0);
+ for (size_type j = 1; j < mat_ncols(l); ++j) o << ", " << l(i, j);
+ }
+ o << " )\n";
+ }
+ }
+
+}
+
+#endif // GMM_DEF_H__
diff --git a/Contrib/gmm/gmm_dense_Householder.h b/Contrib/gmm/gmm_dense_Householder.h
new file mode 100755
index 0000000..9e34c1a
--- /dev/null
+++ b/Contrib/gmm/gmm_dense_Householder.h
@@ -0,0 +1,316 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_dense_Householder.h
+ @author Caroline Lecalvez <Caroline.Lecalvez at gmm.insa-toulouse.fr>
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date June 5, 2003.
+ @brief Householder for dense matrices.
+*/
+
+#ifndef GMM_DENSE_HOUSEHOLDER_H
+#define GMM_DENSE_HOUSEHOLDER_H
+
+#include "gmm_kernel.h"
+
+namespace gmm {
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ /* ********************************************************************* */
+ /* Rank one update (complex and real version) */
+ /* ********************************************************************* */
+
+ template <typename Matrix, typename VecX, typename VecY>
+ inline void rank_one_update(Matrix &A, const VecX& x,
+ const VecY& y, row_major) {
+ typedef typename linalg_traits<Matrix>::value_type T;
+ size_type N = mat_nrows(A);
+ GMM_ASSERT2(N <= vect_size(x) && mat_ncols(A) <= vect_size(y),
+ "dimensions mismatch");
+ typename linalg_traits<VecX>::const_iterator itx = vect_const_begin(x);
+ for (size_type i = 0; i < N; ++i, ++itx) {
+ typedef typename linalg_traits<Matrix>::sub_row_type row_type;
+ row_type row = mat_row(A, i);
+ typename linalg_traits<row_type>::iterator
+ it = vect_begin(row), ite = vect_end(row);
+ typename linalg_traits<VecY>::const_iterator ity = vect_const_begin(y);
+ T tx = *itx;
+ for (; it != ite; ++it, ++ity) *it += conj_product(*ity, tx);
+ }
+ }
+
+ template <typename Matrix, typename VecX, typename VecY>
+ inline void rank_one_update(Matrix &A, const VecX& x,
+ const VecY& y, col_major) {
+ typedef typename linalg_traits<Matrix>::value_type T;
+ size_type M = mat_ncols(A);
+ GMM_ASSERT2(mat_nrows(A) <= vect_size(x) && M <= vect_size(y),
+ "dimensions mismatch");
+ typename linalg_traits<VecY>::const_iterator ity = vect_const_begin(y);
+ for (size_type i = 0; i < M; ++i, ++ity) {
+ typedef typename linalg_traits<Matrix>::sub_col_type col_type;
+ col_type col = mat_col(A, i);
+ typename linalg_traits<col_type>::iterator
+ it = vect_begin(col), ite = vect_end(col);
+ typename linalg_traits<VecX>::const_iterator itx = vect_const_begin(x);
+ T ty = *ity;
+ for (; it != ite; ++it, ++itx) *it += conj_product(ty, *itx);
+ }
+ }
+
+ ///@endcond
+ template <typename Matrix, typename VecX, typename VecY>
+ inline void rank_one_update(const Matrix &AA, const VecX& x,
+ const VecY& y) {
+ Matrix& A = const_cast<Matrix&>(AA);
+ rank_one_update(A, x, y, typename principal_orientation_type<typename
+ linalg_traits<Matrix>::sub_orientation>::potype());
+ }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ /* ********************************************************************* */
+ /* Rank two update (complex and real version) */
+ /* ********************************************************************* */
+
+ template <typename Matrix, typename VecX, typename VecY>
+ inline void rank_two_update(Matrix &A, const VecX& x,
+ const VecY& y, row_major) {
+ typedef typename linalg_traits<Matrix>::value_type value_type;
+ size_type N = mat_nrows(A);
+ GMM_ASSERT2(N <= vect_size(x) && mat_ncols(A) <= vect_size(y),
+ "dimensions mismatch");
+ typename linalg_traits<VecX>::const_iterator itx1 = vect_const_begin(x);
+ typename linalg_traits<VecY>::const_iterator ity2 = vect_const_begin(y);
+ for (size_type i = 0; i < N; ++i, ++itx1, ++ity2) {
+ typedef typename linalg_traits<Matrix>::sub_row_type row_type;
+ row_type row = mat_row(A, i);
+ typename linalg_traits<row_type>::iterator
+ it = vect_begin(row), ite = vect_end(row);
+ typename linalg_traits<VecX>::const_iterator itx2 = vect_const_begin(x);
+ typename linalg_traits<VecY>::const_iterator ity1 = vect_const_begin(y);
+ value_type tx = *itx1, ty = *ity2;
+ for (; it != ite; ++it, ++ity1, ++itx2)
+ *it += conj_product(*ity1, tx) + conj_product(*itx2, ty);
+ }
+ }
+
+ template <typename Matrix, typename VecX, typename VecY>
+ inline void rank_two_update(Matrix &A, const VecX& x,
+ const VecY& y, col_major) {
+ typedef typename linalg_traits<Matrix>::value_type value_type;
+ size_type M = mat_ncols(A);
+ GMM_ASSERT2(mat_nrows(A) <= vect_size(x) && M <= vect_size(y),
+ "dimensions mismatch");
+ typename linalg_traits<VecX>::const_iterator itx2 = vect_const_begin(x);
+ typename linalg_traits<VecY>::const_iterator ity1 = vect_const_begin(y);
+ for (size_type i = 0; i < M; ++i, ++ity1, ++itx2) {
+ typedef typename linalg_traits<Matrix>::sub_col_type col_type;
+ col_type col = mat_col(A, i);
+ typename linalg_traits<col_type>::iterator
+ it = vect_begin(col), ite = vect_end(col);
+ typename linalg_traits<VecX>::const_iterator itx1 = vect_const_begin(x);
+ typename linalg_traits<VecY>::const_iterator ity2 = vect_const_begin(y);
+ value_type ty = *ity1, tx = *itx2;
+ for (; it != ite; ++it, ++itx1, ++ity2)
+ *it += conj_product(ty, *itx1) + conj_product(tx, *ity2);
+ }
+ }
+
+ ///@endcond
+ template <typename Matrix, typename VecX, typename VecY>
+ inline void rank_two_update(const Matrix &AA, const VecX& x,
+ const VecY& y) {
+ Matrix& A = const_cast<Matrix&>(AA);
+ rank_two_update(A, x, y, typename principal_orientation_type<typename
+ linalg_traits<Matrix>::sub_orientation>::potype());
+ }
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+ /* ********************************************************************* */
+ /* Householder vector computation (complex and real version) */
+ /* ********************************************************************* */
+
+ template <typename VECT> void house_vector(const VECT &VV) {
+ VECT &V = const_cast<VECT &>(VV);
+ typedef typename linalg_traits<VECT>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ R mu = vect_norm2(V), abs_v0 = gmm::abs(V[0]);
+ if (mu != R(0))
+ gmm::scale(V, (abs_v0 == R(0)) ? T(R(1) / mu)
+ : (safe_divide(T(abs_v0), V[0]) / (abs_v0 + mu)));
+ if (gmm::real(V[vect_size(V)-1]) * R(0) != R(0)) gmm::clear(V);
+ V[0] = T(1);
+ }
+
+ template <typename VECT> void house_vector_last(const VECT &VV) {
+ VECT &V = const_cast<VECT &>(VV);
+ typedef typename linalg_traits<VECT>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type m = vect_size(V);
+ R mu = vect_norm2(V), abs_v0 = gmm::abs(V[m-1]);
+ if (mu != R(0))
+ gmm::scale(V, (abs_v0 == R(0)) ? T(R(1) / mu)
+ : ((abs_v0 / V[m-1]) / (abs_v0 + mu)));
+ if (gmm::real(V[0]) * R(0) != R(0)) gmm::clear(V);
+ V[m-1] = T(1);
+ }
+
+ /* ********************************************************************* */
+ /* Householder updates (complex and real version) */
+ /* ********************************************************************* */
+
+ // multiply A to the left by the reflector stored in V. W is a temporary.
+ template <typename MAT, typename VECT1, typename VECT2> inline
+ void row_house_update(const MAT &AA, const VECT1 &V, const VECT2 &WW) {
+ VECT2 &W = const_cast<VECT2 &>(WW); MAT &A = const_cast<MAT &>(AA);
+ typedef typename linalg_traits<MAT>::value_type value_type;
+ typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+
+ gmm::mult(conjugated(A),
+ scaled(V, value_type(magnitude_type(-2)/vect_norm2_sqr(V))), W);
+ rank_one_update(A, V, W);
+ }
+
+ // multiply A to the right by the reflector stored in V. W is a temporary.
+ template <typename MAT, typename VECT1, typename VECT2> inline
+ void col_house_update(const MAT &AA, const VECT1 &V, const VECT2 &WW) {
+ VECT2 &W = const_cast<VECT2 &>(WW); MAT &A = const_cast<MAT &>(AA);
+ typedef typename linalg_traits<MAT>::value_type value_type;
+ typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+
+ gmm::mult(A,
+ scaled(V, value_type(magnitude_type(-2)/vect_norm2_sqr(V))), W);
+ rank_one_update(A, W, V);
+ }
+
+ ///@endcond
+
+ /* ********************************************************************* */
+ /* Hessemberg reduction with Householder. */
+ /* ********************************************************************* */
+
+ template <typename MAT1, typename MAT2>
+ void Hessenberg_reduction(const MAT1& AA, const MAT2 &QQ, bool compute_Q){
+ MAT1& A = const_cast<MAT1&>(AA); MAT2& Q = const_cast<MAT2&>(QQ);
+ typedef typename linalg_traits<MAT1>::value_type value_type;
+ if (compute_Q) gmm::copy(identity_matrix(), Q);
+ size_type n = mat_nrows(A); if (n < 2) return;
+ std::vector<value_type> v(n), w(n);
+ sub_interval SUBK(0,n);
+ for (size_type k = 1; k+1 < n; ++k) {
+ sub_interval SUBI(k, n-k), SUBJ(k-1,n-k+1);
+ v.resize(n-k);
+ for (size_type j = k; j < n; ++j) v[j-k] = A(j, k-1);
+ house_vector(v);
+ row_house_update(sub_matrix(A, SUBI, SUBJ), v, sub_vector(w, SUBJ));
+ col_house_update(sub_matrix(A, SUBK, SUBI), v, w);
+ // is it possible to "unify" the two on the common part of the matrix?
+ if (compute_Q) col_house_update(sub_matrix(Q, SUBK, SUBI), v, w);
+ }
+ }
+
+ /* ********************************************************************* */
+ /* Householder tridiagonalization for symmetric matrices */
+ /* ********************************************************************* */
+
+ template <typename MAT1, typename MAT2>
+ void Householder_tridiagonalization(const MAT1 &AA, const MAT2 &QQ,
+ bool compute_q) {
+ MAT1 &A = const_cast<MAT1 &>(AA); MAT2 &Q = const_cast<MAT2 &>(QQ);
+ typedef typename linalg_traits<MAT1>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type n = mat_nrows(A); if (n < 2) return;
+ std::vector<T> v(n), p(n), w(n), ww(n);
+ sub_interval SUBK(0,n);
+
+ for (size_type k = 1; k+1 < n; ++k) { // not optimized ...
+ sub_interval SUBI(k, n-k);
+ v.resize(n-k); p.resize(n-k); w.resize(n-k);
+ for (size_type l = k; l < n; ++l)
+ { v[l-k] = w[l-k] = A(l, k-1); A(l, k-1) = A(k-1, l) = T(0); }
+ house_vector(v);
+ R norm = vect_norm2_sqr(v);
+ A(k-1, k) = gmm::conj(A(k, k-1) = w[0] - T(2)*v[0]*vect_hp(w, v)/norm);
+
+ gmm::mult(sub_matrix(A, SUBI), gmm::scaled(v, T(-2) / norm), p);
+ gmm::add(p, gmm::scaled(v, -vect_hp(v, p) / norm), w);
+ rank_two_update(sub_matrix(A, SUBI), v, w);
+ // it should be possible to compute only the upper or lower part
+
+ if (compute_q) col_house_update(sub_matrix(Q, SUBK, SUBI), v, ww);
+ }
+ }
+
+ /* ********************************************************************* */
+ /* Real and complex Givens rotations */
+ /* ********************************************************************* */
+
+ template <typename T> void Givens_rotation(T a, T b, T &c, T &s) {
+ typedef typename number_traits<T>::magnitude_type R;
+ R aa = gmm::abs(a), bb = gmm::abs(b);
+ if (bb == R(0)) { c = T(1); s = T(0); return; }
+ if (aa == R(0)) { c = T(0); s = b / bb; return; }
+ if (bb > aa)
+ { T t = -safe_divide(a,b); s = T(R(1) / (sqrt(R(1)+gmm::abs_sqr(t)))); c = s * t; }
+ else
+ { T t = -safe_divide(b,a); c = T(R(1) / (sqrt(R(1)+gmm::abs_sqr(t)))); s = c * t; }
+ }
+
+ // Apply Q* v
+ template <typename T> inline
+ void Apply_Givens_rotation_left(T &x, T &y, T c, T s)
+ { T t1=x, t2=y; x = gmm::conj(c)*t1 - gmm::conj(s)*t2; y = c*t2 + s*t1; }
+
+ // Apply v^T Q
+ template <typename T> inline
+ void Apply_Givens_rotation_right(T &x, T &y, T c, T s)
+ { T t1=x, t2=y; x = c*t1 - s*t2; y = gmm::conj(c)*t2 + gmm::conj(s)*t1; }
+
+ template <typename MAT, typename T>
+ void row_rot(const MAT &AA, T c, T s, size_type i, size_type k) {
+ MAT &A = const_cast<MAT &>(AA); // can be specialized for row matrices
+ for (size_type j = 0; j < mat_ncols(A); ++j)
+ Apply_Givens_rotation_left(A(i,j), A(k,j), c, s);
+ }
+
+ template <typename MAT, typename T>
+ void col_rot(const MAT &AA, T c, T s, size_type i, size_type k) {
+ MAT &A = const_cast<MAT &>(AA); // can be specialized for column matrices
+ for (size_type j = 0; j < mat_nrows(A); ++j)
+ Apply_Givens_rotation_right(A(j,i), A(j,k), c, s);
+ }
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_dense_lu.h b/Contrib/gmm/gmm_dense_lu.h
new file mode 100755
index 0000000..23ca9b8
--- /dev/null
+++ b/Contrib/gmm/gmm_dense_lu.h
@@ -0,0 +1,275 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of lu.h from MTL.
+// See http://osl.iu.edu/research/mtl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+// Copyright (c) 2001-2003 The Trustees of Indiana University.
+// All rights reserved.
+// Copyright (c) 1998-2001 University of Notre Dame. All rights reserved.
+// Authors: Andrew Lumsdaine, Jeremy G. Siek, Lie-Quan Lee
+//
+// This file is part of the Matrix Template Library
+//
+// Indiana University has the exclusive rights to license this product under
+// the following license.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 1. All redistributions of source code must retain the above copyright
+// notice, the list of authors in the original source code, this list
+// of conditions and the disclaimer listed in this license;
+// 2. All redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the disclaimer listed
+// in this license in the documentation and/or other materials provided
+// with the distribution;
+// 3. Any documentation included with all redistributions must include the
+// following acknowledgement:
+// "This product includes software developed at the University of
+// Notre Dame and the Pervasive Technology Labs at Indiana University.
+// For technical information contact Andrew Lumsdaine at the Pervasive
+// Technology Labs at Indiana University.
+// For administrative and license questions contact the Advanced
+// Research and Technology Institute at 1100 Waterway Blvd.
+// Indianapolis, Indiana 46202, phone 317-274-5905, fax 317-274-5902."
+// Alternatively, this acknowledgement may appear in the software
+// itself, and wherever such third-party acknowledgments normally appear.
+// 4. The name "MTL" shall not be used to endorse or promote products
+// derived from this software without prior written permission from
+// Indiana University. For written permission, please contact Indiana
+// University Advanced Research & Technology Institute.
+// 5. Products derived from this software may not be called "MTL", nor
+// may "MTL" appear in their name, without prior written permission
+// of Indiana University Advanced Research & Technology Institute.
+//
+// Indiana University provides no reassurances that the source code provided
+// does not infringe the patent or any other intellectual property rights of
+// any other entity. Indiana University disclaims any liability to any
+// recipient for claims brought by any other entity based on infringement of
+// intellectual property rights or otherwise.
+//
+// LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO
+// WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY
+// GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
+// INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
+// INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
+// "VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
+// LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
+// ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF
+// INFORMATION GENERATED USING SOFTWARE.
+//===========================================================================
+
+/**@file gmm_dense_lu.h
+ @author Andrew Lumsdaine, Jeremy G. Siek, Lie-Quan Lee, Y. Renard
+ @date June 5, 2003.
+ @brief LU factorizations and determinant computation for dense matrices.
+*/
+#ifndef GMM_DENSE_LU_H
+#define GMM_DENSE_LU_H
+
+#include "gmm_dense_Householder.h"
+#include "gmm_opt.h"
+
+namespace gmm {
+
+
+ /** LU Factorization of a general (dense) matrix (real or complex).
+
+ This is the outer product (a level-2 operation) form of the LU
+ Factorization with pivoting algorithm . This is equivalent to
+ LAPACK's dgetf2. Also see "Matrix Computations" 3rd Ed. by Golub
+ and Van Loan section 3.2.5 and especially page 115.
+
+ The pivot indices in ipvt are indexed starting from 1
+ so that this is compatible with LAPACK (Fortran).
+ */
+ template <typename DenseMatrix, typename Pvector>
+ size_type lu_factor(DenseMatrix& A, Pvector& ipvt) {
+ typedef typename linalg_traits<DenseMatrix>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ size_type info(0), i, j, jp, M(mat_nrows(A)), N(mat_ncols(A));
+ size_type NN = std::min(M, N);
+ std::vector<T> c(M), r(N);
+
+ GMM_ASSERT2(ipvt.size()+1 >= NN, "IPVT too small");
+ for (i = 0; i+1 < NN; ++i) ipvt[i] = i;
+
+ if (M || N) {
+ for (j = 0; j+1 < NN; ++j) {
+ R max = gmm::abs(A(j,j)); jp = j;
+ for (i = j+1; i < M; ++i) /* find pivot. */
+ if (gmm::abs(A(i,j)) > max) { jp = i; max = gmm::abs(A(i,j)); }
+ ipvt[j] = jp + 1;
+
+ if (max == R(0)) { info = j + 1; break; }
+ if (jp != j) for (i = 0; i < N; ++i) std::swap(A(jp, i), A(j, i));
+
+ for (i = j+1; i < M; ++i) { A(i, j) /= A(j,j); c[i-j-1] = -A(i, j); }
+ for (i = j+1; i < N; ++i) r[i-j-1] = A(j, i); // avoid the copy ?
+ rank_one_update(sub_matrix(A, sub_interval(j+1, M-j-1),
+ sub_interval(j+1, N-j-1)), c, conjugated(r));
+ }
+ ipvt[j] = j + 1;
+ }
+ return info;
+ }
+
+ /** LU Solve : Solve equation Ax=b, given an LU factored matrix.*/
+ // Thanks to Valient Gough for this routine!
+ template <typename DenseMatrix, typename VectorB, typename VectorX,
+ typename Pvector>
+ void lu_solve(const DenseMatrix &LU, const Pvector& pvector,
+ VectorX &x, const VectorB &b) {
+ typedef typename linalg_traits<DenseMatrix>::value_type T;
+ copy(b, x);
+ for(size_type i = 0; i < pvector.size(); ++i) {
+ size_type perm = pvector[i]-1; // permutations stored in 1's offset
+ if(i != perm) { T aux = x[i]; x[i] = x[perm]; x[perm] = aux; }
+ }
+ /* solve Ax = b -> LUx = b -> Ux = L^-1 b. */
+ lower_tri_solve(LU, x, true);
+ upper_tri_solve(LU, x, false);
+ }
+
+ template <typename DenseMatrix, typename VectorB, typename VectorX>
+ void lu_solve(const DenseMatrix &A, VectorX &x, const VectorB &b) {
+ typedef typename linalg_traits<DenseMatrix>::value_type T;
+ dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
+ std::vector<int> ipvt(mat_nrows(A));
+ gmm::copy(A, B);
+ size_type info = lu_factor(B, ipvt);
+ GMM_ASSERT1(!info, "Singular system, pivot = " << info);
+ lu_solve(B, ipvt, x, b);
+ }
+
+ template <typename DenseMatrix, typename VectorB, typename VectorX,
+ typename Pvector>
+ void lu_solve_transposed(const DenseMatrix &LU, const Pvector& pvector,
+ VectorX &x, const VectorB &b) {
+ typedef typename linalg_traits<DenseMatrix>::value_type T;
+ copy(b, x);
+ lower_tri_solve(transposed(LU), x, false);
+ upper_tri_solve(transposed(LU), x, true);
+ for(size_type i = pvector.size(); i > 0; --i) {
+ size_type perm = pvector[i-1]-1; // permutations stored in 1's offset
+ if(i-1 != perm) { T aux = x[i-1]; x[i-1] = x[perm]; x[perm] = aux; }
+ }
+
+ }
+
+
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+ template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
+ void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
+ DenseMatrix& AInv, col_major) {
+ typedef typename linalg_traits<DenseMatrixLU>::value_type T;
+ std::vector<T> tmp(pvector.size(), T(0));
+ std::vector<T> result(pvector.size());
+ for(size_type i = 0; i < pvector.size(); ++i) {
+ tmp[i] = T(1);
+ lu_solve(LU, pvector, result, tmp);
+ copy(result, mat_col(AInv, i));
+ tmp[i] = T(0);
+ }
+ }
+
+ template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
+ void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
+ DenseMatrix& AInv, row_major) {
+ typedef typename linalg_traits<DenseMatrixLU>::value_type T;
+ std::vector<T> tmp(pvector.size(), T(0));
+ std::vector<T> result(pvector.size());
+ for(size_type i = 0; i < pvector.size(); ++i) {
+ tmp[i] = T(1); // to be optimized !!
+ // on peut sur le premier tri solve reduire le systeme
+ // et peut etre faire un solve sur une serie de vecteurs au lieu
+ // de vecteur a vecteur (accumulation directe de l'inverse dans la
+ // matrice au fur et a mesure du calcul ... -> evite la copie finale
+ lu_solve_transposed(LU, pvector, result, tmp);
+ copy(result, mat_row(AInv, i));
+ tmp[i] = T(0);
+ }
+ }
+ ///@endcond
+
+ /** Given an LU factored matrix, build the inverse of the matrix. */
+ template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
+ void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
+ const DenseMatrix& AInv_) {
+ DenseMatrix& AInv = const_cast<DenseMatrix&>(AInv_);
+ lu_inverse(LU, pvector, AInv, typename principal_orientation_type<typename
+ linalg_traits<DenseMatrix>::sub_orientation>::potype());
+ }
+
+ /** Given a dense matrix, build the inverse of the matrix, and
+ return the determinant */
+ template <typename DenseMatrix>
+ typename linalg_traits<DenseMatrix>::value_type
+ lu_inverse(const DenseMatrix& A_) {
+ typedef typename linalg_traits<DenseMatrix>::value_type T;
+ DenseMatrix& A = const_cast<DenseMatrix&>(A_);
+ dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
+ std::vector<int> ipvt(mat_nrows(A));
+ gmm::copy(A, B);
+ size_type info = lu_factor(B, ipvt);
+ GMM_ASSERT1(!info, "Non invertible matrix, pivot = " << info);
+ lu_inverse(B, ipvt, A);
+ return lu_det(B, ipvt);
+ }
+
+ /** Compute the matrix determinant (via a LU factorization) */
+ template <typename DenseMatrixLU, typename Pvector>
+ typename linalg_traits<DenseMatrixLU>::value_type
+ lu_det(const DenseMatrixLU& LU, const Pvector &pvector) {
+ typedef typename linalg_traits<DenseMatrixLU>::value_type T;
+ T det(1);
+ for (size_type j = 0; j < std::min(mat_nrows(LU), mat_ncols(LU)); ++j)
+ det *= LU(j,j);
+ for(size_type i = 0; i < pvector.size(); ++i)
+ if (i != size_type(pvector[i]-1)) { det = -det; }
+ return det;
+ }
+
+ template <typename DenseMatrix>
+ typename linalg_traits<DenseMatrix>::value_type
+ lu_det(const DenseMatrix& A) {
+ typedef typename linalg_traits<DenseMatrix>::value_type T;
+ dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
+ std::vector<int> ipvt(mat_nrows(A));
+ gmm::copy(A, B);
+ lu_factor(B, ipvt);
+ return lu_det(B, ipvt);
+ }
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_dense_qr.h b/Contrib/gmm/gmm_dense_qr.h
new file mode 100755
index 0000000..d9effa2
--- /dev/null
+++ b/Contrib/gmm/gmm_dense_qr.h
@@ -0,0 +1,788 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_dense_qr.h
+ @author Caroline Lecalvez, Caroline.Lecalvez at gmm.insa-tlse.fr, Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date September 12, 2003.
+ @brief Dense QR factorization.
+*/
+#ifndef GMM_DENSE_QR_H
+#define GMM_DENSE_QR_H
+
+#include "gmm_dense_Householder.h"
+
+namespace gmm {
+
+
+ /**
+ QR factorization using Householder method (complex and real version).
+ */
+ template <typename MAT1>
+ void qr_factor(const MAT1 &A_) {
+ MAT1 &A = const_cast<MAT1 &>(A_);
+ typedef typename linalg_traits<MAT1>::value_type value_type;
+
+ size_type m = mat_nrows(A), n = mat_ncols(A);
+ GMM_ASSERT2(m >= n, "dimensions mismatch");
+
+ std::vector<value_type> W(m), V(m);
+
+ for (size_type j = 0; j < n; ++j) {
+ sub_interval SUBI(j, m-j), SUBJ(j, n-j);
+ V.resize(m-j); W.resize(n-j);
+
+ for (size_type i = j; i < m; ++i) V[i-j] = A(i, j);
+ house_vector(V);
+
+ row_house_update(sub_matrix(A, SUBI, SUBJ), V, W);
+ for (size_type i = j+1; i < m; ++i) A(i, j) = V[i-j];
+ }
+ }
+
+
+ // QR comes from QR_factor(QR) where the upper triangular part stands for R
+ // and the lower part contains the Householder reflectors.
+ // A <- AQ
+ template <typename MAT1, typename MAT2>
+ void apply_house_right(const MAT1 &QR, const MAT2 &A_) {
+ MAT2 &A = const_cast<MAT2 &>(A_);
+ typedef typename linalg_traits<MAT1>::value_type T;
+ size_type m = mat_nrows(QR), n = mat_ncols(QR);
+ GMM_ASSERT2(m == mat_ncols(A), "dimensions mismatch");
+ if (m == 0) return;
+ std::vector<T> V(m), W(mat_nrows(A));
+ V[0] = T(1);
+ for (size_type j = 0; j < n; ++j) {
+ V.resize(m-j);
+ for (size_type i = j+1; i < m; ++i) V[i-j] = QR(i, j);
+ col_house_update(sub_matrix(A, sub_interval(0, mat_nrows(A)),
+ sub_interval(j, m-j)), V, W);
+ }
+ }
+
+ // QR comes from QR_factor(QR) where the upper triangular part stands for R
+ // and the lower part contains the Householder reflectors.
+ // A <- Q*A
+ template <typename MAT1, typename MAT2>
+ void apply_house_left(const MAT1 &QR, const MAT2 &A_) {
+ MAT2 &A = const_cast<MAT2 &>(A_);
+ typedef typename linalg_traits<MAT1>::value_type T;
+ size_type m = mat_nrows(QR), n = mat_ncols(QR);
+ GMM_ASSERT2(m == mat_nrows(A), "dimensions mismatch");
+ if (m == 0) return;
+ std::vector<T> V(m), W(mat_ncols(A));
+ V[0] = T(1);
+ for (size_type j = 0; j < n; ++j) {
+ V.resize(m-j);
+ for (size_type i = j+1; i < m; ++i) V[i-j] = QR(i, j);
+ row_house_update(sub_matrix(A, sub_interval(j, m-j),
+ sub_interval(0, mat_ncols(A))), V, W);
+ }
+ }
+
+ /** Compute the QR factorization, where Q is assembled. */
+ template <typename MAT1, typename MAT2, typename MAT3>
+ void qr_factor(const MAT1 &A, const MAT2 &QQ, const MAT3 &RR) {
+ MAT2 &Q = const_cast<MAT2 &>(QQ); MAT3 &R = const_cast<MAT3 &>(RR);
+ typedef typename linalg_traits<MAT1>::value_type value_type;
+
+ size_type m = mat_nrows(A), n = mat_ncols(A);
+ GMM_ASSERT2(m >= n, "dimensions mismatch");
+ gmm::copy(A, Q);
+
+ std::vector<value_type> W(m);
+ dense_matrix<value_type> VV(m, n);
+
+ for (size_type j = 0; j < n; ++j) {
+ sub_interval SUBI(j, m-j), SUBJ(j, n-j);
+
+ for (size_type i = j; i < m; ++i) VV(i,j) = Q(i, j);
+ house_vector(sub_vector(mat_col(VV,j), SUBI));
+
+ row_house_update(sub_matrix(Q, SUBI, SUBJ),
+ sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
+ }
+
+ gmm::copy(sub_matrix(Q, sub_interval(0, n), sub_interval(0, n)), R);
+ gmm::copy(identity_matrix(), Q);
+
+ for (size_type j = n-1; j != size_type(-1); --j) {
+ sub_interval SUBI(j, m-j), SUBJ(j, n-j);
+ row_house_update(sub_matrix(Q, SUBI, SUBJ),
+ sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
+ }
+ }
+
+ ///@cond DOXY_SHOW_ALL_FUNCTIONS
+ template <typename TA, typename TV, typename Ttol,
+ typename MAT, typename VECT>
+ void extract_eig(const MAT &A, VECT &V, Ttol tol, TA, TV) {
+ size_type n = mat_nrows(A);
+ if (n == 0) return;
+ tol *= Ttol(2);
+ Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
+ for (size_type i = 0; i < n; ++i) {
+ if (i < n-1) {
+ tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
+ tol_cplx = std::max(tol_cplx, tol_i);
+ }
+ if ((i < n-1) && gmm::abs(A(i+1,i)) >= tol_i) {
+ TA tr = A(i,i) + A(i+1, i+1);
+ TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
+ TA delta = tr*tr - TA(4) * det;
+ if (delta < -tol_cplx) {
+ GMM_WARNING1("A complex eigenvalue has been detected : "
+ << std::complex<TA>(tr/TA(2), gmm::sqrt(-delta)/TA(2)));
+ V[i] = V[i+1] = tr / TA(2);
+ }
+ else {
+ delta = std::max(TA(0), delta);
+ V[i ] = TA(tr + gmm::sqrt(delta))/ TA(2);
+ V[i+1] = TA(tr - gmm::sqrt(delta))/ TA(2);
+ }
+ ++i;
+ }
+ else
+ V[i] = TV(A(i,i));
+ }
+ }
+
+ template <typename TA, typename TV, typename Ttol,
+ typename MAT, typename VECT>
+ void extract_eig(const MAT &A, VECT &V, Ttol tol, TA, std::complex<TV>) {
+ size_type n = mat_nrows(A);
+ tol *= Ttol(2);
+ for (size_type i = 0; i < n; ++i)
+ if ((i == n-1) ||
+ gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
+ V[i] = std::complex<TV>(A(i,i));
+ else {
+ TA tr = A(i,i) + A(i+1, i+1);
+ TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
+ TA delta = tr*tr - TA(4) * det;
+ if (delta < TA(0)) {
+ V[i] = std::complex<TV>(tr / TA(2), gmm::sqrt(-delta) / TA(2));
+ V[i+1] = std::complex<TV>(tr / TA(2), -gmm::sqrt(-delta)/ TA(2));
+ }
+ else {
+ V[i ] = TA(tr + gmm::sqrt(delta)) / TA(2);
+ V[i+1] = TA(tr - gmm::sqrt(delta)) / TA(2);
+ }
+ ++i;
+ }
+ }
+
+ template <typename TA, typename TV, typename Ttol,
+ typename MAT, typename VECT>
+ void extract_eig(const MAT &A, VECT &V, Ttol tol, std::complex<TA>, TV) {
+ typedef std::complex<TA> T;
+ size_type n = mat_nrows(A);
+ if (n == 0) return;
+ tol *= Ttol(2);
+ Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
+ for (size_type i = 0; i < n; ++i) {
+ if (i < n-1) {
+ tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
+ tol_cplx = std::max(tol_cplx, tol_i);
+ }
+ if ((i == n-1) || gmm::abs(A(i+1,i)) < tol_i) {
+ if (gmm::abs(std::imag(A(i,i))) > tol_cplx)
+ GMM_WARNING1("A complex eigenvalue has been detected : "
+ << T(A(i,i)) << " : " << gmm::abs(std::imag(A(i,i)))
+ / gmm::abs(std::real(A(i,i))) << " : " << tol_cplx);
+ V[i] = std::real(A(i,i));
+ }
+ else {
+ T tr = A(i,i) + A(i+1, i+1);
+ T det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
+ T delta = tr*tr - TA(4) * det;
+ T a1 = (tr + gmm::sqrt(delta)) / TA(2);
+ T a2 = (tr - gmm::sqrt(delta)) / TA(2);
+ if (gmm::abs(std::imag(a1)) > tol_cplx)
+ GMM_WARNING1("A complex eigenvalue has been detected : " << a1);
+ if (gmm::abs(std::imag(a2)) > tol_cplx)
+ GMM_WARNING1("A complex eigenvalue has been detected : " << a2);
+
+ V[i] = std::real(a1); V[i+1] = std::real(a2);
+ ++i;
+ }
+ }
+ }
+
+ template <typename TA, typename TV, typename Ttol,
+ typename MAT, typename VECT>
+ void extract_eig(const MAT &A, VECT &V, Ttol tol,
+ std::complex<TA>, std::complex<TV>) {
+ size_type n = mat_nrows(A);
+ tol *= Ttol(2);
+ for (size_type i = 0; i < n; ++i)
+ if ((i == n-1) ||
+ gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
+ V[i] = std::complex<TV>(A(i,i));
+ else {
+ std::complex<TA> tr = A(i,i) + A(i+1, i+1);
+ std::complex<TA> det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
+ std::complex<TA> delta = tr*tr - TA(4) * det;
+ V[i] = (tr + gmm::sqrt(delta)) / TA(2);
+ V[i+1] = (tr - gmm::sqrt(delta)) / TA(2);
+ ++i;
+ }
+ }
+
+ ///@endcond
+ /**
+ Compute eigenvalue vector.
+ */
+ template <typename MAT, typename Ttol, typename VECT> inline
+ void extract_eig(const MAT &A, const VECT &V, Ttol tol) {
+ extract_eig(A, const_cast<VECT&>(V), tol,
+ typename linalg_traits<MAT>::value_type(),
+ typename linalg_traits<VECT>::value_type());
+ }
+
+ /* ********************************************************************* */
+ /* Stop criterion for QR algorithms */
+ /* ********************************************************************* */
+
+ template <typename MAT, typename Ttol>
+ void qr_stop_criterion(MAT &A, size_type &p, size_type &q, Ttol tol) {
+ typedef typename linalg_traits<MAT>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ R rmin = default_min(R()) * R(2);
+ size_type n = mat_nrows(A);
+ if (n <= 2) { q = n; p = 0; }
+ else {
+ for (size_type i = 1; i < n-q; ++i)
+ if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
+ || gmm::abs(A(i,i-1)) < rmin)
+ A(i,i-1) = T(0);
+
+ while ((q < n-1 && A(n-1-q, n-2-q) == T(0)) ||
+ (q < n-2 && A(n-2-q, n-3-q) == T(0))) ++q;
+ if (q >= n-2) q = n;
+ p = n-q; if (p) --p; if (p) --p;
+ while (p > 0 && A(p,p-1) != T(0)) --p;
+ }
+ }
+
+ template <typename MAT, typename Ttol> inline
+ void symmetric_qr_stop_criterion(const MAT &AA, size_type &p, size_type &q,
+ Ttol tol) {
+ typedef typename linalg_traits<MAT>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ R rmin = default_min(R()) * R(2);
+ MAT& A = const_cast<MAT&>(AA);
+ size_type n = mat_nrows(A);
+ if (n <= 1) { q = n; p = 0; }
+ else {
+ for (size_type i = 1; i < n-q; ++i)
+ if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
+ || gmm::abs(A(i,i-1)) < rmin)
+ A(i,i-1) = T(0);
+
+ while (q < n-1 && A(n-1-q, n-2-q) == T(0)) ++q;
+ if (q >= n-1) q = n;
+ p = n-q; if (p) --p; if (p) --p;
+ while (p > 0 && A(p,p-1) != T(0)) --p;
+ }
+ }
+
+ template <typename VECT1, typename VECT2, typename Ttol> inline
+ void symmetric_qr_stop_criterion(const VECT1 &diag, const VECT2 &sdiag_,
+ size_type &p, size_type &q, Ttol tol) {
+ typedef typename linalg_traits<VECT2>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ R rmin = default_min(R()) * R(2);
+ VECT2 &sdiag = const_cast<VECT2 &>(sdiag_);
+ size_type n = vect_size(diag);
+ if (n <= 1) { q = n; p = 0; return; }
+ for (size_type i = 1; i < n-q; ++i)
+ if (gmm::abs(sdiag[i-1]) < (gmm::abs(diag[i])+ gmm::abs(diag[i-1]))*tol
+ || gmm::abs(sdiag[i-1]) < rmin)
+ sdiag[i-1] = T(0);
+ while (q < n-1 && sdiag[n-2-q] == T(0)) ++q;
+ if (q >= n-1) q = n;
+ p = n-q; if (p) --p; if (p) --p;
+ while (p > 0 && sdiag[p-1] != T(0)) --p;
+ }
+
+ /* ********************************************************************* */
+ /* 2x2 blocks reduction for Schur vectors */
+ /* ********************************************************************* */
+
+ template <typename MATH, typename MATQ, typename Ttol>
+ void block2x2_reduction(MATH &H, MATQ &Q, Ttol tol) {
+ typedef typename linalg_traits<MATH>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type n = mat_nrows(H), nq = mat_nrows(Q);
+ sub_interval SUBQ(0, nq), SUBL(0, 2);
+ std::vector<T> v(2), w(std::max(n, nq)); v[0] = T(1);
+ if (n < 2) return;
+ tol *= Ttol(2);
+ Ttol tol_i = tol * gmm::abs(H(0,0)), tol_cplx = tol_i;
+ for (size_type i = 0; i < n-1; ++i) {
+ tol_i = (gmm::abs(H(i,i))+gmm::abs(H(i+1,i+1)))*tol;
+ tol_cplx = std::max(tol_cplx, tol_i);
+
+ if (gmm::abs(H(i+1,i)) > tol_i) { // 2x2 block detected
+ T tr = (H(i+1, i+1) - H(i,i)) / T(2);
+ T delta = tr*tr + H(i,i+1)*H(i+1, i);
+
+ if (is_complex(T()) || gmm::real(delta) >= R(0)) {
+ sub_interval SUBI(i, 2);
+ T theta = (tr - gmm::sqrt(delta)) / H(i+1,i);
+ R a = gmm::abs(theta);
+ v[1] = (a == R(0)) ? T(-1)
+ : gmm::conj(theta) * (R(1) - gmm::sqrt(a*a + R(1)) / a);
+ row_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
+ col_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
+ col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
+ }
+ ++i;
+ }
+ }
+ }
+
+ /* ********************************************************************* */
+ /* Basic qr algorithm. */
+ /* ********************************************************************* */
+
+ #define tol_type_for_qr typename number_traits<typename \
+ linalg_traits<MAT1>::value_type>::magnitude_type
+ #define default_tol_for_qr \
+ (gmm::default_tol(tol_type_for_qr()) * tol_type_for_qr(3))
+
+ // QR method for real or complex square matrices based on QR factorisation.
+ // eigval has to be a complex vector if A has complex eigeinvalues.
+ // Very slow method. Use implicit_qr_method instead.
+ template <typename MAT1, typename VECT, typename MAT2>
+ void rudimentary_qr_algorithm(const MAT1 &A, const VECT &eigval_,
+ const MAT2 &eigvect_,
+ tol_type_for_qr tol = default_tol_for_qr,
+ bool compvect = true) {
+ VECT &eigval = const_cast<VECT &>(eigval_);
+ MAT2 &eigvect = const_cast<MAT2 &>(eigvect_);
+
+ typedef typename linalg_traits<MAT1>::value_type value_type;
+
+ size_type n = mat_nrows(A), p, q = 0, ite = 0;
+ dense_matrix<value_type> Q(n, n), R(n,n), A1(n,n);
+ gmm::copy(A, A1);
+
+ Hessenberg_reduction(A1, eigvect, compvect);
+ qr_stop_criterion(A1, p, q, tol);
+
+ while (q < n) {
+ qr_factor(A1, Q, R);
+ gmm::mult(R, Q, A1);
+ if (compvect) { gmm::mult(eigvect, Q, R); gmm::copy(R, eigvect); }
+
+ qr_stop_criterion(A1, p, q, tol);
+ ++ite;
+ GMM_ASSERT1(ite < n*1000, "QR algorithm failed");
+ }
+ if (compvect) block2x2_reduction(A1, Q, tol);
+ extract_eig(A1, eigval, tol);
+ }
+
+ template <typename MAT1, typename VECT>
+ void rudimentary_qr_algorithm(const MAT1 &a, VECT &eigval,
+ tol_type_for_qr tol = default_tol_for_qr) {
+ dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
+ rudimentary_qr_algorithm(a, eigval, m, tol, false);
+ }
+
+ /* ********************************************************************* */
+ /* Francis QR step. */
+ /* ********************************************************************* */
+
+ template <typename MAT1, typename MAT2>
+ void Francis_qr_step(const MAT1& HH, const MAT2 &QQ, bool compute_Q) {
+ MAT1& H = const_cast<MAT1&>(HH); MAT2& Q = const_cast<MAT2&>(QQ);
+ typedef typename linalg_traits<MAT1>::value_type value_type;
+ size_type n = mat_nrows(H), nq = mat_nrows(Q);
+
+ std::vector<value_type> v(3), w(std::max(n, nq));
+
+ value_type s = H(n-2, n-2) + H(n-1, n-1);
+ value_type t = H(n-2, n-2) * H(n-1, n-1) - H(n-2, n-1) * H(n-1, n-2);
+ value_type x = H(0, 0) * H(0, 0) + H(0,1) * H(1, 0) - s * H(0,0) + t;
+ value_type y = H(1, 0) * (H(0,0) + H(1,1) - s);
+ value_type z = H(1, 0) * H(2, 1);
+
+ sub_interval SUBQ(0, nq);
+
+ for (size_type k = 0; k < n - 2; ++k) {
+ v[0] = x; v[1] = y; v[2] = z;
+ house_vector(v);
+ size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
+ sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
+
+ row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBK));
+ col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
+
+ if (compute_Q)
+ col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
+
+ x = H(k+1, k); y = H(k+2, k);
+ if (k < n-3) z = H(k+3, k);
+ }
+ sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
+ v.resize(2);
+ v[0] = x; v[1] = y;
+ house_vector(v);
+ row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
+ col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
+ if (compute_Q)
+ col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
+ }
+
+ /* ********************************************************************* */
+ /* Wilkinson Double shift QR step (from Lapack). */
+ /* ********************************************************************* */
+
+ template <typename MAT1, typename MAT2, typename Ttol>
+ void Wilkinson_double_shift_qr_step(const MAT1& HH, const MAT2 &QQ,
+ Ttol tol, bool exc, bool compute_Q) {
+ MAT1& H = const_cast<MAT1&>(HH); MAT2& Q = const_cast<MAT2&>(QQ);
+ typedef typename linalg_traits<MAT1>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type n = mat_nrows(H), nq = mat_nrows(Q), m;
+ std::vector<T> v(3), w(std::max(n, nq));
+ const R dat1(0.75), dat2(-0.4375);
+ T h33, h44, h43h34, v1(0), v2(0), v3(0);
+
+ if (exc) { /* Exceptional shift. */
+ R s = gmm::abs(H(n-1, n-2)) + gmm::abs(H(n-2, n-3));
+ h33 = h44 = dat1 * s;
+ h43h34 = dat2*s*s;
+ }
+ else { /* Wilkinson double shift. */
+ h44 = H(n-1,n-1); h33 = H(n-2, n-2);
+ h43h34 = H(n-1, n-2) * H(n-2, n-1);
+ }
+
+ /* Look for two consecutive small subdiagonal elements. */
+ /* Determine the effect of starting the double-shift QR iteration at */
+ /* row m, and see if this would make H(m-1, m-2) negligible. */
+ for (m = n-2; m != 0; --m) {
+ T h11 = H(m-1, m-1), h22 = H(m, m);
+ T h21 = H(m, m-1), h12 = H(m-1, m);
+ T h44s = h44 - h11, h33s = h33 - h11;
+ v1 = (h33s*h44s-h43h34) / h21 + h12;
+ v2 = h22 - h11 - h33s - h44s;
+ v3 = H(m+1, m);
+ R s = gmm::abs(v1) + gmm::abs(v2) + gmm::abs(v3);
+ v1 /= s; v2 /= s; v3 /= s;
+ if (m == 1) break;
+ T h00 = H(m-2, m-2);
+ T h10 = H(m-1, m-2);
+ R tst1 = gmm::abs(v1)*(gmm::abs(h00)+gmm::abs(h11)+gmm::abs(h22));
+ if (gmm::abs(h10)*(gmm::abs(v2)+gmm::abs(v3)) <= tol * tst1) break;
+ }
+
+ /* Double shift QR step. */
+ sub_interval SUBQ(0, nq);
+ for (size_type k = (m == 0) ? 0 : m-1; k < n-2; ++k) {
+ v[0] = v1; v[1] = v2; v[2] = v3;
+ house_vector(v);
+ size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
+ sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
+
+ row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBK));
+ col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
+ if (k > m-1) { H(k+1, k-1) = T(0); if (k < n-3) H(k+2, k-1) = T(0); }
+
+ if (compute_Q)
+ col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
+
+ v1 = H(k+1, k); v2 = H(k+2, k);
+ if (k < n-3) v3 = H(k+3, k);
+ }
+ sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
+ v.resize(2); v[0] = v1; v[1] = v2;
+ house_vector(v);
+ row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
+ col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
+ if (compute_Q)
+ col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
+ }
+
+ /* ********************************************************************* */
+ /* Implicit QR algorithm. */
+ /* ********************************************************************* */
+
+ // QR method for real or complex square matrices based on an
+ // implicit QR factorisation. eigval has to be a complex vector
+ // if A has complex eigeinvalues. complexity about 10n^3, 25n^3 if
+ // eigenvectors are computed
+ template <typename MAT1, typename VECT, typename MAT2>
+ void implicit_qr_algorithm(const MAT1 &A, const VECT &eigval_,
+ const MAT2 &Q_,
+ tol_type_for_qr tol = default_tol_for_qr,
+ bool compvect = true) {
+ VECT &eigval = const_cast<VECT &>(eigval_);
+ MAT2 &Q = const_cast<MAT2 &>(Q_);
+ typedef typename linalg_traits<MAT1>::value_type value_type;
+
+ size_type n(mat_nrows(A)), q(0), q_old, p(0), ite(0), its(0);
+ dense_matrix<value_type> H(n,n);
+ sub_interval SUBK(0,0);
+
+ gmm::copy(A, H);
+ Hessenberg_reduction(H, Q, compvect);
+ qr_stop_criterion(H, p, q, tol);
+
+ while (q < n) {
+ sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(Q));
+ if (compvect) SUBK = SUBI;
+// Francis_qr_step(sub_matrix(H, SUBI),
+// sub_matrix(Q, SUBJ, SUBK), compvect);
+ Wilkinson_double_shift_qr_step(sub_matrix(H, SUBI),
+ sub_matrix(Q, SUBJ, SUBK),
+ tol, (its == 10 || its == 20), compvect);
+ q_old = q;
+ qr_stop_criterion(H, p, q, tol*2);
+ if (q != q_old) its = 0;
+ ++its; ++ite;
+ GMM_ASSERT1(ite < n*100, "QR algorithm failed");
+ }
+ if (compvect) block2x2_reduction(H, Q, tol);
+ extract_eig(H, eigval, tol);
+ }
+
+
+ template <typename MAT1, typename VECT>
+ void implicit_qr_algorithm(const MAT1 &a, VECT &eigval,
+ tol_type_for_qr tol = default_tol_for_qr) {
+ dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
+ implicit_qr_algorithm(a, eigval, m, tol, false);
+ }
+
+ /* ********************************************************************* */
+ /* Implicit symmetric QR step with Wilkinson Shift. */
+ /* ********************************************************************* */
+
+ template <typename MAT1, typename MAT2>
+ void symmetric_Wilkinson_qr_step(const MAT1& MM, const MAT2 &ZZ,
+ bool compute_z) {
+ MAT1& M = const_cast<MAT1&>(MM); MAT2& Z = const_cast<MAT2&>(ZZ);
+ typedef typename linalg_traits<MAT1>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ size_type n = mat_nrows(M);
+
+ for (size_type i = 0; i < n; ++i) {
+ M(i, i) = T(gmm::real(M(i, i)));
+ if (i > 0) {
+ T a = (M(i, i-1) + gmm::conj(M(i-1, i)))/R(2);
+ M(i, i-1) = a; M(i-1, i) = gmm::conj(a);
+ }
+ }
+
+ R d = gmm::real(M(n-2, n-2) - M(n-1, n-1)) / R(2);
+ R e = gmm::abs_sqr(M(n-1, n-2));
+ R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
+ if (nu == R(0)) { M(n-1, n-2) = T(0); return; }
+ R mu = gmm::real(M(n-1, n-1)) - e / nu;
+ T x = M(0,0) - T(mu), z = M(1, 0), c, s;
+
+ for (size_type k = 1; k < n; ++k) {
+ Givens_rotation(x, z, c, s);
+
+ if (k > 1) Apply_Givens_rotation_left(M(k-1,k-2), M(k,k-2), c, s);
+ Apply_Givens_rotation_left(M(k-1,k-1), M(k,k-1), c, s);
+ Apply_Givens_rotation_left(M(k-1,k ), M(k,k ), c, s);
+ if (k < n-1) Apply_Givens_rotation_left(M(k-1,k+1), M(k,k+1), c, s);
+ if (k > 1) Apply_Givens_rotation_right(M(k-2,k-1), M(k-2,k), c, s);
+ Apply_Givens_rotation_right(M(k-1,k-1), M(k-1,k), c, s);
+ Apply_Givens_rotation_right(M(k ,k-1), M(k,k) , c, s);
+ if (k < n-1) Apply_Givens_rotation_right(M(k+1,k-1), M(k+1,k), c, s);
+
+ if (compute_z) col_rot(Z, c, s, k-1, k);
+ if (k < n-1) { x = M(k, k-1); z = M(k+1, k-1); }
+ }
+
+ }
+
+ template <typename VECT1, typename VECT2, typename MAT>
+ void symmetric_Wilkinson_qr_step(const VECT1& diag_, const VECT2& sdiag_,
+ const MAT &ZZ, bool compute_z) {
+ VECT1& diag = const_cast<VECT1&>(diag_);
+ VECT2& sdiag = const_cast<VECT2&>(sdiag_);
+ MAT& Z = const_cast<MAT&>(ZZ);
+ typedef typename linalg_traits<VECT2>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type n = vect_size(diag);
+ R d = (diag[n-2] - diag[n-1]) / R(2);
+ R e = gmm::abs_sqr(sdiag[n-2]);
+ R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
+ if (nu == R(0)) { sdiag[n-2] = T(0); return; }
+ R mu = diag[n-1] - e / nu;
+ T x = diag[0] - T(mu), z = sdiag[0], c, s;
+
+ T a01(0), a02(0);
+ T a10(0), a11(diag[0]), a12(gmm::conj(sdiag[0])), a13(0);
+ T a20(0), a21(sdiag[0]), a22(diag[1]), a23(gmm::conj(sdiag[1]));
+ T a31(0), a32(sdiag[1]);
+
+ for (size_type k = 1; k < n; ++k) {
+ Givens_rotation(x, z, c, s);
+
+ if (k > 1) Apply_Givens_rotation_left(a10, a20, c, s);
+ Apply_Givens_rotation_left(a11, a21, c, s);
+ Apply_Givens_rotation_left(a12, a22, c, s);
+ if (k < n-1) Apply_Givens_rotation_left(a13, a23, c, s);
+
+ if (k > 1) Apply_Givens_rotation_right(a01, a02, c, s);
+ Apply_Givens_rotation_right(a11, a12, c, s);
+ Apply_Givens_rotation_right(a21, a22, c, s);
+ if (k < n-1) Apply_Givens_rotation_right(a31, a32, c, s);
+
+ if (compute_z) col_rot(Z, c, s, k-1, k);
+
+ diag[k-1] = gmm::real(a11);
+ diag[k] = gmm::real(a22);
+ if (k > 1) sdiag[k-2] = (gmm::conj(a01) + a10) / R(2);
+ sdiag[k-1] = (gmm::conj(a12) + a21) / R(2);
+
+ x = sdiag[k-1]; z = (gmm::conj(a13) + a31) / R(2);
+
+ a01 = a12; a02 = a13;
+ a10 = a21; a11 = a22; a12 = a23; a13 = T(0);
+ a20 = a31; a21 = a32; a31 = T(0);
+
+ if (k < n-1) {
+ sdiag[k] = (gmm::conj(a23) + a32) / R(2);
+ a22 = T(diag[k+1]); a32 = sdiag[k+1]; a23 = gmm::conj(a32);
+ }
+ }
+ }
+
+ /* ********************************************************************* */
+ /* Implicit QR algorithm for symmetric or hermitian matrices. */
+ /* ********************************************************************* */
+
+ // implicit QR method for real square symmetric matrices or complex
+ // hermitian matrices.
+ // eigval has to be a complex vector if A has complex eigeinvalues.
+ // complexity about 4n^3/3, 9n^3 if eigenvectors are computed
+ template <typename MAT1, typename VECT, typename MAT2>
+ void symmetric_qr_algorithm_old(const MAT1 &A, const VECT &eigval_,
+ const MAT2 &eigvect_,
+ tol_type_for_qr tol = default_tol_for_qr,
+ bool compvect = true) {
+ VECT &eigval = const_cast<VECT &>(eigval_);
+ MAT2 &eigvect = const_cast<MAT2 &>(eigvect_);
+ typedef typename linalg_traits<MAT1>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ if (compvect) gmm::copy(identity_matrix(), eigvect);
+ size_type n = mat_nrows(A), q = 0, p, ite = 0;
+ dense_matrix<T> Tri(n, n);
+ gmm::copy(A, Tri);
+
+ Householder_tridiagonalization(Tri, eigvect, compvect);
+
+ symmetric_qr_stop_criterion(Tri, p, q, tol);
+
+ while (q < n) {
+
+ sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
+ if (!compvect) SUBK = sub_interval(0,0);
+ symmetric_Wilkinson_qr_step(sub_matrix(Tri, SUBI),
+ sub_matrix(eigvect, SUBJ, SUBK), compvect);
+
+ symmetric_qr_stop_criterion(Tri, p, q, tol*R(2));
+ ++ite;
+ GMM_ASSERT1(ite < n*100, "QR algorithm failed. Probably, your matrix"
+ " is not real symmetric or complex hermitian");
+ }
+
+ extract_eig(Tri, eigval, tol);
+ }
+
+ template <typename MAT1, typename VECT, typename MAT2>
+ void symmetric_qr_algorithm(const MAT1 &A, const VECT &eigval_,
+ const MAT2 &eigvect_,
+ tol_type_for_qr tol = default_tol_for_qr,
+ bool compvect = true) {
+ VECT &eigval = const_cast<VECT &>(eigval_);
+ MAT2 &eigvect = const_cast<MAT2 &>(eigvect_);
+ typedef typename linalg_traits<MAT1>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type n = mat_nrows(A), q = 0, p, ite = 0;
+ if (compvect) gmm::copy(identity_matrix(), eigvect);
+ if (n == 0) return;
+ if (n == 1) { eigval[0]=gmm::real(A(0,0)); return; }
+ dense_matrix<T> Tri(n, n);
+ gmm::copy(A, Tri);
+
+ Householder_tridiagonalization(Tri, eigvect, compvect);
+
+ std::vector<R> diag(n);
+ std::vector<T> sdiag(n);
+ for (size_type i = 0; i < n; ++i)
+ { diag[i] = gmm::real(Tri(i, i)); if (i+1 < n) sdiag[i] = Tri(i+1, i); }
+
+ symmetric_qr_stop_criterion(diag, sdiag, p, q, tol);
+
+ while (q < n) {
+ sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
+ if (!compvect) SUBK = sub_interval(0,0);
+
+ symmetric_Wilkinson_qr_step(sub_vector(diag, SUBI),
+ sub_vector(sdiag, SUBI),
+ sub_matrix(eigvect, SUBJ, SUBK), compvect);
+
+ symmetric_qr_stop_criterion(diag, sdiag, p, q, tol*R(2));
+ ++ite;
+ GMM_ASSERT1(ite < n*100, "QR algorithm failed.");
+ }
+
+ gmm::copy(diag, eigval);
+ }
+
+
+ template <typename MAT1, typename VECT>
+ void symmetric_qr_algorithm(const MAT1 &a, VECT &eigval,
+ tol_type_for_qr tol = default_tol_for_qr) {
+ dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
+ symmetric_qr_algorithm(a, eigval, m, tol, false);
+ }
+
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_dense_sylvester.h b/Contrib/gmm/gmm_dense_sylvester.h
new file mode 100755
index 0000000..5a4c8fa
--- /dev/null
+++ b/Contrib/gmm/gmm_dense_sylvester.h
@@ -0,0 +1,173 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/** @file gmm_dense_sylvester.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date June 5, 2003.
+ @brief Sylvester equation solver.
+*/
+#ifndef GMM_DENSE_SYLVESTER_H
+#define GMM_DENSE_SYLVESTER_H
+
+#include "gmm_kernel.h"
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* Kronecker system matrix. */
+ /* ********************************************************************* */
+ template <typename MAT1, typename MAT2, typename MAT3>
+ void kron(const MAT1 &m1, const MAT2 &m2, const MAT3 &m3_,
+ bool init = true) {
+ MAT3 &m3 = const_cast<MAT3 &>(m3_);
+ size_type m = mat_nrows(m1), n = mat_ncols(m1);
+ size_type l = mat_nrows(m2), k = mat_ncols(m2);
+
+ GMM_ASSERT2(mat_nrows(m3) == m*l && mat_ncols(m3) == n*k,
+ "dimensions mismatch");
+
+ for (size_type i = 0; i < m; ++i)
+ for (size_type j = 0; j < m; ++j)
+ if (init)
+ gmm::copy(gmm::scaled(m2, m1(i,j)),
+ gmm::sub_matrix(m3, sub_interval(l*i, l),
+ sub_interval(k*j, k)));
+ else
+ gmm::add(gmm::scaled(m2, m1(i,j)),
+ gmm::sub_matrix(m3, sub_interval(l*i, l),
+ sub_interval(k*j, k)));
+ }
+
+
+ /* ********************************************************************* */
+ /* Copy a matrix into a vector. */
+ /* ********************************************************************* */
+
+ template <typename MAT, typename VECT>
+ colmatrix_to_vector(const MAT &A, VECT &v, col_major) {
+ size_type m = mat_nrows(A), n = mat_ncols(A);
+ GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
+ for (size_type i = 0; i < n; ++i)
+ gmm::copy(mat_col(A, i), sub_vector(v, sub_interval(i*m, m)));
+ }
+
+ template <typename MAT, typename VECT>
+ colmatrix_to_vector(const MAT &A, VECT &v, row_and_col)
+ { colmatrix_to_vector(A, v, col_major()); }
+
+ template <typename MAT, typename VECT>
+ colmatrix_to_vector(const MAT &A, VECT &v, col_and_row)
+ { colmatrix_to_vector(A, v, col_major()); }
+
+ template <typename MAT, typename VECT>
+ colmatrix_to_vector(const MAT &A, VECT &v, row_major) {
+ size_type m = mat_nrows(mat), n = mat_ncols(A);
+ GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
+ for (size_type i = 0; i < m; ++i)
+ gmm::copy(mat_row(A, i), sub_vector(v, sub_slice(i, n, m)));
+ }
+
+ template <typename MAT, typename VECT> inline
+ colmatrix_to_vector(const MAT &A, const VECT &v_) {
+ VECT &v = const_cast<VECT &>(v_);
+ colmatrix_to_vector(A, v, typename linalg_traits<MAT>::sub_orientation());
+ }
+
+
+ /* ********************************************************************* */
+ /* Copy a vector into a matrix. */
+ /* ********************************************************************* */
+
+ template <typename MAT, typename VECT>
+ vector_to_colmatrix(const VECT &v, MAT &A, col_major) {
+ size_type m = mat_nrows(A), n = mat_ncols(A);
+ GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
+ for (size_type i = 0; i < n; ++i)
+ gmm::copy(sub_vector(v, sub_interval(i*m, m)), mat_col(A, i));
+ }
+
+ template <typename MAT, typename VECT>
+ vector_to_colmatrix(const VECT &v, MAT &A, row_and_col)
+ { vector_to_colmatrix(v, A, col_major()); }
+
+ template <typename MAT, typename VECT>
+ vector_to_colmatrix(const VECT &v, MAT &A, col_and_row)
+ { vector_to_colmatrix(v, A, col_major()); }
+
+ template <typename MAT, typename VECT>
+ vector_to_colmatrix(const VECT &v, MAT &A, row_major) {
+ size_type m = mat_nrows(mat), n = mat_ncols(A);
+ GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
+ for (size_type i = 0; i < m; ++i)
+ gmm::copy(sub_vector(v, sub_slice(i, n, m)), mat_row(A, i));
+ }
+
+ template <typename MAT, typename VECT> inline
+ vector_to_colmatrix(const VECT &v, const MAT &A_) {
+ MAT &A = const_cast<MAT &>(A_);
+ vector_to_colmatrix(v, A, typename linalg_traits<MAT>::sub_orientation());
+ }
+
+ /* ********************************************************************* */
+ /* Solve sylvester equation. */
+ /* ********************************************************************* */
+
+ // very prohibitive solver, to be replaced ...
+ template <typename MAT1, typename MAT2, typename MAT3, typename MAT4 >
+ void sylvester(const MAT1 &m1, const MAT2 &m2, const MAT3 &m3,
+ const MAT4 &m4_) {
+ typedef typename linalg_traits<Mat>::value_type T;
+
+ MAT3 &m4 = const_cast<MAT4 &>(m4_);
+ size_type m = mat_nrows(m1), n = mat_ncols(m1);
+ size_type l = mat_nrows(m2), k = mat_ncols(m2);
+
+ GMM_ASSERT2(m == n && l == k && m == mat_nrows(m3) &&
+ l == mat_ncols(m3) && m == mat_nrows(m4) && l == mat_ncols(m4),
+ "dimensions mismatch");
+
+ gmm::dense_matrix<T> akronb(m*l, m*l);
+ gmm::dense_matrix<T> idm(m, m), idl(l,l);
+ gmm::copy(identity_matrix(), idm);
+ gmm::copy(identity_matrix(), idl);
+ std::vector<T> x(m*l), c(m*l);
+
+ kron(idl, m1, akronb);
+ kron(gmm::transposed(m2), idm, akronb, false);
+
+ colmatrix_to_vector(m3, c);
+ lu_solve(akronb, c, x);
+ vector_to_colmatrix(x, m4);
+
+ }
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_domain_decomp.h b/Contrib/gmm/gmm_domain_decomp.h
new file mode 100755
index 0000000..a2f9d52
--- /dev/null
+++ b/Contrib/gmm/gmm_domain_decomp.h
@@ -0,0 +1,164 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2004-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/** @file gmm_domain_decomp.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date May 21, 2004.
+ @brief Domain decomposition.
+*/
+#ifndef GMM_DOMAIN_DECOMP_H__
+#define GMM_DOMAIN_DECOMP_H__
+
+#include "gmm_kernel.h"
+#include <map>
+
+
+namespace gmm {
+
+ /** This function separates into small boxes of size msize with a ratio
+ * of overlap (in [0,1[) a set of points. The result is given into a
+ * vector of sparse matrices vB.
+ */
+ template <typename Matrix, typename Point>
+ void rudimentary_regular_decomposition(std::vector<Point> pts,
+ double msize,
+ double overlap,
+ std::vector<Matrix> &vB) {
+ typedef typename linalg_traits<Matrix>::value_type value_type;
+ typedef abstract_null_type void_type;
+ typedef std::map<size_type, void_type> map_type;
+
+ size_type nbpts = pts.size();
+ if (!nbpts || pts[0].size() == 0) { vB.resize(0); return; }
+ int dim = int(pts[0].size());
+
+ // computation of the global box and the number of sub-domains
+ Point pmin = pts[0], pmax = pts[0];
+ for (size_type i = 1; i < nbpts; ++i)
+ for (int k = 0; k < dim; ++k) {
+ pmin[k] = std::min(pmin[k], pts[i][k]);
+ pmax[k] = std::max(pmax[k], pts[i][k]);
+ }
+
+ std::vector<size_type> nbsub(dim), mult(dim);
+ std::vector<int> pts1(dim), pts2(dim);
+ size_type nbtotsub = 1;
+ for (int k = 0; k < dim; ++k) {
+ nbsub[k] = size_type((pmax[k] - pmin[k]) / msize)+1;
+ mult[k] = nbtotsub; nbtotsub *= nbsub[k];
+ }
+
+ std::vector<map_type> subs(nbtotsub);
+ // points ventilation
+ std::vector<size_type> ns(dim), na(dim), nu(dim);
+ for (size_type i = 0; i < nbpts; ++i) {
+ for (int k = 0; k < dim; ++k) {
+ register double a = (pts[i][k] - pmin[k]) / msize;
+ ns[k] = size_type(a) - 1; na[k] = 0;
+ pts1[k] = int(a + overlap); pts2[k] = int(ceil(a-1.0-overlap));
+ }
+ size_type sum = 0;
+ do {
+ bool ok = 1;
+ for (int k = 0; k < dim; ++k)
+ if ((ns[k] >= nbsub[k]) || (pts1[k] < int(ns[k]))
+ || (pts2[k] > int(ns[k]))) { ok = false; break; }
+ if (ok) {
+ size_type ind = ns[0];
+ for (int k=1; k < dim; ++k) ind += ns[k]*mult[k];
+ subs[ind][i] = void_type();
+ }
+ for (int k = 0; k < dim; ++k) {
+ if (na[k] < 2) { na[k]++; ns[k]++; ++sum; break; }
+ na[k] = 0; ns[k] -= 2; sum -= 2;
+ }
+ } while (sum);
+ }
+ // delete too small domains.
+ size_type nbmaxinsub = 0;
+ for (size_type i = 0; i < nbtotsub; ++i)
+ nbmaxinsub = std::max(nbmaxinsub, subs[i].size());
+
+ std::fill(ns.begin(), ns.end(), size_type(0));
+ for (size_type i = 0; i < nbtotsub; ++i) {
+ if (subs[i].size() > 0 && subs[i].size() < nbmaxinsub / 10) {
+
+ for (int k = 0; k < dim; ++k) nu[k] = ns[k];
+ size_type nbmax = 0, imax = 0;
+
+ for (int l = 0; l < dim; ++l) {
+ nu[l]--;
+ for (int m = 0; m < 2; ++m, nu[l]+=2) {
+ bool ok = true;
+ for (int k = 0; k < dim && ok; ++k)
+ if (nu[k] >= nbsub[k]) ok = false;
+ if (ok) {
+ size_type ind = ns[0];
+ for (int k=1; k < dim; ++k) ind += ns[k]*mult[k];
+ if (subs[ind].size() > nbmax)
+ { nbmax = subs[ind].size(); imax = ind; }
+ }
+ }
+ nu[l]--;
+ }
+
+ if (nbmax > subs[i].size()) {
+ for (map_type::iterator it=subs[i].begin(); it!=subs[i].end(); ++it)
+ subs[imax][it->first] = void_type();
+ subs[i].clear();
+ }
+ }
+ for (int k = 0; k < dim; ++k)
+ { ns[k]++; if (ns[k] < nbsub[k]) break; ns[k] = 0; }
+ }
+
+ // delete empty domains.
+ size_type effnb = 0;
+ for (size_type i = 0; i < nbtotsub; ++i) {
+ if (subs[i].size() > 0)
+ { if (i != effnb) std::swap(subs[i], subs[effnb]); ++effnb; }
+ }
+
+ // build matrices
+ subs.resize(effnb);
+ vB.resize(effnb);
+ for (size_type i = 0; i < effnb; ++i) {
+ clear(vB[i]); resize(vB[i], nbpts, subs[i].size());
+ size_type j = 0;
+ for (map_type::iterator it=subs[i].begin(); it!=subs[i].end(); ++it, ++j)
+ vB[i](it->first, j) = value_type(1);
+ }
+ }
+
+
+}
+
+
+#endif
diff --git a/Contrib/gmm/gmm_except.h b/Contrib/gmm/gmm_except.h
new file mode 100755
index 0000000..24b4ab7
--- /dev/null
+++ b/Contrib/gmm/gmm_except.h
@@ -0,0 +1,333 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/** @file gmm_except.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @author Julien Pommier <Julien.Pommier at insa-toulouse.fr>
+ @date September 01, 2002.
+ @brief Definition of basic exceptions.
+*/
+
+#ifndef GMM_EXCEPT_H__
+#define GMM_EXCEPT_H__
+
+#include "gmm_std.h"
+
+namespace gmm {
+
+/* *********************************************************************** */
+/* Getfem++ generic errors. */
+/* *********************************************************************** */
+
+ class gmm_error: public std::logic_error {
+ public:
+ gmm_error(const std::string& what_arg): std::logic_error (what_arg) {}
+ };
+
+#ifdef GETFEM_HAVE_PRETTY_FUNCTION
+# define GMM_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else
+# define GMM_PRETTY_FUNCTION ""
+#endif
+
+ // Errors : GMM_THROW should not be used on its own.
+ // GMM_ASSERT1 : Non-maskable errors. Typically for in/ouput and
+ // when the test do not significantly reduces the performance.
+ // GMM_ASSERT2 : All tests which are potentially performance
+ // consuming. Not hidden by default. Hidden when NDEBUG is
+ // defined.
+ // GMM_ASSERT3 : For internal checks. Hidden by default. Active
+ // only when DEBUG_MODE is defined.
+
+#ifdef __EXCEPTIONS
+ inline void short_error_throw(const char *file, int line, const char *func,
+ const char *errormsg) {
+ std::stringstream msg;
+ msg << "Error in " << file << ", line " << line << " " << func
+ << ": \n" << errormsg << ends;
+ throw gmm::gmm_error(msg.str());
+ }
+# define GMM_THROW_(type, errormsg) { \
+ std::stringstream msg; \
+ msg << "Error in "__FILE__ << ", line " \
+ << __LINE__ << " " << GMM_PRETTY_FUNCTION << ": \n" \
+ << errormsg << ends; \
+ throw (type)(msg.str()); \
+ }
+#else
+ inline void short_error_throw(const char *file, int line, const char *func,
+ const char *errormsg) {
+ std::stringstream msg;
+ msg << "Error in " << file << ", line " << line << " " << func
+ << ": \n" << errormsg << ends;
+ ::abort();
+ }
+# define GMM_THROW_(type, errormsg) { \
+ std::stringstream msg; \
+ msg << "Error in "__FILE__ << ", line " \
+ << __LINE__ << " " << GMM_PRETTY_FUNCTION << ": \n" \
+ << errormsg << ends; \
+ ::abort(); \
+ }
+#endif
+
+# define GMM_ASSERT1(test, errormsg) \
+ { if (!(test)) GMM_THROW_(gmm::gmm_error, errormsg); }
+
+ // inline void GMM_THROW() IS_DEPRECATED;
+ inline void GMM_THROW() {}
+#define GMM_THROW(a, b) { GMM_THROW_(a,b); gmm::GMM_THROW(); }
+
+#if defined(NDEBUG)
+# define GMM_ASSERT2(test, errormsg)
+# define GMM_ASSERT3(test, errormsg)
+#elif !defined(GMM_FULL_NDEBUG)
+# define GMM_ASSERT2(test, errormsg) \
+ { if (!(test)) gmm::short_error_throw(__FILE__, __LINE__, \
+ GMM_PRETTY_FUNCTION, errormsg); }
+# define GMM_ASSERT3(test, errormsg) \
+ { if (!(test)) gmm::short_error_throw(__FILE__, __LINE__, \
+ GMM_PRETTY_FUNCTION, errormsg); }
+#else
+# define GMM_ASSERT2(test, errormsg) \
+ { if (!(test)) gmm::short_error_throw(__FILE__, __LINE__, \
+ GMM_PRETTY_FUNCTION, errormsg); }
+# define GMM_ASSERT3(test, errormsg)
+#endif
+
+/* *********************************************************************** */
+/* Getfem++ warnings. */
+/* *********************************************************************** */
+
+ // This allows to dynamically hide warnings
+ struct warning_level {
+ static int level(int l = -2)
+ { static int level_ = 3; return (l != -2) ? (level_ = l) : level_; }
+ };
+
+ inline void set_warning_level(int l) { warning_level::level(std::max(0,l)); }
+ inline int get_warning_level(void) { return warning_level::level(-2); }
+
+ // This allow not too compile some Warnings
+#ifndef GMM_WARNING_LEVEL
+# define GMM_WARNING_LEVEL 4
+#endif
+
+ // Warning levels : 0 always printed
+ // 1 very important : specify a possible error in the code.
+ // 2 important : specify a default of optimization for inst.
+ // 3 remark
+ // 4 ignored by default.
+
+#define GMM_WARNING_MSG(level_, thestr) { \
+ std::stringstream msg; \
+ msg << "Level " << level_ << " Warning in "__FILE__ << ", line " \
+ << __LINE__ << ": " << thestr << ends; \
+ std::cerr << msg.str() << std::endl; \
+ }
+
+#define GMM_WARNING0(thestr) GMM_WARNING_MSG(0, thestr)
+
+#if GMM_WARNING_LEVEL > 0
+# define GMM_WARNING1(thestr) \
+ { if (1 <= gmm::warning_level::level()) GMM_WARNING_MSG(1, thestr) }
+#else
+# define GMM_WARNING1(thestr) {}
+#endif
+
+#if GMM_WARNING_LEVEL > 1
+# define GMM_WARNING2(thestr) \
+ { if (2 <= gmm::warning_level::level()) GMM_WARNING_MSG(2, thestr) }
+#else
+# define GMM_WARNING1(thestr) {}
+#endif
+
+#if GMM_WARNING_LEVEL > 2
+# define GMM_WARNING3(thestr) \
+ { if (3 <= gmm::warning_level::level()) GMM_WARNING_MSG(3, thestr) }
+#else
+# define GMM_WARNING1(thestr) {}
+#endif
+
+#if GMM_WARNING_LEVEL > 3
+# define GMM_WARNING4(thestr) \
+ { if (4 <= gmm::warning_level::level()) GMM_WARNING_MSG(4, thestr) }
+#else
+# define GMM_WARNING1(thestr) {}
+#endif
+
+/* *********************************************************************** */
+/* Getfem++ traces. */
+/* *********************************************************************** */
+
+ // This allows to dynamically hide traces
+ struct traces_level {
+ static int level(int l = -2)
+ { static int level_ = 3; return (l != -2) ? (level_ = l) : level_; }
+ };
+
+ inline void set_traces_level(int l) { traces_level::level(std::max(0,l)); }
+
+ // This allow not too compile some Warnings
+#ifndef GMM_TRACES_LEVEL
+# define GMM_TRACES_LEVEL 3
+#endif
+
+ // Traces levels : 0 always printed
+ // 1 Susceptible to occur once in a program.
+ // 2 Susceptible to occur occasionnaly in a program (10).
+ // 3 Susceptible to occur often (100).
+ // 4 Susceptible to occur very often (>1000).
+
+#define GMM_TRACE_MSG_MPI // for Parallelized version
+#define GMM_TRACE_MSG(level_, thestr) { \
+ GMM_TRACE_MSG_MPI { \
+ std::stringstream msg; \
+ msg << "Trace " << level_ << " in "__FILE__ << ", line " \
+ << __LINE__ << ": " << thestr \
+ << ends; \
+ std::cout << msg.str() << std::endl; \
+ } \
+ }
+
+#define GMM_TRACE0(thestr) GMM_TRACE_MSG(0, thestr)
+
+#if GMM_TRACES_LEVEL > 0
+# define GMM_TRACE1(thestr) \
+ { if (1 <= gmm::traces_level::level()) GMM_TRACE_MSG(1, thestr) }
+#else
+# define GMM_TRACE1(thestr) {}
+#endif
+
+#if GMM_TRACES_LEVEL > 1
+# define GMM_TRACE2(thestr) \
+ { if (2 <= gmm::traces_level::level()) GMM_TRACE_MSG(2, thestr) }
+#else
+# define GMM_TRACE2(thestr) {}
+#endif
+
+#if GMM_TRACES_LEVEL > 2
+# define GMM_TRACE3(thestr) \
+ { if (3 <= gmm::traces_level::level()) GMM_TRACE_MSG(3, thestr) }
+#else
+# define GMM_TRACE3(thestr) {}
+#endif
+
+#if GMM_TRACES_LEVEL > 3
+# define GMM_TRACE4(thestr) \
+ { if (4 <= gmm::traces_level::level()) GMM_TRACE_MSG(4, thestr) }
+#else
+# define GMM_TRACE4(thestr) {}
+#endif
+
+
+ /* ********************************************************************* */
+ /* Definitions for compatibility with old versions. */
+ /* ********************************************************************* */
+
+ using std::invalid_argument;
+
+ struct dimension_error : public std::logic_error
+ { dimension_error(const std::string& w): std::logic_error(w) {} };
+ struct file_not_found_error : public std::logic_error
+ { file_not_found_error(const std::string& w): std::logic_error (w) {} };
+ struct internal_error : public std::logic_error
+ { internal_error(const std::string& w): std::logic_error(w) {} };
+ struct failure_error : public std::logic_error
+ { failure_error(const std::string& w): std::logic_error (w) {} };
+ struct not_linear_error : public std::logic_error
+ { not_linear_error(const std::string& w): std::logic_error (w) {} };
+ struct to_be_done_error : public std::logic_error
+ { to_be_done_error(const std::string& w): std::logic_error (w) {} };
+
+#define GMM_STANDARD_CATCH_ERROR catch(std::logic_error e) \
+ { \
+ cerr << "============================================\n"; \
+ cerr << "| An error has been detected !!! |\n"; \
+ cerr << "============================================\n"; \
+ cerr << e.what() << endl << endl; \
+ exit(1); \
+ } \
+ catch(std::runtime_error e) \
+ { \
+ cerr << "============================================\n"; \
+ cerr << "| An error has been detected !!! |\n"; \
+ cerr << "============================================\n"; \
+ cerr << e.what() << endl << endl; \
+ exit(1); \
+ } \
+ catch(std::bad_alloc) { \
+ cerr << "============================================\n"; \
+ cerr << "| A bad allocation has been detected !!! |\n"; \
+ cerr << "============================================\n"; \
+ exit(1); \
+ } \
+ catch(std::bad_typeid) { \
+ cerr << "============================================\n"; \
+ cerr << "| A bad typeid has been detected !!! |\n"; \
+ cerr << "============================================\n"; \
+ exit(1); \
+ } \
+ catch(std::bad_exception) { \
+ cerr << "============================================\n"; \
+ cerr << "| A bad exception has been detected !!! |\n"; \
+ cerr << "============================================\n"; \
+ exit(1); \
+ } \
+ catch(std::bad_cast) { \
+ cerr << "============================================\n"; \
+ cerr << "| A bad cast has been detected !!! |\n"; \
+ cerr << "============================================\n"; \
+ exit(1); \
+ } \
+ catch(...) { \
+ cerr << "============================================\n"; \
+ cerr << "| An unknown error has been detected !!! |\n"; \
+ cerr << "============================================\n"; \
+ exit(1); \
+ }
+ // catch(ios_base::failure) {
+ // cerr << "============================================\n";
+ // cerr << "| A ios_base::failure has been detected !!!|\n";
+ // cerr << "============================================\n";
+ // exit(1);
+ // }
+
+#if defined(__GNUC__) && (__GNUC__ > 3)
+# define GMM_SET_EXCEPTION_DEBUG \
+ std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
+#else
+# define GMM_SET_EXCEPTION_DEBUG
+#endif
+
+}
+
+
+#endif /* GMM_EXCEPT_H__ */
diff --git a/Contrib/gmm/gmm_inoutput.h b/Contrib/gmm/gmm_inoutput.h
new file mode 100755
index 0000000..e2455d1
--- /dev/null
+++ b/Contrib/gmm/gmm_inoutput.h
@@ -0,0 +1,1131 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_inoutput.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @author Julien Pommier <Julien.Pommier at insa-toulouse.fr>
+ @date July 8, 2003.
+ @brief Input/output on sparse matrices
+
+ Support Harwell-Boeing and Matrix-Market formats.
+*/
+#ifndef GMM_INOUTPUT_H
+#define GMM_INOUTPUT_H
+
+#include <stdio.h>
+#include "gmm_kernel.h"
+namespace gmm {
+
+ /*************************************************************************/
+ /* */
+ /* Functions to read and write Harwell Boeing format. */
+ /* */
+ /*************************************************************************/
+
+ // Fri Aug 15 16:29:47 EDT 1997
+ //
+ // Harwell-Boeing File I/O in C
+ // V. 1.0
+ //
+ // National Institute of Standards and Technology, MD.
+ // K.A. Remington
+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // NOTICE
+ //
+ // Permission to use, copy, modify, and distribute this software and
+ // its documentation for any purpose and without fee is hereby granted
+ // provided that the above copyright notice appear in all copies and
+ // that both the copyright notice and this permission notice appear in
+ // supporting documentation.
+ //
+ // Neither the Author nor the Institution (National Institute of Standards
+ // and Technology) make any representations about the suitability of this
+ // software for any purpose. This software is provided "as is" without
+ // expressed or implied warranty.
+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+ inline void IOHBTerminate(const char *a) { GMM_ASSERT1(false, a);}
+
+ inline bool is_complex_double__(std::complex<double>) { return true; }
+ inline bool is_complex_double__(double) { return false; }
+
+ inline int ParseIfmt(const char *fmt, int* perline, int* width) {
+ if (SECURE_NONCHAR_SSCANF(fmt, " (%dI%d)", perline, width) != 2) {
+ *perline = 1;
+ int s = SECURE_NONCHAR_SSCANF(fmt, " (I%d)", width);
+ GMM_ASSERT1(s == 1, "invalid HB I-format: " << fmt);
+ }
+ return *width;
+ }
+
+ inline int ParseRfmt(const char *fmt, int* perline, int* width,
+ int* prec, int* flag) {
+ char p;
+ *perline = *width = *flag = *prec = 0;
+#ifdef GMM_SECURE_CRT
+ if (sscanf_s(fmt, " (%d%c%d.%d)", perline, &p, sizeof(char), width, prec)
+ < 3 || !strchr("PEDF", p))
+#else
+ if (sscanf(fmt, " (%d%c%d.%d)", perline, &p, width, prec) < 3
+ || !strchr("PEDF", p))
+#endif
+ {
+ *perline = 1;
+#ifdef GMM_SECURE_CRT
+ int s = sscanf_s(fmt, " (%c%d.%d)", &p, sizeof(char), width, prec);
+#else
+ int s = sscanf(fmt, " (%c%d.%d)", &p, width, prec);
+#endif
+ GMM_ASSERT1(s>=2 && strchr("PEDF",p), "invalid HB REAL format: " << fmt);
+ }
+ *flag = p;
+ return *width;
+ }
+
+ /** matrix input/output for Harwell-Boeing format */
+ struct HarwellBoeing_IO {
+ int nrows() const { return Nrow; }
+ int ncols() const { return Ncol; }
+ int nnz() const { return Nnzero; }
+ int is_complex() const { return Type[0] == 'C'; }
+ int is_symmetric() const { return Type[1] == 'S'; }
+ int is_hermitian() const { return Type[1] == 'H'; }
+ HarwellBoeing_IO() { clear(); }
+ HarwellBoeing_IO(const char *filename) { clear(); open(filename); }
+ ~HarwellBoeing_IO() { close(); }
+ /** open filename and reads header */
+ void open(const char *filename);
+ /** read the opened file */
+ template <typename T, int shift> void read(csc_matrix<T, shift>& A);
+ template <typename MAT> void read(MAT &M) IS_DEPRECATED;
+ template <typename T, int shift>
+ static void write(const char *filename, const csc_matrix<T, shift>& A);
+ template <typename T, int shift>
+ static void write(const char *filename, const csc_matrix<T, shift>& A,
+ const std::vector<T> &rhs);
+ template <typename T, typename INDI, typename INDJ, int shift>
+ static void write(const char *filename,
+ const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A);
+ template <typename T, typename INDI, typename INDJ, int shift>
+ static void write(const char *filename,
+ const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A,
+ const std::vector<T> &rhs);
+
+ /** static method for saving the matrix */
+ template <typename MAT> static void write(const char *filename,
+ const MAT& A) IS_DEPRECATED;
+ private:
+ FILE *f;
+ char Title[73], Key[9], Rhstype[4], Type[4];
+ int Nrow, Ncol, Nnzero, Nrhs;
+ char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21];
+ int Ptrcrd, Indcrd, Valcrd, Rhscrd;
+ int lcount;
+
+
+ void close() { if (f) fclose(f); clear(); }
+ void clear() {
+ Nrow = Ncol = Nnzero = Nrhs = 0; f = 0; lcount = 0;
+ memset(Type, 0, sizeof Type);
+ memset(Key, 0, sizeof Key);
+ memset(Title, 0, sizeof Title);
+ }
+ char *getline(char *buf) {
+ fgets(buf, BUFSIZ, f); ++lcount;
+ int s = SECURE_NONCHAR_SSCANF(buf,"%*s");
+ GMM_ASSERT1(s >= 0, "blank line in HB file at line " << lcount);
+ return buf;
+ }
+
+ int substrtoi(const char *p, size_type len) {
+ char s[100]; len = std::min(len, sizeof s - 1);
+ SECURE_STRNCPY(s, 100, p, len); s[len] = 0; return atoi(s);
+ }
+ double substrtod(const char *p, size_type len, int Valflag) {
+ char s[100]; len = std::min(len, sizeof s - 1);
+ SECURE_STRNCPY(s, 100, p, len); s[len] = 0;
+ if ( Valflag != 'F' && !strchr(s,'E')) {
+ /* insert a char prefix for exp */
+ int last = strlen(s);
+ for (int j=last+1;j>=0;j--) {
+ s[j] = s[j-1];
+ if ( s[j] == '+' || s[j] == '-' ) {
+ s[j-1] = Valflag;
+ break;
+ }
+ }
+ }
+ return atof(s);
+ }
+ template <typename IND_TYPE>
+ int readHB_data(IND_TYPE colptr[], IND_TYPE rowind[],
+ double val[]) {
+ /***********************************************************************/
+ /* This function opens and reads the specified file, interpreting its */
+ /* contents as a sparse matrix stored in the Harwell/Boeing standard */
+ /* format and creating compressed column storage scheme vectors to */
+ /* hold the index and nonzero value information. */
+ /* */
+ /* ---------- */
+ /* **CAVEAT** */
+ /* ---------- */
+ /* Parsing real formats from Fortran is tricky, and this file reader */
+ /* does not claim to be foolproof. It has been tested for cases */
+ /* when the real values are printed consistently and evenly spaced on */
+ /* each line, with Fixed (F), and Exponential (E or D) formats. */
+ /* */
+ /* ** If the input file does not adhere to the H/B format, the ** */
+ /* ** results will be unpredictable. ** */
+ /* */
+ /***********************************************************************/
+ int i,ind,col,offset,count;
+ int Ptrperline, Ptrwidth, Indperline, Indwidth;
+ int Valperline, Valwidth, Valprec, Nentries;
+ int Valflag; /* Indicates 'E','D', or 'F' float format */
+ char line[BUFSIZ];
+
+ /* Parse the array input formats from Line 3 of HB file */
+ ParseIfmt(Ptrfmt,&Ptrperline,&Ptrwidth);
+ ParseIfmt(Indfmt,&Indperline,&Indwidth);
+ if ( Type[0] != 'P' ) { /* Skip if pattern only */
+ ParseRfmt(Valfmt,&Valperline,&Valwidth,&Valprec,&Valflag);
+ }
+
+ cout << "Valwidth = " << Valwidth << endl; getchar();
+
+ /* Read column pointer array: */
+ offset = 0; /* if base 0 storage is declared (via macro def), */
+ /* then storage entries are offset by 1 */
+
+ for (count = 0, i=0;i<Ptrcrd;i++) {
+ getline(line);
+ for (col = 0, ind = 0;ind<Ptrperline;ind++) {
+ if (count > Ncol) break;
+ colptr[count] = substrtoi(line+col,Ptrwidth)-offset;
+ count++; col += Ptrwidth;
+ }
+ }
+
+ /* Read row index array: */
+ for (count = 0, i=0;i<Indcrd;i++) {
+ getline(line);
+ for (col = 0, ind = 0;ind<Indperline;ind++) {
+ if (count == Nnzero) break;
+ rowind[count] = substrtoi(line+col,Indwidth)-offset;
+ count++; col += Indwidth;
+ }
+ }
+
+ /* Read array of values: */
+ if ( Type[0] != 'P' ) { /* Skip if pattern only */
+ if ( Type[0] == 'C' ) Nentries = 2*Nnzero;
+ else Nentries = Nnzero;
+
+ count = 0;
+ for (i=0;i<Valcrd;i++) {
+ getline(line);
+ if (Valflag == 'D') {
+ // const_cast Due to aCC excentricity
+ char *p;
+ while( (p = const_cast<char *>(strchr(line,'D')) )) *p = 'E';
+ }
+ for (col = 0, ind = 0;ind<Valperline;ind++) {
+ if (count == Nentries) break;
+ val[count] = substrtod(line+col, Valwidth, Valflag);
+ count++; col += Valwidth;
+ }
+ }
+ }
+ return 1;
+ }
+ };
+
+ inline void HarwellBoeing_IO::open(const char *filename) {
+ int Totcrd,Neltvl,Nrhsix;
+ char line[BUFSIZ];
+ close();
+ SECURE_FOPEN(&f, filename, "r");
+ GMM_ASSERT1(f, "could not open " << filename);
+ /* First line: */
+#ifdef GMM_SECURE_CRT
+ sscanf_s(getline(line), "%c%s", Title, 72, Key, 8);
+#else
+ sscanf(getline(line), "%72c%8s", Title, Key);
+#endif
+ Key[8] = Title[72] = 0;
+ /* Second line: */
+ Totcrd = Ptrcrd = Indcrd = Valcrd = Rhscrd = 0;
+ SECURE_NONCHAR_SSCANF(getline(line), "%d%d%d%d%d", &Totcrd, &Ptrcrd,
+ &Indcrd, &Valcrd, &Rhscrd);
+
+ /* Third line: */
+ Nrow = Ncol = Nnzero = Neltvl = 0;
+#ifdef GMM_SECURE_CRT
+ if (sscanf_s(getline(line), "%c%d%d%d%d", Type, 3, &Nrow, &Ncol, &Nnzero,
+ &Neltvl) < 1)
+#else
+ if (sscanf(getline(line), "%3c%d%d%d%d", Type, &Nrow, &Ncol, &Nnzero,
+ &Neltvl) < 1)
+#endif
+ IOHBTerminate("Invalid Type info, line 3 of Harwell-Boeing file.\n");
+ for (size_type i = 0; i < 3; ++i) Type[i] = toupper(Type[i]);
+
+ /* Fourth line: */
+#ifdef GMM_SECURE_CRT
+ if ( sscanf_s(getline(line), "%c%c%c%c",Ptrfmt, 16,Indfmt, 16,Valfmt,
+ 20,Rhsfmt, 20) < 3)
+#else
+ if ( sscanf(getline(line), "%16c%16c%20c%20c",Ptrfmt,Indfmt,Valfmt,
+ Rhsfmt) < 3)
+#endif
+ IOHBTerminate("Invalid format info, line 4 of Harwell-Boeing file.\n");
+ Ptrfmt[16] = Indfmt[16] = Valfmt[20] = Rhsfmt[20] = 0;
+
+ /* (Optional) Fifth line: */
+ if (Rhscrd != 0 ) {
+ Nrhs = Nrhsix = 0;
+#ifdef GMM_SECURE_CRT
+ if ( sscanf_s(getline(line), "%c%d%d", Rhstype, 3, &Nrhs, &Nrhsix) != 1)
+#else
+ if ( sscanf(getline(line), "%3c%d%d", Rhstype, &Nrhs, &Nrhsix) != 1)
+#endif
+ IOHBTerminate("Invalid RHS type information, line 5 of"
+ " Harwell-Boeing file.\n");
+ }
+ }
+
+ /* only valid for double and complex<double> csc matrices */
+ template <typename T, int shift> void
+ HarwellBoeing_IO::read(csc_matrix<T, shift>& A) {
+
+ typedef typename csc_matrix<T, shift>::IND_TYPE IND_TYPE;
+
+ GMM_ASSERT1(f, "no file opened!");
+ GMM_ASSERT1(Type[0] != 'P',
+ "Bad HB matrix format (pattern matrices not supported)");
+ GMM_ASSERT1(!is_complex_double__(T()) || Type[0] != 'R',
+ "Bad HB matrix format (file contains a REAL matrix)");
+ GMM_ASSERT1(is_complex_double__(T()) || Type[0] != 'C',
+ "Bad HB matrix format (file contains a COMPLEX matrix)");
+ if (A.pr) { delete[] A.pr; delete[] A.ir; delete[] A.jc; }
+ A.nc = ncols(); A.nr = nrows();
+ A.pr = 0;
+ A.jc = new IND_TYPE[ncols()+1];
+ A.ir = new IND_TYPE[nnz()];
+ A.pr = new T[nnz()];
+ readHB_data(A.jc, A.ir, (double*)A.pr);
+ for (int i = 0; i <= ncols(); ++i) { A.jc[i] += shift; A.jc[i] -= 1; }
+ for (int i = 0; i < nnz(); ++i) { A.ir[i] += shift; A.ir[i] -= 1; }
+ }
+
+ template <typename MAT> void
+ HarwellBoeing_IO::read(MAT &M) {
+ csc_matrix<typename gmm::linalg_traits<MAT>::value_type> csc;
+ read(csc);
+ resize(M, mat_nrows(csc), mat_ncols(csc));
+ copy(csc, M);
+ }
+
+ template <typename IND_TYPE>
+ inline int writeHB_mat_double(const char* filename, int M, int N, int nz,
+ const IND_TYPE colptr[],
+ const IND_TYPE rowind[],
+ const double val[], int Nrhs,
+ const double rhs[], const double guess[],
+ const double exact[], const char* Title,
+ const char* Key, const char* Type,
+ const char* Ptrfmt, const char* Indfmt,
+ const char* Valfmt, const char* Rhsfmt,
+ const char* Rhstype, int shift) {
+ /************************************************************************/
+ /* The writeHB function opens the named file and writes the specified */
+ /* matrix and optional right-hand-side(s) to that file in */
+ /* Harwell-Boeing format. */
+ /* */
+ /* For a description of the Harwell Boeing standard, see: */
+ /* Duff, et al., ACM TOMS Vol.15, No.1, March 1989 */
+ /* */
+ /************************************************************************/
+ FILE *out_file;
+ int i, entry, offset, j, acount, linemod;
+ int totcrd, ptrcrd, indcrd, valcrd, rhscrd;
+ int nvalentries, nrhsentries;
+ int Ptrperline, Ptrwidth, Indperline, Indwidth;
+ int Rhsperline, Rhswidth, Rhsprec, Rhsflag;
+ int Valperline, Valwidth, Valprec;
+ int Valflag; /* Indicates 'E','D', or 'F' float format */
+ char pformat[16],iformat[16],vformat[19],rformat[19];
+
+ if ( Type[0] == 'C' )
+ { nvalentries = 2*nz; nrhsentries = 2*M; }
+ else
+ { nvalentries = nz; nrhsentries = M; }
+
+ if ( filename != NULL ) {
+ SECURE_FOPEN(&out_file, filename, "w");
+ GMM_ASSERT1(out_file != NULL, "Error: Cannot open file: " << filename);
+ } else out_file = stdout;
+
+ if ( Ptrfmt == NULL ) Ptrfmt = "(8I10)";
+ ParseIfmt(Ptrfmt, &Ptrperline, &Ptrwidth);
+ SECURE_SPRINTF1(pformat,sizeof(pformat),"%%%dd",Ptrwidth);
+ ptrcrd = (N+1)/Ptrperline;
+ if ( (N+1)%Ptrperline != 0) ptrcrd++;
+
+ if ( Indfmt == NULL ) Indfmt = Ptrfmt;
+ ParseIfmt(Indfmt, &Indperline, &Indwidth);
+ SECURE_SPRINTF1(iformat,sizeof(iformat), "%%%dd",Indwidth);
+ indcrd = nz/Indperline;
+ if ( nz%Indperline != 0) indcrd++;
+
+ if ( Type[0] != 'P' ) { /* Skip if pattern only */
+ if ( Valfmt == NULL ) Valfmt = "(4E21.13)";
+ ParseRfmt(Valfmt, &Valperline, &Valwidth, &Valprec, &Valflag);
+ if (Valflag == 'D') *strchr(Valfmt,'D') = 'E';
+ if (Valflag == 'F')
+ SECURE_SPRINTF2(vformat, sizeof(vformat), "%% %d.%df", Valwidth,
+ Valprec);
+ else
+ SECURE_SPRINTF2(vformat, sizeof(vformat), "%% %d.%dE", Valwidth,
+ Valprec);
+ valcrd = nvalentries/Valperline;
+ if ( nvalentries%Valperline != 0) valcrd++;
+ } else valcrd = 0;
+
+ if ( Nrhs > 0 ) {
+ if ( Rhsfmt == NULL ) Rhsfmt = Valfmt;
+ ParseRfmt(Rhsfmt,&Rhsperline,&Rhswidth,&Rhsprec, &Rhsflag);
+ if (Rhsflag == 'F')
+ SECURE_SPRINTF2(rformat,sizeof(rformat), "%% %d.%df",Rhswidth,Rhsprec);
+ else
+ SECURE_SPRINTF2(rformat,sizeof(rformat), "%% %d.%dE",Rhswidth,Rhsprec);
+ if (Rhsflag == 'D') *strchr(Rhsfmt,'D') = 'E';
+ rhscrd = nrhsentries/Rhsperline;
+ if ( nrhsentries%Rhsperline != 0) rhscrd++;
+ if ( Rhstype[1] == 'G' ) rhscrd+=rhscrd;
+ if ( Rhstype[2] == 'X' ) rhscrd+=rhscrd;
+ rhscrd*=Nrhs;
+ } else rhscrd = 0;
+
+ totcrd = 4+ptrcrd+indcrd+valcrd+rhscrd;
+
+
+ /* Print header information: */
+
+ fprintf(out_file,"%-72s%-8s\n%14d%14d%14d%14d%14d\n",Title, Key, totcrd,
+ ptrcrd, indcrd, valcrd, rhscrd);
+ fprintf(out_file,"%3s%11s%14d%14d%14d%14d\n",Type," ", M, N, nz, 0);
+ fprintf(out_file,"%-16s%-16s%-20s", Ptrfmt, Indfmt, Valfmt);
+ if ( Nrhs != 0 ) {
+ /* Print Rhsfmt on fourth line and */
+ /* optional fifth header line for auxillary vector information:*/
+ fprintf(out_file,"%-20s\n%-14s%d\n",Rhsfmt,Rhstype,Nrhs);
+ }
+ else
+ fprintf(out_file,"\n");
+
+ offset = 1 - shift; /* if base 0 storage is declared (via macro def), */
+ /* then storage entries are offset by 1 */
+
+ /* Print column pointers: */
+ for (i = 0; i < N+1; i++) {
+ entry = colptr[i]+offset;
+ fprintf(out_file,pformat,entry);
+ if ( (i+1)%Ptrperline == 0 ) fprintf(out_file,"\n");
+ }
+
+ if ( (N+1) % Ptrperline != 0 ) fprintf(out_file,"\n");
+
+ /* Print row indices: */
+ for (i=0;i<nz;i++) {
+ entry = rowind[i]+offset;
+ fprintf(out_file,iformat,entry);
+ if ( (i+1)%Indperline == 0 ) fprintf(out_file,"\n");
+ }
+
+ if ( nz % Indperline != 0 ) fprintf(out_file,"\n");
+
+ /* Print values: */
+
+ if ( Type[0] != 'P' ) { /* Skip if pattern only */
+ for (i=0;i<nvalentries;i++) {
+ fprintf(out_file,vformat,val[i]);
+ if ( (i+1)%Valperline == 0 ) fprintf(out_file,"\n");
+ }
+
+ if ( nvalentries % Valperline != 0 ) fprintf(out_file,"\n");
+
+ /* Print right hand sides: */
+ acount = 1;
+ linemod=0;
+ if ( Nrhs > 0 ) {
+ for (j=0;j<Nrhs;j++) {
+ for (i=0;i<nrhsentries;i++) {
+ fprintf(out_file,rformat,rhs[i] /* *Rhswidth */);
+ if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
+ }
+ if ( acount%Rhsperline != linemod ) {
+ fprintf(out_file,"\n");
+ linemod = (acount-1)%Rhsperline;
+ }
+ if ( Rhstype[1] == 'G' ) {
+ for (i=0;i<nrhsentries;i++) {
+ fprintf(out_file,rformat,guess[i] /* *Rhswidth */);
+ if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
+ }
+ if ( acount%Rhsperline != linemod ) {
+ fprintf(out_file,"\n");
+ linemod = (acount-1)%Rhsperline;
+ }
+ }
+ if ( Rhstype[2] == 'X' ) {
+ for (i=0;i<nrhsentries;i++) {
+ fprintf(out_file,rformat,exact[i] /* *Rhswidth */);
+ if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
+ }
+ if ( acount%Rhsperline != linemod ) {
+ fprintf(out_file,"\n");
+ linemod = (acount-1)%Rhsperline;
+ }
+ }
+ }
+ }
+ }
+ int s = fclose(out_file);
+ GMM_ASSERT1(s == 0, "Error closing file in writeHB_mat_double().");
+ return 1;
+ }
+
+ template <typename T, int shift> void
+ HarwellBoeing_IO::write(const char *filename,
+ const csc_matrix<T, shift>& A) {
+ write(filename, csc_matrix_ref<T*, unsigned*, unsigned *, shift>
+ (A.pr, A.ir, A.jc, A.nr, A.nc));
+ }
+
+ template <typename T, int shift> void
+ HarwellBoeing_IO::write(const char *filename,
+ const csc_matrix<T, shift>& A,
+ const std::vector<T> &rhs) {
+ write(filename, csc_matrix_ref<T*, unsigned*, unsigned *, shift>
+ (A.pr, A.ir, A.jc, A.nr, A.nc), rhs);
+ }
+
+ template <typename T, typename INDI, typename INDJ, int shift> void
+ HarwellBoeing_IO::write(const char *filename,
+ const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A) {
+ const char *t = 0;
+ if (is_complex_double__(T()))
+ if (mat_nrows(A) == mat_ncols(A)) t = "CUA"; else t = "CRA";
+ else
+ if (mat_nrows(A) == mat_ncols(A)) t = "RUA"; else t = "RRA";
+ writeHB_mat_double(filename, mat_nrows(A), mat_ncols(A),
+ A.jc[mat_ncols(A)], A.jc, A.ir,
+ (const double *)A.pr,
+ 0, 0, 0, 0, "GETFEM++ CSC MATRIX", "CSCMAT",
+ t, 0, 0, 0, 0, "F", shift);
+ }
+
+ template <typename T, typename INDI, typename INDJ, int shift> void
+ HarwellBoeing_IO::write(const char *filename,
+ const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A,
+ const std::vector<T> &rhs) {
+ const char *t = 0;
+ if (is_complex_double__(T()))
+ if (mat_nrows(A) == mat_ncols(A)) t = "CUA"; else t = "CRA";
+ else
+ if (mat_nrows(A) == mat_ncols(A)) t = "RUA"; else t = "RRA";
+ int Nrhs = gmm::vect_size(rhs) / mat_nrows(A);
+ writeHB_mat_double(filename, mat_nrows(A), mat_ncols(A),
+ A.jc[mat_ncols(A)], A.jc, A.ir,
+ (const double *)A.pr,
+ Nrhs, (const double *)(&rhs[0]), 0, 0,
+ "GETFEM++ CSC MATRIX", "CSCMAT",
+ t, 0, 0, 0, 0, "F ", shift);
+ }
+
+
+ template <typename MAT> void
+ HarwellBoeing_IO::write(const char *filename, const MAT& A) {
+ gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type>
+ tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
+ gmm::copy(A,tmp);
+ HarwellBoeing_IO::write(filename, tmp);
+ }
+
+ /** save a "double" or "std::complex<double>" csc matrix into a
+ HarwellBoeing file
+ */
+ template <typename T, int shift> inline void
+ Harwell_Boeing_save(const std::string &filename,
+ const csc_matrix<T, shift>& A)
+ { HarwellBoeing_IO::write(filename.c_str(), A); }
+
+ /** save a reference on "double" or "std::complex<double>" csc matrix
+ into a HarwellBoeing file
+ */
+ template <typename T, typename INDI, typename INDJ, int shift> inline void
+ Harwell_Boeing_save(const std::string &filename,
+ const csc_matrix_ref<T, INDI, INDJ, shift>& A)
+ { HarwellBoeing_IO::write(filename.c_str(), A); }
+
+ /** save a "double" or "std::complex<double>" generic matrix
+ into a HarwellBoeing file making a copy in a csc matrix
+ */
+ template <typename MAT> inline void
+ Harwell_Boeing_save(const std::string &filename, const MAT& A) {
+ gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type>
+ tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
+ gmm::copy(A, tmp);
+ HarwellBoeing_IO::write(filename.c_str(), tmp);
+ }
+
+ template <typename MAT, typename VECT> inline void
+ Harwell_Boeing_save(const std::string &filename, const MAT& A,
+ const VECT &RHS) {
+ typedef typename gmm::linalg_traits<MAT>::value_type T;
+ gmm::csc_matrix<T> tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
+ gmm::copy(A, tmp);
+ std::vector<T> tmprhs(gmm::vect_size(RHS));
+ gmm::copy(RHS, tmprhs);
+ HarwellBoeing_IO::write(filename.c_str(), tmp, tmprhs);
+ }
+
+ /** load a "double" or "std::complex<double>" csc matrix from a
+ HarwellBoeing file
+ */
+ template <typename T, int shift> void
+ Harwell_Boeing_load(const std::string &filename, csc_matrix<T, shift>& A) {
+ HarwellBoeing_IO h(filename.c_str()); h.read(A);
+ }
+
+ /** load a "double" or "std::complex<double>" generic matrix from a
+ HarwellBoeing file
+ */
+ template <typename MAT> void
+ Harwell_Boeing_load(const std::string &filename, MAT& A) {
+ csc_matrix<typename gmm::linalg_traits<MAT>::value_type> csc;
+ Harwell_Boeing_load(filename, csc);
+ resize(A, mat_nrows(csc), mat_ncols(csc));
+ copy(csc, A);
+ }
+
+ /*************************************************************************/
+ /* */
+ /* Functions to read and write MatrixMarket format. */
+ /* */
+ /*************************************************************************/
+
+ /*
+ * Matrix Market I/O library for ANSI C
+ *
+ * See http://math.nist.gov/MatrixMarket for details.
+ *
+ *
+ */
+
+#define MM_MAX_LINE_LENGTH 1025
+#define MatrixMarketBanner "%%MatrixMarket"
+#define MM_MAX_TOKEN_LENGTH 64
+
+ typedef char MM_typecode[4];
+
+ /******************* MM_typecode query functions *************************/
+
+#define mm_is_matrix(typecode) ((typecode)[0]=='M')
+
+#define mm_is_sparse(typecode) ((typecode)[1]=='C')
+#define mm_is_coordinate(typecode) ((typecode)[1]=='C')
+#define mm_is_dense(typecode) ((typecode)[1]=='A')
+#define mm_is_array(typecode) ((typecode)[1]=='A')
+
+#define mm_is_complex(typecode) ((typecode)[2]=='C')
+#define mm_is_real(typecode) ((typecode)[2]=='R')
+#define mm_is_pattern(typecode) ((typecode)[2]=='P')
+#define mm_is_integer(typecode) ((typecode)[2]=='I')
+
+#define mm_is_symmetric(typecode) ((typecode)[3]=='S')
+#define mm_is_general(typecode) ((typecode)[3]=='G')
+#define mm_is_skew(typecode) ((typecode)[3]=='K')
+#define mm_is_hermitian(typecode) ((typecode)[3]=='H')
+
+ /******************* MM_typecode modify fucntions ************************/
+
+#define mm_set_matrix(typecode) ((*typecode)[0]='M')
+#define mm_set_coordinate(typecode) ((*typecode)[1]='C')
+#define mm_set_array(typecode) ((*typecode)[1]='A')
+#define mm_set_dense(typecode) mm_set_array(typecode)
+#define mm_set_sparse(typecode) mm_set_coordinate(typecode)
+
+#define mm_set_complex(typecode) ((*typecode)[2]='C')
+#define mm_set_real(typecode) ((*typecode)[2]='R')
+#define mm_set_pattern(typecode) ((*typecode)[2]='P')
+#define mm_set_integer(typecode) ((*typecode)[2]='I')
+
+
+#define mm_set_symmetric(typecode) ((*typecode)[3]='S')
+#define mm_set_general(typecode) ((*typecode)[3]='G')
+#define mm_set_skew(typecode) ((*typecode)[3]='K')
+#define mm_set_hermitian(typecode) ((*typecode)[3]='H')
+
+#define mm_clear_typecode(typecode) ((*typecode)[0]=(*typecode)[1]= \
+ (*typecode)[2]=' ',(*typecode)[3]='G')
+
+#define mm_initialize_typecode(typecode) mm_clear_typecode(typecode)
+
+
+ /******************* Matrix Market error codes ***************************/
+
+
+#define MM_COULD_NOT_READ_FILE 11
+#define MM_PREMATURE_EOF 12
+#define MM_NOT_MTX 13
+#define MM_NO_HEADER 14
+#define MM_UNSUPPORTED_TYPE 15
+#define MM_LINE_TOO_LONG 16
+#define MM_COULD_NOT_WRITE_FILE 17
+
+
+ /******************** Matrix Market internal definitions *****************
+
+ MM_matrix_typecode: 4-character sequence
+
+ object sparse/ data storage
+ dense type scheme
+
+ string position: [0] [1] [2] [3]
+
+ Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
+ A(array) C(omplex) H(ermitian)
+ P(attern) S(ymmetric)
+ I(nteger) K(kew)
+
+ ***********************************************************************/
+
+#define MM_MTX_STR "matrix"
+#define MM_ARRAY_STR "array"
+#define MM_DENSE_STR "array"
+#define MM_COORDINATE_STR "coordinate"
+#define MM_SPARSE_STR "coordinate"
+#define MM_COMPLEX_STR "complex"
+#define MM_REAL_STR "real"
+#define MM_INT_STR "integer"
+#define MM_GENERAL_STR "general"
+#define MM_SYMM_STR "symmetric"
+#define MM_HERM_STR "hermitian"
+#define MM_SKEW_STR "skew-symmetric"
+#define MM_PATTERN_STR "pattern"
+
+ inline char *mm_typecode_to_str(MM_typecode matcode) {
+ char buffer[MM_MAX_LINE_LENGTH];
+ const char *types[4] = {0,0,0,0};
+ /* int error =0; */
+ /* int i; */
+
+ /* check for MTX type */
+ if (mm_is_matrix(matcode))
+ types[0] = MM_MTX_STR;
+ /*
+ else
+ error=1;
+ */
+ /* check for CRD or ARR matrix */
+ if (mm_is_sparse(matcode))
+ types[1] = MM_SPARSE_STR;
+ else
+ if (mm_is_dense(matcode))
+ types[1] = MM_DENSE_STR;
+ else
+ return NULL;
+
+ /* check for element data type */
+ if (mm_is_real(matcode))
+ types[2] = MM_REAL_STR;
+ else
+ if (mm_is_complex(matcode))
+ types[2] = MM_COMPLEX_STR;
+ else
+ if (mm_is_pattern(matcode))
+ types[2] = MM_PATTERN_STR;
+ else
+ if (mm_is_integer(matcode))
+ types[2] = MM_INT_STR;
+ else
+ return NULL;
+
+
+ /* check for symmetry type */
+ if (mm_is_general(matcode))
+ types[3] = MM_GENERAL_STR;
+ else if (mm_is_symmetric(matcode))
+ types[3] = MM_SYMM_STR;
+ else if (mm_is_hermitian(matcode))
+ types[3] = MM_HERM_STR;
+ else if (mm_is_skew(matcode))
+ types[3] = MM_SKEW_STR;
+ else
+ return NULL;
+
+ SECURE_SPRINTF4(buffer, sizeof(buffer), "%s %s %s %s", types[0], types[1],
+ types[2], types[3]);
+ return SECURE_STRDUP(buffer);
+
+ }
+
+ inline int mm_read_banner(FILE *f, MM_typecode *matcode) {
+ char line[MM_MAX_LINE_LENGTH];
+ char banner[MM_MAX_TOKEN_LENGTH];
+ char mtx[MM_MAX_TOKEN_LENGTH];
+ char crd[MM_MAX_TOKEN_LENGTH];
+ char data_type[MM_MAX_TOKEN_LENGTH];
+ char storage_scheme[MM_MAX_TOKEN_LENGTH];
+ char *p;
+ /* int ret_code; */
+
+ mm_clear_typecode(matcode);
+
+ if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
+ return MM_PREMATURE_EOF;
+
+#ifdef GMM_SECURE_CRT
+ if (sscanf_s(line, "%s %s %s %s %s", banner, sizeof(banner),
+ mtx, sizeof(mtx), crd, sizeof(crd), data_type,
+ sizeof(data_type), storage_scheme,
+ sizeof(storage_scheme)) != 5)
+#else
+ if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd,
+ data_type, storage_scheme) != 5)
+#endif
+ return MM_PREMATURE_EOF;
+
+ for (p=mtx; *p!='\0'; *p=tolower(*p),p++); /* convert to lower case */
+ for (p=crd; *p!='\0'; *p=tolower(*p),p++);
+ for (p=data_type; *p!='\0'; *p=tolower(*p),p++);
+ for (p=storage_scheme; *p!='\0'; *p=tolower(*p),p++);
+
+ /* check for banner */
+ if (strncmp(banner, MatrixMarketBanner, strlen(MatrixMarketBanner)) != 0)
+ return MM_NO_HEADER;
+
+ /* first field should be "mtx" */
+ if (strcmp(mtx, MM_MTX_STR) != 0)
+ return MM_UNSUPPORTED_TYPE;
+ mm_set_matrix(matcode);
+
+
+ /* second field describes whether this is a sparse matrix (in coordinate
+ storgae) or a dense array */
+
+
+ if (strcmp(crd, MM_SPARSE_STR) == 0)
+ mm_set_sparse(matcode);
+ else
+ if (strcmp(crd, MM_DENSE_STR) == 0)
+ mm_set_dense(matcode);
+ else
+ return MM_UNSUPPORTED_TYPE;
+
+
+ /* third field */
+
+ if (strcmp(data_type, MM_REAL_STR) == 0)
+ mm_set_real(matcode);
+ else
+ if (strcmp(data_type, MM_COMPLEX_STR) == 0)
+ mm_set_complex(matcode);
+ else
+ if (strcmp(data_type, MM_PATTERN_STR) == 0)
+ mm_set_pattern(matcode);
+ else
+ if (strcmp(data_type, MM_INT_STR) == 0)
+ mm_set_integer(matcode);
+ else
+ return MM_UNSUPPORTED_TYPE;
+
+
+ /* fourth field */
+
+ if (strcmp(storage_scheme, MM_GENERAL_STR) == 0)
+ mm_set_general(matcode);
+ else
+ if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
+ mm_set_symmetric(matcode);
+ else
+ if (strcmp(storage_scheme, MM_HERM_STR) == 0)
+ mm_set_hermitian(matcode);
+ else
+ if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
+ mm_set_skew(matcode);
+ else
+ return MM_UNSUPPORTED_TYPE;
+
+ return 0;
+ }
+
+ inline int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz ) {
+ char line[MM_MAX_LINE_LENGTH];
+ /* int ret_code;*/
+ int num_items_read;
+
+ /* set return null parameter values, in case we exit with errors */
+ *M = *N = *nz = 0;
+
+ /* now continue scanning until you reach the end-of-comments */
+ do {
+ if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
+ return MM_PREMATURE_EOF;
+ } while (line[0] == '%');
+
+ /* line[] is either blank or has M,N, nz */
+ if (SECURE_NONCHAR_SSCANF(line, "%d %d %d", M, N, nz) == 3) return 0;
+ else
+ do {
+ num_items_read = SECURE_NONCHAR_FSCANF(f, "%d %d %d", M, N, nz);
+ if (num_items_read == EOF) return MM_PREMATURE_EOF;
+ }
+ while (num_items_read != 3);
+
+ return 0;
+ }
+
+
+ inline int mm_read_mtx_crd_data(FILE *f, int, int, int nz, int I[],
+ int J[], double val[], MM_typecode matcode) {
+ int i;
+ if (mm_is_complex(matcode)) {
+ for (i=0; i<nz; i++)
+ if (SECURE_NONCHAR_FSCANF(f, "%d %d %lg %lg", &I[i], &J[i],
+ &val[2*i], &val[2*i+1])
+ != 4) return MM_PREMATURE_EOF;
+ }
+ else if (mm_is_real(matcode)) {
+ for (i=0; i<nz; i++) {
+ if (SECURE_NONCHAR_FSCANF(f, "%d %d %lg\n", &I[i], &J[i], &val[i])
+ != 3) return MM_PREMATURE_EOF;
+
+ }
+ }
+ else if (mm_is_pattern(matcode)) {
+ for (i=0; i<nz; i++)
+ if (SECURE_NONCHAR_FSCANF(f, "%d %d", &I[i], &J[i])
+ != 2) return MM_PREMATURE_EOF;
+ }
+ else return MM_UNSUPPORTED_TYPE;
+
+ return 0;
+ }
+
+ inline int mm_write_mtx_crd(const char *fname, int M, int N, int nz,
+ int I[], int J[], const double val[],
+ MM_typecode matcode) {
+ FILE *f;
+ int i;
+
+ if (strcmp(fname, "stdout") == 0)
+ f = stdout;
+ else {
+ SECURE_FOPEN(&f, fname, "w");
+ if (f == NULL)
+ return MM_COULD_NOT_WRITE_FILE;
+ }
+
+ /* print banner followed by typecode */
+ fprintf(f, "%s ", MatrixMarketBanner);
+ char *str = mm_typecode_to_str(matcode);
+ fprintf(f, "%s\n", str);
+ free(str);
+
+ /* print matrix sizes and nonzeros */
+ fprintf(f, "%d %d %d\n", M, N, nz);
+
+ /* print values */
+ if (mm_is_pattern(matcode))
+ for (i=0; i<nz; i++)
+ fprintf(f, "%d %d\n", I[i], J[i]);
+ else
+ if (mm_is_real(matcode))
+ for (i=0; i<nz; i++)
+ fprintf(f, "%d %d %20.16g\n", I[i], J[i], val[i]);
+ else
+ if (mm_is_complex(matcode))
+ for (i=0; i<nz; i++)
+ fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2*i],
+ val[2*i+1]);
+ else {
+ if (f != stdout) fclose(f);
+ return MM_UNSUPPORTED_TYPE;
+ }
+
+ if (f !=stdout) fclose(f);
+ return 0;
+ }
+
+
+ /** matrix input/output for MatrixMarket storage */
+ class MatrixMarket_IO {
+ FILE *f;
+ bool isComplex, isSymmetric, isHermitian;
+ int row, col, nz;
+ MM_typecode matcode;
+ public:
+ MatrixMarket_IO() : f(0) {}
+ MatrixMarket_IO(const char *filename) : f(0) { open(filename); }
+ ~MatrixMarket_IO() { if (f) fclose(f); f = 0; }
+
+ int nrows() const { return row; }
+ int ncols() const { return col; }
+ int nnz() const { return nz; }
+ int is_complex() const { return isComplex; }
+ int is_symmetric() const { return isSymmetric; }
+ int is_hermitian() const { return isHermitian; }
+
+ /* open filename and reads header */
+ void open(const char *filename);
+ /* read opened file */
+ template <typename Matrix> void read(Matrix &A);
+ /* write a matrix */
+ template <typename T, int shift> static void
+ write(const char *filename, const csc_matrix<T, shift>& A);
+ template <typename T, typename INDI, typename INDJ, int shift> static void
+ write(const char *filename,
+ const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A);
+ template <typename MAT> static void
+ write(const char *filename, const MAT& A);
+ };
+
+ /** load a matrix-market file */
+ template <typename Matrix> inline void
+ MatrixMarket_load(const char *filename, Matrix& A) {
+ MatrixMarket_IO mm; mm.open(filename);
+ mm.read(A);
+ }
+ /** write a matrix-market file */
+ template <typename T, int shift> void
+ MatrixMarket_save(const char *filename, const csc_matrix<T, shift>& A) {
+ MatrixMarket_IO mm; mm.write(filename, A);
+ }
+
+ template <typename T, typename INDI, typename INDJ, int shift> inline void
+ MatrixMarket_save(const char *filename,
+ const csc_matrix_ref<T, INDI, INDJ, shift>& A) {
+ MatrixMarket_IO mm; mm.write(filename, A);
+ }
+
+
+ inline void MatrixMarket_IO::open(const char *filename) {
+ if (f) { fclose(f); }
+ SECURE_FOPEN(&f, filename, "r");
+ GMM_ASSERT1(f, "Sorry, cannot open file " << filename);
+ int s1 = mm_read_banner(f, &matcode);
+ GMM_ASSERT1(s1 == 0, "Sorry, cannnot find the matrix market banner in "
+ << filename);
+ int s2 = mm_is_coordinate(matcode), s3 = mm_is_matrix(matcode);
+ GMM_ASSERT1(s2 > 0 && s3 > 0,
+ "file is not coordinate storage or is not a matrix");
+ int s4 = mm_is_pattern(matcode);
+ GMM_ASSERT1(s4 == 0,
+ "the file does only contain the pattern of a sparse matrix");
+ int s5 = mm_is_skew(matcode);
+ GMM_ASSERT1(s5 == 0, "not currently supporting skew symmetric");
+ isSymmetric = mm_is_symmetric(matcode) || mm_is_hermitian(matcode);
+ isHermitian = mm_is_hermitian(matcode);
+ isComplex = mm_is_complex(matcode);
+ mm_read_mtx_crd_size(f, &row, &col, &nz);
+ }
+
+ template <typename Matrix> void MatrixMarket_IO::read(Matrix &A) {
+ typedef typename linalg_traits<Matrix>::value_type T;
+ GMM_ASSERT1(f, "no file opened!");
+ GMM_ASSERT1(!is_complex_double__(T()) || isComplex,
+ "Bad MM matrix format (complex matrix expected)");
+ GMM_ASSERT1(is_complex_double__(T()) || !isComplex,
+ "Bad MM matrix format (real matrix expected)");
+ A = Matrix(row, col);
+ gmm::clear(A);
+
+ std::vector<int> I(nz), J(nz);
+ std::vector<typename Matrix::value_type> PR(nz);
+ mm_read_mtx_crd_data(f, row, col, nz, &I[0], &J[0],
+ (double*)&PR[0], matcode);
+
+ for (size_type i = 0; i < size_type(nz); ++i) A(I[i]-1, J[i]-1) = PR[i];
+ }
+
+ template <typename T, int shift> void
+ MatrixMarket_IO::write(const char *filename, const csc_matrix<T, shift>& A) {
+ write(filename, csc_matrix_ref<T*,unsigned*,unsigned*,shift>
+ (A.pr, A.ir, A.jc, A.nr, A.nc));
+ }
+
+ template <typename T, typename INDI, typename INDJ, int shift> void
+ MatrixMarket_IO::write(const char *filename,
+ const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A) {
+ static MM_typecode t1 = {'M', 'C', 'R', 'G'};
+ static MM_typecode t2 = {'M', 'C', 'C', 'G'};
+ MM_typecode t;
+
+ if (is_complex_double__(T())) std::copy(&(t2[0]), &(t2[0])+4, &(t[0]));
+ else std::copy(&(t1[0]), &(t1[0])+4, &(t[0]));
+ size_type nz = A.jc[mat_ncols(A)];
+ std::vector<int> I(nz), J(nz);
+ for (size_type j=0; j < mat_ncols(A); ++j) {
+ for (size_type i = A.jc[j]; i < A.jc[j+1]; ++i) {
+ I[i] = A.ir[i] + 1 - shift;
+ J[i] = j + 1;
+ }
+ }
+ mm_write_mtx_crd(filename, mat_nrows(A), mat_ncols(A),
+ nz, &I[0], &J[0], (const double *)A.pr, t);
+ }
+
+
+ template <typename MAT> void
+ MatrixMarket_IO::write(const char *filename, const MAT& A) {
+ gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type>
+ tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
+ gmm::copy(A,tmp);
+ MatrixMarket_IO::write(filename, tmp);
+ }
+
+ template<typename VEC> static void vecsave(std::string fname, const VEC& V) {
+ std::ofstream f(fname.c_str()); f.precision(16);
+ for (size_type i=0; i < gmm::vect_size(V); ++i) f << V[i] << "\n";
+ }
+
+ template<typename VEC> static void vecload(std::string fname,
+ const VEC& V_) {
+ VEC &V(const_cast<VEC&>(V_));
+ std::ifstream f(fname.c_str());
+ for (size_type i=0; i < gmm::vect_size(V); ++i) f >> V[i];
+ }
+}
+
+
+#endif // GMM_INOUTPUT_H
diff --git a/Contrib/gmm/gmm_interface.h b/Contrib/gmm/gmm_interface.h
new file mode 100755
index 0000000..d7693d6
--- /dev/null
+++ b/Contrib/gmm/gmm_interface.h
@@ -0,0 +1,1065 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+
+/**@file gmm_interface.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief gmm interface for STL vectors.
+*/
+
+#ifndef GMM_INTERFACE_H__
+#define GMM_INTERFACE_H__
+
+#include "gmm_blas.h"
+#include "gmm_sub_index.h"
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* */
+ /* What is needed for a Vector type : */
+ /* Vector v(n) defines a vector with n components. */
+ /* v[i] allows to access to the ith component of v. */
+ /* linalg_traits<Vector> should be filled with appropriate definitions */
+ /* */
+ /* for a dense vector : the minimum is two random iterators (begin and */
+ /* end) and a pointer to a valid origin. */
+ /* for a sparse vector : the minimum is two forward iterators, with */
+ /* a method it.index() which gives the index of */
+ /* a non zero element, an interface object */
+ /* should describe the method to add new non */
+ /* zero element, and a pointer to a valid */
+ /* origin. */
+ /* */
+ /* What is needed for a Matrix type : */
+ /* Matrix m(n, m) defines a matrix with n rows and m columns. */
+ /* m(i, j) allows to access to the element at row i and column j. */
+ /* linalg_traits<Matrix> should be filled with appropriate definitions */
+ /* */
+ /* What is needed for an iterator on dense vector */
+ /* to be standard random access iterator */
+ /* */
+ /* What is needed for an iterator on a sparse vector */
+ /* to be a standard bidirectional iterator */
+ /* elt should be sorted with increasing indices. */
+ /* it.index() gives the index of the non-zero element. */
+ /* */
+ /* Remark : If original iterators are not convenient, they could be */
+ /* redefined and interfaced in linalg_traits<Vector> without changing */
+ /* the original Vector type. */
+ /* */
+ /* ********************************************************************* */
+
+ /* ********************************************************************* */
+ /* Simple references on vectors */
+ /* ********************************************************************* */
+
+ template <typename PT> struct simple_vector_ref {
+ typedef simple_vector_ref<PT> this_type;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef V * CPT;
+ typedef typename std::iterator_traits<PT>::reference ref_V;
+ typedef typename linalg_traits<this_type>::iterator iterator;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ iterator begin_, end_;
+ porigin_type origin;
+ size_type size_;
+
+ simple_vector_ref(ref_V v) : begin_(vect_begin(const_cast<V&>(v))),
+ end_(vect_end(const_cast<V&>(v))),
+ origin(linalg_origin(const_cast<V&>(v))),
+ size_(vect_size(v)) {}
+
+ simple_vector_ref(const simple_vector_ref<CPT> &cr)
+ : begin_(cr.begin_),end_(cr.end_),origin(cr.origin),size_(cr.size_) {}
+
+ simple_vector_ref(void) {}
+
+ reference operator[](size_type i) const
+ { return linalg_traits<V>::access(origin, begin_, end_, i); }
+ };
+
+ template <typename IT, typename ORG, typename PT> inline
+ void set_to_begin(IT &it, ORG o, simple_vector_ref<PT> *,linalg_modifiable) {
+ typedef typename linalg_traits<simple_vector_ref<PT> >::V_reference ref_t;
+ set_to_begin(it, o, PT(), ref_t());
+ }
+
+ template <typename IT, typename ORG, typename PT> inline
+ void set_to_begin(IT &it, ORG o, const simple_vector_ref<PT> *,
+ linalg_modifiable) {
+ typedef typename linalg_traits<simple_vector_ref<PT> >::V_reference ref_t;
+ set_to_begin(it, o, PT(), ref_t());
+ }
+
+ template <typename IT, typename ORG, typename PT> inline
+ void set_to_end(IT &it, ORG o, simple_vector_ref<PT> *, linalg_modifiable) {
+ typedef typename linalg_traits<simple_vector_ref<PT> >::V_reference ref_t;
+ set_to_end(it, o, PT(), ref_t());
+ }
+
+ template <typename IT, typename ORG, typename PT> inline
+ void set_to_end(IT &it, ORG o, const simple_vector_ref<PT> *,
+ linalg_modifiable) {
+ typedef typename linalg_traits<simple_vector_ref<PT> >::V_reference ref_t;
+ set_to_end(it, o, PT(), ref_t());
+ }
+
+
+ template <typename PT> struct linalg_traits<simple_vector_ref<PT> > {
+ typedef simple_vector_ref<PT> this_type;
+ typedef this_type *pthis_type;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef V *pV;
+ typedef typename linalg_traits<V>::is_reference V_reference;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_vector linalg_type;
+ typedef typename linalg_traits<V>::value_type value_type;
+ typedef typename select_ref<value_type, typename
+ linalg_traits<V>::reference, PT>::ref_type reference;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+ typename linalg_traits<V>::iterator, PT>::ref_type iterator;
+ typedef typename linalg_traits<V>::const_iterator const_iterator;
+ typedef typename linalg_traits<V>::storage_type storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.size_; }
+ static inline iterator begin(this_type &v) {
+ iterator it = v.begin_;
+ set_to_begin(it, v.origin, pthis_type(), is_reference());
+ return it;
+ }
+ static inline const_iterator begin(const this_type &v) {
+ const_iterator it = v.begin_;
+ set_to_begin(it, v.origin, pthis_type(), is_reference());
+ return it;
+ }
+ static inline iterator end(this_type &v) {
+ iterator it = v.end_;
+ set_to_end(it, v.origin, pthis_type(), is_reference());
+ return it;
+ }
+ static inline const_iterator end(const this_type &v) {
+ const_iterator it = v.end_;
+ set_to_end(it, v.origin, pthis_type(), is_reference());
+ return it;
+ }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void clear(origin_type* o, const iterator &it, const iterator &ite)
+ { linalg_traits<V>::clear(o, it, ite); }
+ static void do_clear(this_type &v) { clear(v.origin, v.begin_, v.end_); }
+ static value_type access(const origin_type *o, const const_iterator &it,
+ const const_iterator &ite, size_type i)
+ { return linalg_traits<V>::access(o, it, ite, i); }
+ static reference access(origin_type *o, const iterator &it,
+ const iterator &ite, size_type i)
+ { return linalg_traits<V>::access(o, it, ite, i); }
+ };
+
+ template <typename PT>
+ std::ostream &operator << (std::ostream &o, const simple_vector_ref<PT>& v)
+ { gmm::write(o,v); return o; }
+
+ /* ********************************************************************* */
+ /* */
+ /* Traits for S.T.L. object */
+ /* */
+ /* ********************************************************************* */
+
+ template <typename T, typename alloc>
+ struct linalg_traits<std::vector<T, alloc> > {
+ typedef std::vector<T, alloc> this_type;
+ typedef this_type origin_type;
+ typedef linalg_false is_reference;
+ typedef abstract_vector linalg_type;
+ typedef T value_type;
+ typedef T& reference;
+ typedef typename this_type::iterator iterator;
+ typedef typename this_type::const_iterator const_iterator;
+ typedef abstract_dense storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v) { return v.begin(); }
+ static const_iterator begin(const this_type &v) { return v.begin(); }
+ static iterator end(this_type &v) { return v.end(); }
+ static const_iterator end(const this_type &v) { return v.end(); }
+ static origin_type* origin(this_type &v) { return &v; }
+ static const origin_type* origin(const this_type &v) { return &v; }
+ static void clear(origin_type*, const iterator &it, const iterator &ite)
+ { std::fill(it, ite, value_type(0)); }
+ static void do_clear(this_type &v) { std::fill(v.begin(), v.end(), T(0)); }
+ static value_type access(const origin_type *, const const_iterator &it,
+ const const_iterator &, size_type i)
+ { return it[i]; }
+ static reference access(origin_type *, const iterator &it,
+ const iterator &, size_type i)
+ { return it[i]; }
+ static void resize(this_type &v, size_type n) { v.resize(n); }
+ };
+}
+namespace std {
+ template <typename T> ostream &operator <<
+ (std::ostream &o, const vector<T>& m) { gmm::write(o,m); return o; }
+}
+namespace gmm {
+
+ template <typename T>
+ inline size_type nnz(const std::vector<T>& l) { return l.size(); }
+
+ /* ********************************************************************* */
+ /* */
+ /* Traits for ref objects */
+ /* */
+ /* ********************************************************************* */
+
+ template <typename IT, typename V>
+ struct tab_ref_with_origin : public gmm::tab_ref<IT> {
+ typedef tab_ref_with_origin<IT, V> this_type;
+ // next line replaced by the 4 following lines in order to please aCC
+ //typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef typename std::iterator_traits<IT>::pointer PT;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+
+
+ porigin_type origin;
+
+ tab_ref_with_origin(void) {}
+ template <class PT> tab_ref_with_origin(const IT &b, const IT &e, PT p)
+ : gmm::tab_ref<IT>(b,e), origin(porigin_type(p)) {}
+ tab_ref_with_origin(const IT &b, const IT &e, porigin_type p)
+ : gmm::tab_ref<IT>(b,e), origin(p) {}
+
+ tab_ref_with_origin(const V &v, const sub_interval &si)
+ : gmm::tab_ref<IT>(vect_begin(const_cast<V&>(v))+si.min,
+ vect_begin(const_cast<V&>(v))+si.max),
+ origin(linalg_origin(const_cast<V&>(v))) {}
+ tab_ref_with_origin(V &v, const sub_interval &si)
+ : gmm::tab_ref<IT>(vect_begin(const_cast<V&>(v))+si.min,
+ vect_begin(const_cast<V&>(v))+si.max),
+ origin(linalg_origin(const_cast<V&>(v))) {}
+ };
+
+ template <typename IT, typename V>
+ struct linalg_traits<tab_ref_with_origin<IT, V> > {
+ typedef typename std::iterator_traits<IT>::pointer PT;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef tab_ref_with_origin<IT, V> this_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_vector linalg_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename std::iterator_traits<IT>::value_type value_type;
+ typedef typename std::iterator_traits<IT>::reference reference;
+ typedef typename this_type::iterator iterator;
+ typedef typename this_type::iterator const_iterator;
+ typedef abstract_dense storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v) { return v.begin(); }
+ static const_iterator begin(const this_type &v) { return v.begin(); }
+ static iterator end(this_type &v) { return v.end(); }
+ static const_iterator end(const this_type &v) { return v.end(); }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void clear(origin_type*, const iterator &it, const iterator &ite)
+ { std::fill(it, ite, value_type(0)); }
+ static inline void do_clear(this_type &v)
+ { std::fill(v.begin(), v.end(), value_type(0)); }
+ static value_type access(const origin_type *, const const_iterator &it,
+ const const_iterator &, size_type i)
+ { return it[i]; }
+ static reference access(origin_type *, const iterator &it,
+ const iterator &, size_type i)
+ { return it[i]; }
+ };
+
+ template <typename IT, typename V> std::ostream &operator <<
+ (std::ostream &o, const tab_ref_with_origin<IT, V>& m)
+ { gmm::write(o,m); return o; }
+
+
+ template <typename IT, typename V>
+ struct tab_ref_reg_spaced_with_origin : public gmm::tab_ref_reg_spaced<IT> {
+ typedef tab_ref_reg_spaced_with_origin<IT, V> this_type;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ porigin_type origin;
+
+ tab_ref_reg_spaced_with_origin(void) {}
+ tab_ref_reg_spaced_with_origin(const IT &b, size_type n, size_type s,
+ const porigin_type p)
+ : gmm::tab_ref_reg_spaced<IT>(b,n,s), origin(p) {}
+ tab_ref_reg_spaced_with_origin(const V &v, const sub_slice &si)
+ : gmm::tab_ref_reg_spaced<IT>(vect_begin(const_cast<V&>(v)) + si.min,
+ si.N, (si.max - si.min)/si.N),
+ origin(linalg_origin(const_cast<V&>(v))) {}
+ tab_ref_reg_spaced_with_origin(V &v, const sub_slice &si)
+ : gmm::tab_ref_reg_spaced<IT>(vect_begin(const_cast<V&>(v)) + si.min,
+ si.N, (si.max - si.min)/si.N),
+ origin(linalg_origin(const_cast<V&>(v))) {}
+ };
+
+ template <typename IT, typename V>
+ struct linalg_traits<tab_ref_reg_spaced_with_origin<IT, V> > {
+ typedef typename std::iterator_traits<IT>::pointer PT;
+ typedef tab_ref_reg_spaced_with_origin<IT, V> this_type;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_vector linalg_type;
+ typedef typename std::iterator_traits<IT>::value_type value_type;
+ typedef typename std::iterator_traits<IT>::reference reference;
+ typedef typename this_type::iterator iterator;
+ typedef typename this_type::iterator const_iterator;
+ typedef abstract_dense storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v) { return v.begin(); }
+ static const_iterator begin(const this_type &v) { return v.begin(); }
+ static iterator end(this_type &v) { return v.end(); }
+ static const_iterator end(const this_type &v) { return v.end(); }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void clear(origin_type*, const iterator &it, const iterator &ite)
+ { std::fill(it, ite, value_type(0)); }
+ static void do_clear(this_type &v)
+ { std::fill(v.begin(), v.end(), value_type(0)); }
+ static value_type access(const origin_type *, const const_iterator &it,
+ const const_iterator &, size_type i)
+ { return it[i]; }
+ static reference access(origin_type *, const iterator &it,
+ const iterator &, size_type i)
+ { return it[i]; }
+ };
+
+ template <typename IT, typename V> std::ostream &operator <<
+ (std::ostream &o, const tab_ref_reg_spaced_with_origin<IT, V>& m)
+ { gmm::write(o,m); return o; }
+
+
+ template <typename IT, typename ITINDEX, typename V>
+ struct tab_ref_index_ref_with_origin
+ : public gmm::tab_ref_index_ref<IT, ITINDEX> {
+ typedef tab_ref_index_ref_with_origin<IT, ITINDEX, V> this_type;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ porigin_type origin;
+
+ tab_ref_index_ref_with_origin(void) {}
+ tab_ref_index_ref_with_origin(const IT &b, const ITINDEX &bi,
+ const ITINDEX &ei, porigin_type p)
+ : gmm::tab_ref_index_ref<IT, ITINDEX>(b, bi, ei), origin(p) {}
+
+ tab_ref_index_ref_with_origin(const V &v, const sub_index &si)
+ : gmm::tab_ref_index_ref<IT, ITINDEX>(vect_begin(const_cast<V&>(v)),
+ si.begin(), si.end()),
+ origin(linalg_origin(const_cast<V&>(v))) {}
+ tab_ref_index_ref_with_origin(V &v, const sub_index &si)
+ : gmm::tab_ref_index_ref<IT, ITINDEX>(vect_begin(const_cast<V&>(v)),
+ si.begin(), si.end()),
+ origin(linalg_origin(const_cast<V&>(v))) {}
+ };
+
+ template <typename IT, typename ITINDEX, typename V>
+ struct linalg_traits<tab_ref_index_ref_with_origin<IT, ITINDEX, V> > {
+ typedef typename std::iterator_traits<IT>::pointer PT;
+ typedef tab_ref_index_ref_with_origin<IT, ITINDEX, V> this_type;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_vector linalg_type;
+ typedef typename std::iterator_traits<IT>::value_type value_type;
+ typedef typename std::iterator_traits<IT>::reference reference;
+ typedef typename this_type::iterator iterator;
+ typedef typename this_type::iterator const_iterator;
+ typedef abstract_dense storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v) { return v.begin(); }
+ static const_iterator begin(const this_type &v) { return v.begin(); }
+ static iterator end(this_type &v) { return v.end(); }
+ static const_iterator end(const this_type &v) { return v.end(); }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void clear(origin_type*, const iterator &it, const iterator &ite)
+ { std::fill(it, ite, value_type(0)); }
+ static void do_clear(this_type &v)
+ { std::fill(v.begin(), v.end(), value_type(0)); }
+ static value_type access(const origin_type *, const const_iterator &it,
+ const const_iterator &, size_type i)
+ { return it[i]; }
+ static reference access(origin_type *, const iterator &it,
+ const iterator &, size_type i)
+ { return it[i]; }
+ };
+
+ template <typename IT, typename ITINDEX, typename V>
+ std::ostream &operator <<
+ (std::ostream &o, const tab_ref_index_ref_with_origin<IT, ITINDEX, V>& m)
+ { gmm::write(o,m); return o; }
+
+
+ template<typename ITER, typename MIT, typename PT>
+ struct dense_compressed_iterator {
+ typedef ITER value_type;
+ typedef ITER *pointer;
+ typedef ITER &reference;
+ typedef ptrdiff_t difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef dense_compressed_iterator<ITER, MIT, PT> iterator;
+ typedef typename std::iterator_traits<PT>::value_type *MPT;
+
+ ITER it;
+ size_type N, nrows, ncols, i;
+ PT origin;
+
+ iterator operator ++(int) { iterator tmp = *this; i++; return tmp; }
+ iterator operator --(int) { iterator tmp = *this; i--; return tmp; }
+ iterator &operator ++() { ++i; return *this; }
+ iterator &operator --() { --i; return *this; }
+ iterator &operator +=(difference_type ii) { i += ii; return *this; }
+ iterator &operator -=(difference_type ii) { i -= ii; return *this; }
+ iterator operator +(difference_type ii) const
+ { iterator itt = *this; return (itt += ii); }
+ iterator operator -(difference_type ii) const
+ { iterator itt = *this; return (itt -= ii); }
+ difference_type operator -(const iterator &ii) const
+ { return (N ? (it - ii.it) / N : 0) + i - ii.i; }
+
+ ITER operator *() const { return it+i*N; }
+ ITER operator [](int ii) const { return it + (i+ii) * N; }
+
+ bool operator ==(const iterator &ii) const
+ { return (*this - ii) == difference_type(0); }
+ bool operator !=(const iterator &ii) const { return !(ii == *this); }
+ bool operator < (const iterator &ii) const
+ { return (*this - ii) < difference_type(0); }
+
+ dense_compressed_iterator(void) {}
+ dense_compressed_iterator(const dense_compressed_iterator<MIT,MIT,MPT> &ii)
+ : it(ii.it), N(ii.N), nrows(ii.nrows), ncols(ii.ncols), i(ii.i),
+ origin(ii.origin) {}
+ dense_compressed_iterator(const ITER &iter, size_type n, size_type r,
+ size_type c, size_type ii, PT o)
+ : it(iter), N(n), nrows(r), ncols(c), i(ii), origin(o) { }
+
+ };
+
+ /* ******************************************************************** */
+ /* Read only reference on a compressed sparse vector */
+ /* ******************************************************************** */
+
+ template <typename PT1, typename PT2, int shift = 0>
+ struct cs_vector_ref_iterator {
+ PT1 pr;
+ PT2 ir;
+
+ typedef typename std::iterator_traits<PT1>::value_type value_type;
+ typedef PT1 pointer;
+ typedef typename std::iterator_traits<PT1>::reference reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef cs_vector_ref_iterator<PT1, PT2, shift> iterator;
+
+ cs_vector_ref_iterator(void) {}
+ cs_vector_ref_iterator(PT1 p1, PT2 p2) : pr(p1), ir(p2) {}
+
+ inline size_type index(void) const { return (*ir) - shift; }
+ iterator &operator ++() { ++pr; ++ir; return *this; }
+ iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+ iterator &operator --() { --pr; --ir; return *this; }
+ iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+
+ reference operator *() const { return *pr; }
+ pointer operator ->() const { return pr; }
+
+ bool operator ==(const iterator &i) const { return (i.pr==pr);}
+ bool operator !=(const iterator &i) const { return (i.pr!=pr);}
+ };
+
+ template <typename PT1, typename PT2, int shift = 0> struct cs_vector_ref {
+ PT1 pr;
+ PT2 ir;
+ size_type n, size_;
+
+ typedef cs_vector_ref<PT1, PT2, shift> this_type;
+ typedef typename std::iterator_traits<PT1>::value_type value_type;
+ typedef typename linalg_traits<this_type>::const_iterator const_iterator;
+
+ cs_vector_ref(PT1 pt1, PT2 pt2, size_type nnz, size_type ns)
+ : pr(pt1), ir(pt2), n(nnz), size_(ns) {}
+ cs_vector_ref(void) {}
+
+ size_type size(void) const { return size_; }
+
+ const_iterator begin(void) const { return const_iterator(pr, ir); }
+ const_iterator end(void) const { return const_iterator(pr+n, ir+n); }
+
+ value_type operator[](size_type i) const
+ { return linalg_traits<this_type>::access(pr, begin(), end(),i); }
+ };
+
+ template <typename PT1, typename PT2, int shift>
+ struct linalg_traits<cs_vector_ref<PT1, PT2, shift> > {
+ typedef cs_vector_ref<PT1, PT2, shift> this_type;
+ typedef linalg_const is_reference;
+ typedef abstract_vector linalg_type;
+ typedef typename std::iterator_traits<PT1>::value_type value_type;
+ typedef value_type origin_type;
+ typedef typename std::iterator_traits<PT1>::value_type reference;
+ typedef cs_vector_ref_iterator<typename const_pointer<PT1>::pointer,
+ typename const_pointer<PT2>::pointer, shift> const_iterator;
+ typedef abstract_null_type iterator;
+ typedef abstract_sparse storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v) { return v.begin(); }
+ static const_iterator begin(const this_type &v) { return v.begin(); }
+ static iterator end(this_type &v) { return v.end(); }
+ static const_iterator end(const this_type &v) { return v.end(); }
+ static const origin_type* origin(const this_type &v) { return v.pr; }
+ static value_type access(const origin_type *, const const_iterator &b,
+ const const_iterator &e, size_type i) {
+ if (b.ir == e.ir) return value_type(0);
+ PT2 p = std::lower_bound(b.ir, e.ir, i+shift);
+ return (*p == i+shift && p != e.ir) ? b.pr[p-b.ir] : value_type(0);
+ }
+ };
+
+ template <typename PT1, typename PT2, int shift>
+ std::ostream &operator <<
+ (std::ostream &o, const cs_vector_ref<PT1, PT2, shift>& m)
+ { gmm::write(o,m); return o; }
+
+ template <typename PT1, typename PT2, int shift>
+ inline size_type nnz(const cs_vector_ref<PT1, PT2, shift>& l) { return l.n; }
+
+ /* ******************************************************************** */
+ /* Read only reference on a compressed sparse column matrix */
+ /* ******************************************************************** */
+
+ template <typename PT1, typename PT2, typename PT3, int shift = 0>
+ struct sparse_compressed_iterator {
+ typedef typename std::iterator_traits<PT1>::value_type value_type;
+ typedef const value_type *pointer;
+ typedef const value_type &reference;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef sparse_compressed_iterator<PT1, PT2, PT3, shift> iterator;
+
+ PT1 pr;
+ PT2 ir;
+ PT3 jc;
+ size_type n;
+ const value_type *origin;
+
+ iterator operator ++(int) { iterator tmp = *this; jc++; return tmp; }
+ iterator operator --(int) { iterator tmp = *this; jc--; return tmp; }
+ iterator &operator ++() { jc++; return *this; }
+ iterator &operator --() { jc--; return *this; }
+ iterator &operator +=(difference_type i) { jc += i; return *this; }
+ iterator &operator -=(difference_type i) { jc -= i; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator itt = *this; return (itt += i); }
+ iterator operator -(difference_type i) const
+ { iterator itt = *this; return (itt -= i); }
+ difference_type operator -(const iterator &i) const { return jc - i.jc; }
+
+ reference operator *() const { return pr + *jc - shift; }
+ reference operator [](int ii) { return pr + *(jc+ii) - shift; }
+
+ bool operator ==(const iterator &i) const { return (jc == i.jc); }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+ bool operator < (const iterator &i) const { return (jc < i.jc); }
+
+ sparse_compressed_iterator(void) {}
+ sparse_compressed_iterator(PT1 p1, PT2 p2, PT3 p3, size_type nn,
+ const value_type *o)
+ : pr(p1), ir(p2), jc(p3), n(nn), origin(o) { }
+
+ };
+
+ template <typename PT1, typename PT2, typename PT3, int shift = 0>
+ struct csc_matrix_ref {
+ PT1 pr; // values.
+ PT2 ir; // row indexes.
+ PT3 jc; // column repartition on pr and ir.
+ size_type nc, nr;
+
+ typedef typename std::iterator_traits<PT1>::value_type value_type;
+ csc_matrix_ref(PT1 pt1, PT2 pt2, PT3 pt3, size_type nrr, size_type ncc)
+ : pr(pt1), ir(pt2), jc(pt3), nc(ncc), nr(nrr) {}
+ csc_matrix_ref(void) {}
+
+ size_type nrows(void) const { return nr; }
+ size_type ncols(void) const { return nc; }
+
+ value_type operator()(size_type i, size_type j) const
+ { return mat_col(*this, j)[i]; }
+ };
+
+ template <typename PT1, typename PT2, typename PT3, int shift>
+ struct linalg_traits<csc_matrix_ref<PT1, PT2, PT3, shift> > {
+ typedef csc_matrix_ref<PT1, PT2, PT3, shift> this_type;
+ typedef linalg_const is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename std::iterator_traits<PT1>::value_type value_type;
+ typedef typename std::iterator_traits<PT1>::value_type reference;
+ typedef value_type origin_type;
+ typedef abstract_sparse storage_type;
+ typedef abstract_null_type sub_row_type;
+ typedef abstract_null_type const_sub_row_type;
+ typedef abstract_null_type row_iterator;
+ typedef abstract_null_type const_row_iterator;
+ typedef abstract_null_type sub_col_type;
+ typedef cs_vector_ref<typename const_pointer<PT1>::pointer,
+ typename const_pointer<PT2>::pointer, shift> const_sub_col_type;
+ typedef sparse_compressed_iterator<typename const_pointer<PT1>::pointer,
+ typename const_pointer<PT2>::pointer,
+ typename const_pointer<PT3>::pointer,
+ shift> const_col_iterator;
+ typedef abstract_null_type col_iterator;
+ typedef col_major sub_orientation;
+ typedef linalg_true index_sorted;
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static const_col_iterator col_begin(const this_type &m)
+ { return const_col_iterator(m.pr, m.ir, m.jc, m.nr, m.pr); }
+ static const_col_iterator col_end(const this_type &m)
+ { return const_col_iterator(m.pr, m.ir, m.jc + m.nc, m.nr, m.pr); }
+ static const_sub_col_type col(const const_col_iterator &it) {
+ return const_sub_col_type(it.pr + *(it.jc) - shift,
+ it.ir + *(it.jc) - shift, *(it.jc + 1) - *(it.jc), it.n);
+ }
+ static const origin_type* origin(const this_type &m) { return m.pr; }
+ static value_type access(const const_col_iterator &itcol, size_type j)
+ { return col(itcol)[j]; }
+ };
+
+
+ template <typename PT1, typename PT2, typename PT3, int shift>
+ std::ostream &operator <<
+ (std::ostream &o, const csc_matrix_ref<PT1, PT2, PT3, shift>& m)
+ { gmm::write(o,m); return o; }
+
+ /* ******************************************************************** */
+ /* Read only reference on a compressed sparse row matrix */
+ /* ******************************************************************** */
+
+ template <typename PT1, typename PT2, typename PT3, int shift = 0>
+ struct csr_matrix_ref {
+ PT1 pr; // values.
+ PT2 ir; // column indexes.
+ PT3 jc; // row repartition on pr and ir.
+ size_type nc, nr;
+
+ typedef typename std::iterator_traits<PT1>::value_type value_type;
+ csr_matrix_ref(PT1 pt1, PT2 pt2, PT3 pt3, size_type nrr, size_type ncc)
+ : pr(pt1), ir(pt2), jc(pt3), nc(ncc), nr(nrr) {}
+ csr_matrix_ref(void) {}
+
+ size_type nrows(void) const { return nr; }
+ size_type ncols(void) const { return nc; }
+
+ value_type operator()(size_type i, size_type j) const
+ { return mat_col(*this, i)[j]; }
+ };
+
+ template <typename PT1, typename PT2, typename PT3, int shift>
+ struct linalg_traits<csr_matrix_ref<PT1, PT2, PT3, shift> > {
+ typedef csr_matrix_ref<PT1, PT2, PT3, shift> this_type;
+ typedef linalg_const is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename std::iterator_traits<PT1>::value_type value_type;
+ typedef typename std::iterator_traits<PT1>::value_type reference;
+ typedef value_type origin_type;
+ typedef abstract_sparse storage_type;
+ typedef abstract_null_type sub_col_type;
+ typedef abstract_null_type const_sub_col_type;
+ typedef abstract_null_type col_iterator;
+ typedef abstract_null_type const_col_iterator;
+ typedef abstract_null_type sub_row_type;
+ typedef cs_vector_ref<typename const_pointer<PT1>::pointer,
+ typename const_pointer<PT2>::pointer, shift>
+ const_sub_row_type;
+ typedef sparse_compressed_iterator<typename const_pointer<PT1>::pointer,
+ typename const_pointer<PT2>::pointer,
+ typename const_pointer<PT3>::pointer,
+ shift> const_row_iterator;
+ typedef abstract_null_type row_iterator;
+ typedef row_major sub_orientation;
+ typedef linalg_true index_sorted;
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static const_row_iterator row_begin(const this_type &m)
+ { return const_row_iterator(m.pr, m.ir, m.jc, m.nc, m.pr); }
+ static const_row_iterator row_end(const this_type &m)
+ { return const_row_iterator(m.pr, m.ir, m.jc + m.nr, m.nc, m.pr); }
+ static const_sub_row_type row(const const_row_iterator &it) {
+ return const_sub_row_type(it.pr + *(it.jc) - shift,
+ it.ir + *(it.jc) - shift, *(it.jc + 1) - *(it.jc), it.n);
+ }
+ static const origin_type* origin(const this_type &m) { return m.pr; }
+ static value_type access(const const_row_iterator &itrow, size_type j)
+ { return row(itrow)[j]; }
+ };
+
+ template <typename PT1, typename PT2, typename PT3, int shift>
+ std::ostream &operator <<
+ (std::ostream &o, const csr_matrix_ref<PT1, PT2, PT3, shift>& m)
+ { gmm::write(o,m); return o; }
+
+ /* ********************************************************************* */
+ /* */
+ /* Simple interface for C arrays */
+ /* */
+ /* ********************************************************************* */
+
+ template <class PT> struct array1D_reference {
+
+ typedef typename std::iterator_traits<PT>::value_type value_type;
+
+ PT begin, end;
+
+ const value_type &operator[](size_type i) const { return *(begin+i); }
+ value_type &operator[](size_type i) { return *(begin+i); }
+
+ array1D_reference(PT begin_, size_type s) : begin(begin_), end(begin_+s) {}
+ };
+
+ template <typename PT>
+ struct linalg_traits<array1D_reference<PT> > {
+ typedef array1D_reference<PT> this_type;
+ typedef this_type origin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_vector linalg_type;
+ typedef typename std::iterator_traits<PT>::value_type value_type;
+ typedef typename std::iterator_traits<PT>::reference reference;
+ typedef PT iterator;
+ typedef PT const_iterator;
+ typedef abstract_dense storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.end - v.begin; }
+ static iterator begin(this_type &v) { return v.begin; }
+ static const_iterator begin(const this_type &v) { return v.begin; }
+ static iterator end(this_type &v) { return v.end; }
+ static const_iterator end(const this_type &v) { return v.end; }
+ static origin_type* origin(this_type &v) { return &v; }
+ static const origin_type* origin(const this_type &v) { return &v; }
+ static void clear(origin_type*, const iterator &it, const iterator &ite)
+ { std::fill(it, ite, value_type(0)); }
+ static void do_clear(this_type &v)
+ { std::fill(v.begin, v.end, value_type(0)); }
+ static value_type access(const origin_type *, const const_iterator &it,
+ const const_iterator &, size_type i)
+ { return it[i]; }
+ static reference access(origin_type *, const iterator &it,
+ const iterator &, size_type i)
+ { return it[i]; }
+ static void resize(this_type &, size_type )
+ { GMM_ASSERT1(false, "Not resizable vector"); }
+ };
+
+ template<typename PT> std::ostream &operator <<
+ (std::ostream &o, const array1D_reference<PT>& v)
+ { gmm::write(o,v); return o; }
+
+ template <class PT> struct array2D_col_reference {
+
+ typedef typename std::iterator_traits<PT>::value_type T;
+ typedef typename std::iterator_traits<PT>::reference reference;
+ typedef typename const_reference<reference>::reference const_reference;
+ typedef PT iterator;
+ typedef typename const_pointer<PT>::pointer const_iterator;
+
+ PT begin_;
+ size_type nbl, nbc;
+
+ inline const_reference operator ()(size_type l, size_type c) const {
+ GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+ return *(begin_ + c*nbl+l);
+ }
+ inline reference operator ()(size_type l, size_type c) {
+ GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+ return *(begin_ + c*nbl+l);
+ }
+
+ void resize(size_type, size_type);
+ void reshape(size_type m, size_type n) {
+ GMM_ASSERT2(n*m == nbl*nbc, "dimensions mismatch");
+ nbl = m; nbc = n;
+ }
+
+ void fill(T a, T b = T(0)) {
+ std::fill(begin_, end+nbc*nbl, b);
+ iterator p = begin_, e = end+nbc*nbl;
+ while (p < e) { *p = a; p += nbl+1; }
+ }
+ inline size_type nrows(void) const { return nbl; }
+ inline size_type ncols(void) const { return nbc; }
+
+ iterator begin(void) { return begin_; }
+ const_iterator begin(void) const { return begin_; }
+ iterator end(void) { return begin_+nbl*nbc; }
+ const_iterator end(void) const { return begin_+nbl*nbc; }
+
+ array2D_col_reference(PT begin__, size_type nrows_, size_type ncols_)
+ : begin_(begin__), nbl(nrows_), nbc(ncols_) {}
+ };
+
+ template <typename PT> struct linalg_traits<array2D_col_reference<PT> > {
+ typedef array2D_col_reference<PT> this_type;
+ typedef this_type origin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename std::iterator_traits<PT>::value_type value_type;
+ typedef typename std::iterator_traits<PT>::reference reference;
+ typedef abstract_dense storage_type;
+ typedef tab_ref_reg_spaced_with_origin<typename this_type::iterator,
+ this_type> sub_row_type;
+ typedef tab_ref_reg_spaced_with_origin<typename this_type::const_iterator,
+ this_type> const_sub_row_type;
+ typedef dense_compressed_iterator<typename this_type::iterator,
+ typename this_type::iterator,
+ this_type *> row_iterator;
+ typedef dense_compressed_iterator<typename this_type::const_iterator,
+ typename this_type::iterator,
+ const this_type *> const_row_iterator;
+ typedef tab_ref_with_origin<typename this_type::iterator,
+ this_type> sub_col_type;
+ typedef tab_ref_with_origin<typename this_type::const_iterator,
+ this_type> const_sub_col_type;
+ typedef dense_compressed_iterator<typename this_type::iterator,
+ typename this_type::iterator,
+ this_type *> col_iterator;
+ typedef dense_compressed_iterator<typename this_type::const_iterator,
+ typename this_type::iterator,
+ const this_type *> const_col_iterator;
+ typedef col_and_row sub_orientation;
+ typedef linalg_true index_sorted;
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static const_sub_row_type row(const const_row_iterator &it)
+ { return const_sub_row_type(*it, it.nrows, it.ncols, it.origin); }
+ static const_sub_col_type col(const const_col_iterator &it)
+ { return const_sub_col_type(*it, *it + it.nrows, it.origin); }
+ static sub_row_type row(const row_iterator &it)
+ { return sub_row_type(*it, it.nrows, it.ncols, it.origin); }
+ static sub_col_type col(const col_iterator &it)
+ { return sub_col_type(*it, *it + it.nrows, it.origin); }
+ static row_iterator row_begin(this_type &m)
+ { return row_iterator(m.begin(), 1, m.nrows(), m.ncols(), 0, &m); }
+ static row_iterator row_end(this_type &m)
+ { return row_iterator(m.begin(), 1, m.nrows(), m.ncols(), m.nrows(), &m); }
+ static const_row_iterator row_begin(const this_type &m)
+ { return const_row_iterator(m.begin(), 1, m.nrows(), m.ncols(), 0, &m); }
+ static const_row_iterator row_end(const this_type &m) {
+ return const_row_iterator(m.begin(), 1, m.nrows(),
+ m.ncols(), m.nrows(), &m);
+ }
+ static col_iterator col_begin(this_type &m)
+ { return col_iterator(m.begin(), m.nrows(), m.nrows(), m.ncols(), 0, &m); }
+ static col_iterator col_end(this_type &m) {
+ return col_iterator(m.begin(), m.nrows(), m.nrows(), m.ncols(),
+ m.ncols(), &m);
+ }
+ static const_col_iterator col_begin(const this_type &m) {
+ return const_col_iterator(m.begin(), m.nrows(), m.nrows(),
+ m.ncols(), 0, &m);
+ }
+ static const_col_iterator col_end(const this_type &m) {
+ return const_col_iterator(m.begin(), m.nrows(),m.nrows(),m.ncols(),
+ m.ncols(), &m);
+ }
+ static origin_type* origin(this_type &m) { return &m; }
+ static const origin_type* origin(const this_type &m) { return &m; }
+ static void do_clear(this_type &m) { m.fill(value_type(0)); }
+ static value_type access(const const_col_iterator &itcol, size_type j)
+ { return (*itcol)[j]; }
+ static reference access(const col_iterator &itcol, size_type j)
+ { return (*itcol)[j]; }
+ static void resize(this_type &v, size_type m, size_type n)
+ { v.resize(m,n); }
+ static void reshape(this_type &v, size_type m, size_type n)
+ { v.reshape(m, n); }
+ };
+
+ template<typename PT> std::ostream &operator <<
+ (std::ostream &o, const array2D_col_reference<PT>& m)
+ { gmm::write(o,m); return o; }
+
+
+
+ template <class PT> struct array2D_row_reference {
+
+ typedef typename std::iterator_traits<PT>::value_type T;
+ typedef typename std::iterator_traits<PT>::reference reference;
+ typedef typename const_reference<reference>::reference const_reference;
+ typedef PT iterator;
+ typedef typename const_pointer<PT>::pointer const_iterator;
+
+ PT begin_;
+ size_type nbl, nbc;
+
+ inline const_reference operator ()(size_type l, size_type c) const {
+ GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+ return *(begin_ + l*nbc+c);
+ }
+ inline reference operator ()(size_type l, size_type c) {
+ GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+ return *(begin_ + l*nbc+c);
+ }
+
+ void resize(size_type, size_type);
+ void reshape(size_type m, size_type n) {
+ GMM_ASSERT2(n*m == nbl*nbc, "dimensions mismatch");
+ nbl = m; nbc = n;
+ }
+
+ void fill(T a, T b = T(0)) {
+ std::fill(begin_, end+nbc*nbl, b);
+ iterator p = begin_, e = end+nbc*nbl;
+ while (p < e) { *p = a; p += nbc+1; }
+ }
+ inline size_type nrows(void) const { return nbl; }
+ inline size_type ncols(void) const { return nbc; }
+
+ iterator begin(void) { return begin_; }
+ const_iterator begin(void) const { return begin_; }
+ iterator end(void) { return begin_+nbl*nbc; }
+ const_iterator end(void) const { return begin_+nbl*nbc; }
+
+ array2D_row_reference(PT begin__, size_type nrows_, size_type ncols_)
+ : begin_(begin__), nbl(nrows_), nbc(ncols_) {}
+ };
+
+ template <typename PT> struct linalg_traits<array2D_row_reference<PT> > {
+ typedef array2D_row_reference<PT> this_type;
+ typedef this_type origin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename std::iterator_traits<PT>::value_type value_type;
+ typedef typename std::iterator_traits<PT>::reference reference;
+ typedef abstract_dense storage_type;
+ typedef tab_ref_reg_spaced_with_origin<typename this_type::iterator,
+ this_type> sub_col_type;
+ typedef tab_ref_reg_spaced_with_origin<typename this_type::const_iterator,
+ this_type> const_sub_col_type;
+ typedef dense_compressed_iterator<typename this_type::iterator,
+ typename this_type::iterator,
+ this_type *> col_iterator;
+ typedef dense_compressed_iterator<typename this_type::const_iterator,
+ typename this_type::iterator,
+ const this_type *> const_col_iterator;
+ typedef tab_ref_with_origin<typename this_type::iterator,
+ this_type> sub_row_type;
+ typedef tab_ref_with_origin<typename this_type::const_iterator,
+ this_type> const_sub_row_type;
+ typedef dense_compressed_iterator<typename this_type::iterator,
+ typename this_type::iterator,
+ this_type *> row_iterator;
+ typedef dense_compressed_iterator<typename this_type::const_iterator,
+ typename this_type::iterator,
+ const this_type *> const_row_iterator;
+ typedef col_and_row sub_orientation;
+ typedef linalg_true index_sorted;
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static const_sub_col_type col(const const_col_iterator &it)
+ { return const_sub_col_type(*it, it.ncols, it.nrows, it.origin); }
+ static const_sub_row_type row(const const_row_iterator &it)
+ { return const_sub_row_type(*it, *it + it.ncols, it.origin); }
+ static sub_col_type col(const col_iterator &it)
+ { return sub_col_type(*it, *it, it.ncols, it.nrows, it.origin); }
+ static sub_row_type row(const row_iterator &it)
+ { return sub_row_type(*it, *it + it.ncols, it.origin); }
+ static col_iterator col_begin(this_type &m)
+ { return col_iterator(m.begin(), 1, m.ncols(), m.nrows(), 0, &m); }
+ static col_iterator col_end(this_type &m)
+ { return col_iterator(m.begin(), 1, m.ncols(), m.nrows(), m.ncols(), &m); }
+ static const_col_iterator col_begin(const this_type &m)
+ { return const_col_iterator(m.begin(), 1, m.ncols(), m.nrows(), 0, &m); }
+ static const_col_iterator col_end(const this_type &m) {
+ return const_col_iterator(m.begin(), 1, m.ncols(),
+ m.nrows(), m.ncols(), &m);
+ }
+ static row_iterator row_begin(this_type &m)
+ { return row_iterator(m.begin(), m.ncols(), m.ncols(), m.nrows(), 0, &m); }
+ static row_iterator row_end(this_type &m) {
+ return row_iterator(m.begin(), m.ncols(), m.ncols(), m.nrows(),
+ m.nrows(), &m);
+ }
+ static const_row_iterator row_begin(const this_type &m) {
+ return const_row_iterator(m.begin(), m.ncols(), m.ncols(), m.nrows(),
+ 0, &m);
+ }
+ static const_row_iterator row_end(const this_type &m) {
+ return const_row_iterator(m.begin(), m.ncols(), m.ncols(), m.nrows(),
+ m.nrows(), &m);
+ }
+ static origin_type* origin(this_type &m) { return &m; }
+ static const origin_type* origin(const this_type &m) { return &m; }
+ static void do_clear(this_type &m) { m.fill(value_type(0)); }
+ static value_type access(const const_row_iterator &itrow, size_type j)
+ { return (*itrow)[j]; }
+ static reference access(const row_iterator &itrow, size_type j)
+ { return (*itrow)[j]; }
+ static void resize(this_type &v, size_type m, size_type n)
+ { v.resize(m,n); }
+ static void reshape(this_type &v, size_type m, size_type n)
+ { v.reshape(m, n); }
+ };
+
+ template<typename PT> std::ostream &operator <<
+ (std::ostream &o, const array2D_row_reference<PT>& m)
+ { gmm::write(o,m); return o; }
+
+
+
+
+
+
+}
+
+
+#endif // GMM_INTERFACE_H__
diff --git a/Contrib/gmm/gmm_interface_bgeot.h b/Contrib/gmm/gmm_interface_bgeot.h
new file mode 100755
index 0000000..baa8e77
--- /dev/null
+++ b/Contrib/gmm/gmm_interface_bgeot.h
@@ -0,0 +1,82 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_interface_bgeot.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief interface for bgeot::small_vector
+*/
+#ifndef GMM_INTERFACE_BGEOT_H__
+#define GMM_INTERFACE_BGEOT_H__
+
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* */
+ /* Traits for bgeot objects */
+ /* */
+ /* ********************************************************************* */
+
+ template <typename T> struct linalg_traits<bgeot::small_vector<T> > {
+ typedef bgeot::small_vector<T> this_type;
+ typedef this_type origin_type;
+ typedef linalg_false is_reference;
+ typedef abstract_vector linalg_type;
+ typedef T value_type;
+ typedef T& reference;
+ typedef typename this_type::iterator iterator;
+ typedef typename this_type::const_iterator const_iterator;
+ typedef abstract_dense storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v) { return v.begin(); }
+ static const_iterator begin(const this_type &v) { return v.begin(); }
+ static iterator end(this_type &v) { return v.end(); }
+ static const_iterator end(const this_type &v) { return v.end(); }
+ static origin_type* origin(this_type &v) { return &v; }
+ static const origin_type* origin(const this_type &v) { return &v; }
+ static void clear(origin_type* o, const iterator &it, const iterator &ite)
+ { std::fill(it, ite, value_type(0)); }
+ static void do_clear(this_type &v)
+ { std::fill(v.begin(), v.end(), value_type(0)); }
+ static value_type access(const origin_type *, const const_iterator &it,
+ const const_iterator &, size_type i)
+ { return it[i]; }
+ static reference access(origin_type *, const iterator &it,
+ const iterator &, size_type i)
+ { return it[i]; }
+ static void resize(this_type &v, size_type n) { v.resize(n); }
+ };
+
+}
+
+
+#endif // GMM_INTERFACE_BGEOT_H__
diff --git a/Contrib/gmm/gmm_iter.h b/Contrib/gmm/gmm_iter.h
new file mode 100755
index 0000000..3a593db
--- /dev/null
+++ b/Contrib/gmm/gmm_iter.h
@@ -0,0 +1,139 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_iter.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date February 10, 2003.
+ @brief Iteration object.
+*/
+
+#ifndef GMM_ITER_H__
+#define GMM_ITER_H__
+
+#include "gmm_kernel.h"
+
+namespace gmm {
+
+ /** The Iteration object calculates whether the solution has reached the
+ desired accuracy, or whether the maximum number of iterations has
+ been reached.
+
+ The method finished() checks the convergence. The first()
+ method is used to determine the first iteration of the loop.
+ */
+ class iteration {
+ protected :
+ double rhsn; /* Right hand side norm. */
+ size_type maxiter; /* Max. number of iterations. */
+ int noise; /* if noise > 0 iterations are printed. */
+ double resmax; /* maximum residu. */
+ double resminreach, resadd;
+ size_type nit; /* iteration number. */
+ double res; /* last computed residu. */
+ std::string name; /* eventually, name of the method. */
+ bool written;
+ void (*callback)(const gmm::iteration&);
+ public :
+
+ void init(void) {
+ nit = 0; res = 0.0; written = false;
+ resminreach = 1E50; resadd = 0.0;
+ callback = 0;
+ }
+
+ iteration(double r = 1.0E-8, int noi = 0, size_type mit = size_type(-1))
+ : rhsn(1.0), maxiter(mit), noise(noi), resmax(r) { init(); }
+
+ void operator ++(int) { nit++; written = false; resadd += res; }
+ void operator ++() { (*this)++; }
+
+ bool first(void) { return nit == 0; }
+
+ /* get/set the "noisyness" (verbosity) of the solvers */
+ int get_noisy(void) const { return noise; }
+ void set_noisy(int n) { noise = n; }
+ void reduce_noisy(void) { if (noise > 0) noise--; }
+
+ double get_resmax(void) const { return resmax; }
+ void set_resmax(double r) { resmax = r; }
+
+ double get_res() const { return res; }
+
+ /* change the user-definable callback, called after each iteration */
+ void set_callback(void (*t)(const gmm::iteration&)) {
+ callback = t;
+ }
+
+ size_type get_iteration(void) const { return nit; }
+ void set_iteration(size_type i) { nit = i; }
+
+ size_type get_maxiter(void) const { return maxiter; }
+ void set_maxiter(size_type i) { maxiter = i; }
+
+ double get_rhsnorm(void) const { return rhsn; }
+ void set_rhsnorm(double r) { rhsn = r; }
+
+ bool converged(void) { return res <= rhsn * resmax; }
+ bool converged(double nr) {
+ res = gmm::abs(nr); resminreach = std::min(resminreach, res);
+ return converged();
+ }
+ template <typename VECT> bool converged(const VECT &v)
+ { return converged(gmm::vect_norm2(v)); }
+
+ bool finished(double nr) {
+ if (callback) callback(*this);
+ if (noise > 0 && !written) {
+ double a = (rhsn == 0) ? 1.0 : rhsn;
+ converged(nr);
+ cout << name << " iter " << nit << " residual "
+ << gmm::abs(nr) / a;
+// if (nit % 100 == 0 && nit > 0) {
+// cout << " (residual min " << resminreach / a << " mean val "
+// << resadd / (100.0 * a) << " )";
+// resadd = 0.0;
+// }
+ cout << endl;
+ written = true;
+ }
+ return (nit >= maxiter || converged(nr));
+ }
+ template <typename VECT> bool finished_vect(const VECT &v)
+ { return finished(double(gmm::vect_norm2(v))); }
+
+
+ void set_name(const std::string &n) { name = n; }
+ const std::string &get_name(void) const { return name; }
+
+ };
+
+}
+
+#endif /* GMM_ITER_H__ */
diff --git a/Contrib/gmm/gmm_iter_solvers.h b/Contrib/gmm/gmm_iter_solvers.h
new file mode 100755
index 0000000..4e782c7
--- /dev/null
+++ b/Contrib/gmm/gmm_iter_solvers.h
@@ -0,0 +1,109 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_iter_solvers.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief Include standard gmm iterative solvers (cg, gmres, ...)
+*/
+#ifndef GMM_ITER_SOLVERS_H__
+#define GMM_ITER_SOLVERS_H__
+
+#include "gmm_iter.h"
+
+
+namespace gmm {
+
+ /** mixed method to find a zero of a real function G, a priori
+ * between a and b. If the zero is not between a and b, iterations
+ * of secant are applied. When a convenient interval is found,
+ * iterations of dichotomie and regula falsi are applied.
+ */
+ template <typename FUNC, typename T>
+ T find_root(const FUNC &G, T a = T(0), T b = T(1),
+ T tol = gmm::default_tol(T())) {
+ T c, Ga = G(a), Gb = G(b), Gc, d;
+ d = gmm::abs(b - a);
+#if 0
+ for (int i = 0; i < 4; i++) { /* secant iterations. */
+ if (d < tol) return (b + a) / 2.0;
+ c = b - Gb * (b - a) / (Gb - Ga); Gc = G(c);
+ a = b; b = c; Ga = Gb; Gb = Gc;
+ d = gmm::abs(b - a);
+ }
+#endif
+ while (Ga * Gb > 0.0) { /* secant iterations. */
+ if (d < tol) return (b + a) / 2.0;
+ c = b - Gb * (b - a) / (Gb - Ga); Gc = G(c);
+ a = b; b = c; Ga = Gb; Gb = Gc;
+ d = gmm::abs(b - a);
+ }
+
+ c = std::max(a, b); a = std::min(a, b); b = c;
+ while (d > tol) {
+ c = b - (b - a) * (Gb / (Gb - Ga)); /* regula falsi. */
+ if (c > b) c = b; if (c < a) c = a;
+ Gc = G(c);
+ if (Gc*Gb > 0) { b = c; Gb = Gc; } else { a = c; Ga = Gc; }
+ c = (b + a) / 2.0 ; Gc = G(c); /* Dichotomie. */
+ if (Gc*Gb > 0) { b = c; Gb = Gc; } else { a = c; Ga = Gc; }
+ d = gmm::abs(b - a); c = (b + a) / 2.0; if ((c == a) || (c == b)) d = 0.0;
+ }
+ return (b + a) / 2.0;
+ }
+
+}
+
+#include "gmm_precond_diagonal.h"
+#include "gmm_precond_ildlt.h"
+#include "gmm_precond_ildltt.h"
+#include "gmm_precond_mr_approx_inverse.h"
+#include "gmm_precond_ilu.h"
+#include "gmm_precond_ilut.h"
+#include "gmm_precond_ilutp.h"
+
+
+
+#include "gmm_solver_cg.h"
+#include "gmm_solver_bicgstab.h"
+#include "gmm_solver_qmr.h"
+#include "gmm_solver_constrained_cg.h"
+#include "gmm_solver_Schwarz_additive.h"
+#include "gmm_modified_gram_schmidt.h"
+#include "gmm_tri_solve.h"
+#include "gmm_solver_gmres.h"
+#include "gmm_solver_bfgs.h"
+#include "gmm_least_squares_cg.h"
+
+// #include "gmm_solver_idgmres.h"
+
+
+
+#endif // GMM_ITER_SOLVERS_H__
diff --git a/Contrib/gmm/gmm_kernel.h b/Contrib/gmm/gmm_kernel.h
new file mode 100755
index 0000000..e8fd9a4
--- /dev/null
+++ b/Contrib/gmm/gmm_kernel.h
@@ -0,0 +1,53 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_kernel.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date November 15, 2003.
+ @brief Include the base gmm files.
+ */
+
+#ifndef GMM_KERNEL_H__
+#define GMM_KERNEL_H__
+
+#include "gmm_def.h"
+#include "gmm_blas.h"
+#include "gmm_real_part.h"
+#include "gmm_interface.h"
+#include "gmm_sub_vector.h"
+#include "gmm_sub_matrix.h"
+#include "gmm_vector_to_matrix.h"
+#include "gmm_vector.h"
+#include "gmm_matrix.h"
+#include "gmm_tri_solve.h"
+#include "gmm_blas_interface.h"
+
+
+#endif // GMM_KERNEL_H__
diff --git a/Contrib/gmm/gmm_lapack_interface.h b/Contrib/gmm/gmm_lapack_interface.h
new file mode 100755
index 0000000..ea5edb4
--- /dev/null
+++ b/Contrib/gmm/gmm_lapack_interface.h
@@ -0,0 +1,362 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_lapack_interface.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 7, 2003.
+ @brief gmm interface for LAPACK
+*/
+
+#if defined(GMM_USES_LAPACK) || defined(GMM_USES_ATLAS)
+
+#ifndef GMM_LAPACK_INTERFACE_H
+#define GMM_LAPACK_INTERFACE_H
+
+#include "gmm_blas_interface.h"
+#include "gmm_dense_lu.h"
+#include "gmm_dense_qr.h"
+
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* Operations interfaced for T = float, double, std::complex<float> */
+ /* or std::complex<double> : */
+ /* */
+ /* lu_factor(dense_matrix<T>, std::vector<int>) */
+ /* lu_solve(dense_matrix<T>, std::vector<T>, std::vector<T>) */
+ /* lu_solve(dense_matrix<T>, std::vector<int>, std::vector<T>, */
+ /* std::vector<T>) */
+ /* lu_solve_transposed(dense_matrix<T>, std::vector<int>, std::vector<T>,*/
+ /* std::vector<T>) */
+ /* lu_inverse(dense_matrix<T>) */
+ /* lu_inverse(dense_matrix<T>, std::vector<int>, dense_matrix<T>) */
+ /* */
+ /* qr_factor(dense_matrix<T>, dense_matrix<T>, dense_matrix<T>) */
+ /* */
+ /* implicit_qr_algorithm(dense_matrix<T>, std::vector<T>) */
+ /* implicit_qr_algorithm(dense_matrix<T>, std::vector<T>, */
+ /* dense_matrix<T>) */
+ /* implicit_qr_algorithm(dense_matrix<T>, std::vector<std::complex<T> >) */
+ /* implicit_qr_algorithm(dense_matrix<T>, std::vector<std::complex<T> >, */
+ /* dense_matrix<T>) */
+ /* */
+ /* ********************************************************************* */
+
+ /* ********************************************************************* */
+ /* LAPACK functions used. */
+ /* ********************************************************************* */
+
+ extern "C" {
+ void sgetrf_(...); void dgetrf_(...); void cgetrf_(...); void zgetrf_(...);
+ void sgetrs_(...); void dgetrs_(...); void cgetrs_(...); void zgetrs_(...);
+ void sgetri_(...); void dgetri_(...); void cgetri_(...); void zgetri_(...);
+ void sgeqrf_(...); void dgeqrf_(...); void cgeqrf_(...); void zgeqrf_(...);
+ void sorgqr_(...); void dorgqr_(...); void cungqr_(...); void zungqr_(...);
+ void sormqr_(...); void dormqr_(...); void cunmqr_(...); void zunmqr_(...);
+ void sgees_ (...); void dgees_ (...); void cgees_ (...); void zgees_ (...);
+ void sgeev_ (...); void dgeev_ (...); void cgeev_ (...); void zgeev_ (...);
+ }
+
+ /* ********************************************************************* */
+ /* LU decomposition. */
+ /* ********************************************************************* */
+
+# define getrf_interface(lapack_name, base_type) inline \
+ size_type lu_factor(dense_matrix<base_type > &A, std::vector<int> &ipvt){\
+ GMMLAPACK_TRACE("getrf_interface"); \
+ int m(mat_nrows(A)), n(mat_ncols(A)), lda(m), info(0); \
+ if (m && n) lapack_name(&m, &n, &A(0,0), &lda, &ipvt[0], &info); \
+ return size_type(info); \
+ }
+
+ getrf_interface(sgetrf_, BLAS_S)
+ getrf_interface(dgetrf_, BLAS_D)
+ getrf_interface(cgetrf_, BLAS_C)
+ getrf_interface(zgetrf_, BLAS_Z)
+
+ /* ********************************************************************* */
+ /* LU solve. */
+ /* ********************************************************************* */
+
+# define getrs_interface(f_name, trans1, lapack_name, base_type) inline \
+ void f_name(const dense_matrix<base_type > &A, \
+ const std::vector<int> &ipvt, std::vector<base_type > &x, \
+ const std::vector<base_type > &b) { \
+ GMMLAPACK_TRACE("getrs_interface"); \
+ int n(mat_nrows(A)), info, nrhs(1); \
+ gmm::copy(b, x); trans1; \
+ if (n) \
+ lapack_name(&t, &n, &nrhs, &(A(0,0)),&n,&ipvt[0], &x[0], &n, &info); \
+ }
+
+# define getrs_trans_n const char t = 'N'
+# define getrs_trans_t const char t = 'T'
+
+ getrs_interface(lu_solve, getrs_trans_n, sgetrs_, BLAS_S)
+ getrs_interface(lu_solve, getrs_trans_n, dgetrs_, BLAS_D)
+ getrs_interface(lu_solve, getrs_trans_n, cgetrs_, BLAS_C)
+ getrs_interface(lu_solve, getrs_trans_n, zgetrs_, BLAS_Z)
+ getrs_interface(lu_solve_transposed, getrs_trans_t, sgetrs_, BLAS_S)
+ getrs_interface(lu_solve_transposed, getrs_trans_t, dgetrs_, BLAS_D)
+ getrs_interface(lu_solve_transposed, getrs_trans_t, cgetrs_, BLAS_C)
+ getrs_interface(lu_solve_transposed, getrs_trans_t, zgetrs_, BLAS_Z)
+
+ /* ********************************************************************* */
+ /* LU inverse. */
+ /* ********************************************************************* */
+
+# define getri_interface(lapack_name, base_type) inline \
+ void lu_inverse(const dense_matrix<base_type > &LU, \
+ std::vector<int> &ipvt, const dense_matrix<base_type > &A_) { \
+ GMMLAPACK_TRACE("getri_interface"); \
+ dense_matrix<base_type >& \
+ A = const_cast<dense_matrix<base_type > &>(A_); \
+ int n(mat_nrows(A)), info, lwork(-1); base_type work1; \
+ if (n) { \
+ gmm::copy(LU, A); \
+ lapack_name(&n, &A(0,0), &n, &ipvt[0], &work1, &lwork, &info); \
+ lwork = int(gmm::real(work1)); \
+ std::vector<base_type > work(lwork); \
+ lapack_name(&n, &A(0,0), &n, &ipvt[0], &work[0], &lwork, &info); \
+ } \
+ }
+
+ getri_interface(sgetri_, BLAS_S)
+ getri_interface(dgetri_, BLAS_D)
+ getri_interface(cgetri_, BLAS_C)
+ getri_interface(zgetri_, BLAS_Z)
+
+
+ /* ********************************************************************* */
+ /* QR factorization. */
+ /* ********************************************************************* */
+
+# define geqrf_interface(lapack_name1, base_type) inline \
+ void qr_factor(dense_matrix<base_type > &A){ \
+ GMMLAPACK_TRACE("geqrf_interface"); \
+ int m(mat_nrows(A)), n(mat_ncols(A)), info, lwork(-1); base_type work1;\
+ if (m && n) { \
+ std::vector<base_type > tau(n); \
+ lapack_name1(&m, &n, &A(0,0), &m, &tau[0], &work1 , &lwork, &info); \
+ lwork = int(gmm::real(work1)); \
+ std::vector<base_type > work(lwork); \
+ lapack_name1(&m, &n, &A(0,0), &m, &tau[0], &work[0], &lwork, &info); \
+ GMM_ASSERT1(!info, "QR factorization failed"); \
+ } \
+ }
+
+ geqrf_interface(sgeqrf_, BLAS_S)
+ geqrf_interface(dgeqrf_, BLAS_D)
+ // For complex values, housholder vectors are not the same as in
+ // gmm::lu_factor. Impossible to interface for the moment.
+ // geqrf_interface(cgeqrf_, BLAS_C)
+ // geqrf_interface(zgeqrf_, BLAS_Z)
+
+# define geqrf_interface2(lapack_name1, lapack_name2, base_type) inline \
+ void qr_factor(const dense_matrix<base_type > &A, \
+ dense_matrix<base_type > &Q, dense_matrix<base_type > &R) { \
+ GMMLAPACK_TRACE("geqrf_interface2"); \
+ int m(mat_nrows(A)), n(mat_ncols(A)), info, lwork(-1); base_type work1;\
+ if (m && n) { \
+ gmm::copy(A, Q); \
+ std::vector<base_type > tau(n); \
+ lapack_name1(&m, &n, &Q(0,0), &m, &tau[0], &work1 , &lwork, &info); \
+ lwork = int(gmm::real(work1)); \
+ std::vector<base_type > work(lwork); \
+ lapack_name1(&m, &n, &Q(0,0), &m, &tau[0], &work[0], &lwork, &info); \
+ GMM_ASSERT1(!info, "QR factorization failed"); \
+ base_type *p = &R(0,0), *q = &Q(0,0); \
+ for (int j = 0; j < n; ++j, q += m-n) \
+ for (int i = 0; i < n; ++i, ++p, ++q) \
+ *p = (j < i) ? base_type(0) : *q; \
+ lapack_name2(&m, &n, &n, &Q(0,0), &m,&tau[0],&work[0],&lwork,&info); \
+ } \
+ else gmm::clear(Q); \
+ }
+
+ geqrf_interface2(sgeqrf_, sorgqr_, BLAS_S)
+ geqrf_interface2(dgeqrf_, dorgqr_, BLAS_D)
+ geqrf_interface2(cgeqrf_, cungqr_, BLAS_C)
+ geqrf_interface2(zgeqrf_, zungqr_, BLAS_Z)
+
+ /* ********************************************************************* */
+ /* QR algorithm for eigenvalues search. */
+ /* ********************************************************************* */
+
+# define gees_interface(lapack_name, base_type) \
+ template <typename VECT> inline void implicit_qr_algorithm( \
+ const dense_matrix<base_type > &A, const VECT &eigval_, \
+ dense_matrix<base_type > &Q, \
+ double tol=gmm::default_tol(base_type()), bool compvect = true) { \
+ GMMLAPACK_TRACE("gees_interface"); \
+ typedef bool (*L_fp)(...); L_fp p = 0; \
+ int n(mat_nrows(A)), info, lwork(-1), sdim; base_type work1; \
+ if (!n) return; \
+ dense_matrix<base_type > H(n,n); gmm::copy(A, H); \
+ char jobvs = (compvect ? 'V' : 'N'), sort = 'N'; \
+ std::vector<double> rwork(n), eigv1(n), eigv2(n); \
+ lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigv1[0], \
+ &eigv2[0], &Q(0,0), &n, &work1, &lwork, &rwork[0], &info); \
+ lwork = int(gmm::real(work1)); \
+ std::vector<base_type > work(lwork); \
+ lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigv1[0], \
+ &eigv2[0], &Q(0,0), &n, &work[0], &lwork, &rwork[0],&info);\
+ GMM_ASSERT1(!info, "QR algorithm failed"); \
+ extract_eig(H, const_cast<VECT &>(eigval_), tol); \
+ }
+
+# define gees_interface2(lapack_name, base_type) \
+ template <typename VECT> inline void implicit_qr_algorithm( \
+ const dense_matrix<base_type > &A, const VECT &eigval_, \
+ dense_matrix<base_type > &Q, \
+ double tol=gmm::default_tol(base_type()), bool compvect = true) { \
+ GMMLAPACK_TRACE("gees_interface2"); \
+ typedef bool (*L_fp)(...); L_fp p = 0; \
+ int n(mat_nrows(A)), info, lwork(-1), sdim; base_type work1; \
+ if (!n) return; \
+ dense_matrix<base_type > H(n,n); gmm::copy(A, H); \
+ char jobvs = (compvect ? 'V' : 'N'), sort = 'N'; \
+ std::vector<double> rwork(n), eigvv(n*2); \
+ lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigvv[0], \
+ &Q(0,0), &n, &work1, &lwork, &rwork[0], &rwork[0], &info); \
+ lwork = int(gmm::real(work1)); \
+ std::vector<base_type > work(lwork); \
+ lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigvv[0], \
+ &Q(0,0), &n, &work[0], &lwork, &rwork[0], &rwork[0],&info);\
+ GMM_ASSERT1(!info, "QR algorithm failed"); \
+ extract_eig(H, const_cast<VECT &>(eigval_), tol); \
+ }
+
+ gees_interface(sgees_, BLAS_S)
+ gees_interface(dgees_, BLAS_D)
+ gees_interface2(cgees_, BLAS_C)
+ gees_interface2(zgees_, BLAS_Z)
+
+# define geev_int_right(lapack_name, base_type) \
+ template <typename VECT> inline void geev_interface_right( \
+ const dense_matrix<base_type > &A, const VECT &eigval_, \
+ dense_matrix<base_type > &Q) { \
+ GMMLAPACK_TRACE("geev_interface"); \
+ int n(mat_nrows(A)), info, lwork(-1); base_type work1; \
+ if (!n) return; \
+ dense_matrix<base_type > H(n,n); gmm::copy(A, H); \
+ char jobvl = 'N', jobvr = 'V'; \
+ std::vector<base_type > eigvr(n), eigvi(n); \
+ lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigvr[0], &eigvi[0], \
+ &Q(0,0), &n, &Q(0,0), &n, &work1, &lwork, &info); \
+ lwork = int(gmm::real(work1)); \
+ std::vector<base_type > work(lwork); \
+ lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigvr[0], &eigvi[0], \
+ &Q(0,0), &n, &Q(0,0), &n, &work[0], &lwork, &info); \
+ GMM_ASSERT1(!info, "QR algorithm failed"); \
+ gmm::copy(eigvr, gmm::real_part(const_cast<VECT &>(eigval_))); \
+ gmm::copy(eigvi, gmm::imag_part(const_cast<VECT &>(eigval_))); \
+ }
+
+# define geev_int_rightc(lapack_name, base_type) \
+ template <typename VECT> inline void geev_interface_right( \
+ const dense_matrix<base_type > &A, const VECT &eigval_, \
+ dense_matrix<base_type > &Q) { \
+ GMMLAPACK_TRACE("geev_interface"); \
+ int n(mat_nrows(A)), info, lwork(-1); base_type work1; \
+ if (!n) return; \
+ dense_matrix<base_type > H(n,n); gmm::copy(A, H); \
+ char jobvl = 'N', jobvr = 'V'; \
+ std::vector<double> rwork(2*n); \
+ std::vector<base_type> eigv(n); \
+ lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigv[0], &Q(0,0), &n, \
+ &Q(0,0), &n, &work1, &lwork, &rwork[0], &info); \
+ lwork = int(gmm::real(work1)); \
+ std::vector<base_type > work(lwork); \
+ lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigv[0], &Q(0,0), &n, \
+ &Q(0,0), &n, &work[0], &lwork, &rwork[0], &info); \
+ GMM_ASSERT1(!info, "QR algorithm failed"); \
+ gmm::copy(eigv, const_cast<VECT &>(eigval_)); \
+ }
+
+ geev_int_right(sgeev_, BLAS_S)
+ geev_int_right(dgeev_, BLAS_D)
+ geev_int_rightc(cgeev_, BLAS_C)
+ geev_int_rightc(zgeev_, BLAS_Z)
+
+# define geev_int_left(lapack_name, base_type) \
+ template <typename VECT> inline void geev_interface_left( \
+ const dense_matrix<base_type > &A, const VECT &eigval_, \
+ dense_matrix<base_type > &Q) { \
+ GMMLAPACK_TRACE("geev_interface"); \
+ int n(mat_nrows(A)), info, lwork(-1); base_type work1; \
+ if (!n) return; \
+ dense_matrix<base_type > H(n,n); gmm::copy(A, H); \
+ char jobvl = 'V', jobvr = 'N'; \
+ std::vector<base_type > eigvr(n), eigvi(n); \
+ lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigvr[0], &eigvi[0], \
+ &Q(0,0), &n, &Q(0,0), &n, &work1, &lwork, &info); \
+ lwork = int(gmm::real(work1)); \
+ std::vector<base_type > work(lwork); \
+ lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigvr[0], &eigvi[0], \
+ &Q(0,0), &n, &Q(0,0), &n, &work[0], &lwork, &info); \
+ GMM_ASSERT1(!info, "QR algorithm failed"); \
+ gmm::copy(eigvr, gmm::real_part(const_cast<VECT &>(eigval_))); \
+ gmm::copy(eigvi, gmm::imag_part(const_cast<VECT &>(eigval_))); \
+ }
+
+# define geev_int_leftc(lapack_name, base_type) \
+ template <typename VECT> inline void geev_interface_left( \
+ const dense_matrix<base_type > &A, const VECT &eigval_, \
+ dense_matrix<base_type > &Q) { \
+ GMMLAPACK_TRACE("geev_interface"); \
+ int n(mat_nrows(A)), info, lwork(-1); base_type work1; \
+ if (!n) return; \
+ dense_matrix<base_type > H(n,n); gmm::copy(A, H); \
+ char jobvl = 'V', jobvr = 'N'; \
+ std::vector<double> rwork(2*n); \
+ std::vector<base_type> eigv(n); \
+ lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigv[0], &Q(0,0), &n, \
+ &Q(0,0), &n, &work1, &lwork, &rwork[0], &info); \
+ lwork = int(gmm::real(work1)); \
+ std::vector<base_type > work(lwork); \
+ lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigv[0], &Q(0,0), &n, \
+ &Q(0,0), &n, &work[0], &lwork, &rwork[0], &info); \
+ GMM_ASSERT1(!info, "QR algorithm failed"); \
+ gmm::copy(eigv, const_cast<VECT &>(eigval_)); \
+ }
+
+ geev_int_left(sgeev_, BLAS_S)
+ geev_int_left(dgeev_, BLAS_D)
+ geev_int_leftc(cgeev_, BLAS_C)
+ geev_int_leftc(zgeev_, BLAS_Z)
+
+
+}
+
+#endif // GMM_LAPACK_INTERFACE_H
+
+#endif // GMM_USES_LAPACK || GMM_USES_ATLAS
diff --git a/Contrib/gmm/gmm_least_squares_cg.h b/Contrib/gmm/gmm_least_squares_cg.h
new file mode 100755
index 0000000..711d334
--- /dev/null
+++ b/Contrib/gmm/gmm_least_squares_cg.h
@@ -0,0 +1,95 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_leastsquares_cg.h
+ @author Benjamin Schleimer <bensch128 (at) yahoo (dot) com>
+ @date January 23, 2007.
+ @brief Conjugate gradient least squares algorithm.
+ Algorithm taken from http://www.stat.washington.edu/wxs/Stat538-w05/Notes/conjugate-gradients.pdf page 6
+*/
+#ifndef GMM_LEAST_SQUARES_CG_H__
+#define GMM_LEAST_SQUARES_CG_H__
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+#include "gmm_conjugated.h"
+
+namespace gmm {
+
+ template <typename Matrix, typename Vector1, typename Vector2>
+ void least_squares_cg(const Matrix& C, Vector1& x, const Vector2& y,
+ iteration &iter) {
+
+ typedef typename temporary_dense_vector<Vector1>::vector_type temp_vector;
+ typedef typename linalg_traits<Vector1>::value_type T;
+
+ T rho, rho_1(0), a;
+ temp_vector p(vect_size(x)), q(vect_size(y)), g(vect_size(x));
+ temp_vector r(vect_size(y));
+ iter.set_rhsnorm(gmm::sqrt(gmm::abs(vect_hp(y, y))));
+
+ if (iter.get_rhsnorm() == 0.0)
+ clear(x);
+ else {
+ mult(C, scaled(x, T(-1)), y, r);
+ mult(conjugated(C), r, g);
+ rho = vect_hp(g, g);
+ copy(g, p);
+
+ while (!iter.finished_vect(g)) {
+
+ if (!iter.first()) {
+ rho = vect_hp(g, g);
+ add(g, scaled(p, rho / rho_1), p);
+ }
+
+ mult(C, p, q);
+
+ a = rho / vect_hp(q, q);
+ add(scaled(p, a), x);
+ add(scaled(q, -a), r);
+ // NOTE: how do we minimize the impact to the transpose?
+ mult(conjugated(C), r, g);
+ rho_1 = rho;
+
+ ++iter;
+ }
+ }
+ }
+
+ template <typename Matrix, typename Precond,
+ typename Vector1, typename Vector2> inline
+ void least_squares_cg(const Matrix& C, const Vector1& x, const Vector2& y,
+ iteration &iter)
+ { least_squares_cg(C, linalg_const_cast(x), y, iter); }
+}
+
+
+#endif // GMM_SOLVER_CG_H__
diff --git a/Contrib/gmm/gmm_matrix.h b/Contrib/gmm/gmm_matrix.h
new file mode 100755
index 0000000..e6cb2a7
--- /dev/null
+++ b/Contrib/gmm/gmm_matrix.h
@@ -0,0 +1,1188 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/** @file gmm_matrix.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief Declaration of some matrix types (gmm::dense_matrix,
+ gmm::row_matrix, gmm::col_matrix, gmm::csc_matrix, etc.)
+*/
+
+#ifndef GMM_MATRIX_H__
+#define GMM_MATRIX_H__
+
+#include "gmm_vector.h"
+#include "gmm_sub_vector.h"
+#include "gmm_sub_matrix.h"
+#include "gmm_transposed.h"
+
+namespace gmm
+{
+
+ /* ******************************************************************** */
+ /* */
+ /* Identity matrix */
+ /* */
+ /* ******************************************************************** */
+
+ struct identity_matrix {
+ template <class MAT> void build_with(const MAT &) {}
+ };
+
+ template <typename M> inline
+ void add(const identity_matrix&, M &v1) {
+ size_type n = std::min(gmm::mat_nrows(v1), gmm::mat_ncols(v1));
+ for (size_type i = 0; i < n; ++i)
+ v1(i,i) += typename linalg_traits<M>::value_type(1);
+ }
+ template <typename M> inline
+ void add(const identity_matrix &I, const M &v1)
+ { add(I, linalg_const_cast(v1)); }
+
+ template <typename V1, typename V2> inline
+ void mult(const identity_matrix&, const V1 &v1, V2 &v2)
+ { copy(v1, v2); }
+ template <typename V1, typename V2> inline
+ void mult(const identity_matrix&, const V1 &v1, const V2 &v2)
+ { copy(v1, v2); }
+ template <typename V1, typename V2, typename V3> inline
+ void mult(const identity_matrix&, const V1 &v1, const V2 &v2, V3 &v3)
+ { add(v1, v2, v3); }
+ template <typename V1, typename V2, typename V3> inline
+ void mult(const identity_matrix&, const V1 &v1, const V2 &v2, const V3 &v3)
+ { add(v1, v2, v3); }
+ template <typename V1, typename V2> inline
+ void left_mult(const identity_matrix&, const V1 &v1, V2 &v2)
+ { copy(v1, v2); }
+ template <typename V1, typename V2> inline
+ void left_mult(const identity_matrix&, const V1 &v1, const V2 &v2)
+ { copy(v1, v2); }
+ template <typename V1, typename V2> inline
+ void right_mult(const identity_matrix&, const V1 &v1, V2 &v2)
+ { copy(v1, v2); }
+ template <typename V1, typename V2> inline
+ void right_mult(const identity_matrix&, const V1 &v1, const V2 &v2)
+ { copy(v1, v2); }
+ template <typename V1, typename V2> inline
+ void transposed_left_mult(const identity_matrix&, const V1 &v1, V2 &v2)
+ { copy(v1, v2); }
+ template <typename V1, typename V2> inline
+ void transposed_left_mult(const identity_matrix&, const V1 &v1,const V2 &v2)
+ { copy(v1, v2); }
+ template <typename V1, typename V2> inline
+ void transposed_right_mult(const identity_matrix&, const V1 &v1, V2 &v2)
+ { copy(v1, v2); }
+ template <typename V1, typename V2> inline
+ void transposed_right_mult(const identity_matrix&,const V1 &v1,const V2 &v2)
+ { copy(v1, v2); }
+ template <typename M> void copy_ident(const identity_matrix&, M &m) {
+ size_type i = 0, n = std::min(mat_nrows(m), mat_ncols(m));
+ clear(m);
+ for (; i < n; ++i) m(i,i) = typename linalg_traits<M>::value_type(1);
+ }
+ template <typename M> inline void copy(const identity_matrix&, M &m)
+ { copy_ident(identity_matrix(), m); }
+ template <typename M> inline void copy(const identity_matrix &, const M &m)
+ { copy_ident(identity_matrix(), linalg_const_cast(m)); }
+ template <typename V1, typename V2> inline
+ typename linalg_traits<V1>::value_type
+ vect_sp(const identity_matrix &, const V1 &v1, const V2 &v2)
+ { return vect_sp(v1, v2); }
+ template <typename V1, typename V2> inline
+ typename linalg_traits<V1>::value_type
+ vect_hp(const identity_matrix &, const V1 &v1, const V2 &v2)
+ { return vect_hp(v1, v2); }
+ template<typename M> inline bool is_identity(const M&) { return false; }
+ inline bool is_identity(const identity_matrix&) { return true; }
+
+ /* ******************************************************************** */
+ /* */
+ /* Row matrix */
+ /* */
+ /* ******************************************************************** */
+
+ template<typename V> class row_matrix {
+ protected :
+ std::vector<V> li; /* array of rows. */
+ size_type nc;
+
+ public :
+
+ typedef typename linalg_traits<V>::reference reference;
+ typedef typename linalg_traits<V>::value_type value_type;
+
+ row_matrix(size_type r, size_type c) : li(r, V(c)), nc(c) {}
+ row_matrix(void) : nc(0) {}
+ reference operator ()(size_type l, size_type c)
+ { return li[l][c]; }
+ value_type operator ()(size_type l, size_type c) const
+ { return li[l][c]; }
+
+ void clear_mat();
+ void resize(size_type m, size_type n);
+
+ typename std::vector<V>::iterator begin(void)
+ { return li.begin(); }
+ typename std::vector<V>::iterator end(void)
+ { return li.end(); }
+ typename std::vector<V>::const_iterator begin(void) const
+ { return li.begin(); }
+ typename std::vector<V>::const_iterator end(void) const
+ { return li.end(); }
+
+
+ V& row(size_type i) { return li[i]; }
+ const V& row(size_type i) const { return li[i]; }
+ V& operator[](size_type i) { return li[i]; }
+ const V& operator[](size_type i) const { return li[i]; }
+
+ inline size_type nrows(void) const { return li.size(); }
+ inline size_type ncols(void) const { return nc; }
+
+ void swap(row_matrix<V> &m) { std::swap(li, m.li); std::swap(nc, m.nc); }
+ void swap_row(size_type i, size_type j) { std::swap(li[i], li[j]); }
+ };
+
+ template<typename V> void row_matrix<V>::resize(size_type m, size_type n) {
+ li.resize(m);
+ for (size_type i=0; i < m; ++i) gmm::resize(li[i], n);
+ nc = n;
+ }
+
+
+ template<typename V> void row_matrix<V>::clear_mat()
+ { for (size_type i=0; i < nrows(); ++i) clear(li[i]); }
+
+ template <typename V> struct linalg_traits<row_matrix<V> > {
+ typedef row_matrix<V> this_type;
+ typedef this_type origin_type;
+ typedef linalg_false is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<V>::value_type value_type;
+ typedef typename linalg_traits<V>::reference reference;
+ typedef typename linalg_traits<V>::storage_type storage_type;
+ typedef simple_vector_ref<V *> sub_row_type;
+ typedef simple_vector_ref<const V *> const_sub_row_type;
+ typedef typename std::vector<V>::iterator row_iterator;
+ typedef typename std::vector<V>::const_iterator const_row_iterator;
+ typedef abstract_null_type sub_col_type;
+ typedef abstract_null_type const_sub_col_type;
+ typedef abstract_null_type col_iterator;
+ typedef abstract_null_type const_col_iterator;
+ typedef row_major sub_orientation;
+ typedef linalg_true index_sorted;
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static row_iterator row_begin(this_type &m) { return m.begin(); }
+ static row_iterator row_end(this_type &m) { return m.end(); }
+ static const_row_iterator row_begin(const this_type &m)
+ { return m.begin(); }
+ static const_row_iterator row_end(const this_type &m)
+ { return m.end(); }
+ static const_sub_row_type row(const const_row_iterator &it)
+ { return const_sub_row_type(*it); }
+ static sub_row_type row(const row_iterator &it)
+ { return sub_row_type(*it); }
+ static origin_type* origin(this_type &m) { return &m; }
+ static const origin_type* origin(const this_type &m) { return &m; }
+ static void do_clear(this_type &m) { m.clear_mat(); }
+ static value_type access(const const_row_iterator &itrow, size_type j)
+ { return (*itrow)[j]; }
+ static reference access(const row_iterator &itrow, size_type j)
+ { return (*itrow)[j]; }
+ static void resize(this_type &v, size_type m, size_type n)
+ { v.resize(m, n); }
+ static void reshape(this_type &, size_type, size_type)
+ { GMM_ASSERT1(false, "Sorry, to be done"); }
+ };
+
+ template<typename V> std::ostream &operator <<
+ (std::ostream &o, const row_matrix<V>& m) { gmm::write(o,m); return o; }
+
+ /* ******************************************************************** */
+ /* */
+ /* Column matrix */
+ /* */
+ /* ******************************************************************** */
+
+ template<typename V> class col_matrix {
+ protected :
+ std::vector<V> li; /* array of columns. */
+ size_type nr;
+
+ public :
+
+ typedef typename linalg_traits<V>::reference reference;
+ typedef typename linalg_traits<V>::value_type value_type;
+
+ col_matrix(size_type r, size_type c) : li(c, V(r)), nr(r) { }
+ col_matrix(void) : nr(0) {}
+ reference operator ()(size_type l, size_type c)
+ { return li[c][l]; }
+ value_type operator ()(size_type l, size_type c) const
+ { return li[c][l]; }
+
+ void clear_mat();
+ void resize(size_type, size_type);
+
+ V& col(size_type i) { return li[i]; }
+ const V& col(size_type i) const { return li[i]; }
+ V& operator[](size_type i) { return li[i]; }
+ const V& operator[](size_type i) const { return li[i]; }
+
+ typename std::vector<V>::iterator begin(void)
+ { return li.begin(); }
+ typename std::vector<V>::iterator end(void)
+ { return li.end(); }
+ typename std::vector<V>::const_iterator begin(void) const
+ { return li.begin(); }
+ typename std::vector<V>::const_iterator end(void) const
+ { return li.end(); }
+
+ inline size_type ncols(void) const { return li.size(); }
+ inline size_type nrows(void) const { return nr; }
+
+ void swap(col_matrix<V> &m) { std::swap(li, m.li); std::swap(nr, m.nr); }
+ void swap_col(size_type i, size_type j) { std::swap(li[i], li[j]); }
+ };
+
+ template<typename V> void col_matrix<V>::resize(size_type m, size_type n) {
+ li.resize(n);
+ for (size_type i=0; i < n; ++i) gmm::resize(li[i], m);
+ nr = m;
+ }
+
+ template<typename V> void col_matrix<V>::clear_mat()
+ { for (size_type i=0; i < ncols(); ++i) clear(li[i]); }
+
+ template <typename V> struct linalg_traits<col_matrix<V> > {
+ typedef col_matrix<V> this_type;
+ typedef this_type origin_type;
+ typedef linalg_false is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<V>::value_type value_type;
+ typedef typename linalg_traits<V>::reference reference;
+ typedef typename linalg_traits<V>::storage_type storage_type;
+ typedef simple_vector_ref<V *> sub_col_type;
+ typedef simple_vector_ref<const V *> const_sub_col_type;
+ typedef typename std::vector<V>::iterator col_iterator;
+ typedef typename std::vector<V>::const_iterator const_col_iterator;
+ typedef abstract_null_type sub_row_type;
+ typedef abstract_null_type const_sub_row_type;
+ typedef abstract_null_type row_iterator;
+ typedef abstract_null_type const_row_iterator;
+ typedef col_major sub_orientation;
+ typedef linalg_true index_sorted;
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static col_iterator col_begin(this_type &m) { return m.begin(); }
+ static col_iterator col_end(this_type &m) { return m.end(); }
+ static const_col_iterator col_begin(const this_type &m)
+ { return m.begin(); }
+ static const_col_iterator col_end(const this_type &m)
+ { return m.end(); }
+ static const_sub_col_type col(const const_col_iterator &it)
+ { return const_sub_col_type(*it); }
+ static sub_col_type col(const col_iterator &it)
+ { return sub_col_type(*it); }
+ static origin_type* origin(this_type &m) { return &m; }
+ static const origin_type* origin(const this_type &m) { return &m; }
+ static void do_clear(this_type &m) { m.clear_mat(); }
+ static value_type access(const const_col_iterator &itcol, size_type j)
+ { return (*itcol)[j]; }
+ static reference access(const col_iterator &itcol, size_type j)
+ { return (*itcol)[j]; }
+ static void resize(this_type &v, size_type m, size_type n)
+ { v.resize(m,n); }
+ static void reshape(this_type &, size_type, size_type)
+ { GMM_ASSERT1(false, "Sorry, to be done"); }
+ };
+
+ template<typename V> std::ostream &operator <<
+ (std::ostream &o, const col_matrix<V>& m) { gmm::write(o,m); return o; }
+
+ /* ******************************************************************** */
+ /* */
+ /* Dense matrix */
+ /* */
+ /* ******************************************************************** */
+
+ template<typename T> class dense_matrix : public std::vector<T> {
+ public:
+ typedef typename std::vector<T>::size_type size_type;
+ typedef typename std::vector<T>::iterator iterator;
+ typedef typename std::vector<T>::const_iterator const_iterator;
+
+ protected:
+ size_type nbc, nbl;
+
+ public:
+
+ inline const T& operator ()(size_type l, size_type c) const {
+ GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+ return *(this->begin() + c*nbl+l);
+ }
+ inline T& operator ()(size_type l, size_type c) {
+ GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+ return *(this->begin() + c*nbl+l);
+ }
+
+ void resize(size_type, size_type);
+ void reshape(size_type, size_type);
+
+ void fill(T a, T b = T(0));
+ inline size_type nrows(void) const { return nbl; }
+ inline size_type ncols(void) const { return nbc; }
+ void swap(dense_matrix<T> &m)
+ { std::vector<T>::swap(m); std::swap(nbc, m.nbc); std::swap(nbl, m.nbl); }
+
+ dense_matrix(size_type l, size_type c)
+ : std::vector<T>(c*l), nbc(c), nbl(l) {}
+ dense_matrix(void) { nbl = nbc = 0; }
+ };
+
+ template<typename T> void dense_matrix<T>::reshape(size_type m,size_type n) {
+ GMM_ASSERT2(n*m == nbl*nbc, "dimensions mismatch");
+ nbl = m; nbc = n;
+ }
+
+ template<typename T> void dense_matrix<T>::resize(size_type m, size_type n) {
+ if (n*m > nbc*nbl) std::vector<T>::resize(n*m);
+ if (m < nbl) {
+ for (size_type i = 1; i < std::min(nbc, n); ++i)
+ std::copy(this->begin()+i*nbl, this->begin()+(i*nbl+m),
+ this->begin()+i*m);
+ for (size_type i = std::min(nbc, n); i < n; ++i)
+ std::fill(this->begin()+(i*m), this->begin()+(i+1)*m, T(0));
+ }
+ else if (m > nbl) { /* do nothing when the nb of rows does not change */
+ for (size_type i = std::min(nbc, n); i > 1; --i)
+ std::copy(this->begin()+(i-1)*nbl, this->begin()+i*nbl,
+ this->begin()+(i-1)*m);
+ for (size_type i = 0; i < std::min(nbc, n); ++i)
+ std::fill(this->begin()+(i*m+nbl), this->begin()+(i+1)*m, T(0));
+ }
+ if (n*m < nbc*nbl) std::vector<T>::resize(n*m);
+ nbl = m; nbc = n;
+ }
+
+ template<typename T> void dense_matrix<T>::fill(T a, T b) {
+ std::fill(this->begin(), this->end(), b);
+ size_type n = std::min(nbl, nbc);
+ if (a != b) for (size_type i = 0; i < n; ++i) (*this)(i,i) = a;
+ }
+
+ template <typename T> struct linalg_traits<dense_matrix<T> > {
+ typedef dense_matrix<T> this_type;
+ typedef this_type origin_type;
+ typedef linalg_false is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef T value_type;
+ typedef T& reference;
+ typedef abstract_dense storage_type;
+ typedef tab_ref_reg_spaced_with_origin<typename this_type::iterator,
+ this_type> sub_row_type;
+ typedef tab_ref_reg_spaced_with_origin<typename this_type::const_iterator,
+ this_type> const_sub_row_type;
+ typedef dense_compressed_iterator<typename this_type::iterator,
+ typename this_type::iterator,
+ this_type *> row_iterator;
+ typedef dense_compressed_iterator<typename this_type::const_iterator,
+ typename this_type::iterator,
+ const this_type *> const_row_iterator;
+ typedef tab_ref_with_origin<typename this_type::iterator,
+ this_type> sub_col_type;
+ typedef tab_ref_with_origin<typename this_type::const_iterator,
+ this_type> const_sub_col_type;
+ typedef dense_compressed_iterator<typename this_type::iterator,
+ typename this_type::iterator,
+ this_type *> col_iterator;
+ typedef dense_compressed_iterator<typename this_type::const_iterator,
+ typename this_type::iterator,
+ const this_type *> const_col_iterator;
+ typedef col_and_row sub_orientation;
+ typedef linalg_true index_sorted;
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static const_sub_row_type row(const const_row_iterator &it)
+ { return const_sub_row_type(*it, it.nrows, it.ncols, it.origin); }
+ static const_sub_col_type col(const const_col_iterator &it)
+ { return const_sub_col_type(*it, *it + it.nrows, it.origin); }
+ static sub_row_type row(const row_iterator &it)
+ { return sub_row_type(*it, it.nrows, it.ncols, it.origin); }
+ static sub_col_type col(const col_iterator &it)
+ { return sub_col_type(*it, *it + it.nrows, it.origin); }
+ static row_iterator row_begin(this_type &m)
+ { return row_iterator(m.begin(), m.size() ? 1 : 0, m.nrows(), m.ncols(), 0, &m); }
+ static row_iterator row_end(this_type &m)
+ { return row_iterator(m.begin(), m.size() ? 1 : 0, m.nrows(), m.ncols(), m.nrows(), &m); }
+ static const_row_iterator row_begin(const this_type &m)
+ { return const_row_iterator(m.begin(), m.size() ? 1 : 0, m.nrows(), m.ncols(), 0, &m); }
+ static const_row_iterator row_end(const this_type &m)
+ { return const_row_iterator(m.begin(), m.size() ? 1 : 0, m.nrows(), m.ncols(), m.nrows(), &m); }
+ static col_iterator col_begin(this_type &m)
+ { return col_iterator(m.begin(), m.nrows(), m.nrows(), m.ncols(), 0, &m); }
+ static col_iterator col_end(this_type &m)
+ { return col_iterator(m.begin(), m.nrows(), m.nrows(), m.ncols(), m.ncols(), &m); }
+ static const_col_iterator col_begin(const this_type &m)
+ { return const_col_iterator(m.begin(), m.nrows(), m.nrows(), m.ncols(), 0, &m); }
+ static const_col_iterator col_end(const this_type &m)
+ { return const_col_iterator(m.begin(),m.nrows(),m.nrows(),m.ncols(),m.ncols(), &m); }
+ static origin_type* origin(this_type &m) { return &m; }
+ static const origin_type* origin(const this_type &m) { return &m; }
+ static void do_clear(this_type &m) { m.fill(value_type(0)); }
+ static value_type access(const const_col_iterator &itcol, size_type j)
+ { return (*itcol)[j]; }
+ static reference access(const col_iterator &itcol, size_type j)
+ { return (*itcol)[j]; }
+ static void resize(this_type &v, size_type m, size_type n)
+ { v.resize(m,n); }
+ static void reshape(this_type &v, size_type m, size_type n)
+ { v.reshape(m, n); }
+ };
+
+ template<typename T> std::ostream &operator <<
+ (std::ostream &o, const dense_matrix<T>& m) { gmm::write(o,m); return o; }
+
+ /* ******************************************************************** */
+ /* */
+ /* Read only compressed sparse column matrix */
+ /* */
+ /* ******************************************************************** */
+
+ template <typename T, int shift = 0>
+ struct csc_matrix {
+ typedef unsigned int IND_TYPE;
+
+ T *pr; // values.
+ IND_TYPE *ir; // row indices.
+ IND_TYPE *jc; // column repartition on pr and ir.
+ size_type nc, nr;
+
+ typedef T value_type;
+ typedef T& access_type;
+
+ template <typename Matrix> void init_with_good_format(const Matrix &B);
+ template <typename Matrix> void init_with(const Matrix &A);
+ void init_with(const col_matrix<gmm::rsvector<T> > &B)
+ { init_with_good_format(B); }
+ void init_with(const col_matrix<wsvector<T> > &B)
+ { init_with_good_format(B); }
+ template <typename PT1, typename PT2, typename PT3, int cshift>
+ void init_with(const csc_matrix_ref<PT1,PT2,PT3,cshift>& B)
+ { init_with_good_format(B); }
+ template <typename U, int cshift>
+ void init_with(const csc_matrix<U, cshift>& B)
+ { init_with_good_format(B); }
+
+ void init_with_identity(size_type n);
+
+ csc_matrix(void) : pr(0), ir(0), jc(0), nc(0), nr(0) {}
+ csc_matrix(size_type nnr, size_type nnc);
+ ~csc_matrix() { if (pr) { delete[] pr; delete[] ir; delete[] jc; } }
+
+ size_type nrows(void) const { return nr; }
+ size_type ncols(void) const { return nc; }
+ void swap(csc_matrix<T, shift> &m) {
+ std::swap(pr, m.pr);
+ std::swap(ir,m.ir); std::swap(jc, m.jc);
+ std::swap(nc, m.nc); std::swap(nr,m.nr);
+ }
+ value_type operator()(size_type i, size_type j) const
+ { return mat_col(*this, j)[i]; }
+ };
+
+ template <typename T, int shift> template<typename Matrix>
+ void csc_matrix<T, shift>::init_with_good_format(const Matrix &B) {
+ typedef typename linalg_traits<Matrix>::const_sub_col_type col_type;
+ if (pr) { delete[] pr; delete[] ir; delete[] jc; }
+ nc = mat_ncols(B); nr = mat_nrows(B);
+ jc = new IND_TYPE[nc+1];
+ jc[0] = shift;
+ for (size_type j = 0; j < nc; ++j) {
+ jc[j+1] = jc[j] + nnz(mat_const_col(B, j));
+ }
+ pr = new T[jc[nc]];
+ ir = new IND_TYPE[jc[nc]];
+ for (size_type j = 0; j < nc; ++j) {
+ col_type col = mat_const_col(B, j);
+ typename linalg_traits<col_type>::const_iterator
+ it = vect_const_begin(col), ite = vect_const_end(col);
+ for (size_type k = 0; it != ite; ++it, ++k)
+ { pr[jc[j]-shift+k] = *it; ir[jc[j]-shift+k] = it.index() + shift; }
+ }
+ }
+
+ template <typename T, int shift> template <typename Matrix>
+ void csc_matrix<T, shift>::init_with(const Matrix &A) {
+ col_matrix<wsvector<T> > B(mat_nrows(A), mat_ncols(A));
+ copy(A, B);
+ init_with_good_format(B);
+ }
+
+ template <typename T, int shift>
+ void csc_matrix<T, shift>::init_with_identity(size_type n) {
+ if (pr) { delete[] pr; delete[] ir; delete[] jc; }
+ nc = nr = n;
+ pr = new T[nc];
+ ir = new IND_TYPE[nc];
+ jc = new IND_TYPE[nc+1];
+ for (size_type j = 0; j < nc; ++j)
+ { ir[j] = jc[j] = shift + j; pr[j] = T(1); }
+ jc[nc] = shift + nc;
+ }
+
+ template <typename T, int shift>
+ csc_matrix<T, shift>::csc_matrix(size_type nnr, size_type nnc)
+ : nc(nnc), nr(nnr) {
+ pr = new T[1]; ir = new IND_TYPE[1];
+ jc = new IND_TYPE[nc+1];
+ for (size_type j = 0; j <= nc; ++j) jc[j] = shift;
+ }
+
+ template <typename T, int shift>
+ struct linalg_traits<csc_matrix<T, shift> > {
+ typedef csc_matrix<T, shift> this_type;
+ typedef typename this_type::IND_TYPE IND_TYPE;
+ typedef linalg_const is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef T value_type;
+ typedef T origin_type;
+ typedef T reference;
+ typedef abstract_sparse storage_type;
+ typedef abstract_null_type sub_row_type;
+ typedef abstract_null_type const_sub_row_type;
+ typedef abstract_null_type row_iterator;
+ typedef abstract_null_type const_row_iterator;
+ typedef abstract_null_type sub_col_type;
+ typedef cs_vector_ref<const T *, const IND_TYPE *, shift>
+ const_sub_col_type;
+ typedef sparse_compressed_iterator<const T *, const IND_TYPE *,
+ const IND_TYPE *, shift>
+ const_col_iterator;
+ typedef abstract_null_type col_iterator;
+ typedef col_major sub_orientation;
+ typedef linalg_true index_sorted;
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static const_col_iterator col_begin(const this_type &m)
+ { return const_col_iterator(m.pr, m.ir, m.jc, m.nr, m.pr); }
+ static const_col_iterator col_end(const this_type &m)
+ { return const_col_iterator(m.pr, m.ir, m.jc + m.nc, m.nr, m.pr); }
+ static const_sub_col_type col(const const_col_iterator &it) {
+ return const_sub_col_type(it.pr + *(it.jc) - shift,
+ it.ir + *(it.jc) - shift,
+ *(it.jc + 1) - *(it.jc), it.n);
+ }
+ static const origin_type* origin(const this_type &m) { return m.pr; }
+ static void do_clear(this_type &m) { m.do_clear(); }
+ static value_type access(const const_col_iterator &itcol, size_type j)
+ { return col(itcol)[j]; }
+ };
+
+ template <typename T, int shift>
+ std::ostream &operator <<
+ (std::ostream &o, const csc_matrix<T, shift>& m)
+ { gmm::write(o,m); return o; }
+
+ template <typename T, int shift>
+ inline void copy(const identity_matrix &, csc_matrix<T, shift>& M)
+ { M.init_with_identity(mat_nrows(M)); }
+
+ template <typename Matrix, typename T, int shift>
+ inline void copy(const Matrix &A, csc_matrix<T, shift>& M)
+ { M.init_with(A); }
+
+ /* ******************************************************************** */
+ /* */
+ /* Read only compressed sparse row matrix */
+ /* */
+ /* ******************************************************************** */
+
+ template <typename T, int shift = 0>
+ struct csr_matrix {
+
+ typedef unsigned int IND_TYPE;
+
+ T *pr; // values.
+ IND_TYPE *ir; // col indices.
+ IND_TYPE *jc; // row repartition on pr and ir.
+ size_type nc, nr;
+
+ typedef T value_type;
+ typedef T& access_type;
+
+
+ template <typename Matrix> void init_with_good_format(const Matrix &B);
+ void init_with(const row_matrix<wsvector<T> > &B)
+ { init_with_good_format(B); }
+ void init_with(const row_matrix<rsvector<T> > &B)
+ { init_with_good_format(B); }
+ template <typename PT1, typename PT2, typename PT3, int cshift>
+ void init_with(const csr_matrix_ref<PT1,PT2,PT3,cshift>& B)
+ { init_with_good_format(B); }
+ template <typename U, int cshift>
+ void init_with(const csr_matrix<U, cshift>& B)
+ { init_with_good_format(B); }
+
+ template <typename Matrix> void init_with(const Matrix &A);
+ void init_with_identity(size_type n);
+
+ csr_matrix(void) : pr(0), ir(0), jc(0), nc(0), nr(0) {}
+ csr_matrix(size_type nnr, size_type nnc);
+ ~csr_matrix() { if (pr) { delete[] pr; delete[] ir; delete[] jc; } }
+
+ size_type nrows(void) const { return nr; }
+ size_type ncols(void) const { return nc; }
+ void swap(csr_matrix<T, shift> &m) {
+ std::swap(pr, m.pr);
+ std::swap(ir,m.ir); std::swap(jc, m.jc);
+ std::swap(nc, m.nc); std::swap(nr,m.nr);
+ }
+
+ value_type operator()(size_type i, size_type j) const
+ { return mat_row(*this, i)[j]; }
+ };
+
+ template <typename T, int shift> template <typename Matrix>
+ void csr_matrix<T, shift>::init_with_good_format(const Matrix &B) {
+ typedef typename linalg_traits<Matrix>::const_sub_row_type row_type;
+ if (pr) { delete[] pr; delete[] ir; delete[] jc; }
+ nc = mat_ncols(B); nr = mat_nrows(B);
+ jc = new IND_TYPE[nr+1];
+ jc[0] = shift;
+ for (size_type j = 0; j < nr; ++j) {
+ jc[j+1] = jc[j] + nnz(mat_const_row(B, j));
+ }
+ pr = new T[jc[nr]];
+ ir = new IND_TYPE[jc[nr]];
+ for (size_type j = 0; j < nr; ++j) {
+ row_type row = mat_const_row(B, j);
+ typename linalg_traits<row_type>::const_iterator
+ it = vect_const_begin(row), ite = vect_const_end(row);
+ for (size_type k = 0; it != ite; ++it, ++k)
+ { pr[jc[j]-shift+k] = *it; ir[jc[j]-shift+k] = it.index()+shift; }
+ }
+ }
+
+ template <typename T, int shift> template <typename Matrix>
+ void csr_matrix<T, shift>::init_with(const Matrix &A) {
+ row_matrix<wsvector<T> > B(mat_nrows(A), mat_ncols(A));
+ copy(A, B);
+ init_with_good_format(B);
+ }
+
+ template <typename T, int shift>
+ void csr_matrix<T, shift>::init_with_identity(size_type n) {
+ if (pr) { delete[] pr; delete[] ir; delete[] jc; }
+ nc = nr = n;
+ pr = new T[nr];
+ ir = new IND_TYPE[nr];
+ jc = new IND_TYPE[nr+1];
+ for (size_type j = 0; j < nr; ++j)
+ { ir[j] = jc[j] = shift + j; pr[j] = T(1); }
+ jc[nr] = shift + nr;
+ }
+
+ template <typename T, int shift>
+ csr_matrix<T, shift>::csr_matrix(size_type nnr, size_type nnc)
+ : nc(nnc), nr(nnr) {
+ pr = new T[1]; ir = new IND_TYPE[1];
+ jc = new IND_TYPE[nr+1];
+ for (size_type j = 0; j < nr; ++j) jc[j] = shift;
+ jc[nr] = shift;
+ }
+
+
+ template <typename T, int shift>
+ struct linalg_traits<csr_matrix<T, shift> > {
+ typedef csr_matrix<T, shift> this_type;
+ typedef typename this_type::IND_TYPE IND_TYPE;
+ typedef linalg_const is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef T value_type;
+ typedef T origin_type;
+ typedef T reference;
+ typedef abstract_sparse storage_type;
+ typedef abstract_null_type sub_col_type;
+ typedef abstract_null_type const_sub_col_type;
+ typedef abstract_null_type col_iterator;
+ typedef abstract_null_type const_col_iterator;
+ typedef abstract_null_type sub_row_type;
+ typedef cs_vector_ref<const T *, const IND_TYPE *, shift>
+ const_sub_row_type;
+ typedef sparse_compressed_iterator<const T *, const IND_TYPE *,
+ const IND_TYPE *, shift>
+ const_row_iterator;
+ typedef abstract_null_type row_iterator;
+ typedef row_major sub_orientation;
+ typedef linalg_true index_sorted;
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static const_row_iterator row_begin(const this_type &m)
+ { return const_row_iterator(m.pr, m.ir, m.jc, m.nc, m.pr); }
+ static const_row_iterator row_end(const this_type &m)
+ { return const_row_iterator(m.pr, m.ir, m.jc + m.nr, m.nc, m.pr); }
+ static const_sub_row_type row(const const_row_iterator &it) {
+ return const_sub_row_type(it.pr + *(it.jc) - shift,
+ it.ir + *(it.jc) - shift,
+ *(it.jc + 1) - *(it.jc), it.n);
+ }
+ static const origin_type* origin(const this_type &m) { return m.pr; }
+ static void do_clear(this_type &m) { m.do_clear(); }
+ static value_type access(const const_row_iterator &itrow, size_type j)
+ { return row(itrow)[j]; }
+ };
+
+ template <typename T, int shift>
+ std::ostream &operator <<
+ (std::ostream &o, const csr_matrix<T, shift>& m)
+ { gmm::write(o,m); return o; }
+
+ template <typename T, int shift>
+ inline void copy(const identity_matrix &, csr_matrix<T, shift>& M)
+ { M.init_with_identity(mat_nrows(M)); }
+
+ template <typename Matrix, typename T, int shift>
+ inline void copy(const Matrix &A, csr_matrix<T, shift>& M)
+ { M.init_with(A); }
+
+ /* ******************************************************************** */
+ /* */
+ /* Block matrix */
+ /* */
+ /* ******************************************************************** */
+
+ template <typename MAT> class block_matrix {
+ protected :
+ std::vector<MAT> blocks;
+ size_type nrowblocks_;
+ size_type ncolblocks_;
+ std::vector<sub_interval> introw, intcol;
+
+ public :
+ typedef typename linalg_traits<MAT>::value_type value_type;
+ typedef typename linalg_traits<MAT>::reference reference;
+
+ size_type nrows(void) const { return introw[nrowblocks_-1].max; }
+ size_type ncols(void) const { return intcol[ncolblocks_-1].max; }
+ size_type nrowblocks(void) const { return nrowblocks_; }
+ size_type ncolblocks(void) const { return ncolblocks_; }
+ const sub_interval &subrowinterval(size_type i) const { return introw[i]; }
+ const sub_interval &subcolinterval(size_type i) const { return intcol[i]; }
+ const MAT &block(size_type i, size_type j) const
+ { return blocks[j*ncolblocks_+i]; }
+ MAT &block(size_type i, size_type j)
+ { return blocks[j*ncolblocks_+i]; }
+ void do_clear(void);
+ // to be done : read and write access to a component
+ value_type operator() (size_type i, size_type j) const {
+ size_type k, l;
+ for (k = 0; k < nrowblocks_; ++k)
+ if (i >= introw[k].min && i < introw[k].max) break;
+ for (l = 0; l < nrowblocks_; ++l)
+ if (j >= introw[l].min && j < introw[l].max) break;
+ return (block(k, l))(i - introw[k].min, j - introw[l].min);
+ }
+ reference operator() (size_type i, size_type j) {
+ size_type k, l;
+ for (k = 0; k < nrowblocks_; ++k)
+ if (i >= introw[k].min && i < introw[k].max) break;
+ for (l = 0; l < nrowblocks_; ++l)
+ if (j >= introw[l].min && j < introw[l].max) break;
+ return (block(k, l))(i - introw[k].min, j - introw[l].min);
+ }
+
+ template <typename CONT> void resize(const CONT &c1, const CONT &c2);
+ template <typename CONT> block_matrix(const CONT &c1, const CONT &c2)
+ { resize(c1, c2); }
+ block_matrix(void) {}
+
+ };
+
+ template <typename MAT> struct linalg_traits<block_matrix<MAT> > {
+ typedef block_matrix<MAT> this_type;
+ typedef linalg_false is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef this_type origin_type;
+ typedef typename linalg_traits<MAT>::value_type value_type;
+ typedef typename linalg_traits<MAT>::reference reference;
+ typedef typename linalg_traits<MAT>::storage_type storage_type;
+ typedef abstract_null_type sub_row_type; // to be done ...
+ typedef abstract_null_type const_sub_row_type; // to be done ...
+ typedef abstract_null_type row_iterator; // to be done ...
+ typedef abstract_null_type const_row_iterator; // to be done ...
+ typedef abstract_null_type sub_col_type; // to be done ...
+ typedef abstract_null_type const_sub_col_type; // to be done ...
+ typedef abstract_null_type col_iterator; // to be done ...
+ typedef abstract_null_type const_col_iterator; // to be done ...
+ typedef abstract_null_type sub_orientation; // to be done ...
+ typedef linalg_true index_sorted;
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static origin_type* origin(this_type &m) { return &m; }
+ static const origin_type* origin(const this_type &m) { return &m; }
+ static void do_clear(this_type &m) { m.do_clear(); }
+ // access to be done ...
+ static void resize(this_type &, size_type , size_type)
+ { GMM_ASSERT1(false, "Sorry, to be done"); }
+ static void reshape(this_type &, size_type , size_type)
+ { GMM_ASSERT1(false, "Sorry, to be done"); }
+ };
+
+ template <typename MAT> void block_matrix<MAT>::do_clear(void) {
+ for (size_type j = 0, l = 0; j < ncolblocks_; ++j)
+ for (size_type i = 0, k = 0; i < nrowblocks_; ++i)
+ clear(block(i,j));
+ }
+
+ template <typename MAT> template <typename CONT>
+ void block_matrix<MAT>::resize(const CONT &c1, const CONT &c2) {
+ nrowblocks_ = c1.size(); ncolblocks_ = c2.size();
+ blocks.resize(nrowblocks_ * ncolblocks_);
+ intcol.resize(ncolblocks_);
+ introw.resize(nrowblocks_);
+ for (size_type j = 0, l = 0; j < ncolblocks_; ++j) {
+ intcol[j] = sub_interval(l, c2[j]); l += c2[j];
+ for (size_type i = 0, k = 0; i < nrowblocks_; ++i) {
+ if (j == 0) { introw[i] = sub_interval(k, c1[i]); k += c1[i]; }
+ block(i, j) = MAT(c1[i], c2[j]);
+ }
+ }
+ }
+
+ template <typename M1, typename M2>
+ void copy(const block_matrix<M1> &m1, M2 &m2) {
+ for (size_type j = 0; j < m1.ncolblocks(); ++j)
+ for (size_type i = 0; i < m1.nrowblocks(); ++i)
+ copy(m1.block(i,j), sub_matrix(m2, m1.subrowinterval(i),
+ m1.subcolinterval(j)));
+ }
+
+ template <typename M1, typename M2>
+ void copy(const block_matrix<M1> &m1, const M2 &m2)
+ { copy(m1, linalg_const_cast(m2)); }
+
+
+ template <typename MAT, typename V1, typename V2>
+ void mult(const block_matrix<MAT> &m, const V1 &v1, V2 &v2) {
+ clear(v2);
+ typename sub_vector_type<V2 *, sub_interval>::vector_type sv;
+ for (size_type i = 0; i < m.nrowblocks() ; ++i)
+ for (size_type j = 0; j < m.ncolblocks() ; ++j) {
+ sv = sub_vector(v2, m.subrowinterval(i));
+ mult(m.block(i,j),
+ sub_vector(v1, m.subcolinterval(j)), sv, sv);
+ }
+ }
+
+ template <typename MAT, typename V1, typename V2, typename V3>
+ void mult(const block_matrix<MAT> &m, const V1 &v1, const V2 &v2, V3 &v3) {
+ typename sub_vector_type<V3 *, sub_interval>::vector_type sv;
+ for (size_type i = 0; i < m.nrowblocks() ; ++i)
+ for (size_type j = 0; j < m.ncolblocks() ; ++j) {
+ sv = sub_vector(v3, m.subrowinterval(i));
+ if (j == 0)
+ mult(m.block(i,j),
+ sub_vector(v1, m.subcolinterval(j)),
+ sub_vector(v2, m.subrowinterval(i)), sv);
+ else
+ mult(m.block(i,j),
+ sub_vector(v1, m.subcolinterval(j)), sv, sv);
+ }
+
+ }
+
+ template <typename MAT, typename V1, typename V2>
+ void mult(const block_matrix<MAT> &m, const V1 &v1, const V2 &v2)
+ { mult(m, v1, linalg_const_cast(v2)); }
+
+ template <typename MAT, typename V1, typename V2, typename V3>
+ void mult(const block_matrix<MAT> &m, const V1 &v1, const V2 &v2,
+ const V3 &v3)
+ { mult_const(m, v1, v2, linalg_const_cast(v3)); }
+
+}
+ /* ******************************************************************** */
+ /* */
+ /* Distributed matrices */
+ /* */
+ /* ******************************************************************** */
+
+#ifdef GMM_USES_MPI
+#include <mpi.h>
+
+namespace gmm {
+
+ template <typename T> inline MPI_Datatype mpi_type(T)
+ { GMM_ASSERT1(false, "Sorry unsupported type"); return MPI_FLOAT; }
+ inline MPI_Datatype mpi_type(double) { return MPI_DOUBLE; }
+ inline MPI_Datatype mpi_type(float) { return MPI_FLOAT; }
+ inline MPI_Datatype mpi_type(long double) { return MPI_LONG_DOUBLE; }
+#ifndef LAM_MPI
+ inline MPI_Datatype mpi_type(std::complex<float>) { return MPI_COMPLEX; }
+ inline MPI_Datatype mpi_type(std::complex<double>) { return MPI_DOUBLE_COMPLEX; }
+#endif
+ inline MPI_Datatype mpi_type(int) { return MPI_INT; }
+ inline MPI_Datatype mpi_type(unsigned int) { return MPI_UNSIGNED; }
+ inline MPI_Datatype mpi_type(size_t) {
+ if (sizeof(int) == sizeof(size_t)) return MPI_UNSIGNED;
+ if (sizeof(long) == sizeof(size_t)) return MPI_UNSIGNED_LONG;
+ return MPI_LONG_LONG;
+ }
+
+
+
+ template <typename MAT> struct mpi_distributed_matrix {
+ MAT M;
+
+ mpi_distributed_matrix(size_type n, size_type m) : M(n, m) {}
+ mpi_distributed_matrix() {}
+
+ const MAT &local_matrix(void) const { return M; }
+ MAT &local_matrix(void) { return M; }
+ };
+
+ template <typename MAT> inline MAT &eff_matrix(MAT &m) { return m; }
+ template <typename MAT> inline
+ const MAT &eff_matrix(const MAT &m) { return m; }
+ template <typename MAT> inline
+ MAT &eff_matrix(mpi_distributed_matrix<MAT> &m) { return m.M; }
+ template <typename MAT> inline
+ const MAT &eff_matrix(const mpi_distributed_matrix<MAT> &m) { return m.M; }
+
+
+ template <typename MAT1, typename MAT2>
+ inline void copy(const mpi_distributed_matrix<MAT1> &m1,
+ mpi_distributed_matrix<MAT2> &m2)
+ { copy(eff_matrix(m1), eff_matrix(m2)); }
+ template <typename MAT1, typename MAT2>
+ inline void copy(const mpi_distributed_matrix<MAT1> &m1,
+ const mpi_distributed_matrix<MAT2> &m2)
+ { copy(m1.M, m2.M); }
+
+ template <typename MAT1, typename MAT2>
+ inline void copy(const mpi_distributed_matrix<MAT1> &m1, MAT2 &m2)
+ { copy(m1.M, m2); }
+ template <typename MAT1, typename MAT2>
+ inline void copy(const mpi_distributed_matrix<MAT1> &m1, const MAT2 &m2)
+ { copy(m1.M, m2); }
+
+
+ template <typename MATSP, typename V1, typename V2> inline
+ typename strongest_value_type3<V1,V2,MATSP>::value_type
+ vect_sp(const mpi_distributed_matrix<MATSP> &ps, const V1 &v1,
+ const V2 &v2) {
+ typedef typename strongest_value_type3<V1,V2,MATSP>::value_type T;
+ T res = vect_sp(ps.M, v1, v2), rest;
+ MPI_Allreduce(&res, &rest, 1, mpi_type(T()), MPI_SUM,MPI_COMM_WORLD);
+ return rest;
+ }
+
+ template <typename MAT, typename V1, typename V2>
+ inline void mult_add(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+ V2 &v2) {
+ typedef typename linalg_traits<V2>::value_type T;
+ std::vector<T> v3(vect_size(v2)), v4(vect_size(v2));
+ static double tmult_tot = 0.0;
+ static double tmult_tot2 = 0.0;
+ double t_ref = MPI_Wtime();
+ gmm::mult(m.M, v1, v3);
+ if (is_sparse(v2)) GMM_WARNING2("Using a plain temporary, here.");
+ double t_ref2 = MPI_Wtime();
+ MPI_Allreduce(&(v3[0]), &(v4[0]),gmm::vect_size(v2), mpi_type(T()),
+ MPI_SUM,MPI_COMM_WORLD);
+ tmult_tot2 = MPI_Wtime()-t_ref2;
+ cout << "reduce mult mpi = " << tmult_tot2 << endl;
+ gmm::add(v4, v2);
+ tmult_tot = MPI_Wtime()-t_ref;
+ cout << "tmult mpi = " << tmult_tot << endl;
+ }
+
+ template <typename MAT, typename V1, typename V2>
+ void mult_add(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+ const V2 &v2_)
+ { mult_add(m, v1, const_cast<V2 &>(v2_)); }
+
+ template <typename MAT, typename V1, typename V2>
+ inline void mult(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+ const V2 &v2_)
+ { V2 &v2 = const_cast<V2 &>(v2_); clear(v2); mult_add(m, v1, v2); }
+
+ template <typename MAT, typename V1, typename V2>
+ inline void mult(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+ V2 &v2)
+ { clear(v2); mult_add(m, v1, v2); }
+
+ template <typename MAT, typename V1, typename V2, typename V3>
+ inline void mult(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+ const V2 &v2, const V3 &v3_)
+ { V3 &v3 = const_cast<V3 &>(v3_); gmm::copy(v2, v3); mult_add(m, v1, v3); }
+
+ template <typename MAT, typename V1, typename V2, typename V3>
+ inline void mult(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+ const V2 &v2, V3 &v3)
+ { gmm::copy(v2, v3); mult_add(m, v1, v3); }
+
+
+ template <typename MAT> inline
+ size_type mat_nrows(const mpi_distributed_matrix<MAT> &M)
+ { return mat_nrows(M.M); }
+ template <typename MAT> inline
+ size_type mat_ncols(const mpi_distributed_matrix<MAT> &M)
+ { return mat_nrows(M.M); }
+ template <typename MAT> inline
+ void resize(mpi_distributed_matrix<MAT> &M, size_type m, size_type n)
+ { resize(M.M, m, n); }
+ template <typename MAT> inline void clear(mpi_distributed_matrix<MAT> &M)
+ { clear(M.M); }
+
+
+ // For compute reduced system
+ template <typename MAT1, typename MAT2> inline
+ void mult(const MAT1 &M1, const mpi_distributed_matrix<MAT2> &M2,
+ mpi_distributed_matrix<MAT2> &M3)
+ { mult(M1, M2.M, M3.M); }
+ template <typename MAT1, typename MAT2> inline
+ void mult(const mpi_distributed_matrix<MAT2> &M2,
+ const MAT1 &M1, mpi_distributed_matrix<MAT2> &M3)
+ { mult(M2.M, M1, M3.M); }
+ template <typename MAT1, typename MAT2, typename MAT3> inline
+ void mult(const MAT1 &M1, const mpi_distributed_matrix<MAT2> &M2,
+ MAT3 &M3)
+ { mult(M1, M2.M, M3); }
+ template <typename MAT1, typename MAT2, typename MAT3> inline
+ void mult(const MAT1 &M1, const mpi_distributed_matrix<MAT2> &M2,
+ const MAT3 &M3)
+ { mult(M1, M2.M, M3); }
+
+ template <typename M, typename SUBI1, typename SUBI2>
+ struct sub_matrix_type<const mpi_distributed_matrix<M> *, SUBI1, SUBI2>
+ { typedef abstract_null_type matrix_type; };
+
+ template <typename M, typename SUBI1, typename SUBI2>
+ struct sub_matrix_type<mpi_distributed_matrix<M> *, SUBI1, SUBI2>
+ { typedef abstract_null_type matrix_type; };
+
+ template <typename M, typename SUBI1, typename SUBI2> inline
+ typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI2>
+ ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>::matrix_type,
+ M *>::return_type
+ sub_matrix(mpi_distributed_matrix<M> &m, const SUBI1 &si1, const SUBI2 &si2)
+ { return sub_matrix(m.M, si1, si2); }
+
+ template <typename MAT, typename SUBI1, typename SUBI2> inline
+ typename select_return<typename sub_matrix_type<const MAT *, SUBI1, SUBI2>
+ ::matrix_type, typename sub_matrix_type<MAT *, SUBI1, SUBI2>::matrix_type,
+ const MAT *>::return_type
+ sub_matrix(const mpi_distributed_matrix<MAT> &m, const SUBI1 &si1,
+ const SUBI2 &si2)
+ { return sub_matrix(m.M, si1, si2); }
+
+ template <typename M, typename SUBI1> inline
+ typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI1>
+ ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>::matrix_type,
+ M *>::return_type
+ sub_matrix(mpi_distributed_matrix<M> &m, const SUBI1 &si1)
+ { return sub_matrix(m.M, si1, si1); }
+
+ template <typename M, typename SUBI1> inline
+ typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI1>
+ ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>::matrix_type,
+ const M *>::return_type
+ sub_matrix(const mpi_distributed_matrix<M> &m, const SUBI1 &si1)
+ { return sub_matrix(m.M, si1, si1); }
+
+
+ template <typename L> struct transposed_return<const mpi_distributed_matrix<L> *>
+ { typedef abstract_null_type return_type; };
+ template <typename L> struct transposed_return<mpi_distributed_matrix<L> *>
+ { typedef abstract_null_type return_type; };
+
+ template <typename L> inline typename transposed_return<const L *>::return_type
+ transposed(const mpi_distributed_matrix<L> &l)
+ { return transposed(l.M); }
+
+ template <typename L> inline typename transposed_return<L *>::return_type
+ transposed(mpi_distributed_matrix<L> &l)
+ { return transposed(l.M); }
+
+
+ template <typename MAT>
+ struct linalg_traits<mpi_distributed_matrix<MAT> > {
+ typedef mpi_distributed_matrix<MAT> this_type;
+ typedef MAT origin_type;
+ typedef linalg_false is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<MAT>::value_type value_type;
+ typedef typename linalg_traits<MAT>::reference reference;
+ typedef typename linalg_traits<MAT>::storage_type storage_type;
+ typedef abstract_null_type sub_row_type;
+ typedef abstract_null_type const_sub_row_type;
+ typedef abstract_null_type row_iterator;
+ typedef abstract_null_type const_row_iterator;
+ typedef abstract_null_type sub_col_type;
+ typedef abstract_null_type const_sub_col_type;
+ typedef abstract_null_type col_iterator;
+ typedef abstract_null_type const_col_iterator;
+ typedef abstract_null_type sub_orientation;
+ typedef abstract_null_type index_sorted;
+ static size_type nrows(const this_type &m) { return nrows(m.M); }
+ static size_type ncols(const this_type &m) { return ncols(m.M); }
+ static void do_clear(this_type &m) { clear(m.M); }
+ };
+
+}
+
+
+#endif // GMM_USES_MPI
+
+namespace std {
+ template <typename V>
+ void swap(gmm::row_matrix<V> &m1, gmm::row_matrix<V> &m2)
+ { m1.swap(m2); }
+ template <typename V>
+ void swap(gmm::col_matrix<V> &m1, gmm::col_matrix<V> &m2)
+ { m1.swap(m2); }
+ template <typename T>
+ void swap(gmm::dense_matrix<T> &m1, gmm::dense_matrix<T> &m2)
+ { m1.swap(m2); }
+ template <typename T, int shift> void
+ swap(gmm::csc_matrix<T,shift> &m1, gmm::csc_matrix<T,shift> &m2)
+ { m1.swap(m2); }
+ template <typename T, int shift> void
+ swap(gmm::csr_matrix<T,shift> &m1, gmm::csr_matrix<T,shift> &m2)
+ { m1.swap(m2); }
+}
+
+
+
+
+#endif /* GMM_MATRIX_H__ */
diff --git a/Contrib/gmm/gmm_modified_gram_schmidt.h b/Contrib/gmm/gmm_modified_gram_schmidt.h
new file mode 100755
index 0000000..213cf7a
--- /dev/null
+++ b/Contrib/gmm/gmm_modified_gram_schmidt.h
@@ -0,0 +1,97 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_modified_gram_schmidt.h
+ @author Andrew Lumsdaine <lums at osl.iu.edu>, Lie-Quan Lee <llee at osl.iu.edu>
+ @date October 13, 2002.
+ @brief Modified Gram-Schmidt orthogonalization
+*/
+
+#ifndef GMM_MODIFIED_GRAM_SCHMIDT_H
+#define GMM_MODIFIED_GRAM_SCHMIDT_H
+
+#include "gmm_kernel.h"
+
+namespace gmm {
+
+ template <typename T>
+ class modified_gram_schmidt {
+ protected:
+ typedef dense_matrix<T> MAT;
+ MAT M;
+
+ public:
+
+ modified_gram_schmidt(int restart, size_t s) : M(s, restart+1) {}
+
+ typename linalg_traits<MAT>::const_sub_col_type
+ operator[](size_t i) const { return mat_const_col(M, i); }
+
+ typename linalg_traits<MAT>::sub_col_type
+ operator[](size_t i) { return mat_col(M, i); }
+
+ inline size_type nrows(void) const { return M.nrows(); }
+ inline size_type ncols(void) const { return M.ncols(); }
+ MAT &mat(void) { return M; }
+ const MAT &mat(void) const { return M; }
+
+ };
+
+ template <typename T, typename VecHi> inline
+ void orthogonalize(modified_gram_schmidt<T>& V, const VecHi& Hi_, size_t i) {
+ VecHi& Hi = const_cast<VecHi&>(Hi_);
+
+ for (size_t k = 0; k <= i; k++) {
+ Hi[k] = gmm::vect_hp(V[i+1], V[k]);
+ gmm::add(gmm::scaled(V[k], -Hi[k]), V[i+1]);
+ }
+ }
+
+ template <typename T, typename VecHi>
+ void orthogonalize_with_refinment(modified_gram_schmidt<T>& V,
+ const VecHi& Hi_, size_t i) {
+ VecHi& Hi = const_cast<VecHi&>(Hi_);
+ orthogonalize(V, Hi_, i);
+
+ sub_interval SUBI(0, V.nrows()), SUBJ(0, i+1);
+ std::vector<T> corr(i+1);
+ gmm::mult(conjugated(sub_matrix(V.mat(), SUBI, SUBJ)),
+ V[i+1], corr);
+ gmm::mult(sub_matrix(V.mat(), SUBI, SUBJ),
+ scaled(corr, T(-1)), V[i+1],V[i+1]);
+ gmm::add(corr, sub_vector(Hi, SUBJ));
+ }
+
+ template <typename T, typename VecS, typename VecX>
+ void combine(modified_gram_schmidt<T>& V, const VecS& s, VecX& x, size_t i)
+ { for (size_t j = 0; j < i; ++j) gmm::add(gmm::scaled(V[j], s[j]), x); }
+}
+
+#endif
diff --git a/Contrib/gmm/gmm_opt.h b/Contrib/gmm/gmm_opt.h
new file mode 100755
index 0000000..2dfd9f8
--- /dev/null
+++ b/Contrib/gmm/gmm_opt.h
@@ -0,0 +1,122 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_opt.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date July 9, 2003.
+ @brief Optimization for some small cases (inversion of 2x2 matrices etc.)
+*/
+#ifndef GMM_OPT_H__
+#define GMM_OPT_H__
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* Optimized determinant and inverse for small matrices (2x2 and 3x3) */
+ /* with dense_matrix<T>. */
+ /* ********************************************************************* */
+
+ template <typename T> T lu_det(const dense_matrix<T> &A) {
+ size_type n(mat_nrows(A));
+ if (n) {
+ const T *p = &(A(0,0));
+ switch (n) {
+ case 1 : return (*p);
+ case 2 : return (*p) * (*(p+3)) - (*(p+1)) * (*(p+2));
+ case 3 : return (*p) * ((*(p+4)) * (*(p+8)) - (*(p+5)) * (*(p+7)))
+ - (*(p+1)) * ((*(p+3)) * (*(p+8)) - (*(p+5)) * (*(p+6)))
+ + (*(p+2)) * ((*(p+3)) * (*(p+7)) - (*(p+4)) * (*(p+6)));
+ default :
+ {
+ dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
+ std::vector<size_type> ipvt(mat_nrows(A));
+ gmm::copy(A, B);
+ lu_factor(B, ipvt);
+ return lu_det(B, ipvt);
+ }
+ }
+ }
+ return T(1);
+ }
+
+ template <typename T> T lu_inverse(const dense_matrix<T> &A_) {
+ dense_matrix<T>& A = const_cast<dense_matrix<T> &>(A_);
+ size_type N = mat_nrows(A);
+ T det(1);
+ if (N) {
+ T *p = &(A(0,0));
+ if (N <= 3) {
+ switch (N) {
+ case 1 : {
+ det = *p;
+ GMM_ASSERT1(det!=T(0), "non invertible matrix");
+ *p = T(1) / det;
+ } break;
+ case 2 : {
+ det = (*p) * (*(p+3)) - (*(p+1)) * (*(p+2));
+ GMM_ASSERT1(det!=T(0), "non invertible matrix");
+ std::swap(*p, *(p+3));
+ *p++ /= det; *p++ /= -det; *p++ /= -det; *p++ /= det;
+ } break;
+ case 3 : {
+ T a, b, c, d, e, f, g, h, i;
+ a = (*(p+4)) * (*(p+8)) - (*(p+5)) * (*(p+7));
+ b = - (*(p+1)) * (*(p+8)) + (*(p+2)) * (*(p+7));
+ c = (*(p+1)) * (*(p+5)) - (*(p+2)) * (*(p+4));
+ d = - (*(p+3)) * (*(p+8)) + (*(p+5)) * (*(p+6));
+ e = (*(p+0)) * (*(p+8)) - (*(p+2)) * (*(p+6));
+ f = - (*(p+0)) * (*(p+5)) + (*(p+2)) * (*(p+3));
+ g = (*(p+3)) * (*(p+7)) - (*(p+4)) * (*(p+6));
+ h = - (*(p+0)) * (*(p+7)) + (*(p+1)) * (*(p+6));
+ i = (*(p+0)) * (*(p+4)) - (*(p+1)) * (*(p+3));
+ det = (*p) * a + (*(p+1)) * d + (*(p+2)) * g;
+ GMM_ASSERT1(det!=T(0), "non invertible matrix");
+ *p++ = a / det; *p++ = b / det; *p++ = c / det;
+ *p++ = d / det; *p++ = e / det; *p++ = f / det;
+ *p++ = g / det; *p++ = h / det; *p++ = i / det;
+ } break;
+ }
+ }
+ else {
+ dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
+ std::vector<int> ipvt(mat_nrows(A));
+ gmm::copy(A, B);
+ size_type info = lu_factor(B, ipvt);
+ GMM_ASSERT1(!info, "non invertible matrix");
+ lu_inverse(B, ipvt, A);
+ return lu_det(B, ipvt);
+ }
+ }
+ return det;
+ }
+
+}
+
+#endif // GMM_OPT_H__
diff --git a/Contrib/gmm/gmm_precond.h b/Contrib/gmm/gmm_precond.h
new file mode 100755
index 0000000..7e95dc8
--- /dev/null
+++ b/Contrib/gmm/gmm_precond.h
@@ -0,0 +1,64 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2004-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+#ifndef GMM_PRECOND_H
+#define GMM_PRECOND_H
+
+#include "gmm_kernel.h"
+
+/** @file gmm_precond.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date March 29, 2004.
+ @brief gmm preconditioners.
+ */
+
+/* Preconditioner concept : */
+/* */
+/* A the matrix, P the preconditioner PA well conditioned. */
+/* PRECOND precontioner type. */
+/* mult(P, v, w) : w <- P v */
+/* transposed_mult(P, v, w) : w <- transposed(P) v */
+/* left_mult(P, v, w) : see qmr solver */
+/* right_mult(P, v, w) : see qmr solver */
+/* transposed_left_mult(P, v, w) : see qmr solver */
+/* transposed_right_mult(P, v, w) : see qmr solver */
+/* */
+/* PRECOND P() : empty preconditioner. */
+/* PRECOND P(A, ...) : preconditioner for the matrix A, with optional */
+/* parameters */
+/* PRECOND(...) : empty precondtioner with parameters set. */
+/* P.build_with(A) : build a precondtioner for A. */
+/* */
+/* *********************************************************************** */
+
+
+
+
+#endif
+
diff --git a/Contrib/gmm/gmm_precond_diagonal.h b/Contrib/gmm/gmm_precond_diagonal.h
new file mode 100755
index 0000000..e3f74c6
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_diagonal.h
@@ -0,0 +1,131 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_precond_diagonal.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date June 5, 2003.
+ @brief Diagonal matrix preconditoner.
+*/
+
+#ifndef GMM_PRECOND_DIAGONAL_H
+#define GMM_PRECOND_DIAGONAL_H
+
+#include "gmm_precond.h"
+
+namespace gmm {
+
+ /** Diagonal preconditioner. */
+ template<typename Matrix> struct diagonal_precond {
+ typedef typename linalg_traits<Matrix>::value_type value_type;
+ typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+
+ std::vector<magnitude_type> diag;
+
+ void build_with(const Matrix &M) {
+ diag.resize(mat_nrows(M));
+ for (size_type i = 0; i < mat_nrows(M); ++i) {
+ magnitude_type x = gmm::abs(M(i, i));
+ if (x == magnitude_type(0)) {
+ x = magnitude_type(1);
+ GMM_WARNING2("The matrix has a zero on its diagonal");
+ }
+ diag[i] = magnitude_type(1) / x;
+ }
+ }
+ size_type memsize() const { return sizeof(*this) + diag.size() * sizeof(value_type); }
+ diagonal_precond(const Matrix &M) { build_with(M); }
+ diagonal_precond(void) {}
+ };
+
+ template <typename Matrix, typename V2> inline
+ void mult_diag_p(const diagonal_precond<Matrix>& P, V2 &v2, abstract_sparse){
+ typename linalg_traits<V2>::iterator it = vect_begin(v2),
+ ite = vect_end(v2);
+ for (; it != ite; ++it) *it *= P.diag[it.index()];
+ }
+
+ template <typename Matrix, typename V2> inline
+ void mult_diag_p(const diagonal_precond<Matrix>& P,V2 &v2, abstract_skyline)
+ { mult_diag_p(P, v2, abstract_sparse()); }
+
+ template <typename Matrix, typename V2> inline
+ void mult_diag_p(const diagonal_precond<Matrix>& P, V2 &v2, abstract_dense){
+ for (size_type i = 0; i < P.diag.size(); ++i) v2[i] *= P.diag[i];
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void mult(const diagonal_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ GMM_ASSERT2(P.diag.size() == vect_size(v2),"dimensions mismatch");
+ copy(v1, v2);
+ mult_diag_p(P, v2, typename linalg_traits<V2>::storage_type());
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_mult(const diagonal_precond<Matrix>& P,const V1 &v1,V2 &v2) {
+ mult(P, v1, v2);
+ }
+
+ // # define DIAG_LEFT_MULT_SQRT
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void left_mult(const diagonal_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ GMM_ASSERT2(P.diag.size() == vect_size(v2), "dimensions mismatch");
+ copy(v1, v2);
+# ifdef DIAG_LEFT_MULT_SQRT
+ for (size_type i= 0; i < P.diag.size(); ++i) v2[i] *= gmm::sqrt(P.diag[i]);
+# else
+ for (size_type i= 0; i < P.diag.size(); ++i) v2[i] *= P.diag[i];
+# endif
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_left_mult(const diagonal_precond<Matrix>& P,
+ const V1 &v1, V2 &v2)
+ { left_mult(P, v1, v2); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void right_mult(const diagonal_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ typedef typename linalg_traits<Matrix>::value_type T;
+ GMM_ASSERT2(P.diag.size() == vect_size(v2), "dimensions mismatch");
+ copy(v1, v2);
+# ifdef DIAG_LEFT_MULT_SQRT
+ for (size_type i= 0; i < P.diag.size(); ++i) v2[i] *= gmm::sqrt(P.diag[i]);
+# endif
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_right_mult(const diagonal_precond<Matrix>& P,
+ const V1 &v1, V2 &v2)
+ { right_mult(P, v1, v2); }
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_precond_ildlt.h b/Contrib/gmm/gmm_precond_ildlt.h
new file mode 100755
index 0000000..5c4eece
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_ildlt.h
@@ -0,0 +1,286 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of cholesky.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the University of California, Berkeley nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
+// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+#ifndef GMM_PRECOND_ILDLT_H
+#define GMM_PRECOND_ILDLT_H
+
+/**@file gmm_precond_ildlt.h
+ @author Andrew Lumsdaine <lums at osl.iu.edu>
+ @author Lie-Quan Lee <llee at osl.iu.edu>
+ @author Yves Renard <yves.renard at insa-lyon.fr>
+ @date June 5, 2003.
+ @brief Incomplete Level 0 ILDLT Preconditioner.
+*/
+
+#include "gmm_precond.h"
+
+namespace gmm {
+
+ /** Incomplete Level 0 LDLT Preconditioner.
+
+ For use with symmetric real or hermitian complex sparse matrices.
+
+ Notes: The idea under a concrete Preconditioner such as Incomplete
+ Cholesky is to create a Preconditioner object to use in iterative
+ methods.
+
+
+ Y. Renard : Transformed in LDLT for stability reason.
+
+ U=LT is stored in csr format. D is stored on the diagonal of U.
+ */
+ template <typename Matrix>
+ class ildlt_precond {
+
+ public :
+ typedef typename linalg_traits<Matrix>::value_type value_type;
+ typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+ typedef csr_matrix_ref<value_type *, size_type *, size_type *, 0> tm_type;
+
+ tm_type U;
+
+ protected :
+ std::vector<value_type> Tri_val;
+ std::vector<size_type> Tri_ind, Tri_ptr;
+
+ template<typename M> void do_ildlt(const M& A, row_major);
+ void do_ildlt(const Matrix& A, col_major);
+
+ public:
+
+ size_type nrows(void) const { return mat_nrows(U); }
+ size_type ncols(void) const { return mat_ncols(U); }
+ value_type &D(size_type i) { return Tri_val[Tri_ptr[i]]; }
+ const value_type &D(size_type i) const { return Tri_val[Tri_ptr[i]]; }
+ ildlt_precond(void) {}
+ void build_with(const Matrix& A) {
+ Tri_ptr.resize(mat_nrows(A)+1);
+ do_ildlt(A, typename principal_orientation_type<typename
+ linalg_traits<Matrix>::sub_orientation>::potype());
+ }
+ ildlt_precond(const Matrix& A) { build_with(A); }
+ size_type memsize() const {
+ return sizeof(*this) +
+ Tri_val.size() * sizeof(value_type) +
+ (Tri_ind.size()+Tri_ptr.size()) * sizeof(size_type);
+ }
+ };
+
+ template <typename Matrix> template<typename M>
+ void ildlt_precond<Matrix>::do_ildlt(const M& A, row_major) {
+ typedef typename linalg_traits<Matrix>::storage_type store_type;
+ typedef value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type Tri_loc = 0, n = mat_nrows(A), d, g, h, i, j, k;
+ if (n == 0) return;
+ T z, zz;
+ Tri_ptr[0] = 0;
+ R prec = default_tol(R());
+ R max_pivot = gmm::abs(A(0,0)) * prec;
+
+ for (int count = 0; count < 2; ++count) {
+ if (count) { Tri_val.resize(Tri_loc); Tri_ind.resize(Tri_loc); }
+ for (Tri_loc = 0, i = 0; i < n; ++i) {
+ typedef typename linalg_traits<M>::const_sub_row_type row_type;
+ row_type row = mat_const_row(A, i);
+ typename linalg_traits<row_type>::const_iterator
+ it = vect_const_begin(row), ite = vect_const_end(row);
+
+ if (count) { Tri_val[Tri_loc] = T(0); Tri_ind[Tri_loc] = i; }
+ ++Tri_loc; // diagonal element
+
+ for (k = 0; it != ite; ++it, ++k) {
+ j = index_of_it(it, k, store_type());
+ if (i == j) {
+ if (count) Tri_val[Tri_loc-1] = *it;
+ }
+ else if (j > i) {
+ if (count) { Tri_val[Tri_loc] = *it; Tri_ind[Tri_loc]=j; }
+ ++Tri_loc;
+ }
+ }
+ Tri_ptr[i+1] = Tri_loc;
+ }
+ }
+
+ if (A(0,0) == T(0)) {
+ Tri_val[Tri_ptr[0]] = T(1);
+ GMM_WARNING2("pivot 0 is too small");
+ }
+
+ for (k = 0; k < n; k++) {
+ d = Tri_ptr[k];
+ z = T(gmm::real(Tri_val[d])); Tri_val[d] = z;
+ if (gmm::abs(z) <= max_pivot) {
+ Tri_val[d] = z = T(1);
+ GMM_WARNING2("pivot " << k << " is too small [" << gmm::abs(z) << "]");
+ }
+ max_pivot = std::max(max_pivot, std::min(gmm::abs(z) * prec, R(1)));
+
+ for (i = d + 1; i < Tri_ptr[k+1]; ++i) Tri_val[i] /= z;
+ for (i = d + 1; i < Tri_ptr[k+1]; ++i) {
+ zz = gmm::conj(Tri_val[i] * z);
+ h = Tri_ind[i];
+ g = i;
+
+ for (j = Tri_ptr[h] ; j < Tri_ptr[h+1]; ++j)
+ for ( ; g < Tri_ptr[k+1] && Tri_ind[g] <= Tri_ind[j]; ++g)
+ if (Tri_ind[g] == Tri_ind[j])
+ Tri_val[j] -= zz * Tri_val[g];
+ }
+ }
+ U = tm_type(&(Tri_val[0]), &(Tri_ind[0]), &(Tri_ptr[0]),
+ n, mat_ncols(A));
+ }
+
+ template <typename Matrix>
+ void ildlt_precond<Matrix>::do_ildlt(const Matrix& A, col_major)
+ { do_ildlt(gmm::conjugated(A), row_major()); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void mult(const ildlt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ gmm::copy(v1, v2);
+ gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+ for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+ gmm::upper_tri_solve(P.U, v2, true);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_mult(const ildlt_precond<Matrix>& P,const V1 &v1,V2 &v2)
+ { mult(P, v1, v2); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void left_mult(const ildlt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ copy(v1, v2);
+ gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+ for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void right_mult(const ildlt_precond<Matrix>& P, const V1 &v1, V2 &v2)
+ { copy(v1, v2); gmm::upper_tri_solve(P.U, v2, true); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_left_mult(const ildlt_precond<Matrix>& P, const V1 &v1,
+ V2 &v2) {
+ copy(v1, v2);
+ gmm::upper_tri_solve(P.U, v2, true);
+ for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_right_mult(const ildlt_precond<Matrix>& P, const V1 &v1,
+ V2 &v2)
+ { copy(v1, v2); gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true); }
+
+
+
+ // for compatibility with old versions
+
+ template <typename Matrix>
+ struct cholesky_precond : public ildlt_precond<Matrix> {
+ cholesky_precond(const Matrix& A) : ildlt_precond<Matrix>(A) {}
+ cholesky_precond(void) {}
+ } IS_DEPRECATED;
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void mult(const cholesky_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ gmm::copy(v1, v2);
+ gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+ for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+ gmm::upper_tri_solve(P.U, v2, true);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_mult(const cholesky_precond<Matrix>& P,const V1 &v1,V2 &v2)
+ { mult(P, v1, v2); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void left_mult(const cholesky_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ copy(v1, v2);
+ gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+ for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void right_mult(const cholesky_precond<Matrix>& P, const V1 &v1, V2 &v2)
+ { copy(v1, v2); gmm::upper_tri_solve(P.U, v2, true); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_left_mult(const cholesky_precond<Matrix>& P, const V1 &v1,
+ V2 &v2) {
+ copy(v1, v2);
+ gmm::upper_tri_solve(P.U, v2, true);
+ for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_right_mult(const cholesky_precond<Matrix>& P, const V1 &v1,
+ V2 &v2)
+ { copy(v1, v2); gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true); }
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_precond_ildltt.h b/Contrib/gmm/gmm_precond_ildltt.h
new file mode 100755
index 0000000..8afa9e7
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_ildltt.h
@@ -0,0 +1,217 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_precond_ildltt.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date June 30, 2003.
+ @brief incomplete LDL^t (cholesky) preconditioner with fill-in and threshold.
+*/
+
+#ifndef GMM_PRECOND_ILDLTT_H
+#define GMM_PRECOND_ILDLTT_H
+
+// Store U = LT and D in indiag. On each line, the fill-in is the number
+// of non-zero elements on the line of the original matrix plus K, except if
+// the matrix is dense. In this case the fill-in is K on each line.
+
+#include "gmm_precond_ilut.h"
+
+namespace gmm {
+ /** incomplete LDL^t (cholesky) preconditioner with fill-in and
+ threshold. */
+ template <typename Matrix>
+ class ildltt_precond {
+ public :
+ typedef typename linalg_traits<Matrix>::value_type value_type;
+ typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+
+ typedef rsvector<value_type> svector;
+
+ row_matrix<svector> U;
+ std::vector<magnitude_type> indiag;
+
+ protected:
+ size_type K;
+ double eps;
+
+ template<typename M> void do_ildltt(const M&, row_major);
+ void do_ildltt(const Matrix&, col_major);
+
+ public:
+ void build_with(const Matrix& A) {
+ gmm::resize(U, mat_nrows(A), mat_ncols(A));
+ indiag.resize(std::min(mat_nrows(A), mat_ncols(A)));
+ do_ildltt(A, typename principal_orientation_type<typename
+ linalg_traits<Matrix>::sub_orientation>::potype());
+ }
+ ildltt_precond(const Matrix& A, int k_, double eps_)
+ : U(mat_nrows(A),mat_ncols(A)), K(k_), eps(eps_) { build_with(A); }
+ ildltt_precond(void) { K=10; eps = 1E-7; }
+ ildltt_precond(size_type k_, double eps_) : K(k_), eps(eps_) {}
+ size_type memsize() const {
+ return sizeof(*this) + nnz(U)*sizeof(value_type) + indiag.size() * sizeof(magnitude_type);
+ }
+ };
+
+ template<typename Matrix> template<typename M>
+ void ildltt_precond<Matrix>::do_ildltt(const M& A,row_major) {
+ typedef value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type n = mat_nrows(A);
+ if (n == 0) return;
+ svector w(n);
+ T tmp;
+ R prec = default_tol(R()), max_pivot = gmm::abs(A(0,0)) * prec;
+
+ gmm::clear(U);
+ for (size_type i = 0; i < n; ++i) {
+ gmm::copy(mat_const_row(A, i), w);
+ double norm_row = gmm::vect_norm2(w);
+
+ for (size_type krow = 0, k; krow < w.nb_stored(); ++krow) {
+ typename svector::iterator wk = w.begin() + krow;
+ if ((k = wk->c) >= i) break;
+ if (gmm::is_complex(wk->e)) {
+ tmp = gmm::conj(U(k, i))/indiag[k]; // not completely satisfactory ..
+ gmm::add(scaled(mat_row(U, k), -tmp), w);
+ }
+ else {
+ tmp = wk->e;
+ if (gmm::abs(tmp) < eps * norm_row) { w.sup(k); --krow; }
+ else { wk->e += tmp; gmm::add(scaled(mat_row(U, k), -tmp), w); }
+ }
+ }
+ tmp = w[i];
+
+ if (gmm::abs(gmm::real(tmp)) <= max_pivot)
+ { GMM_WARNING2("pivot " << i << " is too small"); tmp = T(1); }
+
+ max_pivot = std::max(max_pivot, std::min(gmm::abs(tmp) * prec, R(1)));
+ indiag[i] = R(1) / gmm::real(tmp);
+ gmm::clean(w, eps * norm_row);
+ gmm::scale(w, T(indiag[i]));
+ std::sort(w.begin(), w.end(), elt_rsvector_value_less_<T>());
+ typename svector::const_iterator wit = w.begin(), wite = w.end();
+ for (size_type nnu = 0; wit != wite; ++wit) // copy to be optimized ...
+ if (wit->c > i) { if (nnu < K) { U(i, wit->c) = wit->e; ++nnu; } }
+ }
+ }
+
+ template<typename Matrix>
+ void ildltt_precond<Matrix>::do_ildltt(const Matrix& A, col_major)
+ { do_ildltt(gmm::conjugated(A), row_major()); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void mult(const ildltt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ gmm::copy(v1, v2);
+ gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+ for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+ gmm::upper_tri_solve(P.U, v2, true);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_mult(const ildltt_precond<Matrix>& P,const V1 &v1, V2 &v2)
+ { mult(P, v1, v2); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void left_mult(const ildltt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ copy(v1, v2);
+ gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+ for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void right_mult(const ildltt_precond<Matrix>& P, const V1 &v1, V2 &v2)
+ { copy(v1, v2); gmm::upper_tri_solve(P.U, v2, true); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_left_mult(const ildltt_precond<Matrix>& P, const V1 &v1,
+ V2 &v2) {
+ copy(v1, v2);
+ gmm::upper_tri_solve(P.U, v2, true);
+ for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_right_mult(const ildltt_precond<Matrix>& P, const V1 &v1,
+ V2 &v2)
+ { copy(v1, v2); gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true); }
+
+
+ // for compatibility with old versions
+
+ template <typename Matrix>
+ struct choleskyt_precond : public ildltt_precond<Matrix>{
+ choleskyt_precond(const Matrix& A, int k_, double eps_)
+ : ildltt_precond<Matrix>(A, k_, eps_) {}
+ choleskyt_precond(void) {}
+ } IS_DEPRECATED;
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void mult(const choleskyt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ gmm::copy(v1, v2);
+ gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+ for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+ gmm::upper_tri_solve(P.U, v2, true);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_mult(const choleskyt_precond<Matrix>& P,const V1 &v1, V2 &v2)
+ { mult(P, v1, v2); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void left_mult(const choleskyt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ copy(v1, v2);
+ gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+ for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void right_mult(const choleskyt_precond<Matrix>& P, const V1 &v1, V2 &v2)
+ { copy(v1, v2); gmm::upper_tri_solve(P.U, v2, true); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_left_mult(const choleskyt_precond<Matrix>& P, const V1 &v1,
+ V2 &v2) {
+ copy(v1, v2);
+ gmm::upper_tri_solve(P.U, v2, true);
+ for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_right_mult(const choleskyt_precond<Matrix>& P, const V1 &v1,
+ V2 &v2)
+ { copy(v1, v2); gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true); }
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_precond_ilu.h b/Contrib/gmm/gmm_precond_ilu.h
new file mode 100755
index 0000000..4d5f5fa
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_ilu.h
@@ -0,0 +1,280 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of ilu.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the University of California, Berkeley nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
+// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_precond_ilu.h
+ @author Andrew Lumsdaine <lums at osl.iu.edu>
+ @author Lie-Quan Lee <llee at osl.iu.edu>
+ @author Yves Renard <yves.renard at insa-lyon.fr>
+ @date June 5, 2003.
+ @brief Incomplete LU without fill-in Preconditioner.
+*/
+
+#ifndef GMM_PRECOND_ILU_H
+#define GMM_PRECOND_ILU_H
+
+//
+// Notes: The idea under a concrete Preconditioner such
+// as Incomplete LU is to create a Preconditioner
+// object to use in iterative methods.
+//
+
+#include "gmm_precond.h"
+
+namespace gmm {
+ /** Incomplete LU without fill-in Preconditioner. */
+ template <typename Matrix>
+ class ilu_precond {
+
+ public :
+ typedef typename linalg_traits<Matrix>::value_type value_type;
+ typedef csr_matrix_ref<value_type *, size_type *, size_type *, 0> tm_type;
+
+ tm_type U, L;
+ bool invert;
+ protected :
+ std::vector<value_type> L_val, U_val;
+ std::vector<size_type> L_ind, U_ind, L_ptr, U_ptr;
+
+ template<typename M> void do_ilu(const M& A, row_major);
+ void do_ilu(const Matrix& A, col_major);
+
+ public:
+
+ size_type nrows(void) const { return mat_nrows(L); }
+ size_type ncols(void) const { return mat_ncols(U); }
+
+ void build_with(const Matrix& A) {
+ invert = false;
+ L_ptr.resize(mat_nrows(A)+1);
+ U_ptr.resize(mat_nrows(A)+1);
+ do_ilu(A, typename principal_orientation_type<typename
+ linalg_traits<Matrix>::sub_orientation>::potype());
+ }
+ ilu_precond(const Matrix& A) { build_with(A); }
+ ilu_precond(void) {}
+ size_type memsize() const {
+ return sizeof(*this) +
+ (L_val.size()+U_val.size()) * sizeof(value_type) +
+ (L_ind.size()+L_ptr.size()) * sizeof(size_type) +
+ (U_ind.size()+U_ptr.size()) * sizeof(size_type);
+ }
+ };
+
+ template <typename Matrix> template <typename M>
+ void ilu_precond<Matrix>::do_ilu(const M& A, row_major) {
+ typedef typename linalg_traits<Matrix>::storage_type store_type;
+ typedef value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type L_loc = 0, U_loc = 0, n = mat_nrows(A), i, j, k;
+ if (n == 0) return;
+ L_ptr[0] = 0; U_ptr[0] = 0;
+ R prec = default_tol(R());
+ R max_pivot = gmm::abs(A(0,0)) * prec;
+
+
+ for (int count = 0; count < 2; ++count) {
+ if (count) {
+ L_val.resize(L_loc); L_ind.resize(L_loc);
+ U_val.resize(U_loc); U_ind.resize(U_loc);
+ }
+ L_loc = U_loc = 0;
+ for (i = 0; i < n; ++i) {
+ typedef typename linalg_traits<M>::const_sub_row_type row_type;
+ row_type row = mat_const_row(A, i);
+ typename linalg_traits<row_type>::const_iterator
+ it = vect_const_begin(row), ite = vect_const_end(row);
+
+ if (count) { U_val[U_loc] = T(0); U_ind[U_loc] = i; }
+ ++U_loc; // diagonal element
+
+ for (k = 0; it != ite && k < 1000; ++it, ++k) {
+ // if a plain row is present, retains only the 1000 firsts
+ // nonzero elements. ---> a sort should be done.
+ j = index_of_it(it, k, store_type());
+ if (j < i) {
+ if (count) { L_val[L_loc] = *it; L_ind[L_loc] = j; }
+ L_loc++;
+ }
+ else if (i == j) {
+ if (count) U_val[U_loc-1] = *it;
+ }
+ else {
+ if (count) { U_val[U_loc] = *it; U_ind[U_loc] = j; }
+ U_loc++;
+ }
+ }
+ L_ptr[i+1] = L_loc; U_ptr[i+1] = U_loc;
+ }
+ }
+
+ if (A(0,0) == T(0)) {
+ U_val[U_ptr[0]] = T(1);
+ GMM_WARNING2("pivot 0 is too small");
+ }
+
+ size_type qn, pn, rn;
+ for (i = 1; i < n; i++) {
+
+ pn = U_ptr[i];
+ if (gmm::abs(U_val[pn]) <= max_pivot) {
+ U_val[pn] = T(1);
+ GMM_WARNING2("pivot " << i << " is too small");
+ }
+ max_pivot = std::max(max_pivot,
+ std::min(gmm::abs(U_val[pn]) * prec, R(1)));
+
+ for (j = L_ptr[i]; j < L_ptr[i+1]; j++) {
+ pn = U_ptr[L_ind[j]];
+
+ T multiplier = (L_val[j] /= U_val[pn]);
+
+ qn = j + 1;
+ rn = U_ptr[i];
+
+ for (pn++; U_ind[pn] < i && pn < U_ptr[L_ind[j]+1]; pn++) {
+ while (L_ind[qn] < U_ind[pn] && qn < L_ptr[i+1])
+ qn++;
+ if (U_ind[pn] == L_ind[qn] && qn < L_ptr[i+1])
+ L_val[qn] -= multiplier * U_val[pn];
+ }
+ for (; pn < U_ptr[L_ind[j]+1]; pn++) {
+ while (U_ind[rn] < U_ind[pn] && rn < U_ptr[i+1])
+ rn++;
+ if (U_ind[pn] == U_ind[rn] && rn < U_ptr[i+1])
+ U_val[rn] -= multiplier * U_val[pn];
+ }
+ }
+ }
+
+ L = tm_type(&(L_val[0]), &(L_ind[0]), &(L_ptr[0]), n, mat_ncols(A));
+ U = tm_type(&(U_val[0]), &(U_ind[0]), &(U_ptr[0]), n, mat_ncols(A));
+ }
+
+ template <typename Matrix>
+ void ilu_precond<Matrix>::do_ilu(const Matrix& A, col_major) {
+ do_ilu(gmm::transposed(A), row_major());
+ invert = true;
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void mult(const ilu_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ gmm::copy(v1, v2);
+ if (P.invert) {
+ gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ }
+ else {
+ gmm::lower_tri_solve(P.L, v2, true);
+ gmm::upper_tri_solve(P.U, v2, false);
+ }
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_mult(const ilu_precond<Matrix>& P,const V1 &v1,V2 &v2) {
+ gmm::copy(v1, v2);
+ if (P.invert) {
+ gmm::lower_tri_solve(P.L, v2, true);
+ gmm::upper_tri_solve(P.U, v2, false);
+ }
+ else {
+ gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ }
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void left_mult(const ilu_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ copy(v1, v2);
+ if (P.invert) gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ else gmm::lower_tri_solve(P.L, v2, true);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void right_mult(const ilu_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ copy(v1, v2);
+ if (P.invert) gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ else gmm::upper_tri_solve(P.U, v2, false);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_left_mult(const ilu_precond<Matrix>& P, const V1 &v1,
+ V2 &v2) {
+ copy(v1, v2);
+ if (P.invert) gmm::upper_tri_solve(P.U, v2, false);
+ else gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_right_mult(const ilu_precond<Matrix>& P, const V1 &v1,
+ V2 &v2) {
+ copy(v1, v2);
+ if (P.invert) gmm::lower_tri_solve(P.L, v2, true);
+ else gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ }
+
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_precond_ilut.h b/Contrib/gmm/gmm_precond_ilut.h
new file mode 100755
index 0000000..b0c3045
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_ilut.h
@@ -0,0 +1,227 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+#ifndef GMM_PRECOND_ILUT_H
+#define GMM_PRECOND_ILUT_H
+
+/**@file gmm_precond_ilut.h
+ @author Andrew Lumsdaine <lums at osl.iu.edu>, Lie-Quan Lee <llee at osl.iu.edu>
+ @date June 5, 2003.
+ @brief ILUT: Incomplete LU with threshold and K fill-in Preconditioner.
+*/
+
+/*
+ Performane comparing for SSOR, ILU and ILUT based on sherman 5 matrix
+ in Harwell-Boeing collection on Sun Ultra 30 UPA/PCI (UltraSPARC-II 296MHz)
+ Preconditioner & Factorization time & Number of Iteration \\ \hline
+ SSOR & 0.010577 & 41 \\
+ ILU & 0.019336 & 32 \\
+ ILUT with 0 fill-in and threshold of 1.0e-6 & 0.343612 & 23 \\
+ ILUT with 5 fill-in and threshold of 1.0e-6 & 0.343612 & 18 \\ \hline
+*/
+
+#include "gmm_precond.h"
+
+namespace gmm {
+
+ template<typename T> struct elt_rsvector_value_less_ {
+ inline bool operator()(const elt_rsvector_<T>& a,
+ const elt_rsvector_<T>& b) const
+ { return (gmm::abs(a.e) > gmm::abs(b.e)); }
+ };
+
+ /** Incomplete LU with threshold and K fill-in Preconditioner.
+
+ The algorithm of ILUT(A, 0, 1.0e-6) is slower than ILU(A). If No
+ fill-in is arrowed, you can use ILU instead of ILUT.
+
+ Notes: The idea under a concrete Preconditioner such as ilut is to
+ create a Preconditioner object to use in iterative methods.
+ */
+ template <typename Matrix>
+ class ilut_precond {
+ public :
+ typedef typename linalg_traits<Matrix>::value_type value_type;
+ typedef wsvector<value_type> _wsvector;
+ typedef rsvector<value_type> _rsvector;
+ typedef row_matrix<_rsvector> LU_Matrix;
+
+ bool invert;
+ LU_Matrix L, U;
+
+ protected:
+ size_type K;
+ double eps;
+
+ template<typename M> void do_ilut(const M&, row_major);
+ void do_ilut(const Matrix&, col_major);
+
+ public:
+ void build_with(const Matrix& A) {
+ invert = false;
+ gmm::resize(L, mat_nrows(A), mat_ncols(A));
+ gmm::resize(U, mat_nrows(A), mat_ncols(A));
+ do_ilut(A, typename principal_orientation_type<typename
+ linalg_traits<Matrix>::sub_orientation>::potype());
+ }
+ ilut_precond(const Matrix& A, int k_, double eps_)
+ : L(mat_nrows(A), mat_ncols(A)), U(mat_nrows(A), mat_ncols(A)),
+ K(k_), eps(eps_) { build_with(A); }
+ ilut_precond(size_type k_, double eps_) : K(k_), eps(eps_) {}
+ ilut_precond(void) { K = 10; eps = 1E-7; }
+ size_type memsize() const {
+ return sizeof(*this) + (nnz(U)+nnz(L))*sizeof(value_type);
+ }
+ };
+
+ template<typename Matrix> template<typename M>
+ void ilut_precond<Matrix>::do_ilut(const M& A, row_major) {
+ typedef value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type n = mat_nrows(A);
+ if (n == 0) return;
+ std::vector<T> indiag(n);
+ _wsvector w(mat_ncols(A));
+ _rsvector ww(mat_ncols(A)), wL(mat_ncols(A)), wU(mat_ncols(A));
+ T tmp;
+ gmm::clear(U); gmm::clear(L);
+ R prec = default_tol(R());
+ R max_pivot = gmm::abs(A(0,0)) * prec;
+
+ for (size_type i = 0; i < n; ++i) {
+ gmm::copy(mat_const_row(A, i), w);
+ double norm_row = gmm::vect_norm2(w);
+
+ typename _wsvector::iterator wkold = w.begin();
+ bool itfirst = true;
+ for (typename _wsvector::iterator wk = w.begin();
+ wk != w.end() && wk->first < i; ) {
+ size_type k = wk->first;
+ tmp = (wk->second) * indiag[k];
+ if (gmm::abs(tmp) < eps * norm_row) w.erase(k);
+ else { wk->second += tmp; gmm::add(scaled(mat_row(U, k), -tmp), w); }
+ if (itfirst) wk = w.begin(); else wk = ++wkold;
+ if (wk != w.end() && wk->first == k) { ++wk; itfirst = false; }
+ }
+ tmp = w[i];
+
+ if (gmm::abs(tmp) <= max_pivot) {
+ GMM_WARNING2("pivot " << i << " too small. try with ilutp ?");
+ w[i] = tmp = T(1);
+ }
+
+ max_pivot = std::max(max_pivot, std::min(gmm::abs(tmp) * prec, R(1)));
+ indiag[i] = T(1) / tmp;
+ gmm::clean(w, eps * norm_row);
+ gmm::copy(w, ww);
+ std::sort(ww.begin(), ww.end(), elt_rsvector_value_less_<T>());
+ typename _rsvector::const_iterator wit = ww.begin(), wite = ww.end();
+
+ size_type nnl = 0, nnu = 0;
+ wL.base_resize(K); wU.base_resize(K+1);
+ typename _rsvector::iterator witL = wL.begin(), witU = wU.begin();
+ for (; wit != wite; ++wit)
+ if (wit->c < i) { if (nnl < K) { *witL++ = *wit; ++nnl; } }
+ else { if (nnu < K || wit->c == i) { *witU++ = *wit; ++nnu; } }
+ wL.base_resize(nnl); wU.base_resize(nnu);
+ std::sort(wL.begin(), wL.end());
+ std::sort(wU.begin(), wU.end());
+ gmm::copy(wL, L.row(i));
+ gmm::copy(wU, U.row(i));
+ }
+
+ }
+
+ template<typename Matrix>
+ void ilut_precond<Matrix>::do_ilut(const Matrix& A, col_major) {
+ do_ilut(gmm::transposed(A), row_major());
+ invert = true;
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void mult(const ilut_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ gmm::copy(v1, v2);
+ if (P.invert) {
+ gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ }
+ else {
+ gmm::lower_tri_solve(P.L, v2, true);
+ gmm::upper_tri_solve(P.U, v2, false);
+ }
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_mult(const ilut_precond<Matrix>& P,const V1 &v1,V2 &v2) {
+ gmm::copy(v1, v2);
+ if (P.invert) {
+ gmm::lower_tri_solve(P.L, v2, true);
+ gmm::upper_tri_solve(P.U, v2, false);
+ }
+ else {
+ gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ }
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void left_mult(const ilut_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ copy(v1, v2);
+ if (P.invert) gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ else gmm::lower_tri_solve(P.L, v2, true);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void right_mult(const ilut_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ copy(v1, v2);
+ if (P.invert) gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ else gmm::upper_tri_solve(P.U, v2, false);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_left_mult(const ilut_precond<Matrix>& P, const V1 &v1,
+ V2 &v2) {
+ copy(v1, v2);
+ if (P.invert) gmm::upper_tri_solve(P.U, v2, false);
+ else gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_right_mult(const ilut_precond<Matrix>& P, const V1 &v1,
+ V2 &v2) {
+ copy(v1, v2);
+ if (P.invert) gmm::lower_tri_solve(P.L, v2, true);
+ else gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ }
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_precond_ilutp.h b/Contrib/gmm/gmm_precond_ilutp.h
new file mode 100755
index 0000000..68bce2e
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_ilutp.h
@@ -0,0 +1,281 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2004-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_precond_ilutp.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 14, 2004.
+ @brief ILUTP: Incomplete LU with threshold and K fill-in Preconditioner and
+ column pivoting.
+
+
+*/
+#ifndef GMM_PRECOND_ILUTP_H
+#define GMM_PRECOND_ILUTP_H
+
+#include "gmm_precond_ilut.h"
+
+namespace gmm {
+
+ /**
+ ILUTP: Incomplete LU with threshold and K fill-in Preconditioner and
+ column pivoting.
+
+ See Yousef Saad, Iterative Methods for
+ sparse linear systems, PWS Publishing Company, section 10.4.4
+
+ TODO : store the permutation by cycles to avoid the temporary vector
+ */
+ template <typename Matrix>
+ class ilutp_precond {
+ public :
+ typedef typename linalg_traits<Matrix>::value_type value_type;
+ typedef wsvector<value_type> _wsvector;
+ typedef rsvector<value_type> _rsvector;
+ typedef row_matrix<_rsvector> LU_Matrix;
+ typedef col_matrix<_wsvector> CLU_Matrix;
+
+ bool invert;
+ LU_Matrix L, U;
+ gmm::unsorted_sub_index indperm;
+ gmm::unsorted_sub_index indperminv;
+ mutable std::vector<value_type> temporary;
+
+ protected:
+ size_type K;
+ double eps;
+
+ template<typename M> void do_ilutp(const M&, row_major);
+ void do_ilutp(const Matrix&, col_major);
+
+ public:
+ void build_with(const Matrix& A) {
+ invert = false;
+ gmm::resize(L, mat_nrows(A), mat_ncols(A));
+ gmm::resize(U, mat_nrows(A), mat_ncols(A));
+ do_ilutp(A, typename principal_orientation_type<typename
+ linalg_traits<Matrix>::sub_orientation>::potype());
+ }
+ ilutp_precond(const Matrix& A, size_type k_, double eps_)
+ : L(mat_nrows(A), mat_ncols(A)), U(mat_nrows(A), mat_ncols(A)),
+ K(k_), eps(eps_) { build_with(A); }
+ ilutp_precond(int k_, double eps_) : K(k_), eps(eps_) {}
+ ilutp_precond(void) { K = 10; eps = 1E-7; }
+ size_type memsize() const {
+ return sizeof(*this) + (nnz(U)+nnz(L))*sizeof(value_type);
+ }
+ };
+
+
+ template<typename Matrix> template<typename M>
+ void ilutp_precond<Matrix>::do_ilutp(const M& A, row_major) {
+ typedef value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ size_type n = mat_nrows(A);
+ CLU_Matrix CU(n,n);
+ if (n == 0) return;
+ std::vector<T> indiag(n);
+ temporary.resize(n);
+ std::vector<size_type> ipvt(n), ipvtinv(n);
+ for (size_type i = 0; i < n; ++i) ipvt[i] = ipvtinv[i] = i;
+ indperm = unsorted_sub_index(ipvt);
+ indperminv = unsorted_sub_index(ipvtinv);
+ _wsvector w(mat_ncols(A));
+ _rsvector ww(mat_ncols(A));
+
+ T tmp = T(0);
+ gmm::clear(L); gmm::clear(U);
+ R prec = default_tol(R());
+ R max_pivot = gmm::abs(A(0,0)) * prec;
+
+ for (size_type i = 0; i < n; ++i) {
+
+ copy(sub_vector(mat_const_row(A, i), indperm), w);
+ double norm_row = gmm::vect_norm2(mat_const_row(A, i));
+
+ typename _wsvector::iterator wkold = w.begin();
+ bool itfirst = true;
+ for (typename _wsvector::iterator wk = w.begin();
+ wk != w.end() && wk->first < i; ) {
+ size_type k = wk->first;
+ tmp = (wk->second) * indiag[k];
+ if (gmm::abs(tmp) < eps * norm_row) w.erase(k);
+ else { wk->second += tmp; gmm::add(scaled(mat_row(U, k), -tmp), w); }
+ if (itfirst) wk = w.begin(); else wk = ++wkold;
+ if (wk != w.end() && wk->first == k) { ++wk; itfirst = false; }
+ }
+
+ gmm::clean(w, eps * norm_row);
+ gmm::copy(w, ww);
+
+ std::sort(ww.begin(), ww.end(), elt_rsvector_value_less_<T>());
+ typename _rsvector::const_iterator wit = ww.begin(), wite = ww.end();
+ size_type ip = size_type(-1);
+
+ for (; wit != wite; ++wit)
+ if (wit->c >= i) { ip = wit->c; tmp = wit->e; break; }
+ if (ip == size_type(-1) || gmm::abs(tmp) <= max_pivot)
+ { GMM_WARNING2("pivot " << i << " too small"); ip=i; ww[i]=tmp=T(1); }
+ max_pivot = std::max(max_pivot, std::min(gmm::abs(tmp) * prec, R(1)));
+ indiag[i] = T(1) / tmp;
+ wit = ww.begin();
+
+ size_type nnl = 0, nnu = 0;
+ L[i].base_resize(K); U[i].base_resize(K+1);
+ typename _rsvector::iterator witL = L[i].begin(), witU = U[i].begin();
+ for (; wit != wite; ++wit) {
+ if (wit->c < i) { if (nnl < K) { *witL++ = *wit; ++nnl; } }
+ else if (nnu < K || wit->c == i)
+ { CU(i, wit->c) = wit->e; *witU++ = *wit; ++nnu; }
+ }
+ L[i].base_resize(nnl); U[i].base_resize(nnu);
+ std::sort(L[i].begin(), L[i].end());
+ std::sort(U[i].begin(), U[i].end());
+
+ if (ip != i) {
+ typename _wsvector::const_iterator iti = CU.col(i).begin();
+ typename _wsvector::const_iterator itie = CU.col(i).end();
+ typename _wsvector::const_iterator itp = CU.col(ip).begin();
+ typename _wsvector::const_iterator itpe = CU.col(ip).end();
+
+ while (iti != itie && itp != itpe) {
+ if (iti->first < itp->first)
+ { U.row(iti->first).swap_indices(i, ip); ++iti; }
+ else if (iti->first > itp->first)
+ { U.row(itp->first).swap_indices(i,ip);++itp; }
+ else
+ { U.row(iti->first).swap_indices(i, ip); ++iti; ++itp; }
+ }
+
+ for( ; iti != itie; ++iti) U.row(iti->first).swap_indices(i, ip);
+ for( ; itp != itpe; ++itp) U.row(itp->first).swap_indices(i, ip);
+
+ CU.swap_col(i, ip);
+
+ indperm.swap(i, ip);
+ indperminv.swap(ipvt[i], ipvt[ip]);
+ std::swap(ipvtinv[ipvt[i]], ipvtinv[ipvt[ip]]);
+ std::swap(ipvt[i], ipvt[ip]);
+ }
+ }
+ }
+
+ template<typename Matrix>
+ void ilutp_precond<Matrix>::do_ilutp(const Matrix& A, col_major) {
+ do_ilutp(gmm::transposed(A), row_major());
+ invert = true;
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ if (P.invert) {
+ gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
+ gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ }
+ else {
+ gmm::copy(v1, P.temporary);
+ gmm::lower_tri_solve(P.L, P.temporary, true);
+ gmm::upper_tri_solve(P.U, P.temporary, false);
+ gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
+ }
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_mult(const ilutp_precond<Matrix>& P,const V1 &v1,V2 &v2) {
+ if (P.invert) {
+ gmm::copy(v1, P.temporary);
+ gmm::lower_tri_solve(P.L, P.temporary, true);
+ gmm::upper_tri_solve(P.U, P.temporary, false);
+ gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
+ }
+ else {
+ gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
+ gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ }
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void left_mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ if (P.invert) {
+ gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
+ gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ }
+ else {
+ copy(v1, v2);
+ gmm::lower_tri_solve(P.L, v2, true);
+ }
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void right_mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+ if (P.invert) {
+ copy(v1, v2);
+ gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ }
+ else {
+ copy(v1, P.temporary);
+ gmm::upper_tri_solve(P.U, P.temporary, false);
+ gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
+ }
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_left_mult(const ilutp_precond<Matrix>& P, const V1 &v1,
+ V2 &v2) {
+ if (P.invert) {
+ copy(v1, P.temporary);
+ gmm::upper_tri_solve(P.U, P.temporary, false);
+ gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
+ }
+ else {
+ copy(v1, v2);
+ gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+ }
+ }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_right_mult(const ilutp_precond<Matrix>& P, const V1 &v1,
+ V2 &v2) {
+ if (P.invert) {
+ copy(v1, v2);
+ gmm::lower_tri_solve(P.L, v2, true);
+ }
+ else {
+ gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
+ gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+ }
+ }
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_precond_mr_approx_inverse.h b/Contrib/gmm/gmm_precond_mr_approx_inverse.h
new file mode 100755
index 0000000..cb54822
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_mr_approx_inverse.h
@@ -0,0 +1,148 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of approximate_inverse.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the University of California, Berkeley nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
+// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_precond_mr_approx_inverse.h
+ @author Andrew Lumsdaine <lums at osl.iu.edu>
+ @author Lie-Quan Lee <llee at osl.iu.edu>
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date June 5, 2003.
+ @brief Approximate inverse via MR iteration.
+*/
+
+#ifndef GMM_PRECOND_MR_APPROX_INVERSE_H
+#define GMM_PRECOND_MR_APPROX_INVERSE_H
+
+
+#include "gmm_precond.h"
+
+namespace gmm {
+
+ /** Approximate inverse via MR iteration (see P301 of Saad book).
+ */
+ template <typename Matrix>
+ struct mr_approx_inverse_precond {
+
+ typedef typename linalg_traits<Matrix>::value_type value_type;
+ typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+ typedef typename principal_orientation_type<typename
+ linalg_traits<Matrix>::sub_orientation>::potype sub_orientation;
+ typedef wsvector<value_type> VVector;
+ typedef col_matrix<VVector> MMatrix;
+
+ MMatrix M;
+ size_type nb_it;
+ magnitude_type threshold;
+
+ void build_with(const Matrix& A);
+ mr_approx_inverse_precond(const Matrix& A, size_type nb_it_,
+ magnitude_type threshold_)
+ : M(mat_nrows(A), mat_ncols(A))
+ { threshold = threshold_; nb_it = nb_it_; build_with(A); }
+ mr_approx_inverse_precond(void)
+ { threshold = magnitude_type(1E-7); nb_it = 5; }
+ mr_approx_inverse_precond(size_type nb_it_, magnitude_type threshold_)
+ { threshold = threshold_; nb_it = nb_it_; }
+ const MMatrix &approx_inverse(void) const { return M; }
+ };
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void mult(const mr_approx_inverse_precond<Matrix>& P, const V1 &v1, V2 &v2)
+ { mult(P.M, v1, v2); }
+
+ template <typename Matrix, typename V1, typename V2> inline
+ void transposed_mult(const mr_approx_inverse_precond<Matrix>& P,
+ const V1 &v1,V2 &v2)
+ { mult(gmm::conjugated(P.M), v1, v2); }
+
+ template <typename Matrix>
+ void mr_approx_inverse_precond<Matrix>::build_with(const Matrix& A) {
+ gmm::resize(M, mat_nrows(A), mat_ncols(A));
+ typedef value_type T;
+ typedef magnitude_type R;
+ VVector m(mat_ncols(A)),r(mat_ncols(A)),ei(mat_ncols(A)),Ar(mat_ncols(A));
+ T alpha = mat_trace(A)/ mat_euclidean_norm_sqr(A);
+ if (alpha == T(0)) alpha = T(1);
+
+ for (size_type i = 0; i < mat_nrows(A); ++i) {
+ gmm::clear(m); gmm::clear(ei);
+ m[i] = alpha;
+ ei[i] = T(1);
+
+ for (size_type j = 0; j < nb_it; ++j) {
+ gmm::mult(A, gmm::scaled(m, T(-1)), r);
+ gmm::add(ei, r);
+ gmm::mult(A, r, Ar);
+ T nAr = vect_sp(Ar,Ar);
+ if (gmm::abs(nAr) > R(0)) {
+ gmm::add(gmm::scaled(r, gmm::safe_divide(vect_sp(r, Ar), vect_sp(Ar, Ar))), m);
+ gmm::clean(m, threshold * gmm::vect_norm2(m));
+ } else gmm::clear(m);
+ }
+ if (gmm::vect_norm2(m) == R(0)) m[i] = alpha;
+ gmm::copy(m, M.col(i));
+ }
+ }
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_real_part.h b/Contrib/gmm/gmm_real_part.h
new file mode 100755
index 0000000..b023986
--- /dev/null
+++ b/Contrib/gmm/gmm_real_part.h
@@ -0,0 +1,604 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_real_part.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date September 18, 2003.
+ @brief extract the real/imaginary part of vectors/matrices
+*/
+#ifndef GMM_REAL_PART_H
+#define GMM_REAL_PART_H
+
+#include "gmm_def.h"
+#include "gmm_vector.h"
+
+namespace gmm {
+
+ struct linalg_real_part {};
+ struct linalg_imag_part {};
+ template <typename R, typename PART> struct which_part {};
+
+ template <typename C> typename number_traits<C>::magnitude_type
+ real_or_imag_part(C x, linalg_real_part) { return gmm::real(x); }
+ template <typename C> typename number_traits<C>::magnitude_type
+ real_or_imag_part(C x, linalg_imag_part) { return gmm::imag(x); }
+ template <typename T, typename C, typename OP> C
+ complex_from(T x, C y, OP op, linalg_real_part) { return std::complex<T>(op(std::real(y), x), std::imag(y)); }
+ template <typename T, typename C, typename OP> C
+ complex_from(T x, C y, OP op,linalg_imag_part) { return std::complex<T>(std::real(y), op(std::imag(y), x)); }
+
+ template<typename T> struct project2nd {
+ T operator()(T , T b) const { return b; }
+ };
+
+ template<typename T, typename R, typename PART> class ref_elt_vector<T, which_part<R, PART> > {
+
+ R r;
+
+ public :
+
+ operator T() const { return real_or_imag_part(std::complex<T>(r), PART()); }
+ ref_elt_vector(R r_) : r(r_) {}
+ inline ref_elt_vector &operator =(T v)
+ { r = complex_from(v, std::complex<T>(r), gmm::project2nd<T>(), PART()); return *this; }
+ inline bool operator ==(T v) const { return (r == v); }
+ inline bool operator !=(T v) const { return (r != v); }
+ inline ref_elt_vector &operator +=(T v)
+ { r = complex_from(v, std::complex<T>(r), std::plus<T>(), PART()); return *this; }
+ inline ref_elt_vector &operator -=(T v)
+ { r = complex_from(v, std::complex<T>(r), std::minus<T>(), PART()); return *this; }
+ inline ref_elt_vector &operator /=(T v)
+ { r = complex_from(v, std::complex<T>(r), std::divides<T>(), PART()); return *this; }
+ inline ref_elt_vector &operator *=(T v)
+ { r = complex_from(v, std::complex<T>(r), std::multiplies<T>(), PART()); return *this; }
+ inline ref_elt_vector &operator =(const ref_elt_vector &re)
+ { *this = T(re); return *this; }
+ T operator +() { return T(*this); } // necessary for unknow reason
+ T operator -() { return -T(*this); } // necessary for unknow reason
+ T operator +(T v) { return T(*this)+ v; } // necessary for unknow reason
+ T operator -(T v) { return T(*this)- v; } // necessary for unknow reason
+ T operator *(T v) { return T(*this)* v; } // necessary for unknow reason
+ T operator /(T v) { return T(*this)/ v; } // necessary for unknow reason
+ };
+
+ template<typename reference> struct ref_or_value_type {
+ template <typename T, typename W>
+ static W r(const T &x, linalg_real_part, W) {
+ return gmm::real(x);
+ }
+ template <typename T, typename W>
+ static W r(const T &x, linalg_imag_part, W) {
+ return gmm::imag(x);
+ }
+ };
+
+ template<typename U, typename R, typename PART>
+ struct ref_or_value_type<ref_elt_vector<U, which_part<R, PART> > > {
+ template<typename T , typename W>
+ static const T &r(const T &x, linalg_real_part, W)
+ { return x; }
+ template<typename T, typename W>
+ static const T &r(const T &x, linalg_imag_part, W) {
+ return x;
+ }
+ template<typename T , typename W>
+ static T &r(T &x, linalg_real_part, W)
+ { return x; }
+ template<typename T, typename W>
+ static T &r(T &x, linalg_imag_part, W) {
+ return x;
+ }
+ };
+
+
+ /* ********************************************************************* */
+ /* Reference to the real part of (complex) vectors */
+ /* ********************************************************************* */
+
+ template <typename IT, typename MIT, typename PART>
+ struct part_vector_iterator {
+ typedef typename std::iterator_traits<IT>::value_type vtype;
+ typedef typename gmm::number_traits<vtype>::magnitude_type value_type;
+ typedef value_type *pointer;
+ typedef ref_elt_vector<value_type, which_part<typename std::iterator_traits<IT>::reference, PART> > reference;
+ typedef typename std::iterator_traits<IT>::difference_type difference_type;
+ typedef typename std::iterator_traits<IT>::iterator_category
+ iterator_category;
+
+ IT it;
+
+ part_vector_iterator(void) {}
+ explicit part_vector_iterator(const IT &i) : it(i) {}
+ part_vector_iterator(const part_vector_iterator<MIT, MIT, PART> &i) : it(i.it) {}
+
+
+ size_type index(void) const { return it.index(); }
+ part_vector_iterator operator ++(int)
+ { part_vector_iterator tmp = *this; ++it; return tmp; }
+ part_vector_iterator operator --(int)
+ { part_vector_iterator tmp = *this; --it; return tmp; }
+ part_vector_iterator &operator ++() { ++it; return *this; }
+ part_vector_iterator &operator --() { --it; return *this; }
+ part_vector_iterator &operator +=(difference_type i)
+ { it += i; return *this; }
+ part_vector_iterator &operator -=(difference_type i)
+ { it -= i; return *this; }
+ part_vector_iterator operator +(difference_type i) const
+ { part_vector_iterator itb = *this; return (itb += i); }
+ part_vector_iterator operator -(difference_type i) const
+ { part_vector_iterator itb = *this; return (itb -= i); }
+ difference_type operator -(const part_vector_iterator &i) const
+ { return difference_type(it - i.it); }
+
+ reference operator *() const { return reference(*it); }
+ reference operator [](size_type ii) const { return reference(it[ii]); }
+
+ bool operator ==(const part_vector_iterator &i) const
+ { return (i.it == it); }
+ bool operator !=(const part_vector_iterator &i) const
+ { return (i.it != it); }
+ bool operator < (const part_vector_iterator &i) const
+ { return (it < i.it); }
+ };
+
+
+ template <typename PT, typename PART> struct part_vector {
+ typedef part_vector<PT, PART> this_type;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef V * CPT;
+ typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+ typename linalg_traits<V>::iterator, PT>::ref_type iterator;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::value_type value_type;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ iterator begin_, end_;
+ porigin_type origin;
+ size_type size_;
+
+ size_type size(void) const { return size_; }
+
+ reference operator[](size_type i) const {
+ return reference(ref_or_value_type<reference>::r(
+ linalg_traits<V>::access(origin, begin_, end_, i),
+ PART(), value_type()));
+ }
+
+ part_vector(V &v)
+ : begin_(vect_begin(v)), end_(vect_end(v)),
+ origin(linalg_origin(v)), size_(gmm::vect_size(v)) {}
+ part_vector(const V &v)
+ : begin_(vect_begin(const_cast<V &>(v))),
+ end_(vect_end(const_cast<V &>(v))),
+ origin(linalg_origin(const_cast<V &>(v))), size_(gmm::vect_size(v)) {}
+ part_vector() {}
+ part_vector(const part_vector<CPT, PART> &cr)
+ : begin_(cr.begin_),end_(cr.end_),origin(cr.origin), size_(cr.size_) {}
+ };
+
+ template <typename IT, typename MIT, typename ORG, typename PT,
+ typename PART> inline
+ void set_to_begin(part_vector_iterator<IT, MIT, PART> &it,
+ ORG o, part_vector<PT, PART> *, linalg_modifiable) {
+ typedef part_vector<PT, PART> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ set_to_begin(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
+ }
+ template <typename IT, typename MIT, typename ORG, typename PT,
+ typename PART> inline
+ void set_to_begin(part_vector_iterator<IT, MIT, PART> &it,
+ ORG o, const part_vector<PT, PART> *, linalg_modifiable) {
+ typedef part_vector<PT, PART> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ set_to_begin(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
+ }
+ template <typename IT, typename MIT, typename ORG, typename PT,
+ typename PART> inline
+ void set_to_end(part_vector_iterator<IT, MIT, PART> &it,
+ ORG o, part_vector<PT, PART> *, linalg_modifiable) {
+ typedef part_vector<PT, PART> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ set_to_end(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
+ }
+ template <typename IT, typename MIT, typename ORG,
+ typename PT, typename PART> inline
+ void set_to_end(part_vector_iterator<IT, MIT, PART> &it,
+ ORG o, const part_vector<PT, PART> *,
+ linalg_modifiable) {
+ typedef part_vector<PT, PART> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ set_to_end(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
+ }
+
+ template <typename PT, typename PART>
+ struct linalg_traits<part_vector<PT, PART> > {
+ typedef part_vector<PT, PART> this_type;
+ typedef this_type * pthis_type;
+ typedef PT pV;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef typename linalg_traits<V>::index_sorted index_sorted;
+ typedef typename linalg_traits<V>::is_reference V_reference;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_vector linalg_type;
+ typedef typename linalg_traits<V>::value_type vtype;
+ typedef typename number_traits<vtype>::magnitude_type value_type;
+ typedef typename select_ref<value_type, ref_elt_vector<value_type,
+ which_part<typename linalg_traits<V>::reference,
+ PART> >, PT>::ref_type reference;
+ typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+ typename linalg_traits<V>::iterator, PT>::ref_type pre_iterator;
+ typedef typename select_ref<abstract_null_type,
+ part_vector_iterator<pre_iterator, pre_iterator, PART>,
+ PT>::ref_type iterator;
+ typedef part_vector_iterator<typename linalg_traits<V>::const_iterator,
+ pre_iterator, PART> const_iterator;
+ typedef typename linalg_traits<V>::storage_type storage_type;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v) {
+ iterator it; it.it = v.begin_;
+ if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
+ set_to_begin(it, v.origin, pthis_type(), is_reference());
+ return it;
+ }
+ static const_iterator begin(const this_type &v) {
+ const_iterator it(v.begin_);
+ if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
+ { set_to_begin(it, v.origin, pthis_type(), is_reference()); }
+ return it;
+ }
+ static iterator end(this_type &v) {
+ iterator it(v.end_);
+ if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
+ set_to_end(it, v.origin, pthis_type(), is_reference());
+ return it;
+ }
+ static const_iterator end(const this_type &v) {
+ const_iterator it(v.end_);
+ if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
+ set_to_end(it, v.origin, pthis_type(), is_reference());
+ return it;
+ }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+
+ static void clear(origin_type* o, const iterator &begin_,
+ const iterator &end_, abstract_sparse) {
+ std::deque<size_type> ind;
+ iterator it = begin_;
+ for (; it != end_; ++it) ind.push_front(it.index());
+ for (; !(ind.empty()); ind.pop_back())
+ access(o, begin_, end_, ind.back()) = value_type(0);
+ }
+ static void clear(origin_type* o, const iterator &begin_,
+ const iterator &end_, abstract_skyline) {
+ clear(o, begin_, end_, abstract_sparse());
+ }
+ static void clear(origin_type* o, const iterator &begin_,
+ const iterator &end_, abstract_dense) {
+ for (iterator it = begin_; it != end_; ++it) *it = value_type(0);
+ }
+
+ static void clear(origin_type* o, const iterator &begin_,
+ const iterator &end_)
+ { clear(o, begin_, end_, storage_type()); }
+ static void do_clear(this_type &v) { clear(v.origin, begin(v), end(v)); }
+ static value_type access(const origin_type *o, const const_iterator &it,
+ const const_iterator &ite, size_type i) {
+ return real_or_imag_part(linalg_traits<V>::access(o, it.it, ite.it,i),
+ PART());
+ }
+ static reference access(origin_type *o, const iterator &it,
+ const iterator &ite, size_type i)
+ { return reference(linalg_traits<V>::access(o, it.it, ite.it,i)); }
+ };
+
+ template <typename PT, typename PART> std::ostream &operator <<
+ (std::ostream &o, const part_vector<PT, PART>& m)
+ { gmm::write(o,m); return o; }
+
+
+ /* ********************************************************************* */
+ /* Reference to the real or imaginary part of (complex) matrices */
+ /* ********************************************************************* */
+
+
+ template <typename PT, typename PART> struct part_row_ref {
+
+ typedef part_row_ref<PT, PART> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef M * CPT;
+ typedef typename std::iterator_traits<PT>::reference ref_M;
+ typedef typename select_ref<typename linalg_traits<this_type>
+ ::const_row_iterator, typename linalg_traits<this_type>
+ ::row_iterator, PT>::ref_type iterator;
+ typedef typename linalg_traits<this_type>::value_type value_type;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ iterator begin_, end_;
+ porigin_type origin;
+ size_type nr, nc;
+
+ part_row_ref(ref_M m)
+ : begin_(mat_row_begin(m)), end_(mat_row_end(m)),
+ origin(linalg_origin(m)), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
+
+ part_row_ref(const part_row_ref<CPT, PART> &cr) :
+ begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
+
+ reference operator()(size_type i, size_type j) const {
+ return reference(ref_or_value_type<reference>::r(
+ linalg_traits<M>::access(begin_+j, i),
+ PART(), value_type()));
+ }
+ };
+
+ template <typename PT, typename PART>
+ struct linalg_traits<part_row_ref<PT, PART> > {
+ typedef part_row_ref<PT, PART> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef typename linalg_traits<M>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<M>::value_type vtype;
+ typedef typename number_traits<vtype>::magnitude_type value_type;
+ typedef typename linalg_traits<M>::storage_type storage_type;
+ typedef abstract_null_type sub_col_type;
+ typedef abstract_null_type const_sub_col_type;
+ typedef abstract_null_type col_iterator;
+ typedef abstract_null_type const_col_iterator;
+ typedef typename linalg_traits<M>::const_sub_row_type
+ pre_const_sub_row_type;
+ typedef typename linalg_traits<M>::sub_row_type pre_sub_row_type;
+ typedef part_vector<const pre_const_sub_row_type *, PART>
+ const_sub_row_type;
+ typedef typename select_ref<abstract_null_type,
+ part_vector<pre_sub_row_type *, PART>, PT>::ref_type sub_row_type;
+ typedef typename linalg_traits<M>::const_row_iterator const_row_iterator;
+ typedef typename select_ref<abstract_null_type, typename
+ linalg_traits<M>::row_iterator, PT>::ref_type row_iterator;
+ typedef typename select_ref<
+ typename linalg_traits<const_sub_row_type>::reference,
+ typename linalg_traits<sub_row_type>::reference,
+ PT>::ref_type reference;
+ typedef row_major sub_orientation;
+ typedef typename linalg_traits<M>::index_sorted index_sorted;
+ static size_type ncols(const this_type &v) { return v.nc; }
+ static size_type nrows(const this_type &v) { return v.nr; }
+ static const_sub_row_type row(const const_row_iterator &it)
+ { return const_sub_row_type(linalg_traits<M>::row(it)); }
+ static sub_row_type row(const row_iterator &it)
+ { return sub_row_type(linalg_traits<M>::row(it)); }
+ static row_iterator row_begin(this_type &m) { return m.begin_; }
+ static row_iterator row_end(this_type &m) { return m.end_; }
+ static const_row_iterator row_begin(const this_type &m)
+ { return m.begin_; }
+ static const_row_iterator row_end(const this_type &m) { return m.end_; }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void do_clear(this_type &v);
+ static value_type access(const const_row_iterator &itrow, size_type i)
+ { return real_or_imag_part(linalg_traits<M>::access(itrow, i), PART()); }
+ static reference access(const row_iterator &itrow, size_type i) {
+ return reference(ref_or_value_type<reference>::r(
+ linalg_traits<M>::access(itrow, i),
+ PART(), value_type()));
+ }
+ };
+
+ template <typename PT, typename PART>
+ void linalg_traits<part_row_ref<PT, PART> >::do_clear(this_type &v) {
+ row_iterator it = mat_row_begin(v), ite = mat_row_end(v);
+ for (; it != ite; ++it) clear(row(it));
+ }
+
+ template<typename PT, typename PART> std::ostream &operator <<
+ (std::ostream &o, const part_row_ref<PT, PART>& m)
+ { gmm::write(o,m); return o; }
+
+ template <typename PT, typename PART> struct part_col_ref {
+
+ typedef part_col_ref<PT, PART> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef M * CPT;
+ typedef typename std::iterator_traits<PT>::reference ref_M;
+ typedef typename select_ref<typename linalg_traits<this_type>
+ ::const_col_iterator, typename linalg_traits<this_type>
+ ::col_iterator, PT>::ref_type iterator;
+ typedef typename linalg_traits<this_type>::value_type value_type;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ iterator begin_, end_;
+ porigin_type origin;
+ size_type nr, nc;
+
+ part_col_ref(ref_M m)
+ : begin_(mat_col_begin(m)), end_(mat_col_end(m)),
+ origin(linalg_origin(m)), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
+
+ part_col_ref(const part_col_ref<CPT, PART> &cr) :
+ begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
+
+ reference operator()(size_type i, size_type j) const {
+ return reference(ref_or_value_type<reference>::r(
+ linalg_traits<M>::access(begin_+j, i),
+ PART(), value_type()));
+ }
+ };
+
+ template <typename PT, typename PART>
+ struct linalg_traits<part_col_ref<PT, PART> > {
+ typedef part_col_ref<PT, PART> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef typename linalg_traits<M>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<M>::value_type vtype;
+ typedef typename number_traits<vtype>::magnitude_type value_type;
+ typedef typename linalg_traits<M>::storage_type storage_type;
+ typedef abstract_null_type sub_row_type;
+ typedef abstract_null_type const_sub_row_type;
+ typedef abstract_null_type row_iterator;
+ typedef abstract_null_type const_row_iterator;
+ typedef typename linalg_traits<M>::const_sub_col_type
+ pre_const_sub_col_type;
+ typedef typename linalg_traits<M>::sub_col_type pre_sub_col_type;
+ typedef part_vector<const pre_const_sub_col_type *, PART>
+ const_sub_col_type;
+ typedef typename select_ref<abstract_null_type,
+ part_vector<pre_sub_col_type *, PART>, PT>::ref_type sub_col_type;
+ typedef typename linalg_traits<M>::const_col_iterator const_col_iterator;
+ typedef typename select_ref<abstract_null_type, typename
+ linalg_traits<M>::col_iterator, PT>::ref_type col_iterator;
+ typedef typename select_ref<
+ typename linalg_traits<const_sub_col_type>::reference,
+ typename linalg_traits<sub_col_type>::reference,
+ PT>::ref_type reference;
+ typedef col_major sub_orientation;
+ typedef typename linalg_traits<M>::index_sorted index_sorted;
+ static size_type nrows(const this_type &v) { return v.nr; }
+ static size_type ncols(const this_type &v) { return v.nc; }
+ static const_sub_col_type col(const const_col_iterator &it)
+ { return const_sub_col_type(linalg_traits<M>::col(it)); }
+ static sub_col_type col(const col_iterator &it)
+ { return sub_col_type(linalg_traits<M>::col(it)); }
+ static col_iterator col_begin(this_type &m) { return m.begin_; }
+ static col_iterator col_end(this_type &m) { return m.end_; }
+ static const_col_iterator col_begin(const this_type &m)
+ { return m.begin_; }
+ static const_col_iterator col_end(const this_type &m) { return m.end_; }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void do_clear(this_type &v);
+ static value_type access(const const_col_iterator &itcol, size_type i)
+ { return real_or_imag_part(linalg_traits<M>::access(itcol, i), PART()); }
+ static reference access(const col_iterator &itcol, size_type i) {
+ return reference(ref_or_value_type<reference>::r(
+ linalg_traits<M>::access(itcol, i),
+ PART(), value_type()));
+ }
+ };
+
+ template <typename PT, typename PART>
+ void linalg_traits<part_col_ref<PT, PART> >::do_clear(this_type &v) {
+ col_iterator it = mat_col_begin(v), ite = mat_col_end(v);
+ for (; it != ite; ++it) clear(col(it));
+ }
+
+ template<typename PT, typename PART> std::ostream &operator <<
+ (std::ostream &o, const part_col_ref<PT, PART>& m)
+ { gmm::write(o,m); return o; }
+
+
+
+
+
+
+template <typename TYPE, typename PART, typename PT>
+ struct part_return_ {
+ typedef abstract_null_type return_type;
+ };
+ template <typename PT, typename PART>
+ struct part_return_<row_major, PART, PT> {
+ typedef typename std::iterator_traits<PT>::value_type L;
+ typedef typename select_return<part_row_ref<const L *, PART>,
+ part_row_ref< L *, PART>, PT>::return_type return_type;
+ };
+ template <typename PT, typename PART>
+ struct part_return_<col_major, PART, PT> {
+ typedef typename std::iterator_traits<PT>::value_type L;
+ typedef typename select_return<part_col_ref<const L *, PART>,
+ part_col_ref<L *, PART>, PT>::return_type return_type;
+ };
+
+ template <typename PT, typename PART, typename LT> struct part_return__{
+ typedef abstract_null_type return_type;
+ };
+
+ template <typename PT, typename PART>
+ struct part_return__<PT, PART, abstract_matrix> {
+ typedef typename std::iterator_traits<PT>::value_type L;
+ typedef typename part_return_<typename principal_orientation_type<
+ typename linalg_traits<L>::sub_orientation>::potype, PART,
+ PT>::return_type return_type;
+ };
+
+ template <typename PT, typename PART>
+ struct part_return__<PT, PART, abstract_vector> {
+ typedef typename std::iterator_traits<PT>::value_type L;
+ typedef typename select_return<part_vector<const L *, PART>,
+ part_vector<L *, PART>, PT>::return_type return_type;
+ };
+
+ template <typename PT, typename PART> struct part_return {
+ typedef typename std::iterator_traits<PT>::value_type L;
+ typedef typename part_return__<PT, PART,
+ typename linalg_traits<L>::linalg_type>::return_type return_type;
+ };
+
+ template <typename L> inline
+ typename part_return<const L *, linalg_real_part>::return_type
+ real_part(const L &l) {
+ return typename part_return<const L *, linalg_real_part>::return_type
+ (linalg_cast(const_cast<L &>(l)));
+ }
+
+ template <typename L> inline
+ typename part_return<L *, linalg_real_part>::return_type
+ real_part(L &l) {
+ return typename part_return<L *, linalg_real_part>::return_type(linalg_cast(l));
+ }
+
+ template <typename L> inline
+ typename part_return<const L *, linalg_imag_part>::return_type
+ imag_part(const L &l) {
+ return typename part_return<const L *, linalg_imag_part>::return_type
+ (linalg_cast(const_cast<L &>(l)));
+ }
+
+ template <typename L> inline
+ typename part_return<L *, linalg_imag_part>::return_type
+ imag_part(L &l) {
+ return typename part_return<L *, linalg_imag_part>::return_type(linalg_cast(l));
+ }
+
+
+
+}
+
+#endif // GMM_REAL_PART_H
diff --git a/Contrib/gmm/gmm_ref.h b/Contrib/gmm/gmm_ref.h
new file mode 100755
index 0000000..0f6c745
--- /dev/null
+++ b/Contrib/gmm/gmm_ref.h
@@ -0,0 +1,525 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2000-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+
+#ifndef GMM_REF_H__
+#define GMM_REF_H__
+
+/** @file gmm_ref.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date August 26, 2000.
+ * @brief Provide some simple pseudo-containers.
+ *
+ * WARNING : modifiying the container infirm the validity of references.
+ */
+
+
+#include <iterator>
+#include "gmm_except.h"
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* Simple reference. */
+ /* ********************************************************************* */
+
+ template<typename ITER> class tab_ref {
+
+ protected :
+
+ ITER begin_, end_;
+
+ public :
+
+ typedef typename std::iterator_traits<ITER>::value_type value_type;
+ typedef typename std::iterator_traits<ITER>::pointer pointer;
+ typedef typename std::iterator_traits<ITER>::pointer const_pointer;
+ typedef typename std::iterator_traits<ITER>::reference reference;
+ typedef typename std::iterator_traits<ITER>::reference const_reference;
+ typedef typename std::iterator_traits<ITER>::difference_type
+ difference_type;
+ typedef ITER iterator;
+ typedef ITER const_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef size_t size_type;
+
+ bool empty(void) const { return begin_ == end_; }
+ size_type size(void) const { return end_ - begin_; }
+
+ const iterator &begin(void) { return begin_; }
+ const const_iterator &begin(void) const { return begin_; }
+ const iterator &end(void) { return end_; }
+ const const_iterator &end(void) const { return end_; }
+ reverse_iterator rbegin(void) { return reverse_iterator(end()); }
+ const_reverse_iterator rbegin(void) const
+ { return const_reverse_iterator(end()); }
+ reverse_iterator rend(void) { return reverse_iterator(begin()); }
+ const_reverse_iterator rend(void) const
+ { return const_reverse_iterator(begin()); }
+
+ reference front(void) { return *begin(); }
+ const_reference front(void) const { return *begin(); }
+ reference back(void) { return *(--(end())); }
+ const_reference back(void) const { return *(--(end())); }
+ void pop_front(void) { ++begin_; }
+
+ const_reference operator [](size_type ii) const { return *(begin_ + ii);}
+ reference operator [](size_type ii) { return *(begin_ + ii); }
+
+ tab_ref(void) {}
+ tab_ref(const ITER &b, const ITER &e) : begin_(b), end_(e) {}
+ };
+
+
+ /* ********************************************************************* */
+ /* Reference with index. */
+ /* ********************************************************************* */
+
+// template<typename ITER> struct tab_ref_index_iterator_
+// : public dynamic_array<size_t>::const_iterator
+// {
+// typedef typename std::iterator_traits<ITER>::value_type value_type;
+// typedef typename std::iterator_traits<ITER>::pointer pointer;
+// typedef typename std::iterator_traits<ITER>::reference reference;
+// typedef typename std::iterator_traits<ITER>::difference_type
+// difference_type;
+// typedef std::random_access_iterator_tag iterator_category;
+// typedef size_t size_type;
+// typedef dynamic_array<size_type>::const_iterator dnas_iterator_;
+// typedef tab_ref_index_iterator_<ITER> iterator;
+
+
+// ITER piter;
+
+// iterator operator ++(int)
+// { iterator tmp = *this; ++(*((dnas_iterator_ *)(this))); return tmp; }
+// iterator operator --(int)
+// { iterator tmp = *this; --(*((dnas_iterator_ *)(this))); return tmp; }
+// iterator &operator ++()
+// { ++(*((dnas_iterator_ *)(this))); return *this; }
+// iterator &operator --()
+// { --(*((dnas_iterator_ *)(this))); return *this; }
+// iterator &operator +=(difference_type i)
+// { (*((dnas_iterator_ *)(this))) += i; return *this; }
+// iterator &operator -=(difference_type i)
+// { (*((dnas_iterator_ *)(this))) -= i; return *this; }
+// iterator operator +(difference_type i) const
+// { iterator it = *this; return (it += i); }
+// iterator operator -(difference_type i) const
+// { iterator it = *this; return (it -= i); }
+// difference_type operator -(const iterator &i) const
+// { return *((dnas_iterator_ *)(this)) - *((dnas_iterator_ *)(&i)); }
+
+// reference operator *() const
+// { return *(piter + *((*((dnas_iterator_ *)(this))))); }
+// reference operator [](int ii)
+// { return *(piter + *((*((dnas_iterator_ *)(this+ii))))); }
+
+// bool operator ==(const iterator &i) const
+// {
+// return ((piter) == ((i.piter))
+// && *((dnas_iterator_ *)(this)) == *((*((dnas_iterator_ *)(this)))));
+// }
+// bool operator !=(const iterator &i) const
+// { return !(i == *this); }
+// bool operator < (const iterator &i) const
+// {
+// return ((piter) == ((i.piter))
+// && *((dnas_iterator_ *)(this)) < *((*((dnas_iterator_ *)(this)))));
+// }
+
+// tab_ref_index_iterator_(void) {}
+// tab_ref_index_iterator_(const ITER &iter, const dnas_iterator_ &dnas_iter)
+// : dnas_iterator_(dnas_iter), piter(iter) {}
+// };
+
+
+// template<typename ITER> class tab_ref_index
+// {
+// public :
+
+// typedef typename std::iterator_traits<ITER>::value_type value_type;
+// typedef typename std::iterator_traits<ITER>::pointer pointer;
+// typedef typename std::iterator_traits<ITER>::pointer const_pointer;
+// typedef typename std::iterator_traits<ITER>::reference reference;
+// typedef typename std::iterator_traits<ITER>::reference const_reference;
+// typedef typename std::iterator_traits<ITER>::difference_type
+// difference_type;
+// typedef size_t size_type;
+// typedef tab_ref_index_iterator_<ITER> iterator;
+// typedef iterator const_iterator;
+// typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+// typedef std::reverse_iterator<iterator> reverse_iterator;
+
+// protected :
+
+// ITER begin_;
+// dynamic_array<size_type> index_;
+
+// public :
+
+// bool empty(void) const { return index_.empty(); }
+// size_type size(void) const { return index_.size(); }
+
+
+// iterator begin(void) { return iterator(begin_, index_.begin()); }
+// const_iterator begin(void) const
+// { return iterator(begin_, index_.begin()); }
+// iterator end(void) { return iterator(begin_, index_.end()); }
+// const_iterator end(void) const { return iterator(begin_, index_.end()); }
+// reverse_iterator rbegin(void) { return reverse_iterator(end()); }
+// const_reverse_iterator rbegin(void) const
+// { return const_reverse_iterator(end()); }
+// reverse_iterator rend(void) { return reverse_iterator(begin()); }
+// const_reverse_iterator rend(void) const
+// { return const_reverse_iterator(begin()); }
+
+
+// reference front(void) { return *(begin_ +index_[0]); }
+// const_reference front(void) const { return *(begin_ +index_[0]); }
+// reference back(void) { return *(--(end())); }
+// const_reference back(void) const { return *(--(end())); }
+
+// tab_ref_index(void) {}
+// tab_ref_index(const ITER &b, const dynamic_array<size_type> &ind)
+// { begin_ = b; index_ = ind; }
+
+// // to be changed in a const_reference ?
+// value_type operator [](size_type ii) const
+// { return *(begin_ + index_[ii]);}
+// reference operator [](size_type ii) { return *(begin_ + index_[ii]); }
+
+// };
+
+
+ /// iterator over a gmm::tab_ref_index_ref<ITER,ITER_INDEX>
+ template<typename ITER, typename ITER_INDEX>
+ struct tab_ref_index_ref_iterator_
+ {
+ typedef typename std::iterator_traits<ITER>::value_type value_type;
+ typedef typename std::iterator_traits<ITER>::pointer pointer;
+ typedef typename std::iterator_traits<ITER>::reference reference;
+ typedef typename std::iterator_traits<ITER>::difference_type
+ difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef tab_ref_index_ref_iterator_<ITER, ITER_INDEX> iterator;
+ typedef size_t size_type;
+
+ ITER piter;
+ ITER_INDEX iter_index;
+
+ iterator operator ++(int)
+ { iterator tmp = *this; ++iter_index; return tmp; }
+ iterator operator --(int)
+ { iterator tmp = *this; --iter_index; return tmp; }
+ iterator &operator ++() { ++iter_index; return *this; }
+ iterator &operator --() { --iter_index; return *this; }
+ iterator &operator +=(difference_type i)
+ { iter_index += i; return *this; }
+ iterator &operator -=(difference_type i)
+ { iter_index -= i; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator it = *this; return (it += i); }
+ iterator operator -(difference_type i) const
+ { iterator it = *this; return (it -= i); }
+ difference_type operator -(const iterator &i) const
+ { return iter_index - i.iter_index; }
+
+ reference operator *() const
+ { return *(piter + *iter_index); }
+ reference operator [](int ii) const
+ { return *(piter + *(iter_index+ii)); }
+
+ bool operator ==(const iterator &i) const
+ { return ((piter) == ((i.piter)) && iter_index == i.iter_index); }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+ bool operator < (const iterator &i) const
+ { return ((piter) == ((i.piter)) && iter_index < i.iter_index); }
+
+ tab_ref_index_ref_iterator_(void) {}
+ tab_ref_index_ref_iterator_(const ITER &iter,
+ const ITER_INDEX &dnas_iter)
+ : piter(iter), iter_index(dnas_iter) {}
+
+ };
+
+ /**
+ convenience template function for quick obtention of a indexed iterator
+ without having to specify its (long) typename
+ */
+ template<typename ITER, typename ITER_INDEX>
+ tab_ref_index_ref_iterator_<ITER,ITER_INDEX>
+ index_ref_iterator(ITER it, ITER_INDEX it_i) {
+ return tab_ref_index_ref_iterator_<ITER,ITER_INDEX>(it, it_i);
+ }
+
+ /** indexed array reference (given a container X, and a set of indexes I,
+ this class provides a pseudo-container Y such that
+ @code Y[i] = X[I[i]] @endcode
+ */
+ template<typename ITER, typename ITER_INDEX> class tab_ref_index_ref {
+ public :
+
+ typedef std::iterator_traits<ITER> traits_type;
+ typedef typename traits_type::value_type value_type;
+ typedef typename traits_type::pointer pointer;
+ typedef typename traits_type::pointer const_pointer;
+ typedef typename traits_type::reference reference;
+ typedef typename traits_type::reference const_reference;
+ typedef typename traits_type::difference_type difference_type;
+ typedef size_t size_type;
+ typedef tab_ref_index_ref_iterator_<ITER, ITER_INDEX> iterator;
+ typedef iterator const_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+
+ protected :
+
+ ITER begin_;
+ ITER_INDEX index_begin_, index_end_;
+
+ public :
+
+ bool empty(void) const { return index_begin_ == index_end_; }
+ size_type size(void) const { return index_end_ - index_begin_; }
+
+ iterator begin(void) { return iterator(begin_, index_begin_); }
+ const_iterator begin(void) const
+ { return iterator(begin_, index_begin_); }
+ iterator end(void) { return iterator(begin_, index_end_); }
+ const_iterator end(void) const { return iterator(begin_, index_end_); }
+ reverse_iterator rbegin(void) { return reverse_iterator(end()); }
+ const_reverse_iterator rbegin(void) const
+ { return const_reverse_iterator(end()); }
+ reverse_iterator rend(void) { return reverse_iterator(begin()); }
+ const_reverse_iterator rend(void) const
+ { return const_reverse_iterator(begin()); }
+
+ reference front(void) { return *(begin_ + *index_begin_); }
+ const_reference front(void) const { return *(begin_ + *index_begin_); }
+ reference back(void) { return *(--(end())); }
+ const_reference back(void) const { return *(--(end())); }
+ void pop_front(void) { ++index_begin_; }
+
+ tab_ref_index_ref(void) {}
+ tab_ref_index_ref(const ITER &b, const ITER_INDEX &bi,
+ const ITER_INDEX &ei)
+ : begin_(b), index_begin_(bi), index_end_(ei) {}
+
+ // to be changed in a const_reference ?
+ const_reference operator [](size_type ii) const
+ { return *(begin_ + index_begin_[ii]);}
+ reference operator [](size_type ii)
+ { return *(begin_ + index_begin_[ii]); }
+
+ };
+
+
+ /* ********************************************************************* */
+ /* Reference on regularly spaced elements. */
+ /* ********************************************************************* */
+
+ template<typename ITER> struct tab_ref_reg_spaced_iterator_ {
+
+ typedef typename std::iterator_traits<ITER>::value_type value_type;
+ typedef typename std::iterator_traits<ITER>::pointer pointer;
+ typedef typename std::iterator_traits<ITER>::reference reference;
+ typedef typename std::iterator_traits<ITER>::difference_type
+ difference_type;
+ typedef typename std::iterator_traits<ITER>::iterator_category
+ iterator_category;
+ typedef size_t size_type;
+ typedef tab_ref_reg_spaced_iterator_<ITER> iterator;
+
+ ITER it;
+ size_type N, i;
+
+ iterator operator ++(int) { iterator tmp = *this; i++; return tmp; }
+ iterator operator --(int) { iterator tmp = *this; i--; return tmp; }
+ iterator &operator ++() { i++; return *this; }
+ iterator &operator --() { i--; return *this; }
+ iterator &operator +=(difference_type ii) { i+=ii; return *this; }
+ iterator &operator -=(difference_type ii) { i-=ii; return *this; }
+ iterator operator +(difference_type ii) const
+ { iterator itt = *this; return (itt += ii); }
+ iterator operator -(difference_type ii) const
+ { iterator itt = *this; return (itt -= ii); }
+ difference_type operator -(const iterator &ii) const
+ { return (N ? (it - ii.it) / N : 0) + i - ii.i; }
+
+ reference operator *() const { return *(it + i*N); }
+ reference operator [](int ii) const { return *(it + (i+ii)*N); }
+
+ bool operator ==(const iterator &ii) const
+ { return (*this - ii) == difference_type(0); }
+ bool operator !=(const iterator &ii) const
+ { return (*this - ii) != difference_type(0); }
+ bool operator < (const iterator &ii) const
+ { return (*this - ii) < difference_type(0); }
+
+ tab_ref_reg_spaced_iterator_(void) {}
+ tab_ref_reg_spaced_iterator_(const ITER &iter, size_type n, size_type ii)
+ : it(iter), N(n), i(ii) { }
+
+ };
+
+ /**
+ convenience template function for quick obtention of a strided iterator
+ without having to specify its (long) typename
+ */
+ template<typename ITER> tab_ref_reg_spaced_iterator_<ITER>
+ reg_spaced_iterator(ITER it, size_t stride) {
+ return tab_ref_reg_spaced_iterator_<ITER>(it, stride);
+ }
+
+ /**
+ provide a "strided" view a of container
+ */
+ template<typename ITER> class tab_ref_reg_spaced {
+ public :
+
+ typedef typename std::iterator_traits<ITER>::value_type value_type;
+ typedef typename std::iterator_traits<ITER>::pointer pointer;
+ typedef typename std::iterator_traits<ITER>::pointer const_pointer;
+ typedef typename std::iterator_traits<ITER>::reference reference;
+ typedef typename std::iterator_traits<ITER>::reference const_reference;
+ typedef typename std::iterator_traits<ITER>::difference_type
+ difference_type;
+ typedef size_t size_type;
+ typedef tab_ref_reg_spaced_iterator_<ITER> iterator;
+ typedef iterator const_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+
+ protected :
+
+ ITER begin_;
+ size_type N, size_;
+
+ public :
+
+ bool empty(void) const { return size_ == 0; }
+ size_type size(void) const { return size_; }
+
+ iterator begin(void) { return iterator(begin_, N, 0); }
+ const_iterator begin(void) const { return iterator(begin_, N, 0); }
+ iterator end(void) { return iterator(begin_, N, size_); }
+ const_iterator end(void) const { return iterator(begin_, N, size_); }
+ reverse_iterator rbegin(void) { return reverse_iterator(end()); }
+ const_reverse_iterator rbegin(void) const
+ { return const_reverse_iterator(end()); }
+ reverse_iterator rend(void) { return reverse_iterator(begin()); }
+ const_reverse_iterator rend(void) const
+ { return const_reverse_iterator(begin()); }
+
+ reference front(void) { return *begin_; }
+ const_reference front(void) const { return *begin_; }
+ reference back(void) { return *(begin_ + N * (size_-1)); }
+ const_reference back(void) const { return *(begin_ + N * (size_-1)); }
+ void pop_front(void) { begin_ += N; }
+
+ tab_ref_reg_spaced(void) {}
+ tab_ref_reg_spaced(const ITER &b, size_type n, size_type s)
+ : begin_(b), N(n), size_(s) {}
+
+
+ const_reference operator [](size_type ii) const
+ { return *(begin_ + ii * N);}
+ reference operator [](size_type ii) { return *(begin_ + ii * N); }
+
+ };
+
+ /// iterator over a tab_ref_with_selection
+ template<typename ITER, typename COND>
+ struct tab_ref_with_selection_iterator_ : public ITER {
+ typedef typename std::iterator_traits<ITER>::value_type value_type;
+ typedef typename std::iterator_traits<ITER>::pointer pointer;
+ typedef typename std::iterator_traits<ITER>::reference reference;
+ typedef typename std::iterator_traits<ITER>::difference_type
+ difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef tab_ref_with_selection_iterator_<ITER, COND> iterator;
+ const COND cond;
+
+ void forward(void) { while (!(cond)(*this)) ITER::operator ++(); }
+ iterator &operator ++()
+ { ITER::operator ++(); forward(); return *this; }
+ iterator operator ++(int)
+ { iterator tmp = *this; ++(*this); return tmp; }
+
+ tab_ref_with_selection_iterator_(void) {}
+ tab_ref_with_selection_iterator_(const ITER &iter, const COND c)
+ : ITER(iter), cond(c) {}
+
+ };
+
+ /**
+ given a container X and a predicate P, provide pseudo-container Y
+ of all elements of X such that P(X[i]).
+ */
+ template<typename ITER, typename COND> class tab_ref_with_selection {
+
+ protected :
+
+ ITER begin_, end_;
+ COND cond;
+
+ public :
+
+ typedef typename std::iterator_traits<ITER>::value_type value_type;
+ typedef typename std::iterator_traits<ITER>::pointer pointer;
+ typedef typename std::iterator_traits<ITER>::pointer const_pointer;
+ typedef typename std::iterator_traits<ITER>::reference reference;
+ typedef typename std::iterator_traits<ITER>::reference const_reference;
+ typedef size_t size_type;
+ typedef tab_ref_with_selection_iterator_<ITER, COND> iterator;
+ typedef iterator const_iterator;
+
+ iterator begin(void) const
+ { iterator it(begin_, cond); it.forward(); return it; }
+ iterator end(void) const { return iterator(end_, cond); }
+ bool empty(void) const { return begin_ == end_; }
+
+ value_type front(void) const { return *begin(); }
+ void pop_front(void) { ++begin_; begin_ = begin(); }
+
+ COND &condition(void) { return cond; }
+ const COND &condition(void) const { return cond; }
+
+ tab_ref_with_selection(void) {}
+ tab_ref_with_selection(const ITER &b, const ITER &e, const COND &c)
+ : begin_(b), end_(e), cond(c) { begin_ = begin(); }
+
+ };
+
+}
+
+#endif /* GMM_REF_H__ */
diff --git a/Contrib/gmm/gmm_scaled.h b/Contrib/gmm/gmm_scaled.h
new file mode 100755
index 0000000..281ef59
--- /dev/null
+++ b/Contrib/gmm/gmm_scaled.h
@@ -0,0 +1,427 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_scaled.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date November 10, 2002.
+ @brief get a scaled view of a vector/matrix.
+*/
+#ifndef GMM_SCALED_H__
+#define GMM_SCALED_H__
+
+#include "gmm_def.h"
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* Scaled references on vectors */
+ /* ********************************************************************* */
+
+ template <typename IT, typename S> struct scaled_const_iterator {
+ typedef typename strongest_numeric_type<typename std::iterator_traits<IT>::value_type,
+ S>::T value_type;
+
+ typedef typename std::iterator_traits<IT>::pointer pointer;
+ typedef typename std::iterator_traits<IT>::reference reference;
+ typedef typename std::iterator_traits<IT>::difference_type difference_type;
+ typedef typename std::iterator_traits<IT>::iterator_category
+ iterator_category;
+
+ IT it;
+ S r;
+
+ scaled_const_iterator(void) {}
+ scaled_const_iterator(const IT &i, S x) : it(i), r(x) {}
+
+ inline size_type index(void) const { return it.index(); }
+ inline scaled_const_iterator operator ++(int)
+ { scaled_const_iterator tmp = *this; ++it; return tmp; }
+ inline scaled_const_iterator operator --(int)
+ { scaled_const_iterator tmp = *this; --it; return tmp; }
+ inline scaled_const_iterator &operator ++() { ++it; return *this; }
+ inline scaled_const_iterator &operator --() { --it; return *this; }
+ inline scaled_const_iterator &operator +=(difference_type i)
+ { it += i; return *this; }
+ inline scaled_const_iterator &operator -=(difference_type i)
+ { it -= i; return *this; }
+ inline scaled_const_iterator operator +(difference_type i) const
+ { scaled_const_iterator itb = *this; return (itb += i); }
+ inline scaled_const_iterator operator -(difference_type i) const
+ { scaled_const_iterator itb = *this; return (itb -= i); }
+ inline difference_type operator -(const scaled_const_iterator &i) const
+ { return difference_type(it - i.it); }
+
+ inline value_type operator *() const { return (*it) * r; }
+ inline value_type operator [](size_type ii) const { return it[ii] * r; }
+
+ inline bool operator ==(const scaled_const_iterator &i) const
+ { return (i.it == it); }
+ inline bool operator !=(const scaled_const_iterator &i) const
+ { return (i.it != it); }
+ inline bool operator < (const scaled_const_iterator &i) const
+ { return (it < i.it); }
+ };
+
+ template <typename V, typename S> struct scaled_vector_const_ref {
+ typedef scaled_vector_const_ref<V,S> this_type;
+ typedef typename linalg_traits<this_type>::value_type value_type;
+ typedef typename linalg_traits<V>::const_iterator iterator;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+ iterator begin_, end_;
+ const origin_type *origin;
+ size_type size_;
+ S r;
+
+ scaled_vector_const_ref(const V &v, S rr)
+ : begin_(vect_const_begin(v)), end_(vect_const_end(v)),
+ origin(linalg_origin(v)), size_(vect_size(v)), r(rr) {}
+
+ reference operator[](size_type i) const
+ { return r * linalg_traits<V>::access(origin, begin_, end_, i); }
+ };
+
+ template <typename V, typename S> struct linalg_traits<scaled_vector_const_ref<V,S> > {
+ typedef scaled_vector_const_ref<V,S> this_type;
+ typedef linalg_const is_reference;
+ typedef abstract_vector linalg_type;
+ typedef typename strongest_numeric_type<S, typename linalg_traits<V>::value_type>::T value_type;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef value_type reference;
+ typedef abstract_null_type iterator;
+ typedef scaled_const_iterator<typename linalg_traits<V>::const_iterator, S>
+ const_iterator;
+ typedef typename linalg_traits<V>::storage_type storage_type;
+ typedef typename linalg_traits<V>::index_sorted index_sorted;
+ static size_type size(const this_type &v) { return v.size_; }
+ static const_iterator begin(const this_type &v)
+ { return const_iterator(v.begin_, v.r); }
+ static const_iterator end(const this_type &v)
+ { return const_iterator(v.end_, v.r); }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static value_type access(const origin_type *o, const const_iterator &it,
+ const const_iterator &ite, size_type i)
+ { return it.r * (linalg_traits<V>::access(o, it.it, ite.it, i)); }
+
+ };
+
+ template<typename V, typename S> std::ostream &operator <<
+ (std::ostream &o, const scaled_vector_const_ref<V,S>& m)
+ { gmm::write(o,m); return o; }
+
+ /* ********************************************************************* */
+ /* Scaled references on matrices */
+ /* ********************************************************************* */
+
+ template <typename M, typename S> struct scaled_row_const_iterator {
+ typedef scaled_row_const_iterator<M,S> iterator;
+ typedef typename linalg_traits<M>::const_row_iterator ITER;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+
+ ITER it;
+ S r;
+
+ inline iterator operator ++(int) { iterator tmp=*this; it++; return tmp; }
+ inline iterator operator --(int) { iterator tmp=*this; it--; return tmp; }
+ inline iterator &operator ++() { it++; return *this; }
+ inline iterator &operator --() { it--; return *this; }
+ iterator &operator +=(difference_type i) { it += i; return *this; }
+ iterator &operator -=(difference_type i) { it -= i; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator itt = *this; return (itt += i); }
+ iterator operator -(difference_type i) const
+ { iterator itt = *this; return (itt -= i); }
+ difference_type operator -(const iterator &i) const
+ { return it - i.it; }
+
+ inline ITER operator *() const { return it; }
+ inline ITER operator [](int i) { return it + i; }
+
+ inline bool operator ==(const iterator &i) const { return (it == i.it); }
+ inline bool operator !=(const iterator &i) const { return !(i == *this); }
+ inline bool operator < (const iterator &i) const { return (it < i.it); }
+
+ scaled_row_const_iterator(void) {}
+ scaled_row_const_iterator(const ITER &i, S rr)
+ : it(i), r(rr) { }
+
+ };
+
+ template <typename M, typename S> struct scaled_row_matrix_const_ref {
+
+ typedef scaled_row_matrix_const_ref<M,S> this_type;
+ typedef typename linalg_traits<M>::const_row_iterator iterator;
+ typedef typename linalg_traits<this_type>::value_type value_type;
+ typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+ iterator begin_, end_;
+ const origin_type *origin;
+ S r;
+ size_type nr, nc;
+
+ scaled_row_matrix_const_ref(const M &m, S rr)
+ : begin_(mat_row_begin(m)), end_(mat_row_end(m)),
+ origin(linalg_origin(m)), r(rr), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
+
+ value_type operator()(size_type i, size_type j) const
+ { return r * linalg_traits<M>::access(begin_+i, j); }
+ };
+
+ template <typename M, typename S> struct linalg_traits<scaled_row_matrix_const_ref<M,S> > {
+ typedef scaled_row_matrix_const_ref<M,S> this_type;
+ typedef linalg_const is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<M>::origin_type origin_type;
+ typedef typename strongest_numeric_type<S, typename linalg_traits<M>::value_type>::T value_type;
+ typedef value_type reference;
+ typedef typename linalg_traits<M>::storage_type storage_type;
+ typedef typename linalg_traits<M>::const_sub_row_type vector_type;
+ typedef scaled_vector_const_ref<vector_type,S> sub_row_type;
+ typedef scaled_vector_const_ref<vector_type,S> const_sub_row_type;
+ typedef scaled_row_const_iterator<M,S> row_iterator;
+ typedef scaled_row_const_iterator<M,S> const_row_iterator;
+ typedef abstract_null_type const_sub_col_type;
+ typedef abstract_null_type sub_col_type;
+ typedef abstract_null_type const_col_iterator;
+ typedef abstract_null_type col_iterator;
+ typedef row_major sub_orientation;
+ typedef typename linalg_traits<M>::index_sorted index_sorted;
+ static size_type nrows(const this_type &m)
+ { return m.nr; }
+ static size_type ncols(const this_type &m)
+ { return m.nc; }
+ static const_sub_row_type row(const const_row_iterator &it)
+ { return scaled(linalg_traits<M>::row(it.it), it.r); }
+ static const_row_iterator row_begin(const this_type &m)
+ { return const_row_iterator(m.begin_, m.r); }
+ static const_row_iterator row_end(const this_type &m)
+ { return const_row_iterator(m.end_, m.r); }
+ static const origin_type* origin(const this_type &m) { return m.origin; }
+ static value_type access(const const_row_iterator &it, size_type i)
+ { return it.r * (linalg_traits<M>::access(it.it, i)); }
+ };
+
+ template<typename M, typename S> std::ostream &operator <<
+ (std::ostream &o, const scaled_row_matrix_const_ref<M,S>& m)
+ { gmm::write(o,m); return o; }
+
+
+ template <typename M, typename S> struct scaled_col_const_iterator {
+ typedef scaled_col_const_iterator<M,S> iterator;
+ typedef typename linalg_traits<M>::const_col_iterator ITER;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+
+ ITER it;
+ S r;
+
+ iterator operator ++(int) { iterator tmp = *this; it++; return tmp; }
+ iterator operator --(int) { iterator tmp = *this; it--; return tmp; }
+ iterator &operator ++() { it++; return *this; }
+ iterator &operator --() { it--; return *this; }
+ iterator &operator +=(difference_type i) { it += i; return *this; }
+ iterator &operator -=(difference_type i) { it -= i; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator itt = *this; return (itt += i); }
+ iterator operator -(difference_type i) const
+ { iterator itt = *this; return (itt -= i); }
+ difference_type operator -(const iterator &i) const
+ { return it - i.it; }
+
+ ITER operator *() const { return it; }
+ ITER operator [](int i) { return it + i; }
+
+ bool operator ==(const iterator &i) const { return (it == i.it); }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+ bool operator < (const iterator &i) const { return (it < i.it); }
+
+ scaled_col_const_iterator(void) {}
+ scaled_col_const_iterator(const ITER &i, S rr)
+ : it(i), r(rr) { }
+
+ };
+
+ template <typename M, typename S> struct scaled_col_matrix_const_ref {
+
+ typedef scaled_col_matrix_const_ref<M,S> this_type;
+ typedef typename linalg_traits<M>::const_col_iterator iterator;
+ typedef typename linalg_traits<this_type>::value_type value_type;
+ typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+ iterator begin_, end_;
+ const origin_type *origin;
+ S r;
+ size_type nr, nc;
+
+ scaled_col_matrix_const_ref(const M &m, S rr)
+ : begin_(mat_col_begin(m)), end_(mat_col_end(m)),
+ origin(linalg_origin(m)), r(rr), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
+
+ value_type operator()(size_type i, size_type j) const
+ { return r * linalg_traits<M>::access(begin_+j, i); }
+ };
+
+ template <typename M, typename S> struct linalg_traits<scaled_col_matrix_const_ref<M,S> > {
+ typedef scaled_col_matrix_const_ref<M,S> this_type;
+ typedef linalg_const is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename strongest_numeric_type<S, typename linalg_traits<M>::value_type>::T value_type;
+ typedef typename linalg_traits<M>::origin_type origin_type;
+ typedef value_type reference;
+ typedef typename linalg_traits<M>::storage_type storage_type;
+ typedef typename linalg_traits<M>::const_sub_col_type vector_type;
+ typedef abstract_null_type sub_col_type;
+ typedef scaled_vector_const_ref<vector_type,S> const_sub_col_type;
+ typedef abstract_null_type col_iterator;
+ typedef scaled_col_const_iterator<M,S> const_col_iterator;
+ typedef abstract_null_type const_sub_row_type;
+ typedef abstract_null_type sub_row_type;
+ typedef abstract_null_type const_row_iterator;
+ typedef abstract_null_type row_iterator;
+ typedef col_major sub_orientation;
+ typedef typename linalg_traits<M>::index_sorted index_sorted;
+ static size_type ncols(const this_type &m)
+ { return m.nc; }
+ static size_type nrows(const this_type &m)
+ { return m.nr; }
+ static const_sub_col_type col(const const_col_iterator &it)
+ { return scaled(linalg_traits<M>::col(it.it), it.r); }
+ static const_col_iterator col_begin(const this_type &m)
+ { return const_col_iterator(m.begin_, m.r); }
+ static const_col_iterator col_end(const this_type &m)
+ { return const_col_iterator(m.end_, m.r); }
+ static const origin_type* origin(const this_type &m) { return m.origin; }
+ static value_type access(const const_col_iterator &it, size_type i)
+ { return it.r * (linalg_traits<M>::access(it.it, i)); }
+ };
+
+ template<typename M, typename S> std::ostream &operator <<
+ (std::ostream &o, const scaled_col_matrix_const_ref<M,S>& m)
+ { gmm::write(o,m); return o; }
+
+
+ template <typename L, typename S, typename R> struct scaled_return__ {
+ typedef abstract_null_type return_type;
+ };
+ template <typename L, typename S> struct scaled_return__<L, S, row_major>
+ { typedef scaled_row_matrix_const_ref<L,S> return_type; };
+ template <typename L, typename S> struct scaled_return__<L, S, col_major>
+ { typedef scaled_col_matrix_const_ref<L,S> return_type; };
+
+
+ template <typename L, typename S, typename LT> struct scaled_return_ {
+ typedef abstract_null_type return_type;
+ };
+ template <typename L, typename S> struct scaled_return_<L, S, abstract_vector>
+ { typedef scaled_vector_const_ref<L,S> return_type; };
+ template <typename L, typename S> struct scaled_return_<L, S, abstract_matrix> {
+ typedef typename scaled_return__<L, S,
+ typename principal_orientation_type<typename
+ linalg_traits<L>::sub_orientation>::potype>::return_type return_type;
+ };
+
+ template <typename L, typename S> struct scaled_return {
+ typedef typename scaled_return_<L, S, typename
+ linalg_traits<L>::linalg_type>::return_type return_type;
+ };
+
+ template <typename L, typename S> inline
+ typename scaled_return<L,S>::return_type
+ scaled(const L &v, S x)
+ { return scaled(v, x, typename linalg_traits<L>::linalg_type()); }
+
+ template <typename V, typename S> inline
+ typename scaled_return<V,S>::return_type
+ scaled(const V &v, S x, abstract_vector)
+ { return scaled_vector_const_ref<V,S>(v, x); }
+
+ template <typename M, typename S> inline
+ typename scaled_return<M,S>::return_type
+ scaled(const M &m, S x,abstract_matrix) {
+ return scaled(m, x, typename principal_orientation_type<typename
+ linalg_traits<M>::sub_orientation>::potype());
+ }
+
+ template <typename M, typename S> inline
+ typename scaled_return<M,S>::return_type
+ scaled(const M &m, S x, row_major) {
+ return scaled_row_matrix_const_ref<M,S>(m, x);
+ }
+
+ template <typename M, typename S> inline
+ typename scaled_return<M,S>::return_type
+ scaled(const M &m, S x, col_major) {
+ return scaled_col_matrix_const_ref<M,S>(m, x);
+ }
+
+
+ /* ******************************************************************** */
+ /* matrix or vector scale */
+ /* ******************************************************************** */
+
+ template <typename L> inline
+ void scale(L& l, typename linalg_traits<L>::value_type a)
+ { scale(l, a, typename linalg_traits<L>::linalg_type()); }
+
+ template <typename L> inline
+ void scale(const L& l, typename linalg_traits<L>::value_type a)
+ { scale(linalg_const_cast(l), a); }
+
+ template <typename L> inline
+ void scale(L& l, typename linalg_traits<L>::value_type a, abstract_vector) {
+ typename linalg_traits<L>::iterator it = vect_begin(l), ite = vect_end(l);
+ for ( ; it != ite; ++it) *it *= a;
+ }
+
+ template <typename L>
+ void scale(L& l, typename linalg_traits<L>::value_type a, abstract_matrix) {
+ scale(l, a, typename principal_orientation_type<typename
+ linalg_traits<L>::sub_orientation>::potype());
+ }
+
+ template <typename L>
+ void scale(L& l, typename linalg_traits<L>::value_type a, row_major) {
+ typename linalg_traits<L>::row_iterator it = mat_row_begin(l),
+ ite = mat_row_end(l);
+ for ( ; it != ite; ++it) scale(linalg_traits<L>::row(it), a);
+ }
+
+ template <typename L>
+ void scale(L& l, typename linalg_traits<L>::value_type a, col_major) {
+ typename linalg_traits<L>::col_iterator it = mat_col_begin(l),
+ ite = mat_col_end(l);
+ for ( ; it != ite; ++it) scale(linalg_traits<L>::col(it), a);
+ }
+
+}
+
+#endif // GMM_SCALED_H__
diff --git a/Contrib/gmm/gmm_solver_Newton.h b/Contrib/gmm/gmm_solver_Newton.h
new file mode 100755
index 0000000..34c95dd
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_Newton.h
@@ -0,0 +1,137 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2006-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_solver_Newton.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @author Michel Fournie <fournie at mip.ups-tlse.fr>
+ @date January 24, 2006.
+*/
+#ifndef GMM_SOLVERS_NEWTON_H__
+#define GMM_SOLVERS_NEWTON_H__
+
+namespace gmm {
+
+#include "gmm_kernel.h"
+
+ /* ***************************************************************** */
+ /* Line search definition */
+ /* ***************************************************************** */
+
+ struct abstract_newton_line_search {
+ double conv_alpha, conv_r;
+ size_t it, itmax, glob_it;
+ virtual void init_search(double r, size_t git) = 0;
+ virtual double next_try(void) = 0;
+ virtual bool is_converged(double) = 0;
+ virtual double converged_value(void) { return conv_alpha; };
+ virtual double converged_residual(void) { return conv_r; };
+ virtual ~abstract_newton_line_search() {}
+ };
+
+
+ struct simplest_newton_line_search : public abstract_newton_line_search {
+ double alpha, alpha_mult, first_res, alpha_max_ratio, alpha_min;
+ virtual void init_search(double r, size_t git) {
+ glob_it = git;
+ conv_alpha = alpha = double(1); conv_r = first_res = r; it = 0;
+ }
+ virtual double next_try(void)
+ { conv_alpha = alpha; alpha *= alpha_mult; ++it; return conv_alpha; }
+ virtual bool is_converged(double r) {
+ conv_r = r;
+ return ((it <= 1 && r < first_res)
+ || (r <= first_res * alpha_max_ratio)
+ || (conv_alpha <= alpha_min)
+ || it >= itmax);
+ }
+ simplest_newton_line_search
+ (size_t imax = size_t(-1), double a_max_ratio = 6.0/5.0,
+ double a_min = 1.0/1000.0, double a_mult = 3.0/5.0)
+ : alpha_mult(a_mult), alpha_max_ratio(a_max_ratio), alpha_min(a_min)
+ { itmax = imax; }
+ };
+
+ struct default_newton_line_search : public abstract_newton_line_search {
+ double alpha, alpha_mult, first_res, alpha_max_ratio;
+ double alpha_min, prev_res, alpha_max_augment;
+ virtual void init_search(double r, size_t git) {
+ glob_it = git;
+ conv_alpha = alpha = double(1);
+ prev_res = conv_r = first_res = r; it = 0;
+ }
+ virtual double next_try(void)
+ { conv_alpha = alpha; alpha *= alpha_mult; ++it; return conv_alpha; }
+ virtual bool is_converged(double r) {
+ if (glob_it == 0 || (r < first_res / double(2))
+ || (conv_alpha <= alpha_min && r < first_res * alpha_max_augment)
+ || it >= itmax)
+ { conv_r = r; return true; }
+ if (it > 1 && r > prev_res && prev_res < alpha_max_ratio * first_res)
+ return true;
+ prev_res = conv_r = r;
+ return false;
+ }
+ default_newton_line_search
+ (size_t imax = size_t(-1),
+ double a_max_ratio = 5.0/3.0,
+ double a_min = 1.0/1000.0, double a_mult = 3.0/5.0, double a_augm = 2.0)
+ : alpha_mult(a_mult), alpha_max_ratio(a_max_ratio),
+ alpha_min(a_min), alpha_max_augment(a_augm) { itmax = imax; }
+ };
+
+
+ struct systematic_newton_line_search : public abstract_newton_line_search {
+ double alpha, alpha_mult, first_res;
+ double alpha_min, prev_res;
+ bool first;
+ virtual void init_search(double r, size_t git) {
+ glob_it = git;
+ conv_alpha = alpha = double(1);
+ prev_res = conv_r = first_res = r; it = 0; first = true;
+ }
+ virtual double next_try(void)
+ { double a = alpha; alpha *= alpha_mult; ++it; return a; }
+ virtual bool is_converged(double r) {
+ // cout << "a = " << alpha / alpha_mult << " r = " << r << endl;
+ if (r < conv_r || first)
+ { conv_r = r; conv_alpha = alpha / alpha_mult; first = false; }
+ if ((alpha <= alpha_min*alpha_mult) || it >= itmax) return true;
+ return false;
+ }
+ systematic_newton_line_search
+ (size_t imax = size_t(-1),
+ double a_min = 1.0/10000.0, double a_mult = 3.0/5.0)
+ : alpha_mult(a_mult), alpha_min(a_min) { itmax = imax; }
+ };
+
+}
+
+
+#endif
diff --git a/Contrib/gmm/gmm_solver_Schwarz_additive.h b/Contrib/gmm/gmm_solver_Schwarz_additive.h
new file mode 100755
index 0000000..7f4c958
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_Schwarz_additive.h
@@ -0,0 +1,746 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_solver_Schwarz_additive.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @author Michel Fournie <fournie at mip.ups-tlse.fr>
+ @date October 13, 2002.
+*/
+
+#ifndef GMM_SOLVERS_SCHWARZ_ADDITIVE_H__
+#define GMM_SOLVERS_SCHWARZ_ADDITIVE_H__
+
+#include "gmm_kernel.h"
+#include "gmm_superlu_interface.h"
+#include "gmm_solver_cg.h"
+#include "gmm_solver_gmres.h"
+#include "gmm_solver_bicgstab.h"
+#include "gmm_solver_qmr.h"
+#include "gmm_solver_Newton.h"
+
+namespace gmm {
+
+ /* ******************************************************************** */
+ /* Additive Schwarz interfaced local solvers */
+ /* ******************************************************************** */
+
+ struct using_cg {};
+ struct using_gmres {};
+ struct using_bicgstab {};
+ struct using_qmr {};
+
+ template <typename P, typename local_solver, typename Matrix>
+ struct actual_precond {
+ typedef P APrecond;
+ static const APrecond &transform(const P &PP) { return PP; }
+ };
+
+ template <typename Matrix1, typename Precond, typename Vector>
+ void AS_local_solve(using_cg, const Matrix1 &A, Vector &x, const Vector &b,
+ const Precond &P, iteration &iter)
+ { cg(A, x, b, P, iter); }
+
+ template <typename Matrix1, typename Precond, typename Vector>
+ void AS_local_solve(using_gmres, const Matrix1 &A, Vector &x,
+ const Vector &b, const Precond &P, iteration &iter)
+ { gmres(A, x, b, P, 100, iter); }
+
+ template <typename Matrix1, typename Precond, typename Vector>
+ void AS_local_solve(using_bicgstab, const Matrix1 &A, Vector &x,
+ const Vector &b, const Precond &P, iteration &iter)
+ { bicgstab(A, x, b, P, iter); }
+
+ template <typename Matrix1, typename Precond, typename Vector>
+ void AS_local_solve(using_qmr, const Matrix1 &A, Vector &x,
+ const Vector &b, const Precond &P, iteration &iter)
+ { qmr(A, x, b, P, iter); }
+
+#if defined(GMM_USES_SUPERLU)
+ struct using_superlu {};
+
+ template <typename P, typename Matrix>
+ struct actual_precond<P, using_superlu, Matrix> {
+ typedef typename linalg_traits<Matrix>::value_type value_type;
+ typedef SuperLU_factor<value_type> APrecond;
+ template <typename PR>
+ static APrecond transform(const PR &) { return APrecond(); }
+ static const APrecond &transform(const APrecond &PP) { return PP; }
+ };
+
+ template <typename Matrix1, typename Precond, typename Vector>
+ void AS_local_solve(using_superlu, const Matrix1 &, Vector &x,
+ const Vector &b, const Precond &P, iteration &iter)
+ { P.solve(x, b); iter.set_iteration(1); }
+#endif
+
+ /* ******************************************************************** */
+ /* Additive Schwarz Linear system */
+ /* ******************************************************************** */
+
+ template <typename Matrix1, typename Matrix2, typename Precond,
+ typename local_solver>
+ struct add_schwarz_mat{
+ typedef typename linalg_traits<Matrix1>::value_type value_type;
+
+ const Matrix1 *A;
+ const std::vector<Matrix2> *vB;
+ std::vector<Matrix2> vAloc;
+ mutable iteration iter;
+ double residual;
+ mutable size_type itebilan;
+ mutable std::vector<std::vector<value_type> > gi, fi;
+ std::vector<typename actual_precond<Precond, local_solver,
+ Matrix1>::APrecond> precond1;
+
+ void init(const Matrix1 &A_, const std::vector<Matrix2> &vB_,
+ iteration iter_, const Precond &P, double residual_);
+
+ add_schwarz_mat(void) {}
+ add_schwarz_mat(const Matrix1 &A_, const std::vector<Matrix2> &vB_,
+ iteration iter_, const Precond &P, double residual_)
+ { init(A_, vB_, iter_, P, residual_); }
+ };
+
+ template <typename Matrix1, typename Matrix2, typename Precond,
+ typename local_solver>
+ void add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver>::init(
+ const Matrix1 &A_, const std::vector<Matrix2> &vB_,
+ iteration iter_, const Precond &P, double residual_) {
+
+ vB = &vB_; A = &A_; iter = iter_;
+ residual = residual_;
+
+ size_type nb_sub = vB->size();
+ vAloc.resize(nb_sub);
+ gi.resize(nb_sub); fi.resize(nb_sub);
+ precond1.resize(nb_sub);
+ std::fill(precond1.begin(), precond1.end(),
+ actual_precond<Precond, local_solver, Matrix1>::transform(P));
+ itebilan = 0;
+
+ if (iter.get_noisy()) cout << "Init pour sub dom ";
+#ifdef GMM_USES_MPI
+ int size,tranche,borne_sup,borne_inf,rank,tag1=11,tag2=12,tag3=13,sizepr = 0;
+ // int tab[4];
+ double t_ref,t_final;
+ MPI_Status status;
+ t_ref=MPI_Wtime();
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ MPI_Comm_size(MPI_COMM_WORLD, &size);
+ tranche=nb_sub/size;
+ borne_inf=rank*tranche;
+ borne_sup=(rank+1)*tranche;
+ // if (rank==size-1) borne_sup = nb_sub;
+
+ cout << "Nombre de sous domaines " << borne_sup - borne_inf << endl;
+
+ int sizeA = mat_nrows(*A);
+ gmm::csr_matrix<value_type> Acsr(sizeA, sizeA), Acsrtemp(sizeA, sizeA);
+ gmm::copy(gmm::eff_matrix(*A), Acsr);
+ int next = (rank + 1) % size;
+ int previous = (rank + size - 1) % size;
+ //communication of local information on ring pattern
+ //Each process receive Nproc-1 contributions
+
+ for (int nproc = 0; nproc < size; ++nproc) {
+ for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i) {
+// for (size_type i = 0; i < nb_sub/size; ++i) {
+// for (size_type i = 0; i < nb_sub; ++i) {
+ // size_type i=(rank+size*(j-1)+nb_sub)%nb_sub;
+
+ cout << "Sous domaines " << i << " : " << mat_ncols((*vB)[i]) << endl;
+#else
+ for (size_type i = 0; i < nb_sub; ++i) {
+#endif
+
+ if (iter.get_noisy()) cout << i << " " << std::flush;
+ Matrix2 Maux(mat_ncols((*vB)[i]), mat_nrows((*vB)[i]));
+
+#ifdef GMM_USES_MPI
+ Matrix2 Maux2(mat_ncols((*vB)[i]), mat_ncols((*vB)[i]));
+ if (nproc == 0) {
+ gmm::resize(vAloc[i], mat_ncols((*vB)[i]), mat_ncols((*vB)[i]));
+ gmm::clear(vAloc[i]);
+ }
+ gmm::mult(gmm::transposed((*vB)[i]), Acsr, Maux);
+ gmm::mult(Maux, (*vB)[i], Maux2);
+ gmm::add(Maux2, vAloc[i]);
+#else
+ gmm::resize(vAloc[i], mat_ncols((*vB)[i]), mat_ncols((*vB)[i]));
+ gmm::mult(gmm::transposed((*vB)[i]), *A, Maux);
+ gmm::mult(Maux, (*vB)[i], vAloc[i]);
+#endif
+
+#ifdef GMM_USES_MPI
+ if (nproc == size - 1 ) {
+#endif
+ precond1[i].build_with(vAloc[i]);
+ gmm::resize(fi[i], mat_ncols((*vB)[i]));
+ gmm::resize(gi[i], mat_ncols((*vB)[i]));
+#ifdef GMM_USES_MPI
+ }
+#else
+ }
+#endif
+#ifdef GMM_USES_MPI
+ }
+ if (nproc != size - 1) {
+ MPI_Sendrecv(Acsr.jc, sizeA+1, MPI_INT, next, tag2,
+ Acsrtemp.jc, sizeA+1,MPI_INT,previous,tag2,
+ MPI_COMM_WORLD,&status);
+ if (Acsrtemp.jc[sizeA] > size_type(sizepr)) {
+ sizepr = Acsrtemp.jc[sizeA];
+ delete[] Acsrtemp.pr; delete[] Acsrtemp.ir;
+ Acsrtemp.pr = new value_type[sizepr];
+ Acsrtemp.ir = new unsigned int[sizepr];
+ }
+ MPI_Sendrecv(Acsr.ir, Acsr.jc[sizeA], MPI_INT, next, tag1,
+ Acsrtemp.ir, Acsrtemp.jc[sizeA],MPI_INT,previous,tag1,
+ MPI_COMM_WORLD,&status);
+
+ MPI_Sendrecv(Acsr.pr, Acsr.jc[sizeA], mpi_type(value_type()), next, tag3,
+ Acsrtemp.pr, Acsrtemp.jc[sizeA],mpi_type(value_type()),previous,tag3,
+ MPI_COMM_WORLD,&status);
+ gmm::copy(Acsrtemp, Acsr);
+ }
+ }
+ t_final=MPI_Wtime();
+ cout<<"temps boucle precond "<< t_final-t_ref<<endl;
+#endif
+ if (iter.get_noisy()) cout << "\n";
+ }
+
+ template <typename Matrix1, typename Matrix2, typename Precond,
+ typename Vector2, typename Vector3, typename local_solver>
+ void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
+ const Vector2 &p, Vector3 &q) {
+ size_type itebilan = 0;
+#ifdef GMM_USES_MPI
+ static double tmult_tot = 0.0;
+ double t_ref = MPI_Wtime();
+#endif
+ // cout << "tmult AS begin " << endl;
+ mult(*(M.A), p, q);
+#ifdef GMM_USES_MPI
+ tmult_tot += MPI_Wtime()-t_ref;
+ cout << "tmult_tot = " << tmult_tot << endl;
+#endif
+ std::vector<double> qbis(gmm::vect_size(q));
+ std::vector<double> qter(gmm::vect_size(q));
+#ifdef GMM_USES_MPI
+ // MPI_Status status;
+ // MPI_Request request,request1;
+ // int tag=111;
+ int size,tranche,borne_sup,borne_inf,rank;
+ size_type nb_sub=M.fi.size();
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ MPI_Comm_size(MPI_COMM_WORLD, &size);
+ tranche=nb_sub/size;
+ borne_inf=rank*tranche;
+ borne_sup=(rank+1)*tranche;
+ // if (rank==size-1) borne_sup=nb_sub;
+ // int next = (rank + 1) % size;
+ // int previous = (rank + size - 1) % size;
+ t_ref = MPI_Wtime();
+ for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i)
+// for (size_type i = 0; i < nb_sub/size; ++i)
+ // for (size_type j = 0; j < nb_sub; ++j)
+#else
+ for (size_type i = 0; i < M.fi.size(); ++i)
+#endif
+ {
+#ifdef GMM_USES_MPI
+ // size_type i=j; // (rank+size*(j-1)+nb_sub)%nb_sub;
+#endif
+ gmm::mult(gmm::transposed((*(M.vB))[i]), q, M.fi[i]);
+ M.iter.init();
+ AS_local_solve(local_solver(), (M.vAloc)[i], (M.gi)[i],
+ (M.fi)[i],(M.precond1)[i],M.iter);
+ itebilan = std::max(itebilan, M.iter.get_iteration());
+ }
+
+#ifdef GMM_USES_MPI
+ cout << "First AS loop time " << MPI_Wtime() - t_ref << endl;
+#endif
+
+ gmm::clear(q);
+#ifdef GMM_USES_MPI
+ t_ref = MPI_Wtime();
+ // for (size_type j = 0; j < nb_sub; ++j)
+ for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i)
+
+#else
+ for (size_type i = 0; i < M.gi.size(); ++i)
+#endif
+ {
+
+#ifdef GMM_USES_MPI
+ // size_type i=j; // (rank+size*(j-1)+nb_sub)%nb_sub;
+// gmm::mult((*(M.vB))[i], M.gi[i], qbis,qbis);
+ gmm::mult((*(M.vB))[i], M.gi[i], qter);
+ add(qter,qbis,qbis);
+#else
+ gmm::mult((*(M.vB))[i], M.gi[i], q, q);
+#endif
+ }
+#ifdef GMM_USES_MPI
+ //WARNING this add only if you use the ring pattern below
+ // need to do this below if using a n explicit ring pattern communication
+
+// add(qbis,q,q);
+ cout << "Second AS loop time " << MPI_Wtime() - t_ref << endl;
+#endif
+
+
+#ifdef GMM_USES_MPI
+ // int tag1=11;
+ static double t_tot = 0.0;
+ double t_final;
+ t_ref=MPI_Wtime();
+// int next = (rank + 1) % size;
+// int previous = (rank + size - 1) % size;
+ //communication of local information on ring pattern
+ //Each process receive Nproc-1 contributions
+
+// if (size > 1) {
+// for (int nproc = 0; nproc < size-1; ++nproc)
+// {
+
+// MPI_Sendrecv(&(qbis[0]), gmm::vect_size(q), MPI_DOUBLE, next, tag1,
+// &(qter[0]), gmm::vect_size(q),MPI_DOUBLE,previous,tag1,
+// MPI_COMM_WORLD,&status);
+// gmm::copy(qter, qbis);
+// add(qbis,q,q);
+// }
+// }
+ MPI_Allreduce(&(qbis[0]), &(q[0]),gmm::vect_size(q), MPI_DOUBLE,
+ MPI_SUM,MPI_COMM_WORLD);
+ t_final=MPI_Wtime();
+ t_tot += t_final-t_ref;
+ cout<<"["<< rank<<"] temps reduce Resol "<< t_final-t_ref << " t_tot = " << t_tot << endl;
+#endif
+
+ if (M.iter.get_noisy() > 0) cout << "itebloc = " << itebilan << endl;
+ M.itebilan += itebilan;
+ M.iter.set_resmax((M.iter.get_resmax() + M.residual) * 0.5);
+ }
+
+ template <typename Matrix1, typename Matrix2, typename Precond,
+ typename Vector2, typename Vector3, typename local_solver>
+ void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
+ const Vector2 &p, const Vector3 &q) {
+ mult(M, p, const_cast<Vector3 &>(q));
+ }
+
+ template <typename Matrix1, typename Matrix2, typename Precond,
+ typename Vector2, typename Vector3, typename Vector4,
+ typename local_solver>
+ void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
+ const Vector2 &p, const Vector3 &p2, Vector4 &q)
+ { mult(M, p, q); add(p2, q); }
+
+ template <typename Matrix1, typename Matrix2, typename Precond,
+ typename Vector2, typename Vector3, typename Vector4,
+ typename local_solver>
+ void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
+ const Vector2 &p, const Vector3 &p2, const Vector4 &q)
+ { mult(M, p, const_cast<Vector4 &>(q)); add(p2, q); }
+
+ /* ******************************************************************** */
+ /* Additive Schwarz interfaced global solvers */
+ /* ******************************************************************** */
+
+ template <typename ASM_type, typename Vect>
+ void AS_global_solve(using_cg, const ASM_type &ASM, Vect &x,
+ const Vect &b, iteration &iter)
+ { cg(ASM, x, b, *(ASM.A), identity_matrix(), iter); }
+
+ template <typename ASM_type, typename Vect>
+ void AS_global_solve(using_gmres, const ASM_type &ASM, Vect &x,
+ const Vect &b, iteration &iter)
+ { gmres(ASM, x, b, identity_matrix(), 100, iter); }
+
+ template <typename ASM_type, typename Vect>
+ void AS_global_solve(using_bicgstab, const ASM_type &ASM, Vect &x,
+ const Vect &b, iteration &iter)
+ { bicgstab(ASM, x, b, identity_matrix(), iter); }
+
+ template <typename ASM_type, typename Vect>
+ void AS_global_solve(using_qmr,const ASM_type &ASM, Vect &x,
+ const Vect &b, iteration &iter)
+ { qmr(ASM, x, b, identity_matrix(), iter); }
+
+#if defined(GMM_USES_SUPERLU)
+ template <typename ASM_type, typename Vect>
+ void AS_global_solve(using_superlu, const ASM_type &, Vect &,
+ const Vect &, iteration &) {
+ GMM_ASSERT1(false, "You cannot use SuperLU as "
+ "global solver in additive Schwarz meethod");
+ }
+#endif
+
+ /* ******************************************************************** */
+ /* Linear Additive Schwarz method */
+ /* ******************************************************************** */
+ /* ref : Domain decomposition algorithms for the p-version finite */
+ /* element method for elliptic problems, Luca F. Pavarino, */
+ /* PhD thesis, Courant Institute of Mathematical Sciences, 1992. */
+ /* ******************************************************************** */
+
+ /** Function to call if the ASM matrix is precomputed for successive solve
+ * with the same system.
+ */
+ template <typename Matrix1, typename Matrix2,
+ typename Vector2, typename Vector3, typename Precond,
+ typename local_solver, typename global_solver>
+ void additive_schwarz(
+ add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &ASM, Vector3 &u,
+ const Vector2 &f, iteration &iter, const global_solver&) {
+
+ typedef typename linalg_traits<Matrix1>::value_type value_type;
+
+ size_type nb_sub = ASM.vB->size(), nb_dof = gmm::vect_size(f);
+ ASM.itebilan = 0;
+ std::vector<value_type> g(nb_dof);
+ std::vector<value_type> gbis(nb_dof);
+#ifdef GMM_USES_MPI
+ double t_init=MPI_Wtime();
+ int size,tranche,borne_sup,borne_inf,rank;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ MPI_Comm_size(MPI_COMM_WORLD, &size);
+ tranche=nb_sub/size;
+ borne_inf=rank*tranche;
+ borne_sup=(rank+1)*tranche;
+ // if (rank==size-1) borne_sup=nb_sub*size;
+ for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i)
+// for (size_type i = 0; i < nb_sub/size; ++i)
+ // for (size_type j = 0; j < nb_sub; ++j)
+ // for (size_type i = rank; i < nb_sub; i+=size)
+#else
+ for (size_type i = 0; i < nb_sub; ++i)
+#endif
+ {
+
+#ifdef GMM_USES_MPI
+ // size_type i=j; // (rank+size*(j-1)+nb_sub)%nb_sub;
+#endif
+ gmm::mult(gmm::transposed((*(ASM.vB))[i]), f, ASM.fi[i]);
+ ASM.iter.init();
+ AS_local_solve(local_solver(), ASM.vAloc[i], ASM.gi[i], ASM.fi[i],
+ ASM.precond1[i], ASM.iter);
+ ASM.itebilan = std::max(ASM.itebilan, ASM.iter.get_iteration());
+#ifdef GMM_USES_MPI
+ gmm::mult((*(ASM.vB))[i], ASM.gi[i], gbis,gbis);
+#else
+ gmm::mult((*(ASM.vB))[i], ASM.gi[i], g, g);
+#endif
+ }
+#ifdef GMM_USES_MPI
+ cout<<"temps boucle init "<< MPI_Wtime()-t_init<<endl;
+ double t_ref,t_final;
+ t_ref=MPI_Wtime();
+ MPI_Allreduce(&(gbis[0]), &(g[0]),gmm::vect_size(g), MPI_DOUBLE,
+ MPI_SUM,MPI_COMM_WORLD);
+ t_final=MPI_Wtime();
+ cout<<"temps reduce init "<< t_final-t_ref<<endl;
+#endif
+#ifdef GMM_USES_MPI
+ t_ref=MPI_Wtime();
+ cout<<"begin global AS"<<endl;
+#endif
+ AS_global_solve(global_solver(), ASM, u, g, iter);
+#ifdef GMM_USES_MPI
+ t_final=MPI_Wtime();
+ cout<<"temps AS Global Solve "<< t_final-t_ref<<endl;
+#endif
+ if (iter.get_noisy())
+ cout << "Total number of internal iterations : " << ASM.itebilan << endl;
+ }
+
+ /** Global function. Compute the ASM matrix and call the previous function.
+ * The ASM matrix represent the preconditionned linear system.
+ */
+ template <typename Matrix1, typename Matrix2,
+ typename Vector2, typename Vector3, typename Precond,
+ typename local_solver, typename global_solver>
+ void additive_schwarz(const Matrix1 &A, Vector3 &u,
+ const Vector2 &f, const Precond &P,
+ const std::vector<Matrix2> &vB,
+ iteration &iter, local_solver,
+ global_solver) {
+ iter.set_rhsnorm(vect_norm2(f));
+ if (iter.get_rhsnorm() == 0.0) { gmm::clear(u); return; }
+ iteration iter2 = iter; iter2.reduce_noisy();
+ iter2.set_maxiter(size_type(-1));
+ add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver>
+ ASM(A, vB, iter2, P, iter.get_resmax());
+ additive_schwarz(ASM, u, f, iter, global_solver());
+ }
+
+ /* ******************************************************************** */
+ /* Sequential Non-Linear Additive Schwarz method */
+ /* ******************************************************************** */
+ /* ref : Nonlinearly Preconditionned Inexact Newton Algorithms, */
+ /* Xiao-Chuan Cai, David E. Keyes, */
+ /* SIAM J. Sci. Comp. 24: p183-200. l */
+ /* ******************************************************************** */
+
+ template <typename Matrixt, typename MatrixBi>
+ class NewtonAS_struct {
+
+ public :
+ typedef Matrixt tangent_matrix_type;
+ typedef MatrixBi B_matrix_type;
+ typedef typename linalg_traits<Matrixt>::value_type value_type;
+ typedef std::vector<value_type> Vector;
+
+ virtual size_type size(void) = 0;
+ virtual const std::vector<MatrixBi> &get_vB() = 0;
+
+ virtual void compute_F(Vector &f, Vector &x) = 0;
+ virtual void compute_tangent_matrix(Matrixt &M, Vector &x) = 0;
+ // compute Bi^T grad(F(X)) Bi
+ virtual void compute_sub_tangent_matrix(Matrixt &Mloc, Vector &x,
+ size_type i) = 0;
+ // compute Bi^T F(X)
+ virtual void compute_sub_F(Vector &fi, Vector &x, size_type i) = 0;
+
+ virtual ~NewtonAS_struct() {}
+ };
+
+ template <typename Matrixt, typename MatrixBi>
+ struct AS_exact_gradient {
+ const std::vector<MatrixBi> &vB;
+ std::vector<Matrixt> vM;
+ std::vector<Matrixt> vMloc;
+
+ void init(void) {
+ for (size_type i = 0; i < vB.size(); ++i) {
+ Matrixt aux(gmm::mat_ncols(vB[i]), gmm::mat_ncols(vM[i]));
+ gmm::resize(vMloc[i], gmm::mat_ncols(vB[i]), gmm::mat_ncols(vB[i]));
+ gmm::mult(gmm::transposed(vB[i]), vM[i], aux);
+ gmm::mult(aux, vB[i], vMloc[i]);
+ }
+ }
+ AS_exact_gradient(const std::vector<MatrixBi> &vB_) : vB(vB_) {
+ vM.resize(vB.size()); vMloc.resize(vB.size());
+ for (size_type i = 0; i < vB.size(); ++i) {
+ gmm::resize(vM[i], gmm::mat_nrows(vB[i]), gmm::mat_nrows(vB[i]));
+ }
+ }
+ };
+
+ template <typename Matrixt, typename MatrixBi,
+ typename Vector2, typename Vector3>
+ void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
+ const Vector2 &p, Vector3 &q) {
+ gmm::clear(q);
+ typedef typename gmm::linalg_traits<Vector3>::value_type T;
+ std::vector<T> v(gmm::vect_size(p)), w, x;
+ for (size_type i = 0; i < M.vB.size(); ++i) {
+ w.resize(gmm::mat_ncols(M.vB[i]));
+ x.resize(gmm::mat_ncols(M.vB[i]));
+ gmm::mult(M.vM[i], p, v);
+ gmm::mult(gmm::transposed(M.vB[i]), v, w);
+ double rcond;
+ SuperLU_solve(M.vMloc[i], x, w, rcond);
+ // gmm::iteration iter(1E-10, 0, 100000);
+ //gmm::gmres(M.vMloc[i], x, w, gmm::identity_matrix(), 50, iter);
+ gmm::mult_add(M.vB[i], x, q);
+ }
+ }
+
+ template <typename Matrixt, typename MatrixBi,
+ typename Vector2, typename Vector3>
+ void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
+ const Vector2 &p, const Vector3 &q) {
+ mult(M, p, const_cast<Vector3 &>(q));
+ }
+
+ template <typename Matrixt, typename MatrixBi,
+ typename Vector2, typename Vector3, typename Vector4>
+ void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
+ const Vector2 &p, const Vector3 &p2, Vector4 &q)
+ { mult(M, p, q); add(p2, q); }
+
+ template <typename Matrixt, typename MatrixBi,
+ typename Vector2, typename Vector3, typename Vector4>
+ void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
+ const Vector2 &p, const Vector3 &p2, const Vector4 &q)
+ { mult(M, p, const_cast<Vector4 &>(q)); add(p2, q); }
+
+
+
+ template <typename Matrixt, typename MatrixBi, typename Vector,
+ typename Precond, typename local_solver, typename global_solver>
+ void Newton_additive_Schwarz(NewtonAS_struct<Matrixt, MatrixBi> &NS,
+ const Vector &u_,
+ iteration &iter, const Precond &P,
+ local_solver, global_solver) {
+ Vector &u = const_cast<Vector &>(u_);
+ typedef typename linalg_traits<Vector>::value_type value_type;
+ typedef typename number_traits<value_type>::magnitude_type mtype;
+ typedef actual_precond<Precond, local_solver, Matrixt> chgt_precond;
+
+ double residual = iter.get_resmax();
+
+ default_newton_line_search internal_ls;
+ default_newton_line_search external_ls(size_t(-1), 5.0/3, 1.0/1000, 3.0/5);
+
+ // systematic_newton_line_search external_ls(size_t(-1), 1.0/10000.0, 3.0/100.0);
+
+ typename chgt_precond::APrecond PP = chgt_precond::transform(P);
+ iter.set_rhsnorm(mtype(1));
+ iteration iternc(iter);
+ iternc.reduce_noisy(); iternc.set_maxiter(size_type(-1));
+ iteration iter2(iternc);
+ iteration iter3(iter2); iter3.reduce_noisy();
+ iteration iter4(iter3);
+ iternc.set_name("Local Newton");
+ iter2.set_name("Linear System for Global Newton");
+ iternc.set_resmax(residual/100.0);
+ iter3.set_resmax(residual/10000.0);
+ iter2.set_resmax(residual/1000.0);
+ iter4.set_resmax(residual/1000.0);
+ std::vector<value_type> rhs(NS.size()), x(NS.size()), d(NS.size());
+ std::vector<value_type> xi, xii, fi, di;
+
+ std::vector< std::vector<value_type> > vx(NS.get_vB().size());
+ for (size_type i = 0; i < NS.get_vB().size(); ++i) // for exact gradient
+ vx[i].resize(NS.size()); // for exact gradient
+
+ Matrixt Mloc, M(NS.size(), NS.size());
+ NS.compute_F(rhs, u);
+ mtype act_res=gmm::vect_norm2(rhs), act_res_new(0), precond_res = act_res;
+ mtype alpha;
+
+ while(!iter.finished(std::min(act_res, precond_res))) {
+ for (int SOR_step = 0; SOR_step >= 0; --SOR_step) {
+ gmm::clear(rhs);
+ for (size_type isd = 0; isd < NS.get_vB().size(); ++isd) {
+ const MatrixBi &Bi = (NS.get_vB())[isd];
+ size_type si = mat_ncols(Bi);
+ gmm::resize(Mloc, si, si);
+ xi.resize(si); xii.resize(si); fi.resize(si); di.resize(si);
+
+ iternc.init();
+ iternc.set_maxiter(30); // ?
+ if (iternc.get_noisy())
+ cout << "Non-linear local problem " << isd << endl;
+ gmm::clear(xi);
+ gmm::copy(u, x);
+ NS.compute_sub_F(fi, x, isd); gmm::scale(fi, value_type(-1));
+ mtype r = gmm::vect_norm2(fi), r_t(r);
+ if (r > value_type(0)) {
+ iternc.set_rhsnorm(std::max(r, mtype(1)));
+ while(!iternc.finished(r)) {
+ NS.compute_sub_tangent_matrix(Mloc, x, isd);
+
+ PP.build_with(Mloc);
+ iter3.init();
+ AS_local_solve(local_solver(), Mloc, di, fi, PP, iter3);
+
+ internal_ls.init_search(r, iternc.get_iteration());
+ do {
+ alpha = internal_ls.next_try();
+ gmm::add(xi, gmm::scaled(di, -alpha), xii);
+ gmm::mult(Bi, gmm::scaled(xii, -1.0), u, x);
+ NS.compute_sub_F(fi, x, isd); gmm::scale(fi, value_type(-1));
+ r_t = gmm::vect_norm2(fi);
+ } while (!internal_ls.is_converged(r_t));
+
+ if (alpha != internal_ls.converged_value()) {
+ alpha = internal_ls.converged_value();
+ gmm::add(xi, gmm::scaled(di, -alpha), xii);
+ gmm::mult(Bi, gmm::scaled(xii, -1.0), u, x);
+ NS.compute_sub_F(fi, x, isd); gmm::scale(fi, value_type(-1));
+ r_t = gmm::vect_norm2(fi);
+ }
+ gmm::copy(x, vx[isd]); // for exact gradient
+
+ if (iternc.get_noisy()) cout << "(step=" << alpha << ")\t";
+ ++iternc; r = r_t; gmm::copy(xii, xi);
+ }
+ if (SOR_step) gmm::mult(Bi, gmm::scaled(xii, -1.0), u, u);
+ gmm::mult(Bi, gmm::scaled(xii, -1.0), rhs, rhs);
+ }
+ }
+ precond_res = gmm::vect_norm2(rhs);
+ if (SOR_step) cout << "SOR step residual = " << precond_res << endl;
+ if (precond_res < residual) break;
+ cout << "Precond residual = " << precond_res << endl;
+ }
+
+ iter2.init();
+ // solving linear system for the global Newton method
+ if (0) {
+ NS.compute_tangent_matrix(M, u);
+ add_schwarz_mat<Matrixt, MatrixBi, Precond, local_solver>
+ ASM(M, NS.get_vB(), iter4, P, iter.get_resmax());
+ AS_global_solve(global_solver(), ASM, d, rhs, iter2);
+ }
+ else { // for exact gradient
+ AS_exact_gradient<Matrixt, MatrixBi> eg(NS.get_vB());
+ for (size_type i = 0; i < NS.get_vB().size(); ++i) {
+ NS.compute_tangent_matrix(eg.vM[i], vx[i]);
+ }
+ eg.init();
+ gmres(eg, d, rhs, gmm::identity_matrix(), 50, iter2);
+ }
+
+ // gmm::add(gmm::scaled(rhs, 0.1), u); ++iter;
+ external_ls.init_search(act_res, iter.get_iteration());
+ do {
+ alpha = external_ls.next_try();
+ gmm::add(gmm::scaled(d, alpha), u, x);
+ NS.compute_F(rhs, x);
+ act_res_new = gmm::vect_norm2(rhs);
+ } while (!external_ls.is_converged(act_res_new));
+
+ if (alpha != external_ls.converged_value()) {
+ alpha = external_ls.converged_value();
+ gmm::add(gmm::scaled(d, alpha), u, x);
+ NS.compute_F(rhs, x);
+ act_res_new = gmm::vect_norm2(rhs);
+ }
+
+ if (iter.get_noisy() > 1) cout << endl;
+ act_res = act_res_new;
+ if (iter.get_noisy()) cout << "(step=" << alpha << ")\t unprecond res = " << act_res << " ";
+
+
+ ++iter; gmm::copy(x, u);
+ }
+ }
+
+}
+
+
+#endif // GMM_SOLVERS_SCHWARZ_ADDITIVE_H__
diff --git a/Contrib/gmm/gmm_solver_bfgs.h b/Contrib/gmm/gmm_solver_bfgs.h
new file mode 100755
index 0000000..297b802
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_bfgs.h
@@ -0,0 +1,207 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2004-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_solver_bfgs.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 14 2004.
+ @brief Implements BFGS (Broyden, Fletcher, Goldfarb, Shanno) algorithm.
+ */
+#ifndef GMM_BFGS_H
+#define GMM_BFGS_H
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+
+namespace gmm {
+
+ // BFGS algorithm (Broyden, Fletcher, Goldfarb, Shanno)
+ // Quasi Newton method for optimization problems.
+ // with Wolfe Line search.
+
+
+ // delta[k] = x[k+1] - x[k]
+ // gamma[k] = grad f(x[k+1]) - grad f(x[k])
+ // H[0] = I
+ // BFGS : zeta[k] = delta[k] - H[k] gamma[k]
+ // DFP : zeta[k] = H[k] gamma[k]
+ // tau[k] = gamma[k]^T zeta[k]
+ // rho[k] = 1 / gamma[k]^T delta[k]
+ // BFGS : H[k+1] = H[k] + rho[k](zeta[k] delta[k]^T + delta[k] zeta[k]^T)
+ // - rho[k]^2 tau[k] delta[k] delta[k]^T
+ // DFP : H[k+1] = H[k] + rho[k] delta[k] delta[k]^T
+ // - (1/tau[k])zeta[k] zeta[k]^T
+
+ // Object representing the inverse of the Hessian
+ template <typename VECTOR> struct bfgs_invhessian {
+
+ typedef typename linalg_traits<VECTOR>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ std::vector<VECTOR> delta, gamma, zeta;
+ std::vector<T> tau, rho;
+ int version;
+
+ template<typename VEC1, typename VEC2> void hmult(const VEC1 &X, VEC2 &Y) {
+ copy(X, Y);
+ for (size_type k = 0 ; k < delta.size(); ++k) {
+ T xdelta = vect_sp(X, delta[k]), xzeta = vect_sp(X, zeta[k]);
+ switch (version) {
+ case 0 : // BFGS
+ add(scaled(zeta[k], rho[k]*xdelta), Y);
+ add(scaled(delta[k], rho[k]*(xzeta-rho[k]*tau[k]*xdelta)), Y);
+ break;
+ case 1 : // DFP
+ add(scaled(delta[k], rho[k]*xdelta), Y);
+ add(scaled(zeta[k], -xzeta/tau[k]), Y);
+ break;
+ }
+ }
+ }
+
+ void restart(void) {
+ delta.resize(0); gamma.resize(0); zeta.resize(0);
+ tau.resize(0); rho.resize(0);
+ }
+
+ template<typename VECT1, typename VECT2>
+ void update(const VECT1 &deltak, const VECT2 &gammak) {
+ size_type N = vect_size(deltak), k = delta.size();
+ VECTOR Y(N);
+ hmult(gammak, Y);
+ delta.resize(k+1); gamma.resize(k+1); zeta.resize(k+1);
+ tau.resize(k+1); rho.resize(k+1);
+ resize(delta[k], N); resize(gamma[k], N); resize(zeta[k], N);
+ gmm::copy(deltak, delta[k]);
+ gmm::copy(gammak, gamma[k]);
+ rho[k] = R(1) / vect_sp(deltak, gammak);
+ if (version == 0)
+ add(delta[k], scaled(Y, -1), zeta[k]);
+ else
+ gmm::copy(Y, zeta[k]);
+ tau[k] = vect_sp(gammak, zeta[k]);
+ }
+
+ bfgs_invhessian(int v = 0) { version = v; }
+ };
+
+
+ template <typename FUNCTION, typename DERIVATIVE, typename VECTOR>
+ void bfgs(FUNCTION f, DERIVATIVE grad, VECTOR &x,
+ int restart, iteration& iter, int version = 0,
+ float lambda_init=0.001, float print_norm=1.0) {
+
+ typedef typename linalg_traits<VECTOR>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ bfgs_invhessian<VECTOR> invhessian(version);
+ VECTOR r(vect_size(x)), d(vect_size(x)), y(vect_size(x)), r2(vect_size(x));
+ grad(x, r);
+ R lambda = lambda_init, valx = f(x), valy;
+ int nb_restart(0);
+
+ if (iter.get_noisy() >= 1) cout << "value " << valx / print_norm << " ";
+ while (! iter.finished_vect(r)) {
+
+ invhessian.hmult(r, d); gmm::scale(d, T(-1));
+
+ // Wolfe Line search
+ R derivative = gmm::vect_sp(r, d);
+ R lambda_min(0), lambda_max(0), m1 = 0.27, m2 = 0.57;
+ bool unbounded = true, blocked = false, grad_computed = false;
+
+ for(;;) {
+ add(x, scaled(d, lambda), y);
+ valy = f(y);
+ if (iter.get_noisy() >= 2) {
+ cout.precision(15);
+ cout << "Wolfe line search, lambda = " << lambda
+ << " value = " << valy /print_norm << endl;
+// << " derivative = " << derivative
+// << " lambda min = " << lambda_min << " lambda max = "
+// << lambda_max << endl; getchar();
+ }
+ if (valy <= valx + m1 * lambda * derivative) {
+ grad(y, r2); grad_computed = true;
+ T derivative2 = gmm::vect_sp(r2, d);
+ if (derivative2 >= m2*derivative) break;
+ lambda_min = lambda;
+ }
+ else {
+ lambda_max = lambda;
+ unbounded = false;
+ }
+ if (unbounded) lambda *= R(10);
+ else lambda = (lambda_max + lambda_min) / R(2);
+ if (lambda == lambda_max || lambda == lambda_min) break;
+ // valy <= R(2)*valx replaced by
+ // valy <= valx + gmm::abs(derivative)*lambda_init
+ // for compatibility with negative values (08.24.07).
+ if (valy <= valx + R(2)*gmm::abs(derivative)*lambda &&
+ (lambda < R(lambda_init*1E-8) ||
+ (!unbounded && lambda_max-lambda_min < R(lambda_init*1E-8))))
+ { blocked = true; lambda = lambda_init; break; }
+ }
+
+ // Rank two update
+ ++iter;
+ if (!grad_computed) grad(y, r2);
+ gmm::add(scaled(r2, -1), r);
+ if (iter.get_iteration() % restart == 0 || blocked) {
+ if (iter.get_noisy() >= 1) cout << "Restart\n";
+ invhessian.restart();
+ if (++nb_restart > 10) {
+ if (iter.get_noisy() >= 1) cout << "BFGS is blocked, exiting\n";
+ return;
+ }
+ }
+ else {
+ invhessian.update(gmm::scaled(d,lambda), gmm::scaled(r,-1));
+ nb_restart = 0;
+ }
+ copy(r2, r); copy(y, x); valx = valy;
+ if (iter.get_noisy() >= 1)
+ cout << "BFGS value " << valx/print_norm << "\t";
+ }
+
+ }
+
+
+ template <typename FUNCTION, typename DERIVATIVE, typename VECTOR>
+ inline void dfp(FUNCTION f, DERIVATIVE grad, VECTOR &x,
+ int restart, iteration& iter, int version = 1) {
+ bfgs(f, grad, x, restart, iter, version);
+
+ }
+
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_solver_bicgstab.h b/Contrib/gmm/gmm_solver_bicgstab.h
new file mode 100755
index 0000000..0fa6ab8
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_bicgstab.h
@@ -0,0 +1,160 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of bicgstab.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the University of California, Berkeley nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
+// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_solver_bicgstab.h
+ @author Andrew Lumsdaine <lums at osl.iu.edu>
+ @author Lie-Quan Lee <llee at osl.iu.edu>
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief BiCGStab iterative solver.
+*/
+
+#ifndef GMM_SOLVER_BICGSTAB_H__
+#define GMM_SOLVER_BICGSTAB_H__
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+
+namespace gmm {
+
+ /* ******************************************************************** */
+ /* BiConjugate Gradient Stabilized */
+ /* (preconditionned, with parametrable scalar product) */
+ /* ******************************************************************** */
+
+ template <typename Matrix, typename Vector, typename VectorB,
+ typename Preconditioner>
+ void bicgstab(const Matrix& A, Vector& x, const VectorB& b,
+ const Preconditioner& M, iteration &iter) {
+
+ typedef typename linalg_traits<Vector>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ typedef typename temporary_dense_vector<Vector>::vector_type temp_vector;
+
+ T rho_1, rho_2(0), alpha(0), beta, omega(0);
+ temp_vector p(vect_size(x)), phat(vect_size(x)), s(vect_size(x)),
+ shat(vect_size(x)),
+ t(vect_size(x)), v(vect_size(x)), r(vect_size(x)), rtilde(vect_size(x));
+
+ gmm::mult(A, gmm::scaled(x, -T(1)), b, r);
+ gmm::copy(r, rtilde);
+ R norm_r = gmm::vect_norm2(r);
+ iter.set_rhsnorm(gmm::vect_norm2(b));
+
+ if (iter.get_rhsnorm() == 0.0) { clear(x); return; }
+
+ while (!iter.finished(norm_r)) {
+
+ rho_1 = gmm::vect_sp(rtilde, r);
+ if (rho_1 == T(0)) {
+ if (iter.get_maxiter() == size_type(-1))
+ { GMM_ASSERT1(false, "Bicgstab failed to converge"); }
+ else { GMM_WARNING1("Bicgstab failed to converge"); return; }
+ }
+
+ if (iter.first())
+ gmm::copy(r, p);
+ else {
+ if (omega == T(0)) {
+ if (iter.get_maxiter() == size_type(-1))
+ { GMM_ASSERT1(false, "Bicgstab failed to converge"); }
+ else { GMM_WARNING1("Bicgstab failed to converge"); return; }
+ }
+
+ beta = (rho_1 / rho_2) * (alpha / omega);
+
+ gmm::add(gmm::scaled(v, -omega), p);
+ gmm::add(r, gmm::scaled(p, beta), p);
+ }
+ gmm::mult(M, p, phat);
+ gmm::mult(A, phat, v);
+ alpha = rho_1 / gmm::vect_sp(v, rtilde);
+ gmm::add(r, gmm::scaled(v, -alpha), s);
+
+ if (iter.finished_vect(s))
+ { gmm::add(gmm::scaled(phat, alpha), x); break; }
+
+ gmm::mult(M, s, shat);
+ gmm::mult(A, shat, t);
+ omega = gmm::vect_sp(t, s) / gmm::vect_norm2_sqr(t);
+
+ gmm::add(gmm::scaled(phat, alpha), x);
+ gmm::add(gmm::scaled(shat, omega), x);
+ gmm::add(s, gmm::scaled(t, -omega), r);
+ norm_r = gmm::vect_norm2(r);
+ rho_2 = rho_1;
+
+ ++iter;
+ }
+ }
+
+ template <typename Matrix, typename Vector, typename VectorB,
+ typename Preconditioner>
+ void bicgstab(const Matrix& A, const Vector& x, const VectorB& b,
+ const Preconditioner& M, iteration &iter)
+ { bicgstab(A, linalg_const_cast(x), b, M, iter); }
+
+}
+
+
+#endif // GMM_SOLVER_BICGSTAB_H__
diff --git a/Contrib/gmm/gmm_solver_cg.h b/Contrib/gmm/gmm_solver_cg.h
new file mode 100755
index 0000000..a6d29ae
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_cg.h
@@ -0,0 +1,212 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of cg.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the University of California, Berkeley nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
+// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_solver_cg.h
+ @author Andrew Lumsdaine <lums at osl.iu.edu>
+ @author Lie-Quan Lee <llee at osl.iu.edu>
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief Conjugate gradient iterative solver.
+*/
+#ifndef GMM_SOLVER_CG_H__
+#define GMM_SOLVER_CG_H__
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+
+namespace gmm {
+
+ /* ******************************************************************** */
+ /* conjugate gradient */
+ /* (preconditionned, with parametrable additional scalar product) */
+ /* ******************************************************************** */
+
+ template <typename Matrix, typename Matps, typename Precond,
+ typename Vector1, typename Vector2>
+ void cg(const Matrix& A, Vector1& x, const Vector2& b, const Matps& PS,
+ const Precond &P, iteration &iter) {
+
+ typedef typename temporary_dense_vector<Vector1>::vector_type temp_vector;
+ typedef typename linalg_traits<Vector1>::value_type T;
+
+ T rho, rho_1(0), a;
+ temp_vector p(vect_size(x)), q(vect_size(x)), r(vect_size(x)),
+ z(vect_size(x));
+ iter.set_rhsnorm(gmm::sqrt(gmm::abs(vect_hp(PS, b, b))));
+
+ if (iter.get_rhsnorm() == 0.0)
+ clear(x);
+ else {
+ mult(A, scaled(x, T(-1)), b, r);
+ mult(P, r, z);
+ rho = vect_hp(PS, z, r);
+ copy(z, p);
+
+// #ifdef GMM_USES_MPI
+// double t_ref, t_prec = MPI_Wtime(), t_tot = 0;
+// static double tmult_tot = 0.0;
+// #endif
+ while (!iter.finished_vect(r)) {
+
+ if (!iter.first()) {
+ mult(P, r, z);
+ rho = vect_hp(PS, z, r);
+ add(z, scaled(p, rho / rho_1), p);
+ }
+// #ifdef GMM_USES_MPI
+// t_ref = MPI_Wtime();
+// cout << "mult CG " << endl;
+// #endif
+ mult(A, p, q);
+// #ifdef GMM_USES_MPI
+// tmult_tot += MPI_Wtime()-t_ref;
+// cout << "tmult_tot CG = " << tmult_tot << endl;
+// #endif
+ a = rho / vect_hp(PS, q, p);
+ add(scaled(p, a), x);
+ add(scaled(q, -a), r);
+ rho_1 = rho;
+
+// #ifdef GMM_USES_MPI
+// t_tot = MPI_Wtime() - t_prec;
+// cout << "temps CG : " << t_tot << endl;
+// #endif
+ ++iter;
+ }
+ }
+ }
+
+ template <typename Matrix, typename Matps, typename Precond,
+ typename Vector1, typename Vector2>
+ void cg(const Matrix& A, Vector1& x, const Vector2& b, const Matps& PS,
+ const gmm::identity_matrix &, iteration &iter) {
+
+ typedef typename temporary_dense_vector<Vector1>::vector_type temp_vector;
+ typedef typename linalg_traits<Vector1>::value_type T;
+
+ T rho, rho_1(0), a;
+ temp_vector p(vect_size(x)), q(vect_size(x)), r(vect_size(x));
+ iter.set_rhsnorm(gmm::sqrt(gmm::abs(vect_hp(PS, b, b))));
+
+ if (iter.get_rhsnorm() == 0.0)
+ clear(x);
+ else {
+ mult(A, scaled(x, T(-1)), b, r);
+ rho = vect_hp(PS, r, r);
+ copy(r, p);
+
+// #ifdef GMM_USES_MPI
+// double t_ref, t_prec = MPI_Wtime(), t_tot = 0;
+// static double tmult_tot = 0.0;
+// #endif
+ while (!iter.finished_vect(r)) {
+
+ if (!iter.first()) {
+ rho = vect_hp(PS, r, r);
+ add(r, scaled(p, rho / rho_1), p);
+ }
+// #ifdef GMM_USES_MPI
+// t_ref = MPI_Wtime();
+// cout << "mult CG " << endl;
+// #endif
+ mult(A, p, q);
+// #ifdef GMM_USES_MPI
+// tmult_tot += MPI_Wtime()-t_ref;
+// cout << "tmult_tot CG = " << tmult_tot << endl;
+// #endif
+ a = rho / vect_hp(PS, q, p);
+ add(scaled(p, a), x);
+ add(scaled(q, -a), r);
+ rho_1 = rho;
+
+// #ifdef GMM_USES_MPI
+// t_tot = MPI_Wtime() - t_prec;
+// cout << "temps CG : " << t_tot << endl;
+// #endif
+ ++iter;
+ }
+ }
+ }
+
+ template <typename Matrix, typename Matps, typename Precond,
+ typename Vector1, typename Vector2> inline
+ void cg(const Matrix& A, const Vector1& x, const Vector2& b, const Matps& PS,
+ const Precond &P, iteration &iter)
+ { cg(A, linalg_const_cast(x), b, PS, P, iter); }
+
+ template <typename Matrix, typename Precond,
+ typename Vector1, typename Vector2> inline
+ void cg(const Matrix& A, Vector1& x, const Vector2& b,
+ const Precond &P, iteration &iter)
+ { cg(A, x , b, identity_matrix(), P, iter); }
+
+ template <typename Matrix, typename Precond,
+ typename Vector1, typename Vector2> inline
+ void cg(const Matrix& A, const Vector1& x, const Vector2& b,
+ const Precond &P, iteration &iter)
+ { cg(A, x , b , identity_matrix(), P , iter); }
+
+}
+
+
+#endif // GMM_SOLVER_CG_H__
diff --git a/Contrib/gmm/gmm_solver_constrained_cg.h b/Contrib/gmm/gmm_solver_constrained_cg.h
new file mode 100755
index 0000000..c7442c8
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_constrained_cg.h
@@ -0,0 +1,166 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_solver_constrained_cg.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief Constrained conjugate gradient. */
+// preconditionning does not work
+
+#ifndef GMM_SOLVER_CCG_H__
+#define GMM_SOLVER_CCG_H__
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+
+namespace gmm {
+
+ template <typename CMatrix, typename CINVMatrix, typename Matps,
+ typename VectorX>
+ void pseudo_inverse(const CMatrix &C, CINVMatrix &CINV,
+ const Matps& /* PS */, VectorX&) {
+ // compute the pseudo inverse of the non-square matrix C such
+ // CINV = inv(C * trans(C)) * C.
+ // based on a conjugate gradient method.
+
+ // optimisable : copie de la ligne, precalcul de C * trans(C).
+
+ typedef VectorX TmpVec;
+ typedef size_t size_type;
+ typedef typename linalg_traits<VectorX>::value_type value_type;
+
+ size_type nr = mat_nrows(C), nc = mat_ncols(C);
+
+ TmpVec d(nr), e(nr), l(nc), p(nr), q(nr), r(nr);
+ value_type rho, rho_1, alpha;
+ clear(d);
+ clear(CINV);
+
+ for (size_type i = 0; i < nr; ++i) {
+ d[i] = 1.0; rho = 1.0;
+ clear(e);
+ copy(d, r);
+ copy(d, p);
+
+ while (rho >= 1E-38) { /* conjugate gradient to compute e */
+ /* which is the i nd row of inv(C * trans(C)) */
+ mult(gmm::transposed(C), p, l);
+ mult(C, l, q);
+ alpha = rho / vect_sp(p, q);
+ add(scaled(p, alpha), e);
+ add(scaled(q, -alpha), r);
+ rho_1 = rho;
+ rho = vect_sp(r, r);
+ add(r, scaled(p, rho / rho_1), p);
+ }
+
+ mult(transposed(C), e, l); /* l is the i nd row of CINV */
+ // cout << "l = " << l << endl;
+ clean(l, 1E-15);
+ copy(l, mat_row(CINV, i));
+
+ d[i] = 0.0;
+ }
+ }
+
+ /** Compute the minimum of @f$ 1/2((Ax).x) - bx @f$ under the contraint @f$ Cx <= f @f$ */
+ template < typename Matrix, typename CMatrix, typename Matps,
+ typename VectorX, typename VectorB, typename VectorF,
+ typename Preconditioner >
+ void constrained_cg(const Matrix& A, const CMatrix& C, VectorX& x,
+ const VectorB& b, const VectorF& f,const Matps& PS,
+ const Preconditioner& M, iteration &iter) {
+ typedef typename temporary_dense_vector<VectorX>::vector_type TmpVec;
+ typedef typename temporary_vector<CMatrix>::vector_type TmpCVec;
+ typedef row_matrix<TmpCVec> TmpCmat;
+
+ typedef size_t size_type;
+ typedef typename linalg_traits<VectorX>::value_type value_type;
+ value_type rho = 1.0, rho_1, lambda, gamma;
+ TmpVec p(vect_size(x)), q(vect_size(x)), q2(vect_size(x)),
+ r(vect_size(x)), old_z(vect_size(x)), z(vect_size(x)),
+ memox(vect_size(x));
+ std::vector<bool> satured(mat_nrows(C));
+ clear(p);
+ iter.set_rhsnorm(sqrt(vect_sp(PS, b, b)));
+ if (iter.get_rhsnorm() == 0.0) iter.set_rhsnorm(1.0);
+
+ TmpCmat CINV(mat_nrows(C), mat_ncols(C));
+ pseudo_inverse(C, CINV, PS, x);
+
+ while(true) {
+ // computation of residu
+ copy(z, old_z);
+ copy(x, memox);
+ mult(A, scaled(x, -1.0), b, r);
+ mult(M, r, z); // preconditionner not coherent
+ bool transition = false;
+ for (size_type i = 0; i < mat_nrows(C); ++i) {
+ value_type al = vect_sp(mat_row(C, i), x) - f[i];
+ if (al >= -1.0E-15) {
+ if (!satured[i]) { satured[i] = true; transition = true; }
+ value_type bb = vect_sp(mat_row(CINV, i), z);
+ if (bb > 0.0) add(scaled(mat_row(C, i), -bb), z);
+ }
+ else
+ satured[i] = false;
+ }
+
+ // descent direction
+ rho_1 = rho; rho = vect_sp(PS, r, z); // ...
+
+ if (iter.finished(rho)) break;
+
+ if (iter.get_noisy() > 0 && transition) std::cout << "transition\n";
+ if (transition || iter.first()) gamma = 0.0;
+ else gamma = std::max(0.0, (rho - vect_sp(PS, old_z, z) ) / rho_1);
+ // std::cout << "gamma = " << gamma << endl;
+ // itl::add(r, itl::scaled(p, gamma), p);
+ add(z, scaled(p, gamma), p); // ...
+
+ ++iter;
+ // one dimensionnal optimization
+ mult(A, p, q);
+ lambda = rho / vect_sp(PS, q, p);
+ for (size_type i = 0; i < mat_nrows(C); ++i)
+ if (!satured[i]) {
+ value_type bb = vect_sp(mat_row(C, i), p) - f[i];
+ if (bb > 0.0)
+ lambda = std::min(lambda, (f[i]-vect_sp(mat_row(C, i), x)) / bb);
+ }
+ add(x, scaled(p, lambda), x);
+ add(memox, scaled(x, -1.0), memox);
+
+ }
+ }
+
+}
+
+#endif // GMM_SOLVER_CCG_H__
diff --git a/Contrib/gmm/gmm_solver_gmres.h b/Contrib/gmm/gmm_solver_gmres.h
new file mode 100755
index 0000000..fde56e4
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_gmres.h
@@ -0,0 +1,173 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of gmres.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the University of California, Berkeley nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
+// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_solver_gmres.h
+ @author Andrew Lumsdaine <lums at osl.iu.edu>
+ @author Lie-Quan Lee <llee at osl.iu.edu>
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief GMRES (Generalized Minimum Residual) iterative solver.
+*/
+#ifndef GMM_KRYLOV_GMRES_H
+#define GMM_KRYLOV_GMRES_H
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+#include "gmm_modified_gram_schmidt.h"
+
+namespace gmm {
+
+ /** Generalized Minimum Residual
+
+ This solve the unsymmetric linear system Ax = b using restarted GMRES.
+
+ See: Y. Saad and M. Schulter. GMRES: A generalized minimum residual
+ algorithm for solving nonsysmmetric linear systems, SIAM
+ J. Sci. Statist. Comp. 7(1986), pp, 856-869
+ */
+ template <typename Mat, typename Vec, typename VecB, typename Precond,
+ typename Basis >
+ void gmres(const Mat &A, Vec &x, const VecB &b, const Precond &M,
+ int restart, iteration &outer, Basis& KS) {
+
+ typedef typename linalg_traits<Vec>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ std::vector<T> w(vect_size(x)), r(vect_size(x)), u(vect_size(x));
+ std::vector<T> c_rot(restart+1), s_rot(restart+1), s(restart+1);
+ gmm::dense_matrix<T> H(restart+1, restart);
+#ifdef GMM_USES_MPI
+ double t_ref, t_prec = MPI_Wtime(), t_tot = 0;
+ static double tmult_tot = 0.0;
+t_ref = MPI_Wtime();
+ cout << "GMRES " << endl;
+#endif
+ mult(M,b,r);
+ outer.set_rhsnorm(gmm::vect_norm2(r));
+ if (outer.get_rhsnorm() == 0.0) { clear(x); return; }
+
+ mult(A, scaled(x, -1), b, w);
+ mult(M, w, r);
+ R beta = gmm::vect_norm2(r), beta_old = beta;
+ int blocked = 0;
+
+ iteration inner = outer;
+ inner.reduce_noisy();
+ inner.set_maxiter(restart);
+ inner.set_name("GMRes inner");
+
+ while (! outer.finished(beta)) {
+
+ gmm::copy(gmm::scaled(r, R(1)/beta), KS[0]);
+ gmm::clear(s);
+ s[0] = beta;
+
+ size_type i = 0; inner.init();
+
+ do {
+ mult(A, KS[i], u);
+ mult(M, u, KS[i+1]);
+ orthogonalize(KS, mat_col(H, i), i);
+ R a = gmm::vect_norm2(KS[i+1]);
+ H(i+1, i) = T(a);
+ gmm::scale(KS[i+1], T(1) / a);
+ for (size_type k = 0; k < i; ++k)
+ Apply_Givens_rotation_left(H(k,i), H(k+1,i), c_rot[k], s_rot[k]);
+
+ Givens_rotation(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
+ Apply_Givens_rotation_left(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
+ Apply_Givens_rotation_left(s[i], s[i+1], c_rot[i], s_rot[i]);
+
+ ++inner, ++outer, ++i;
+ } while (! inner.finished(gmm::abs(s[i])));
+
+ upper_tri_solve(H, s, i, false);
+ combine(KS, s, x, i);
+ mult(A, gmm::scaled(x, -1), b, w);
+ mult(M, w, r);
+ beta_old = std::min(beta, beta_old); beta = gmm::vect_norm2(r);
+ if (int(inner.get_iteration()) < restart -1 || beta_old <= beta)
+ ++blocked; else blocked = 0;
+ if (blocked > 10) {
+ if (outer.get_noisy()) cout << "Gmres is blocked, exiting\n";
+ break;
+ }
+#ifdef GMM_USES_MPI
+ t_tot = MPI_Wtime() - t_ref;
+ cout << "temps GMRES : " << t_tot << endl;
+#endif
+ }
+ }
+
+
+ template <typename Mat, typename Vec, typename VecB, typename Precond >
+ void gmres(const Mat &A, Vec &x, const VecB &b,
+ const Precond &M, int restart, iteration& outer) {
+ typedef typename linalg_traits<Vec>::value_type T;
+ modified_gram_schmidt<T> orth(restart, vect_size(x));
+ gmres(A, x, b, M, restart, outer, orth);
+ }
+
+}
+
+#endif
diff --git a/Contrib/gmm/gmm_solver_idgmres.h b/Contrib/gmm/gmm_solver_idgmres.h
new file mode 100755
index 0000000..2a472ce
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_idgmres.h
@@ -0,0 +1,804 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_solver_idgmres.h
+ @author Caroline Lecalvez <Caroline.Lecalvez at gmm.insa-tlse.fr>
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 6, 2003.
+ @brief Implicitly restarted and deflated Generalized Minimum Residual.
+*/
+#ifndef GMM_IDGMRES_H
+#define GMM_IDGMRES_H
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+#include "gmm_dense_sylvester.h"
+
+namespace gmm {
+
+ template <typename T> compare_vp {
+ bool operator()(const std::pair<T, size_type> &a,
+ const std::pair<T, size_type> &b) const
+ { return (gmm::abs(a.first) > gmm::abs(b.first)); }
+ }
+
+ struct idgmres_state {
+ size_type m, tb_deb, tb_def, p, k, nb_want, nb_unwant;
+ size_type nb_nolong, tb_deftot, tb_defwant, conv, nb_un, fin;
+ bool ok;
+
+ idgmres_state(size_type mm, size_type pp, size_type kk)
+ : m(mm), tb_deb(1), tb_def(0), p(pp), k(kk), nb_want(0),
+ nb_unwant(0), nb_nolong(0), tb_deftot(0), tb_defwant(0),
+ conv(0), nb_un(0), fin(0), ok(false); {}
+ }
+
+ idgmres_state(size_type mm, size_type pp, size_type kk)
+ : m(mm), tb_deb(1), tb_def(0), p(pp), k(kk), nb_want(0),
+ nb_unwant(0), nb_nolong(0), tb_deftot(0), tb_defwant(0),
+ conv(0), nb_un(0), fin(0), ok(false); {}
+
+
+ template <typename CONT, typename IND>
+ apply_permutation(CONT &cont, const IND &ind) {
+ size_type m = ind.end() - ind.begin();
+ std::vector<bool> sorted(m, false);
+
+ for (size_type l = 0; l < m; ++l)
+ if (!sorted[l] && ind[l] != l) {
+
+ typeid(cont[0]) aux = cont[l];
+ k = ind[l];
+ cont[l] = cont[k];
+ sorted[l] = true;
+
+ for(k2 = ind[k]; k2 != l; k2 = ind[k]) {
+ cont[k] = cont[k2];
+ sorted[k] = true;
+ k = k2;
+ }
+ cont[k] = aux;
+ }
+ }
+
+
+ /** Implicitly restarted and deflated Generalized Minimum Residual
+
+ See: C. Le Calvez, B. Molina, Implicitly restarted and deflated
+ FOM and GMRES, numerical applied mathematics,
+ (30) 2-3 (1999) pp191-212.
+
+ @param A Real or complex unsymmetric matrix.
+ @param x initial guess vector and final result.
+ @param b right hand side
+ @param M preconditionner
+ @param m size of the subspace between two restarts
+ @param p number of converged ritz values seeked
+ @param k size of the remaining Krylov subspace when the p ritz values
+ have not yet converged 0 <= p <= k < m.
+ @param tol_vp : tolerance on the ritz values.
+ @param outer
+ @param KS
+ */
+ template < typename Mat, typename Vec, typename VecB, typename Precond,
+ typename Basis >
+ void idgmres(const Mat &A, Vec &x, const VecB &b, const Precond &M,
+ size_type m, size_type p, size_type k, double tol_vp,
+ iteration &outer, Basis& KS) {
+
+ typedef typename linalg_traits<Mat>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ R a, beta;
+ idgmres_state st(m, p, k);
+
+ std::vector<T> w(vect_size(x)), r(vect_size(x)), u(vect_size(x));
+ std::vector<T> c_rot(m+1), s_rot(m+1), s(m+1);
+ std::vector<T> y(m+1), ztest(m+1), gam(m+1);
+ std::vector<T> gamma(m+1);
+ gmm::dense_matrix<T> H(m+1, m), Hess(m+1, m),
+ Hobl(m+1, m), W(vect_size(x), m+1);
+
+ gmm::clear(H);
+
+ outer.set_rhsnorm(gmm::vect_norm2(b));
+ if (outer.get_rhsnorm() == 0.0) { clear(x); return; }
+
+ mult(A, scaled(x, -1.0), b, w);
+ mult(M, w, r);
+ beta = gmm::vect_norm2(r);
+
+ iteration inner = outer;
+ inner.reduce_noisy();
+ inner.set_maxiter(m);
+ inner.set_name("GMRes inner iter");
+
+ while (! outer.finished(beta)) {
+
+ gmm::copy(gmm::scaled(r, 1.0/beta), KS[0]);
+ gmm::clear(s);
+ s[0] = beta;
+ gmm::copy(s, gamma);
+
+ inner.set_maxiter(m - st.tb_deb + 1);
+ size_type i = st.tb_deb - 1; inner.init();
+
+ do {
+ mult(A, KS[i], u);
+ mult(M, u, KS[i+1]);
+ orthogonalize_with_refinment(KS, mat_col(H, i), i);
+ H(i+1, i) = a = gmm::vect_norm2(KS[i+1]);
+ gmm::scale(KS[i+1], R(1) / a);
+
+ gmm::copy(mat_col(H, i), mat_col(Hess, i));
+ gmm::copy(mat_col(H, i), mat_col(Hobl, i));
+
+
+ for (size_type l = 0; l < i; ++l)
+ Apply_Givens_rotation_left(H(l,i), H(l+1,i), c_rot[l], s_rot[l]);
+
+ Givens_rotation(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
+ Apply_Givens_rotation_left(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
+ H(i+1, i) = T(0);
+ Apply_Givens_rotation_left(s[i], s[i+1], c_rot[i], s_rot[i]);
+
+ ++inner, ++outer, ++i;
+ } while (! inner.finished(gmm::abs(s[i])));
+
+ if (inner.converged()) {
+ gmm::copy(s, y);
+ upper_tri_solve(H, y, i, false);
+ combine(KS, y, x, i);
+ mult(A, gmm::scaled(x, T(-1)), b, w);
+ mult(M, w, r);
+ beta = gmm::vect_norm2(r); // + verif sur beta ... à faire
+ break;
+ }
+
+ gmm::clear(gam); gam[m] = s[i];
+ for (size_type l = m; l > 0; --l)
+ Apply_Givens_rotation_left(gam[l-1], gam[l], gmm::conj(c_rot[l-1]),
+ -s_rot[l-1]);
+
+ mult(KS.mat(), gam, r);
+ beta = gmm::vect_norm2(r);
+
+ mult(Hess, scaled(y, T(-1)), gamma, ztest);
+ // En fait, d'après Caroline qui s'y connait ztest et gam devrait
+ // être confondus
+ // Quand on aura vérifié que ça marche, il faudra utiliser gam à la
+ // place de ztest.
+ if (st.tb_def < p) {
+ T nss = H(m,m-1) / ztest[m];
+ nss /= gmm::abs(nss); // ns à calculer plus tard aussi
+ gmm::copy(KS.mat(), W); gmm::copy(scaled(r, nss /beta), mat_col(W, m));
+
+ // Computation of the oblique matrix
+ sub_interval SUBI(0, m);
+ add(scaled(sub_vector(ztest, SUBI), -Hobl(m, m-1) / ztest[m]),
+ sub_vector(mat_col(Hobl, m-1), SUBI));
+ Hobl(m, m-1) *= nss * beta / ztest[m];
+
+ /* **************************************************************** */
+ /* Locking */
+ /* **************************************************************** */
+
+ // Computation of the Ritz eigenpairs.
+ std::vector<std::complex<R> > eval(m);
+ dense_matrix<T> YB(m-st.tb_def, m-st.tb_def);
+ std::vector<char> pure(m-st.tb_def, 0);
+ gmm::clear(YB);
+
+ select_eval(Hobl, eval, YB, pure, st);
+
+ if (st.conv != 0) {
+ // DEFLATION using the QR Factorization of YB
+
+ T alpha = Lock(W, Hobl,
+ sub_matrix(YB, sub_interval(0, m-st.tb_def)),
+ sub_interval(st.tb_def, m-st.tb_def),
+ (st.tb_defwant < p));
+ // ns *= alpha; // à calculer plus tard ??
+ // V(:,m+1) = alpha*V(:, m+1); ça devait servir à qlq chose ...
+
+
+ // Clean the portions below the diagonal corresponding
+ // to the lock Schur vectors
+
+ for (size_type j = st.tb_def; j < st.tb_deftot; ++j) {
+ if ( pure[j-st.tb_def] == 0)
+ gmm::clear(sub_vector(mat_col(Hobl,j), sub_interval(j+1,m-j)));
+ else if (pure[j-st.tb_def] == 1) {
+ gmm::clear(sub_matrix(Hobl, sub_interval(j+2,m-j-1),
+ sub_interval(j, 2)));
+ ++j;
+ }
+ else GMM_ASSERT3(false, "internal error");
+ }
+
+ if (!st.ok) {
+
+ // attention si m = 0;
+ size_type mm = std::min(k+st.nb_unwant+st.nb_nolong, m-1);
+
+ if (eval_sort[m-mm-1].second != R(0)
+ && eval_sort[m-mm-1].second == -eval_sort[m-mm].second) ++mm;
+
+ std::vector<complex<R> > shifts(m-mm);
+ for (size_type i = 0; i < m-mm; ++i)
+ shifts[i] = eval_sort[i].second;
+
+ apply_shift_to_Arnoldi_factorization(W, Hobl, shifts, mm,
+ m-mm, true);
+
+ st.fin = mm;
+ }
+ else
+ st.fin = st.tb_deftot;
+
+
+ /* ************************************************************** */
+ /* Purge */
+ /* ************************************************************** */
+
+ if (st.nb_nolong + st.nb_unwant > 0) {
+
+ std::vector<std::complex<R> > eval(m);
+ dense_matrix<T> YB(st.fin, st.tb_deftot);
+ std::vector<char> pure(st.tb_deftot, 0);
+ gmm::clear(YB);
+ st.nb_un = st.nb_nolong + st.nb_unwant;
+
+ select_eval_for_purging(Hobl, eval, YB, pure, st);
+
+ T alpha = Lock(W, Hobl, YB, sub_interval(0, st.fin), ok);
+
+ // Clean the portions below the diagonal corresponding
+ // to the unwanted lock Schur vectors
+
+ for (size_type j = 0; j < st.tb_deftot; ++j) {
+ if ( pure[j] == 0)
+ gmm::clear(sub_vector(mat_col(Hobl,j), sub_interval(j+1,m-j)));
+ else if (pure[j] == 1) {
+ gmm::clear(sub_matrix(Hobl, sub_interval(j+2,m-j-1),
+ sub_interval(j, 2)));
+ ++j;
+ }
+ else GMM_ASSERT3(false, "internal error");
+ }
+
+ gmm::dense_matrix<T> z(st.nb_un, st.fin - st.nb_un);
+ sub_interval SUBI(0, st.nb_un), SUBJ(st.nb_un, st.fin - st.nb_un);
+ sylvester(sub_matrix(Hobl, SUBI),
+ sub_matrix(Hobl, SUBJ),
+ sub_matrix(gmm::scaled(Hobl, -T(1)), SUBI, SUBJ), z);
+
+ }
+
+ }
+
+ }
+ }
+ }
+
+
+ template < typename Mat, typename Vec, typename VecB, typename Precond >
+ void idgmres(const Mat &A, Vec &x, const VecB &b,
+ const Precond &M, size_type m, iteration& outer) {
+ typedef typename linalg_traits<Mat>::value_type T;
+ modified_gram_schmidt<T> orth(m, vect_size(x));
+ gmres(A, x, b, M, m, outer, orth);
+ }
+
+
+ // Lock stage of an implicit restarted Arnoldi process.
+ // 1- QR factorization of YB through Householder matrices
+ // Q(Rl) = YB
+ // (0 )
+ // 2- Update of the Arnoldi factorization.
+ // H <- Q*HQ, W <- WQ
+ // 3- Restore the Hessemberg form of H.
+
+ template <typename T, typename MATYB>
+ void Lock(gmm::dense_matrix<T> &W, gmm::dense_matrix<T> &H,
+ const MATYB &YB, const sub_interval SUB,
+ bool restore, T &ns) {
+
+ size_type n = mat_nrows(W), m = mat_ncols(W) - 1;
+ size_type ncols = mat_ncols(YB), nrows = mat_nrows(YB);
+ size_type begin = min(SUB); end = max(SUB) - 1;
+ sub_interval SUBR(0, nrows), SUBC(0, ncols);
+ T alpha(1);
+
+ GMM_ASSERT2(((end-begin) == ncols) && (m == mat_nrows(H))
+ && (m+1 == mat_ncols(H)), "dimensions mismatch");
+
+ // DEFLATION using the QR Factorization of YB
+
+ dense_matrix<T> QR(n_rows, n_rows);
+ gmmm::copy(YB, sub_matrix(QR, SUBR, SUBC));
+ gmm::clear(submatrix(QR, SUBR, sub_interval(ncols, nrows-ncols)));
+ qr_factor(QR);
+
+
+ apply_house_left(QR, sub_matrix(H, SUB));
+ apply_house_right(QR, sub_matrix(H, SUBR, SUB));
+ apply_house_right(QR, sub_matrix(W, sub_interval(0, n), SUB));
+
+ // Restore to the initial block hessenberg form
+
+ if (restore) {
+
+ // verifier quand m = 0 ...
+ gmm::dense_matrix tab_p(end - st.tb_deftot, end - st.tb_deftot);
+ gmm::copy(identity_matrix(), tab_p);
+
+ for (size_type j = end-1; j >= st.tb_deftot+2; --j) {
+
+ size_type jm = j-1;
+ std::vector<T> v(jm - st.tb_deftot);
+ sub_interval SUBtot(st.tb_deftot, jm - st.tb_deftot);
+ sub_interval SUBtot2(st.tb_deftot, end - st.tb_deftot);
+ gmm::copy(sub_vector(mat_row(H, j), SUBtot), v);
+ house_vector_last(v);
+ w.resize(end);
+ col_house_update(sub_matrix(H, SUBI, SUBtot), v, w);
+ w.resize(end - st.tb_deftot);
+ row_house_update(sub_matrix(H, SUBtot, SUBtot2), v, w);
+ gmm::clear(sub_vector(mat_row(H, j),
+ sub_interval(st.tb_deftot, j-1-st.tb_deftot)));
+ w.resize(end - st.tb_deftot);
+ col_house_update(sub_matrix(tab_p, sub_interval(0, end-st.tb_deftot),
+ sub_interval(0, jm-st.tb_deftot)), v, w);
+ w.resize(n);
+ col_house_update(sub_matrix(W, sub_interval(0, n), SUBtot), v, w);
+ }
+
+ // restore positive subdiagonal elements
+
+ std::vector<T> d(fin-st.tb_deftot); d[0] = T(1);
+
+ // We compute d[i+1] in order
+ // (d[i+1] * H(st.tb_deftot+i+1,st.tb_deftoti)) / d[i]
+ // be equal to |H(st.tb_deftot+i+1,st.tb_deftot+i))|.
+ for (size_type j = 0; j+1 < end-st.tb_deftot; ++j) {
+ T e = H(st.tb_deftot+j, st.tb_deftot+j-1);
+ d[j+1] = (e == T(0)) ? T(1) : d[j] * gmm::abs(e) / e;
+ scale(sub_vector(mat_row(H, st.tb_deftot+j+1),
+ sub_interval(st.tb_deftot, m-st.tb_deftot)), d[j+1]);
+ scale(mat_col(H, st.tb_deftot+j+1), T(1) / d[j+1]);
+ scale(mat_col(W, st.tb_deftot+j+1), T(1) / d[j+1]);
+ }
+
+ alpha = tab_p(end-st.tb_deftot-1, end-st.tb_deftot-1) / d[end-st.tb_deftot-1];
+ alpha /= gmm::abs(alpha);
+ scale(mat_col(W, m), alpha);
+
+ }
+
+ return alpha;
+ }
+
+
+
+
+
+
+
+
+ // Apply p implicit shifts to the Arnoldi factorization
+ // AV = VH+H(k+p+1,k+p) V(:,k+p+1) e_{k+p}*
+ // and produces the following new Arnoldi factorization
+ // A(VQ) = (VQ)(Q*HQ)+H(k+p+1,k+p) V(:,k+p+1) e_{k+p}* Q
+ // where only the first k columns are relevant.
+ //
+ // Dan Sorensen and Richard J. Radke, 11/95
+ template<typename T, typename C>
+ apply_shift_to_Arnoldi_factorization(dense_matrix<T> V, dense_matrix<T> H,
+ std::vector<C> Lambda, size_type &k,
+ size_type p, bool true_shift = false) {
+
+
+ size_type k1 = 0, num = 0, kend = k+p, kp1 = k + 1;
+ bool mark = false;
+ T c, s, x, y, z;
+
+ dense_matrix<T> q(1, kend);
+ gmm::clear(q); q(0,kend-1) = T(1);
+ std::vector<T> hv(3), w(std::max(kend, mat_nrows(V)));
+
+ for(size_type jj = 0; jj < p; ++jj) {
+ // compute and apply a bulge chase sweep initiated by the
+ // implicit shift held in w(jj)
+
+ if (abs(Lambda[jj].real()) == 0.0) {
+ // apply a real shift using 2 by 2 Givens rotations
+
+ for (size_type k1 = 0, k2 = 0; k2 != kend-1; k1 = k2+1) {
+ k2 = k1;
+ while (h(k2+1, k2) != T(0) && k2 < kend-1) ++k2;
+
+ Givens_rotation(H(k1, k1) - Lambda[jj], H(k1+1, k1), c, s);
+
+ for (i = k1; i <= k2; ++i) {
+ if (i > k1) Givens_rotation(H(i, i-1), H(i+1, i-1), c, s);
+
+ // Ne pas oublier de nettoyer H(i+1,i-1) (le mettre à zéro).
+ // Vérifier qu'au final H(i+1,i) est bien un réel positif.
+
+ // apply rotation from left to rows of H
+ row_rot(sub_matrix(H, sub_interval(i,2), sub_interval(i, kend-i)),
+ c, s, 0, 0);
+
+ // apply rotation from right to columns of H
+ size_type ip2 = std::min(i+2, kend);
+ col_rot(sub_matrix(H, sub_interval(0, ip2), sub_interval(i, 2))
+ c, s, 0, 0);
+
+ // apply rotation from right to columns of V
+ col_rot(V, c, s, i, i+1);
+
+ // accumulate e' Q so residual can be updated k+p
+ Apply_Givens_rotation_left(q(0,i), q(0,i+1), c, s);
+ // peut être que nous utilisons G au lieu de G* et que
+ // nous allons trop loin en k2.
+ }
+ }
+
+ num = num + 1;
+ }
+ else {
+
+ // Apply a double complex shift using 3 by 3 Householder
+ // transformations
+
+ if (jj == p || mark)
+ mark = false; // skip application of conjugate shift
+ else {
+ num = num + 2; // mark that a complex conjugate
+ mark = true; // pair has been applied
+
+ // Indices de fin de boucle à surveiller... de près !
+ for (size_type k1 = 0, k3 = 0; k3 != kend-2; k1 = k3+1) {
+ k3 = k1;
+ while (h(k3+1, k3) != T(0) && k3 < kend-2) ++k3;
+ size_type k2 = k1+1;
+
+
+ x = H(k1,k1) * H(k1,k1) + H(k1,k2) * H(k2,k1)
+ - 2.0*Lambda[jj].real() * H(k1,k1) + gmm::abs_sqr(Lambda[jj]);
+ y = H(k2,k1) * (H(k1,k1) + H(k2,k2) - 2.0*Lambda[jj].real());
+ z = H(k2+1,k2) * H(k2,k1);
+
+ for (size_type i = k1; i <= k3; ++i) {
+ if (i > k1) {
+ x = H(i, i-1);
+ y = H(i+1, i-1);
+ z = H(i+2, i-1);
+ // Ne pas oublier de nettoyer H(i+1,i-1) et H(i+2,i-1)
+ // (les mettre à zéro).
+ }
+
+ hv[0] = x; hv[1] = y; hv[2] = z;
+ house_vector(v);
+
+ // Vérifier qu'au final H(i+1,i) est bien un réel positif
+
+ // apply transformation from left to rows of H
+ w.resize(kend-i);
+ row_house_update(sub_matrix(H, sub_interval(i, 2),
+ sub_interval(i, kend-i)), v, w);
+
+ // apply transformation from right to columns of H
+
+ size_type ip3 = std::min(kend, i + 3);
+ w.resize(ip3);
+ col_house_update(sub_matrix(H, sub_interval(0, ip3),
+ sub_interval(i, 2)), v, w);
+
+ // apply transformation from right to columns of V
+
+ w.resize(mat_nrows(V));
+ col_house_update(sub_matrix(V, sub_interval(0, mat_nrows(V)),
+ sub_interval(i, 2)), v, w);
+
+ // accumulate e' Q so residual can be updated k+p
+
+ w.resize(1);
+ col_house_update(sub_matrix(q, sub_interval(0,1),
+ sub_interval(i,2)), v, w);
+
+ }
+ }
+
+ // clean up step with Givens rotation
+
+ i = kend-2;
+ c = x; s = y;
+ if (i > k1) Givens_rotation(H(i, i-1), H(i+1, i-1), c, s);
+
+ // Ne pas oublier de nettoyer H(i+1,i-1) (le mettre à zéro).
+ // Vérifier qu'au final H(i+1,i) est bien un réel positif.
+
+ // apply rotation from left to rows of H
+ row_rot(sub_matrix(H, sub_interval(i,2), sub_interval(i, kend-i)),
+ c, s, 0, 0);
+
+ // apply rotation from right to columns of H
+ size_type ip2 = std::min(i+2, kend);
+ col_rot(sub_matrix(H, sub_interval(0, ip2), sub_interval(i, 2))
+ c, s, 0, 0);
+
+ // apply rotation from right to columns of V
+ col_rot(V, c, s, i, i+1);
+
+ // accumulate e' Q so residual can be updated k+p
+ Apply_Givens_rotation_left(q(0,i), q(0,i+1), c, s);
+
+ }
+ }
+ }
+
+ // update residual and store in the k+1 -st column of v
+
+ k = kend - num;
+ scale(mat_col(V, kend), q(0, k));
+
+ if (k < mat_nrows(H)) {
+ if (true_shift)
+ gmm::copy(mat_col(V, kend), mat_col(V, k));
+ else
+ // v(:,k+1) = v(:,kend+1) + v(:,k+1)*h(k+1,k);
+ // v(:,k+1) = v(:,kend+1) ;
+ gmm::add(scaled(mat_col(V, kend), H(kend, kend-1)),
+ scaled(mat_col(V, k), H(k, k-1)), mat_col(V, k));
+ }
+
+ H(k, k-1) = vect_norm2(mat_col(V, k));
+ scale(mat_col(V, kend), T(1) / H(k, k-1));
+ }
+
+
+
+ template<typename MAT, typename EVAL, typename PURE>
+ void select_eval(const MAT &Hobl, EVAL &eval, MAT &YB, PURE &pure,
+ idgmres_state &st) {
+
+ typedef typename linalg_traits<MAT>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ size_type m = st.m;
+
+ // Computation of the Ritz eigenpairs.
+
+ col_matrix< std::vector<T> > evect(m-st.tb_def, m-st.tb_def);
+ // std::vector<std::complex<R> > eval(m);
+ std::vector<R> ritznew(m, T(-1));
+
+ // dense_matrix<T> evect_lock(st.tb_def, st.tb_def);
+
+ sub_interval SUB1(st.tb_def, m-st.tb_def);
+ implicit_qr_algorithm(sub_matrix(Hobl, SUB1),
+ sub_vector(eval, SUB1), evect);
+ sub_interval SUB2(0, st.tb_def);
+ implicit_qr_algorithm(sub_matrix(Hobl, SUB2),
+ sub_vector(eval, SUB2), /* evect_lock */);
+
+ for (size_type l = st.tb_def; l < m; ++l)
+ ritznew[l] = gmm::abs(evect(m-st.tb_def-1, l-st.tb_def) * Hobl(m, m-1));
+
+ std::vector< std::pair<T, size_type> > eval_sort(m);
+ for (size_type l = 0; l < m; ++l)
+ eval_sort[l] = std::pair<T, size_type>(eval[l], l);
+ std::sort(eval_sort.begin(), eval_sort.end(), compare_vp());
+
+ std::vector<size_type> index(m);
+ for (size_type l = 0; l < m; ++l) index[l] = eval_sort[l].second;
+
+ std::vector<bool> kept(m, false);
+ std::fill(kept.begin(), kept.begin()+st.tb_def, true);
+
+ apply_permutation(eval, index);
+ apply_permutation(evect, index);
+ apply_permutation(ritznew, index);
+ apply_permutation(kept, index);
+
+ // Which are the eigenvalues that converged ?
+ //
+ // nb_want is the number of eigenvalues of
+ // Hess(tb_def+1:n,tb_def+1:n) that converged and are WANTED
+ //
+ // nb_unwant is the number of eigenvalues of
+ // Hess(tb_def+1:n,tb_def+1:n) that converged and are UNWANTED
+ //
+ // nb_nolong is the number of eigenvalues of
+ // Hess(1:tb_def,1:tb_def) that are NO LONGER WANTED.
+ //
+ // tb_deftot is the number of the deflated eigenvalues
+ // that is tb_def + nb_want + nb_unwant
+ //
+ // tb_defwant is the number of the wanted deflated eigenvalues
+ // that is tb_def + nb_want - nb_nolong
+
+ st.nb_want = 0, st.nb_unwant = 0, st.nb_nolong = 0;
+ size_type j, ind;
+
+ for (j = 0, ind = 0; j < m-p; ++j) {
+ if (ritznew[j] == R(-1)) {
+ if (std::imag(eval[j]) != R(0)) {
+ st.nb_nolong += 2; ++j; // à adapter dans le cas complexe ...
+ }
+ else st.nb_nolong++;
+ }
+ else {
+ if (ritznew[j]
+ < tol_vp * gmm::abs(eval[j])) {
+
+ for (size_type l = 0, l < m-st.tb_def; ++l)
+ YB(l, ind) = std::real(evect(l, j));
+ kept[j] = true;
+ ++j; ++st.nb_unwant; ind++;
+
+ if (std::imag(eval[j]) != R(0)) {
+ for (size_type l = 0, l < m-st.tb_def; ++l)
+ YB(l, ind) = std::imag(evect(l, j));
+ pure[ind-1] = 1;
+ pure[ind] = 2;
+
+ kept[j] = true;
+
+ st.nb_unwant++;
+ ++ind;
+ }
+ }
+ }
+ }
+
+
+ for (; j < m; ++j) {
+ if (ritznew[j] != R(-1)) {
+
+ for (size_type l = 0, l < m-st.tb_def; ++l)
+ YB(l, ind) = std::real(evect(l, j));
+ pure[ind] = 1;
+ ++ind;
+ kept[j] = true;
+ ++st.nb_want;
+
+ if (ritznew[j]
+ < tol_vp * gmm::abs(eval[j])) {
+ for (size_type l = 0, l < m-st.tb_def; ++l)
+ YB(l, ind) = std::imag(evect(l, j));
+ pure[ind] = 2;
+
+ j++;
+ kept[j] = true;
+
+ st.nb_want++;
+ ++ind;
+ }
+ }
+ }
+
+ std::vector<T> shift(m - st.tb_def - st.nb_want - st.nb_unwant);
+ for (size_type j = 0, i = 0; j < m; ++j)
+ if (!kept[j]) shift[i++] = eval[j];
+
+ // st.conv (st.nb_want+st.nb_unwant) is the number of eigenpairs that
+ // have just converged.
+ // st.tb_deftot is the total number of eigenpairs that have converged.
+
+ size_type st.conv = ind;
+ size_type st.tb_deftot = st.tb_def + st.conv;
+ size_type st.tb_defwant = st.tb_def + st.nb_want - st.nb_nolong;
+
+ sub_interval SUBYB(0, st.conv);
+
+ if ( st.tb_defwant >= p ) { // An invariant subspace has been found.
+
+ st.nb_unwant = 0;
+ st.nb_want = p + st.nb_nolong - st.tb_def;
+ st.tb_defwant = p;
+
+ if ( pure[st.conv - st.nb_want + 1] == 2 ) {
+ ++st.nb_want; st.tb_defwant = ++p;// il faudrait que ce soit un p local
+ }
+
+ SUBYB = sub_interval(st.conv - st.nb_want, st.nb_want);
+ // YB = YB(:, st.conv-st.nb_want+1 : st.conv); // On laisse en suspend ..
+ // pure = pure(st.conv-st.nb_want+1 : st.conv,1); // On laisse suspend ..
+ st.conv = st.nb_want;
+ st.tb_deftot = st.tb_def + st.conv;
+ st.ok = true;
+ }
+
+ }
+
+
+
+ template<typename MAT, typename EVAL, typename PURE>
+ void select_eval_for_purging(const MAT &Hobl, EVAL &eval, MAT &YB,
+ PURE &pure, idgmres_state &st) {
+
+ typedef typename linalg_traits<MAT>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+ size_type m = st.m;
+
+ // Computation of the Ritz eigenpairs.
+
+ col_matrix< std::vector<T> > evect(st.tb_deftot, st.tb_deftot);
+
+ sub_interval SUB1(0, st.tb_deftot);
+ implicit_qr_algorithm(sub_matrix(Hobl, SUB1),
+ sub_vector(eval, SUB1), evect);
+ std::fill(eval.begin() + st.tb_deftot, eval.end(), std::complex<R>(0));
+
+ std::vector< std::pair<T, size_type> > eval_sort(m);
+ for (size_type l = 0; l < m; ++l)
+ eval_sort[l] = std::pair<T, size_type>(eval[l], l);
+ std::sort(eval_sort.begin(), eval_sort.end(), compare_vp());
+
+ std::vector<bool> sorted(m);
+ std::fill(sorted.begin(), sorted.end(), false);
+
+ std::vector<size_type> ind(m);
+ for (size_type l = 0; l < m; ++l) ind[l] = eval_sort[l].second;
+
+ std::vector<bool> kept(m, false);
+ std::fill(kept.begin(), kept.begin()+st.tb_def, true);
+
+ apply_permutation(eval, ind);
+ apply_permutation(evect, ind);
+
+ size_type j;
+ for (j = 0; j < st.tb_deftot; ++j) {
+
+ for (size_type l = 0, l < st.tb_deftot; ++l)
+ YB(l, j) = std::real(evect(l, j));
+
+ if (std::imag(eval[j]) != R(0)) {
+ for (size_type l = 0, l < m-st.tb_def; ++l)
+ YB(l, j+1) = std::imag(evect(l, j));
+ pure[j] = 1;
+ pure[j+1] = 2;
+
+ j += 2;
+ }
+ else ++j;
+ }
+ }
+
+
+
+
+
+
+}
+
+#endif
diff --git a/Contrib/gmm/gmm_solver_qmr.h b/Contrib/gmm/gmm_solver_qmr.h
new file mode 100755
index 0000000..a9a5582
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_qmr.h
@@ -0,0 +1,209 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of qmr.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the University of California, Berkeley nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
+// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_solver_qmr.h
+ @author Andrew Lumsdaine <lums at osl.iu.edu>
+ @author Lie-Quan Lee <llee at osl.iu.edu>
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief Quasi-Minimal Residual iterative solver.
+*/
+#ifndef GMM_QMR_H
+#define GMM_QMR_H
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+
+namespace gmm {
+
+ /** Quasi-Minimal Residual.
+
+ This routine solves the unsymmetric linear system Ax = b using
+ the Quasi-Minimal Residual method.
+
+ See: R. W. Freund and N. M. Nachtigal, A quasi-minimal residual
+ method for non-Hermitian linear systems, Numerical Math.,
+ 60(1991), pp. 315-339
+
+ Preconditioner - Incomplete LU, Incomplete LU with threshold,
+ SSOR or identity_preconditioner.
+ */
+ template <typename Matrix, typename Vector, typename VectorB,
+ typename Precond1>
+ void qmr(const Matrix &A, Vector &x, const VectorB &b, const Precond1 &M1,
+ iteration& iter) {
+
+ typedef typename linalg_traits<Vector>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ T delta(0), ep(0), beta(0), theta_1(0), gamma_1(0);
+ T theta(0), gamma(1), eta(-1);
+ R rho_1(0), rho, xi;
+
+ typedef typename temporary_vector<Vector>::vector_type TmpVec;
+ size_type nn = vect_size(x);
+ TmpVec r(nn), v_tld(nn), y(nn), w_tld(nn), z(nn), v(nn), w(nn);
+ TmpVec y_tld(nn), z_tld(nn), p(nn), q(nn), p_tld(nn), d(nn), s(nn);
+
+ iter.set_rhsnorm(double(gmm::vect_norm2(b)));
+ if (iter.get_rhsnorm() == 0.0) { clear(x); return; }
+
+ gmm::mult(A, gmm::scaled(x, T(-1)), b, r);
+ gmm::copy(r, v_tld);
+
+ gmm::left_mult(M1, v_tld, y);
+ rho = gmm::vect_norm2(y);
+
+ gmm::copy(r, w_tld);
+ gmm::transposed_right_mult(M1, w_tld, z);
+ xi = gmm::vect_norm2(z);
+
+ while (! iter.finished_vect(r)) {
+
+ if (rho == R(0) || xi == R(0))
+ if (iter.get_maxiter() == size_type(-1))
+ { GMM_ASSERT1(false, "QMR failed to converge"); }
+ else { GMM_WARNING1("QMR failed to converge"); return; }
+
+ gmm::copy(gmm::scaled(v_tld, T(R(1)/rho)), v);
+ gmm::scale(y, T(R(1)/rho));
+
+ gmm::copy(gmm::scaled(w_tld, T(R(1)/xi)), w);
+ gmm::scale(z, T(R(1)/xi));
+
+ delta = gmm::vect_sp(z, y);
+ if (delta == T(0))
+ if (iter.get_maxiter() == size_type(-1))
+ { GMM_ASSERT1(false, "QMR failed to converge"); }
+ else { GMM_WARNING1("QMR failed to converge"); return; }
+
+ gmm::right_mult(M1, y, y_tld);
+ gmm::transposed_left_mult(M1, z, z_tld);
+
+ if (iter.first()) {
+ gmm::copy(y_tld, p);
+ gmm::copy(z_tld, q);
+ } else {
+ gmm::add(y_tld, gmm::scaled(p, -(T(xi * delta) / ep)), p);
+ gmm::add(z_tld, gmm::scaled(q, -(T(rho * delta) / ep)), q);
+ }
+
+ gmm::mult(A, p, p_tld);
+
+ ep = gmm::vect_sp(q, p_tld);
+ if (ep == T(0))
+ if (iter.get_maxiter() == size_type(-1))
+ { GMM_ASSERT1(false, "QMR failed to converge"); }
+ else { GMM_WARNING1("QMR failed to converge"); return; }
+
+ beta = ep / delta;
+ if (beta == T(0))
+ if (iter.get_maxiter() == size_type(-1))
+ { GMM_ASSERT1(false, "QMR failed to converge"); }
+ else { GMM_WARNING1("QMR failed to converge"); return; }
+
+ gmm::add(p_tld, gmm::scaled(v, -beta), v_tld);
+ gmm::left_mult(M1, v_tld, y);
+
+ rho_1 = rho;
+ rho = gmm::vect_norm2(y);
+
+ gmm::mult(gmm::transposed(A), q, w_tld);
+ gmm::add(w_tld, gmm::scaled(w, -beta), w_tld);
+ gmm::transposed_right_mult(M1, w_tld, z);
+
+ xi = gmm::vect_norm2(z);
+
+ gamma_1 = gamma;
+ theta_1 = theta;
+
+ theta = rho / (gamma_1 * beta);
+ gamma = T(1) / gmm::sqrt(T(1) + gmm::sqr(theta));
+
+ if (gamma == T(0))
+ if (iter.get_maxiter() == size_type(-1))
+ { GMM_ASSERT1(false, "QMR failed to converge"); }
+ else { GMM_WARNING1("QMR failed to converge"); return; }
+
+ eta = -eta * T(rho_1) * gmm::sqr(gamma) / (beta * gmm::sqr(gamma_1));
+
+ if (iter.first()) {
+ gmm::copy(gmm::scaled(p, eta), d);
+ gmm::copy(gmm::scaled(p_tld, eta), s);
+ } else {
+ T tmp = gmm::sqr(theta_1 * gamma);
+ gmm::add(gmm::scaled(p, eta), gmm::scaled(d, tmp), d);
+ gmm::add(gmm::scaled(p_tld, eta), gmm::scaled(s, tmp), s);
+ }
+ gmm::add(d, x);
+ gmm::add(gmm::scaled(s, T(-1)), r);
+
+ ++iter;
+ }
+ }
+
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_std.h b/Contrib/gmm/gmm_std.h
new file mode 100755
index 0000000..4e476d5
--- /dev/null
+++ b/Contrib/gmm/gmm_std.h
@@ -0,0 +1,255 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1995-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_std.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>,
+ @author Julien Pommier <Julien.Pommier at insa-toulouse.fr>
+ @date June 01, 1995.
+ @brief basic setup for gmm (includes, typedefs etc.)
+*/
+#ifndef GMM_STD_H__
+#define GMM_STD_H__
+
+#ifndef __USE_STD_IOSTREAM
+# define __USE_STD_IOSTREAM
+#endif
+
+#ifndef __USE_BSD
+# define __USE_BSD
+#endif
+
+#ifndef __USE_ISOC99
+# define __USE_ISOC99
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // Secure versions for VC++
+# define GMM_SECURE_CRT
+# define SECURE_NONCHAR_SSCANF sscanf_s
+# define SECURE_NONCHAR_FSCANF fscanf_s
+# define SECURE_STRNCPY(a, la, b, lb) strncpy_s(a, la, b, lb)
+# define SECURE_FOPEN(F, filename, mode) (*(F) = 0, fopen_s(F, filename, mode))
+# define SECURE_SPRINTF1(S, l, st, p1) sprintf_s(S, l, st, p1)
+# define SECURE_SPRINTF2(S, l, st, p1, p2) sprintf_s(S, l, st, p1, p2)
+# define SECURE_SPRINTF4(S, l, st, p1, p2, p3, p4) sprintf_s(S, l, st, p1, p2, p3, p4)
+# define SECURE_STRDUP(s) _strdup(s)
+# ifndef _SCL_SECURE_NO_DEPRECATE
+# error Add the option /D_SCL_SECURE_NO_DEPRECATE to the compilation command
+# endif
+#else
+# define SECURE_NONCHAR_SSCANF sscanf
+# define SECURE_NONCHAR_FSCANF fscanf
+# define SECURE_STRNCPY(a, la, b, lb) strncpy(a, b, lb)
+# define SECURE_FOPEN(F, filename, mode) ((*(F)) = fopen(filename, mode))
+# define SECURE_SPRINTF1(S, l, st, p1) sprintf(S, st, p1)
+# define SECURE_SPRINTF2(S, l, st, p1, p2) sprintf(S, st, p1, p2)
+# define SECURE_SPRINTF4(S, l, st, p1, p2, p3, p4) sprintf(S, st, p1, p2, p3, p4)
+# define SECURE_STRDUP(s) strdup(s)
+#endif
+
+
+#if !defined(GMM_USES_MPI) && GETFEM_PARA_LEVEL > 0
+# define GMM_USES_MPI
+#endif
+
+/* ********************************************************************** */
+/* Compilers detection. */
+/* ********************************************************************** */
+
+/* for sun CC 5.0 ...
+#if defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x500
+# include <stdcomp.h>
+# undef _RWSTD_NO_CLASS_PARTIAL_SPEC
+# undef _RWSTD_NO_NAMESPACE
+#endif
+*/
+/* for VISUAL C++ ...
+ #if defined(_MSC_VER) // && !defined(__MWERKS__)
+ #define _GETFEM_MSVCPP_ _MSC_VER
+ #endif
+*/
+
+#if defined(__GNUC__)
+# if (__GNUC__ < 3)
+# error : PLEASE UPDATE g++ TO AT LEAST 3.0 VERSION
+# endif
+#endif
+
+/* ********************************************************************** */
+/* C++ Standard Headers. */
+/* ********************************************************************** */
+#include <cstdlib>
+#include <cstddef>
+#include <cmath>
+#include <cstring>
+#include <cctype>
+#include <cassert>
+#include <climits>
+#include <iostream>
+//#include <ios>
+#include <fstream>
+#include <ctime>
+#include <exception>
+#include <typeinfo>
+#include <stdexcept>
+#include <iterator>
+#include <algorithm>
+#include <vector>
+#include <deque>
+#include <string>
+#include <complex>
+#include <limits>
+#include <sstream>
+#include <numeric>
+
+
+using std::endl; using std::cout; using std::cerr;
+using std::ends; using std::cin;
+
+namespace gmm {
+
+ /* ******************************************************************* */
+ /* Clock functions. */
+ /* ******************************************************************* */
+
+# if defined(HAVE_SYS_TIMES)
+ inline double uclock_sec(void) {
+ static double ttclk = 0.;
+ if (ttclk == 0.) ttclk = sysconf(_SC_CLK_TCK);
+ tms t; times(&t); return double(t.tms_utime) / ttclk;
+ }
+# else
+ inline double uclock_sec(void)
+ { return double(clock())/double(CLOCKS_PER_SEC); }
+# endif
+
+ /* ******************************************************************** */
+ /* Fixed size integer types. */
+ /* ******************************************************************** */
+ // Remark : the test program dynamic_array tests the lenght of
+ // resulting integers
+
+ template <size_t s> struct fixed_size_integer_generator {
+ typedef void int_base_type;
+ typedef void uint_base_type;
+ };
+
+ template <> struct fixed_size_integer_generator<sizeof(char)> {
+ typedef signed char int_base_type;
+ typedef unsigned char uint_base_type;
+ };
+
+ template <> struct fixed_size_integer_generator<sizeof(short int)
+ - ((sizeof(short int) == sizeof(char)) ? 78 : 0)> {
+ typedef signed short int int_base_type;
+ typedef unsigned short int uint_base_type;
+ };
+
+ template <> struct fixed_size_integer_generator<sizeof(int)
+ - ((sizeof(int) == sizeof(short int)) ? 59 : 0)> {
+ typedef signed int int_base_type;
+ typedef unsigned int uint_base_type;
+ };
+
+ template <> struct fixed_size_integer_generator<sizeof(long)
+ - ((sizeof(int) == sizeof(long)) ? 93 : 0)> {
+ typedef signed long int_base_type;
+ typedef unsigned long uint_base_type;
+ };
+
+ template <> struct fixed_size_integer_generator<sizeof(long long)
+ - ((sizeof(long long) == sizeof(long)) ? 99 : 0)> {
+ typedef signed long long int_base_type;
+ typedef unsigned long long uint_base_type;
+ };
+
+ typedef fixed_size_integer_generator<1>::int_base_type int8_type;
+ typedef fixed_size_integer_generator<1>::uint_base_type uint8_type;
+ typedef fixed_size_integer_generator<2>::int_base_type int16_type;
+ typedef fixed_size_integer_generator<2>::uint_base_type uint16_type;
+ typedef fixed_size_integer_generator<4>::int_base_type int32_type;
+ typedef fixed_size_integer_generator<4>::uint_base_type uint32_type;
+ typedef fixed_size_integer_generator<8>::int_base_type int64_type;
+ typedef fixed_size_integer_generator<8>::uint_base_type uint64_type;
+
+// #if INT_MAX == 32767
+// typedef signed int int16_type;
+// typedef unsigned int uint16_type;
+// #elif SHRT_MAX == 32767
+// typedef signed short int int16_type;
+// typedef unsigned short int uint16_type;
+// #else
+// # error "impossible to build a 16 bits integer"
+// #endif
+
+// #if INT_MAX == 2147483647
+// typedef signed int int32_type;
+// typedef unsigned int uint32_type;
+// #elif SHRT_MAX == 2147483647
+// typedef signed short int int32_type;
+// typedef unsigned short int uint32_type;
+// #elif LONG_MAX == 2147483647
+// typedef signed long int int32_type;
+// typedef unsigned long int uint32_type;
+// #else
+// # error "impossible to build a 32 bits integer"
+// #endif
+
+// #if INT_MAX == 9223372036854775807L || INT_MAX == 9223372036854775807
+// typedef signed int int64_type;
+// typedef unsigned int uint64_type;
+// #elif LONG_MAX == 9223372036854775807L || LONG_MAX == 9223372036854775807
+// typedef signed long int int64_type;
+// typedef unsigned long int uint64_type;
+// #elif LLONG_MAX == 9223372036854775807LL || LLONG_MAX == 9223372036854775807L || LLONG_MAX == 9223372036854775807
+// typedef signed long long int int64_type;
+// typedef unsigned long long int uint64_type;
+// #else
+// # error "impossible to build a 64 bits integer"
+// #endif
+
+#if defined(__GNUC__) && !defined(__ICC)
+/*
+ g++ can issue a warning at each usage of a function declared with this special attribute
+ (also works with typedefs and variable declarations)
+*/
+# define IS_DEPRECATED __attribute__ ((__deprecated__))
+/*
+ the specified function is inlined at any optimization level
+*/
+# define ALWAYS_INLINE __attribute__((always_inline))
+#else
+# define IS_DEPRECATED
+# define ALWAYS_INLINE
+#endif
+
+}
+
+#endif /* GMM_STD_H__ */
+
diff --git a/Contrib/gmm/gmm_sub_index.h b/Contrib/gmm/gmm_sub_index.h
new file mode 100755
index 0000000..387c707
--- /dev/null
+++ b/Contrib/gmm/gmm_sub_index.h
@@ -0,0 +1,217 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_sub_index.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief sub-indices.
+*/
+
+#ifndef GMM_SUB_INDEX_H__
+#define GMM_SUB_INDEX_H__
+
+#include "gmm_def.h"
+
+namespace gmm {
+
+ /* ******************************************************************** */
+ /* sub indices */
+ /* ******************************************************************** */
+
+ struct basic_index : public std::vector<size_t> {
+
+ mutable size_type nb_ref;
+ // size_type key1; faire la somme des composantes
+ // const basic_index *rind; rindex s'il existe
+
+
+ size_t operator[](size_type i) const {
+ return (i < size()) ? std::vector<size_t>::operator[](i) : size_type(-1);
+ }
+
+ basic_index() : nb_ref(1) {}
+ basic_index(size_type j) : std::vector<size_t>(j), nb_ref(1) {}
+ template <typename IT> basic_index(IT b, IT e)
+ : std::vector<size_t>(e-b), nb_ref(1) { std::copy(b, e, begin()); }
+ basic_index(const basic_index *pbi) : nb_ref(1) {
+ const_iterator it = pbi->begin(), ite = pbi->end();
+ size_type i = 0;
+ for ( ; it != ite; ++it) i = std::max(i, *it);
+ resize(i+1); std::fill(begin(), end(), size_type(-1));
+ for (it = pbi->begin(), i = 0; it != ite; ++it, ++i)
+ std::vector<size_t>::operator[](*it) = i;
+ }
+ void swap(size_type i, size_type j) {
+ std::swap(std::vector<size_t>::operator[](i),
+ std::vector<size_t>::operator[](j));
+ }
+
+ };
+
+ typedef basic_index *pbasic_index;
+
+ struct index_generator {
+
+ template <typename IT> static pbasic_index create_index(IT begin, IT end)
+ { return new basic_index(begin, end); }
+ static pbasic_index create_rindex(pbasic_index pbi)
+ { return new basic_index(pbi); }
+ static void attach(pbasic_index pbi) { if (pbi) pbi->nb_ref++; }
+ static void unattach(pbasic_index pbi)
+ { if (pbi && --(pbi->nb_ref) == 0) delete pbi; }
+
+ };
+
+ struct sub_index {
+
+ size_type first_, last_;
+ typedef basic_index base_type;
+ typedef base_type::const_iterator const_iterator;
+
+ mutable pbasic_index ind;
+ mutable pbasic_index rind;
+
+ void comp_extr(void) {
+ std::vector<size_t>::const_iterator it = ind->begin(), ite = ind->end();
+ if (it != ite) { first_=last_= *it; ++it; } else { first_=last_= 0; }
+ for (; it != ite; ++it)
+ { first_ = std::min(first_, *it); last_ = std::max(last_, *it); }
+ }
+
+ // inline void test_rind(void) const
+ // { if (!rind) rind = index_generator::create_rindex(ind); }
+ size_type size(void) const { return ind->size(); }
+ size_type first(void) const { return first_; }
+ size_type last(void) const { return last_; }
+ size_type index(size_type i) const { return (*ind)[i]; }
+ size_type rindex(size_type i) const {
+ // test_rind();
+ if (i < rind->size()) return (*rind)[i]; else return size_type(-1);
+ }
+
+ const_iterator begin(void) const { return ind->begin(); }
+ const_iterator end(void) const { return ind->end(); }
+ const_iterator rbegin(void) const {/*test_rind();*/ return rind->begin(); }
+ const_iterator rend(void) const {/*test_rind();*/ return rind->end(); }
+
+ sub_index() : ind(0), rind(0) {}
+ template <typename IT> sub_index(IT it, IT ite)
+ : ind(index_generator::create_index(it, ite)),
+ rind(index_generator::create_rindex(ind)) { comp_extr(); }
+ template <typename CONT> sub_index(const CONT &c)
+ : ind(index_generator::create_index(c.begin(), c.end())),
+ rind(index_generator::create_rindex(ind))
+ { comp_extr(); }
+ ~sub_index()
+ { index_generator::unattach(rind); index_generator::unattach(ind); }
+ sub_index(const sub_index &si) : first_(si.first_), last_(si.last_),
+ ind(si.ind), rind(si.rind)
+ { index_generator::attach(rind); index_generator::attach(ind); }
+ sub_index &operator =(const sub_index &si) {
+ index_generator::unattach(rind); index_generator::unattach(ind);
+ ind = si.ind; rind = si.rind; index_generator::attach(rind);
+ index_generator::attach(ind);
+ first_ = si.first_; last_ = si.last_;
+ return *this;
+ }
+ };
+
+ struct unsorted_sub_index : public sub_index {
+ template <typename IT> unsorted_sub_index(IT it, IT ite)
+ : sub_index(it, ite) {}
+ template <typename CONT> unsorted_sub_index(const CONT &c)
+ : sub_index(c) {}
+ unsorted_sub_index() {}
+ unsorted_sub_index(const unsorted_sub_index &si) : sub_index(si) {}
+ unsorted_sub_index &operator =(const unsorted_sub_index &si)
+ { sub_index::operator =(si); return *this; }
+ void swap(size_type i, size_type j) {
+ GMM_ASSERT2(ind->nb_ref <= 1, "Operation not allowed on this index");
+ if (rind) rind->swap((*ind)[i], (*ind)[j]);
+ ind->swap(i, j);
+ }
+ };
+
+ inline std::ostream &operator << (std::ostream &o, const sub_index &si) {
+ o << "sub_index(";
+ if (si.size() != 0) o << si.index(0);
+ for (size_type i = 1; i < si.size(); ++i) o << ", " << si.index(i);
+ o << ")";
+ return o;
+ }
+
+ struct sub_interval {
+ size_type min, max;
+
+ size_type size(void) const { return max - min; }
+ size_type first(void) const { return min; }
+ size_type last(void) const { return max; }
+ size_type index(size_type i) const { return min + i; }
+ size_type step(void) const { return 1; }
+ size_type rindex(size_type i) const
+ { if (i >= min && i < max) return i - min; return size_type(-1); }
+ sub_interval(size_type mi, size_type l) : min(mi), max(mi+l) {}
+ sub_interval() {}
+ };
+
+ inline std::ostream &operator << (std::ostream &o, const sub_interval &si)
+ { o << "sub_interval(" << si.min << ", " << si.size() << ")"; return o; }
+
+ struct sub_slice {
+ size_type min, max, N;
+
+ size_type size(void) const { return (max - min) / N; }
+ size_type first(void) const { return min; }
+ size_type last(void) const { return (min == max) ? max : max+1-N; }
+ size_type step(void) const { return N; }
+ size_type index(size_type i) const { return min + N * i; }
+ size_type rindex(size_type i) const {
+ if (i >= min && i < max)
+ { size_type j = (i - min); if (j % N == 0) return j / N; }
+ return size_type(-1);
+ }
+ sub_slice(size_type mi, size_type l, size_type n)
+ : min(mi), max(mi+l*n), N(n) {}
+ sub_slice(void) {}
+ };
+
+ inline std::ostream &operator << (std::ostream &o, const sub_slice &si) {
+ o << "sub_slice(" << si.min << ", " << si.size() << ", " << si.step()
+ << ")"; return o;
+ }
+
+ template<class SUBI> struct index_is_sorted
+ { typedef linalg_true bool_type; };
+ template<> struct index_is_sorted<unsorted_sub_index>
+ { typedef linalg_false bool_type; };
+
+}
+
+#endif // GMM_SUB_INDEX_H__
diff --git a/Contrib/gmm/gmm_sub_matrix.h b/Contrib/gmm/gmm_sub_matrix.h
new file mode 100755
index 0000000..efc36bc
--- /dev/null
+++ b/Contrib/gmm/gmm_sub_matrix.h
@@ -0,0 +1,409 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_sub_matrix.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief Generic sub-matrices.
+*/
+
+#ifndef GMM_SUB_MATRIX_H__
+#define GMM_SUB_MATRIX_H__
+
+#include "gmm_sub_vector.h"
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* sub row matrices type */
+ /* ********************************************************************* */
+
+ template <typename PT, typename SUBI1, typename SUBI2>
+ struct gen_sub_row_matrix {
+ typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef M * CPT;
+ typedef typename std::iterator_traits<PT>::reference ref_M;
+ typedef typename select_ref<typename linalg_traits<M>
+ ::const_row_iterator, typename linalg_traits<M>::row_iterator,
+ PT>::ref_type iterator;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ SUBI1 si1;
+ SUBI2 si2;
+ iterator begin_;
+ porigin_type origin;
+
+ reference operator()(size_type i, size_type j) const
+ { return linalg_traits<M>::access(begin_ + si1.index(i), si2.index(j)); }
+
+ size_type nrows(void) const { return si1.size(); }
+ size_type ncols(void) const { return si2.size(); }
+
+ gen_sub_row_matrix(ref_M m, const SUBI1 &s1, const SUBI2 &s2)
+ : si1(s1), si2(s2), begin_(mat_row_begin(m)),
+ origin(linalg_origin(m)) {}
+ gen_sub_row_matrix() {}
+ gen_sub_row_matrix(const gen_sub_row_matrix<CPT, SUBI1, SUBI2> &cr) :
+ si1(cr.si1), si2(cr.si2), begin_(cr.begin_),origin(cr.origin) {}
+ };
+
+ template <typename PT, typename SUBI1, typename SUBI2>
+ struct gen_sub_row_matrix_iterator {
+ typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> this_type;
+ typedef typename modifiable_pointer<PT>::pointer MPT;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef typename select_ref<typename linalg_traits<M>
+ ::const_row_iterator, typename linalg_traits<M>::row_iterator,
+ PT>::ref_type ITER;
+ typedef ITER value_type;
+ typedef ITER *pointer;
+ typedef ITER &reference;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef gen_sub_row_matrix_iterator<PT, SUBI1, SUBI2> iterator;
+
+ ITER it;
+ SUBI1 si1;
+ SUBI2 si2;
+ size_type ii;
+
+ iterator operator ++(int) { iterator tmp = *this; ii++; return tmp; }
+ iterator operator --(int) { iterator tmp = *this; ii--; return tmp; }
+ iterator &operator ++() { ii++; return *this; }
+ iterator &operator --() { ii--; return *this; }
+ iterator &operator +=(difference_type i) { ii += i; return *this; }
+ iterator &operator -=(difference_type i) { ii -= i; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator itt = *this; return (itt += i); }
+ iterator operator -(difference_type i) const
+ { iterator itt = *this; return (itt -= i); }
+ difference_type operator -(const iterator &i) const { return ii - i.ii; }
+
+ ITER operator *() const { return it + si1.index(ii); }
+ ITER operator [](int i) { return it + si1.index(ii+i); }
+
+ bool operator ==(const iterator &i) const { return (ii == i.ii); }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+ bool operator < (const iterator &i) const { return (ii < i.ii); }
+
+ gen_sub_row_matrix_iterator(void) {}
+ gen_sub_row_matrix_iterator(const
+ gen_sub_row_matrix_iterator<MPT, SUBI1, SUBI2> &itm)
+ : it(itm.it), si1(itm.si1), si2(itm.si2), ii(itm.ii) {}
+ gen_sub_row_matrix_iterator(const ITER &iter, const SUBI1 &s1,
+ const SUBI2 &s2, size_type i)
+ : it(iter), si1(s1), si2(s2), ii(i) { }
+
+ };
+
+ template <typename PT, typename SUBI1, typename SUBI2>
+ struct linalg_traits<gen_sub_row_matrix<PT, SUBI1, SUBI2> > {
+ typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<M>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename linalg_traits<M>::value_type value_type;
+ typedef typename select_ref<value_type,
+ typename linalg_traits<M>::reference, PT>::ref_type reference;
+ typedef abstract_null_type sub_col_type;
+ typedef abstract_null_type col_iterator;
+ typedef abstract_null_type const_sub_col_type;
+ typedef abstract_null_type const_col_iterator;
+ typedef typename sub_vector_type<const typename
+ linalg_traits<M>::const_sub_row_type *, SUBI2>::vector_type
+ const_sub_row_type;
+ typedef typename select_ref<abstract_null_type,
+ typename sub_vector_type<typename linalg_traits<M>::sub_row_type *,
+ SUBI2>::vector_type, PT>::ref_type sub_row_type;
+ typedef gen_sub_row_matrix_iterator<typename const_pointer<PT>::pointer,
+ SUBI1, SUBI2> const_row_iterator;
+ typedef typename select_ref<abstract_null_type,
+ gen_sub_row_matrix_iterator<PT, SUBI1, SUBI2>, PT>::ref_type
+ row_iterator;
+ typedef typename linalg_traits<const_sub_row_type>::storage_type
+ storage_type;
+ typedef row_major sub_orientation;
+ typedef linalg_true index_sorted;
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static const_sub_row_type row(const const_row_iterator &it)
+ { return const_sub_row_type(linalg_traits<M>::row(*it), it.si2); }
+ static sub_row_type row(const row_iterator &it)
+ { return sub_row_type(linalg_traits<M>::row(*it), it.si2); }
+ static const_row_iterator row_begin(const this_type &m)
+ { return const_row_iterator(m.begin_, m.si1, m.si2, 0); }
+ static row_iterator row_begin(this_type &m)
+ { return row_iterator(m.begin_, m.si1, m.si2, 0); }
+ static const_row_iterator row_end(const this_type &m)
+ { return const_row_iterator(m.begin_, m.si1, m.si2, m.nrows()); }
+ static row_iterator row_end(this_type &m)
+ { return row_iterator(m.begin_, m.si1, m.si2, m.nrows()); }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void do_clear(this_type &m) {
+ row_iterator it = mat_row_begin(m), ite = mat_row_end(m);
+ for (; it != ite; ++it) clear(row(it));
+ }
+ static value_type access(const const_row_iterator &itrow, size_type i)
+ { return linalg_traits<M>::access(*itrow, itrow.si2.index(i)); }
+ static reference access(const row_iterator &itrow, size_type i)
+ { return linalg_traits<M>::access(*itrow, itrow.si2.index(i)); }
+ };
+
+ template <typename PT, typename SUBI1, typename SUBI2>
+ std::ostream &operator <<(std::ostream &o,
+ const gen_sub_row_matrix<PT, SUBI1, SUBI2>& m)
+ { gmm::write(o,m); return o; }
+
+
+ /* ********************************************************************* */
+ /* sub column matrices type */
+ /* ********************************************************************* */
+
+ template <typename PT, typename SUBI1, typename SUBI2>
+ struct gen_sub_col_matrix {
+ typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef M * CPT;
+ typedef typename std::iterator_traits<PT>::reference ref_M;
+ typedef typename select_ref<typename linalg_traits<M>
+ ::const_col_iterator, typename linalg_traits<M>::col_iterator,
+ PT>::ref_type iterator;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ SUBI1 si1;
+ SUBI2 si2;
+ iterator begin_;
+ porigin_type origin;
+
+ reference operator()(size_type i, size_type j) const
+ { return linalg_traits<M>::access(begin_ + si2.index(j), si1.index(i)); }
+
+ size_type nrows(void) const { return si1.size(); }
+ size_type ncols(void) const { return si2.size(); }
+
+ gen_sub_col_matrix(ref_M m, const SUBI1 &s1, const SUBI2 &s2)
+ : si1(s1), si2(s2), begin_(mat_col_begin(m)),
+ origin(linalg_origin(m)) {}
+ gen_sub_col_matrix() {}
+ gen_sub_col_matrix(const gen_sub_col_matrix<CPT, SUBI1, SUBI2> &cr) :
+ si1(cr.si1), si2(cr.si2), begin_(cr.begin_),origin(cr.origin) {}
+ };
+
+ template <typename PT, typename SUBI1, typename SUBI2>
+ struct gen_sub_col_matrix_iterator {
+ typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> this_type;
+ typedef typename modifiable_pointer<PT>::pointer MPT;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef typename select_ref<typename linalg_traits<M>::const_col_iterator,
+ typename linalg_traits<M>::col_iterator,
+ PT>::ref_type ITER;
+ typedef ITER value_type;
+ typedef ITER *pointer;
+ typedef ITER &reference;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef gen_sub_col_matrix_iterator<PT, SUBI1, SUBI2> iterator;
+
+ ITER it;
+ SUBI1 si1;
+ SUBI2 si2;
+ size_type ii;
+
+ iterator operator ++(int) { iterator tmp = *this; ii++; return tmp; }
+ iterator operator --(int) { iterator tmp = *this; ii--; return tmp; }
+ iterator &operator ++() { ii++; return *this; }
+ iterator &operator --() { ii--; return *this; }
+ iterator &operator +=(difference_type i) { ii += i; return *this; }
+ iterator &operator -=(difference_type i) { ii -= i; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator itt = *this; return (itt += i); }
+ iterator operator -(difference_type i) const
+ { iterator itt = *this; return (itt -= i); }
+ difference_type operator -(const iterator &i) const { return ii - i.ii; }
+
+ ITER operator *() const { return it + si2.index(ii); }
+ ITER operator [](int i) { return it + si2.index(ii+i); }
+
+ bool operator ==(const iterator &i) const { return (ii == i.ii); }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+ bool operator < (const iterator &i) const { return (ii < i.ii); }
+
+ gen_sub_col_matrix_iterator(void) {}
+ gen_sub_col_matrix_iterator(const
+ gen_sub_col_matrix_iterator<MPT, SUBI1, SUBI2> &itm)
+ : it(itm.it), si1(itm.si1), si2(itm.si2), ii(itm.ii) {}
+ gen_sub_col_matrix_iterator(const ITER &iter, const SUBI1 &s1,
+ const SUBI2 &s2, size_type i)
+ : it(iter), si1(s1), si2(s2), ii(i) { }
+ };
+
+ template <typename PT, typename SUBI1, typename SUBI2>
+ struct linalg_traits<gen_sub_col_matrix<PT, SUBI1, SUBI2> > {
+ typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef typename linalg_traits<M>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<M>::value_type value_type;
+ typedef typename select_ref<value_type,
+ typename linalg_traits<M>::reference, PT>::ref_type reference;
+ typedef abstract_null_type sub_row_type;
+ typedef abstract_null_type row_iterator;
+ typedef abstract_null_type const_sub_row_type;
+ typedef abstract_null_type const_row_iterator;
+ typedef typename sub_vector_type<const typename
+ linalg_traits<M>::const_sub_col_type *, SUBI1>::vector_type
+ const_sub_col_type;
+ typedef typename select_ref<abstract_null_type,
+ typename sub_vector_type<typename linalg_traits<M>::sub_col_type *,
+ SUBI1>::vector_type, PT>::ref_type sub_col_type;
+ typedef gen_sub_col_matrix_iterator<typename const_pointer<PT>::pointer,
+ SUBI1, SUBI2> const_col_iterator;
+ typedef typename select_ref<abstract_null_type,
+ gen_sub_col_matrix_iterator<PT, SUBI1, SUBI2>, PT>::ref_type
+ col_iterator;
+ typedef col_major sub_orientation;
+ typedef linalg_true index_sorted;
+ typedef typename linalg_traits<const_sub_col_type>::storage_type
+ storage_type;
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static const_sub_col_type col(const const_col_iterator &it)
+ { return const_sub_col_type(linalg_traits<M>::col(*it), it.si1); }
+ static sub_col_type col(const col_iterator &it)
+ { return sub_col_type(linalg_traits<M>::col(*it), it.si1); }
+ static const_col_iterator col_begin(const this_type &m)
+ { return const_col_iterator(m.begin_, m.si1, m.si2, 0); }
+ static col_iterator col_begin(this_type &m)
+ { return col_iterator(m.begin_, m.si1, m.si2, 0); }
+ static const_col_iterator col_end(const this_type &m)
+ { return const_col_iterator(m.begin_, m.si1, m.si2, m.ncols()); }
+ static col_iterator col_end(this_type &m)
+ { return col_iterator(m.begin_, m.si1, m.si2, m.ncols()); }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void do_clear(this_type &m) {
+ col_iterator it = mat_col_begin(m), ite = mat_col_end(m);
+ for (; it != ite; ++it) clear(col(it));
+ }
+ static value_type access(const const_col_iterator &itcol, size_type i)
+ { return linalg_traits<M>::access(*itcol, itcol.si1.index(i)); }
+ static reference access(const col_iterator &itcol, size_type i)
+ { return linalg_traits<M>::access(*itcol, itcol.si1.index(i)); }
+ };
+
+ template <typename PT, typename SUBI1, typename SUBI2> std::ostream &operator <<
+ (std::ostream &o, const gen_sub_col_matrix<PT, SUBI1, SUBI2>& m)
+ { gmm::write(o,m); return o; }
+
+ /* ******************************************************************** */
+ /* sub matrices */
+ /* ******************************************************************** */
+
+ template <typename PT, typename SUBI1, typename SUBI2, typename ST>
+ struct sub_matrix_type_ {
+ typedef abstract_null_type return_type;
+ };
+ template <typename PT, typename SUBI1, typename SUBI2>
+ struct sub_matrix_type_<PT, SUBI1, SUBI2, col_major>
+ { typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> matrix_type; };
+ template <typename PT, typename SUBI1, typename SUBI2>
+ struct sub_matrix_type_<PT, SUBI1, SUBI2, row_major>
+ { typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> matrix_type; };
+ template <typename PT, typename SUBI1, typename SUBI2>
+ struct sub_matrix_type {
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef typename sub_matrix_type_<PT, SUBI1, SUBI2,
+ typename principal_orientation_type<typename
+ linalg_traits<M>::sub_orientation>::potype>::matrix_type matrix_type;
+ };
+
+ template <typename M, typename SUBI1, typename SUBI2> inline
+ typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI2>
+ ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>::matrix_type,
+ M *>::return_type
+ sub_matrix(M &m, const SUBI1 &si1, const SUBI2 &si2) {
+ GMM_ASSERT2(si1.last() <= mat_nrows(m) && si2.last() <= mat_ncols(m),
+ "sub matrix too large");
+ return typename select_return<typename sub_matrix_type<const M *, SUBI1,
+ SUBI2>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>
+ ::matrix_type, M *>::return_type(linalg_cast(m), si1, si2);
+ }
+
+ template <typename M, typename SUBI1, typename SUBI2> inline
+ typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI2>
+ ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>::matrix_type,
+ const M *>::return_type
+ sub_matrix(const M &m, const SUBI1 &si1, const SUBI2 &si2) {
+ GMM_ASSERT2(si1.last() <= mat_nrows(m) && si2.last() <= mat_ncols(m),
+ "sub matrix too large");
+ return typename select_return<typename sub_matrix_type<const M *, SUBI1,
+ SUBI2>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>
+ ::matrix_type, const M *>::return_type(linalg_cast(m), si1, si2);
+ }
+
+ template <typename M, typename SUBI1> inline
+ typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI1>
+ ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>::matrix_type,
+ M *>::return_type
+ sub_matrix(M &m, const SUBI1 &si1) {
+ GMM_ASSERT2(si1.last() <= mat_nrows(m) && si1.last() <= mat_ncols(m),
+ "sub matrix too large");
+ return typename select_return<typename sub_matrix_type<const M *, SUBI1,
+ SUBI1>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>
+ ::matrix_type, M *>::return_type(linalg_cast(m), si1, si1);
+ }
+
+ template <typename M, typename SUBI1> inline
+ typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI1>
+ ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>::matrix_type,
+ const M *>::return_type
+ sub_matrix(const M &m, const SUBI1 &si1) {
+ GMM_ASSERT2(si1.last() <= mat_nrows(m) && si1.last() <= mat_ncols(m),
+ "sub matrix too large");
+ return typename select_return<typename sub_matrix_type<const M *, SUBI1,
+ SUBI1>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>
+ ::matrix_type, const M *>::return_type(linalg_cast(m), si1, si1);
+ }
+
+}
+
+#endif // GMM_SUB_MATRIX_H__
diff --git a/Contrib/gmm/gmm_sub_vector.h b/Contrib/gmm/gmm_sub_vector.h
new file mode 100755
index 0000000..4f3292d
--- /dev/null
+++ b/Contrib/gmm/gmm_sub_vector.h
@@ -0,0 +1,557 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_sub_vector.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief Generic sub-vectors.
+*/
+
+#ifndef GMM_SUB_VECTOR_H__
+#define GMM_SUB_VECTOR_H__
+
+#include "gmm_interface.h"
+#include "gmm_sub_index.h"
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* sparse sub-vectors */
+ /* ********************************************************************* */
+
+ template <typename IT, typename MIT, typename SUBI>
+ struct sparse_sub_vector_iterator {
+
+ IT itb, itbe;
+ SUBI si;
+
+ typedef std::iterator_traits<IT> traits_type;
+ typedef typename traits_type::value_type value_type;
+ typedef typename traits_type::pointer pointer;
+ typedef typename traits_type::reference reference;
+ typedef typename traits_type::difference_type difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef sparse_sub_vector_iterator<IT, MIT, SUBI> iterator;
+
+ size_type index(void) const { return si.rindex(itb.index()); }
+ void forward(void);
+ void backward(void);
+ iterator &operator ++()
+ { ++itb; forward(); return *this; }
+ iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+ iterator &operator --()
+ { --itb; backward(); return *this; }
+ iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+ reference operator *() const { return *itb; }
+
+ bool operator ==(const iterator &i) const { return itb == i.itb; }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+
+ sparse_sub_vector_iterator(void) {}
+ sparse_sub_vector_iterator(const IT &it, const IT &ite, const SUBI &s)
+ : itb(it), itbe(ite), si(s) { forward(); }
+ sparse_sub_vector_iterator(const sparse_sub_vector_iterator<MIT, MIT,
+ SUBI> &it) : itb(it.itb), itbe(it.itbe), si(it.si) {}
+ };
+
+ template <typename IT, typename MIT, typename SUBI>
+ void sparse_sub_vector_iterator<IT, MIT, SUBI>::forward(void)
+ { while(itb!=itbe && index()==size_type(-1)) { ++itb; } }
+
+ template <typename IT, typename MIT, typename SUBI>
+ void sparse_sub_vector_iterator<IT, MIT, SUBI>::backward(void)
+ { while(itb!=itbe && index()==size_type(-1)) --itb; }
+
+ template <typename PT, typename SUBI> struct sparse_sub_vector {
+ typedef sparse_sub_vector<PT, SUBI> this_type;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef V * CPT;
+ typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+ typename linalg_traits<V>::iterator, PT>::ref_type iterator;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ iterator begin_, end_;
+ porigin_type origin;
+ SUBI si;
+
+ size_type size(void) const { return si.size(); }
+
+ reference operator[](size_type i) const
+ { return linalg_traits<V>::access(origin, begin_, end_, si.index(i)); }
+
+ sparse_sub_vector(V &v, const SUBI &s) : begin_(vect_begin(v)),
+ end_(vect_end(v)), origin(linalg_origin(v)), si(s) {}
+ sparse_sub_vector(const V &v, const SUBI &s)
+ : begin_(vect_begin(const_cast<V &>(v))),
+ end_(vect_end(const_cast<V &>(v))),
+ origin(linalg_origin(const_cast<V &>(v))), si(s) {}
+ sparse_sub_vector() {}
+ sparse_sub_vector(const sparse_sub_vector<CPT, SUBI> &cr)
+ : begin_(cr.begin_),end_(cr.end_),origin(cr.origin), si(cr.si) {}
+ };
+
+ template <typename IT, typename MIT, typename SUBI, typename ORG,
+ typename PT> inline
+ void set_to_begin(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
+ ORG o, sparse_sub_vector<PT, SUBI> *,
+ linalg_modifiable) {
+ typedef sparse_sub_vector<PT, SUBI> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+ set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+ it.forward();
+ }
+ template <typename IT, typename MIT, typename SUBI, typename ORG,
+ typename PT> inline
+ void set_to_begin(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
+ ORG o, const sparse_sub_vector<PT, SUBI> *,
+ linalg_modifiable) {
+ typedef sparse_sub_vector<PT, SUBI> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+ set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+ it.forward();
+ }
+
+ template <typename IT, typename MIT, typename SUBI, typename ORG,
+ typename PT> inline
+ void set_to_end(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
+ ORG o, sparse_sub_vector<PT, SUBI> *, linalg_modifiable) {
+ typedef sparse_sub_vector<PT, SUBI> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+ set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+ it.forward();
+ }
+ template <typename IT, typename MIT, typename SUBI, typename ORG,
+ typename PT> inline
+ void set_to_end(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
+ ORG o, const sparse_sub_vector<PT, SUBI> *,
+ linalg_modifiable) {
+ typedef sparse_sub_vector<PT, SUBI> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+ set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+ it.forward();
+ }
+
+ template <typename PT, typename SUBI>
+ struct linalg_traits<sparse_sub_vector<PT, SUBI> > {
+ typedef sparse_sub_vector<PT, SUBI> this_type;
+ typedef this_type * pthis_type;
+ typedef PT pV;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef typename linalg_and<typename index_is_sorted<SUBI>::bool_type,
+ typename linalg_traits<V>::index_sorted>::bool_type index_sorted;
+ typedef typename linalg_traits<V>::is_reference V_reference;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_vector linalg_type;
+ typedef typename linalg_traits<V>::value_type value_type;
+ typedef typename select_ref<value_type, typename
+ linalg_traits<V>::reference, PT>::ref_type reference;
+ typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+ typename linalg_traits<V>::iterator, PT>::ref_type pre_iterator;
+ typedef typename select_ref<abstract_null_type,
+ sparse_sub_vector_iterator<pre_iterator, pre_iterator, SUBI>,
+ PT>::ref_type iterator;
+ typedef sparse_sub_vector_iterator<typename linalg_traits<V>
+ ::const_iterator, pre_iterator, SUBI> const_iterator;
+ typedef abstract_sparse storage_type;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v) {
+ iterator it;
+ it.itb = v.begin_; it.itbe = v.end_; it.si = v.si;
+ if (!is_const_reference(is_reference()))
+ set_to_begin(it, v.origin, pthis_type(), is_reference());
+ else it.forward();
+ return it;
+ }
+ static const_iterator begin(const this_type &v) {
+ const_iterator it; it.itb = v.begin_; it.itbe = v.end_; it.si = v.si;
+ if (!is_const_reference(is_reference()))
+ { set_to_begin(it, v.origin, pthis_type(), is_reference()); }
+ else it.forward();
+ return it;
+ }
+ static iterator end(this_type &v) {
+ iterator it;
+ it.itb = v.end_; it.itbe = v.end_; it.si = v.si;
+ if (!is_const_reference(is_reference()))
+ set_to_end(it, v.origin, pthis_type(), is_reference());
+ else it.forward();
+ return it;
+ }
+ static const_iterator end(const this_type &v) {
+ const_iterator it; it.itb = v.end_; it.itbe = v.end_; it.si = v.si;
+ if (!is_const_reference(is_reference()))
+ set_to_end(it, v.origin, pthis_type(), is_reference());
+ else it.forward();
+ return it;
+ }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void clear(origin_type* o, const iterator &begin_,
+ const iterator &end_) {
+ std::deque<size_type> ind;
+ iterator it = begin_;
+ for (; it != end_; ++it) ind.push_front(it.index());
+ for (; !(ind.empty()); ind.pop_back())
+ access(o, begin_, end_, ind.back()) = value_type(0);
+ }
+ static void do_clear(this_type &v) { clear(v.origin, begin(v), end(v)); }
+ static value_type access(const origin_type *o, const const_iterator &it,
+ const const_iterator &ite, size_type i)
+ { return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
+ static reference access(origin_type *o, const iterator &it,
+ const iterator &ite, size_type i)
+ { return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
+ };
+
+ template <typename PT, typename SUBI> std::ostream &operator <<
+ (std::ostream &o, const sparse_sub_vector<PT, SUBI>& m)
+ { gmm::write(o,m); return o; }
+
+ /* ********************************************************************* */
+ /* skyline sub-vectors */
+ /* ********************************************************************* */
+
+ template <typename IT, typename MIT, typename SUBI>
+ struct skyline_sub_vector_iterator {
+
+ IT itb;
+ SUBI si;
+
+ typedef std::iterator_traits<IT> traits_type;
+ typedef typename traits_type::value_type value_type;
+ typedef typename traits_type::pointer pointer;
+ typedef typename traits_type::reference reference;
+ typedef typename traits_type::difference_type difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef skyline_sub_vector_iterator<IT, MIT, SUBI> iterator;
+
+ size_type index(void) const
+ { return (itb.index() - si.min + si.step() - 1) / si.step(); }
+ void backward(void);
+ iterator &operator ++()
+ { itb += si.step(); return *this; }
+ iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+ iterator &operator --()
+ { itb -= si.step(); return *this; }
+ iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+
+ iterator &operator +=(difference_type i)
+ { itb += si.step() * i; return *this; }
+ iterator &operator -=(difference_type i)
+ { itb -= si.step() * i; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator ii = *this; return (ii += i); }
+ iterator operator -(difference_type i) const
+ { iterator ii = *this; return (ii -= i); }
+ difference_type operator -(const iterator &i) const
+ { return (itb - i.itb) / si.step(); }
+
+ reference operator *() const { return *itb; }
+ reference operator [](int ii) { return *(itb + ii * si.step()); }
+
+ bool operator ==(const iterator &i) const { return index() == i.index();}
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+ bool operator < (const iterator &i) const { return index() < i.index();}
+
+ skyline_sub_vector_iterator(void) {}
+ skyline_sub_vector_iterator(const IT &it, const SUBI &s)
+ : itb(it), si(s) {}
+ skyline_sub_vector_iterator(const skyline_sub_vector_iterator<MIT, MIT,
+ SUBI> &it) : itb(it.itb), si(it.si) {}
+ };
+
+ template <typename IT, typename SUBI>
+ void update_for_sub_skyline(IT &it, IT &ite, const SUBI &si) {
+ if (it.index() >= si.max || ite.index() <= si.min) { it = ite; return; }
+ ptrdiff_t dec1 = si.min - it.index(), dec2 = ite.index() - si.max;
+ it += (dec1 < 0) ? ((si.step()-((-dec1) % si.step())) % si.step()) : dec1;
+ ite -= (dec2 < 0) ? -((-dec2) % si.step()) : dec2;
+ }
+
+ template <typename PT, typename SUBI> struct skyline_sub_vector {
+ typedef skyline_sub_vector<PT, SUBI> this_type;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef V * pV;
+ typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+ typename linalg_traits<V>::iterator, PT>::ref_type iterator;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ iterator begin_, end_;
+ porigin_type origin;
+ SUBI si;
+
+ size_type size(void) const { return si.size(); }
+
+ reference operator[](size_type i) const
+ { return linalg_traits<V>::access(origin, begin_, end_, si.index(i)); }
+
+ skyline_sub_vector(V &v, const SUBI &s) : begin_(vect_begin(v)),
+ end_(vect_end(v)), origin(linalg_origin(v)), si(s) {
+ update_for_sub_skyline(begin_, end_, si);
+ }
+ skyline_sub_vector(const V &v, const SUBI &s)
+ : begin_(vect_begin(const_cast<V &>(v))),
+ end_(vect_end(const_cast<V &>(v))),
+ origin(linalg_origin(const_cast<V &>(v))), si(s) {
+ update_for_sub_skyline(begin_, end_, si);
+ }
+ skyline_sub_vector() {}
+ skyline_sub_vector(const skyline_sub_vector<pV, SUBI> &cr)
+ : begin_(cr.begin_),end_(cr.end_),origin(cr.origin), si(cr.si) {}
+ };
+
+ template <typename IT, typename MIT, typename SUBI, typename ORG,
+ typename PT> inline
+ void set_to_begin(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
+ ORG o, skyline_sub_vector<PT, SUBI> *,
+ linalg_modifiable) {
+ typedef skyline_sub_vector<PT, SUBI> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ IT itbe = it.itb;
+ set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+ set_to_end(itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+ update_for_sub_skyline(it.itb, itbe, it.si);
+ }
+ template <typename IT, typename MIT, typename SUBI, typename ORG,
+ typename PT> inline
+ void set_to_begin(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
+ ORG o, const skyline_sub_vector<PT, SUBI> *,
+ linalg_modifiable) {
+ typedef skyline_sub_vector<PT, SUBI> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ IT itbe = it.itb;
+ set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+ set_to_end(itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+ update_for_sub_skyline(it.itb, itbe, it.si);
+ }
+
+ template <typename IT, typename MIT, typename SUBI, typename ORG,
+ typename PT> inline
+ void set_to_end(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
+ ORG o, skyline_sub_vector<PT, SUBI> *,
+ linalg_modifiable) {
+ typedef skyline_sub_vector<PT, SUBI> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ IT itb = it.itb;
+ set_to_begin(itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+ set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+ update_for_sub_skyline(itb, it.itb, it.si);
+ }
+ template <typename IT, typename MIT, typename SUBI, typename ORG,
+ typename PT> inline
+ void set_to_end(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
+ ORG o, const skyline_sub_vector<PT, SUBI> *,
+ linalg_modifiable) {
+ typedef skyline_sub_vector<PT, SUBI> VECT;
+ typedef typename linalg_traits<VECT>::V_reference ref_t;
+ IT itb = it.itb;
+ set_to_begin(itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+ set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+ update_for_sub_skyline(itb, it.itb, it.si);
+ }
+
+
+ template <typename PT, typename SUBI>
+ struct linalg_traits<skyline_sub_vector<PT, SUBI> > {
+ typedef skyline_sub_vector<PT, SUBI> this_type;
+ typedef this_type *pthis_type;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef typename linalg_traits<V>::is_reference V_reference;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef V * pV;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_vector linalg_type;
+ typedef typename linalg_traits<V>::value_type value_type;
+ typedef typename select_ref<value_type, typename
+ linalg_traits<V>::reference, PT>::ref_type reference;
+ typedef typename linalg_traits<V>::const_iterator const_V_iterator;
+ typedef typename linalg_traits<V>::iterator V_iterator;
+ typedef typename select_ref<const_V_iterator, V_iterator,
+ PT>::ref_type pre_iterator;
+ typedef typename select_ref<abstract_null_type,
+ skyline_sub_vector_iterator<pre_iterator, pre_iterator, SUBI>,
+ PT>::ref_type iterator;
+ typedef skyline_sub_vector_iterator<const_V_iterator, pre_iterator, SUBI>
+ const_iterator;
+ typedef abstract_skyline storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v) {
+ iterator it;
+ it.itb = v.begin_; it.si = v.si;
+ if (!is_const_reference(is_reference()))
+ set_to_begin(it, v.origin, pthis_type(), is_reference());
+ return it;
+ }
+ static const_iterator begin(const this_type &v) {
+ const_iterator it; it.itb = v.begin_; it.si = v.si;
+ if (!is_const_reference(is_reference()))
+ { set_to_begin(it, v.origin, pthis_type(), is_reference()); }
+ return it;
+ }
+ static iterator end(this_type &v) {
+ iterator it;
+ it.itb = v.end_; it.si = v.si;
+ if (!is_const_reference(is_reference()))
+ set_to_end(it, v.origin, pthis_type(), is_reference());
+ return it;
+ }
+ static const_iterator end(const this_type &v) {
+ const_iterator it; it.itb = v.end_; it.si = v.si;
+ if (!is_const_reference(is_reference()))
+ set_to_end(it, v.origin, pthis_type(), is_reference());
+ return it;
+ }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void clear(origin_type*, const iterator &it, const iterator &ite)
+ { std::fill(it, ite, value_type(0)); }
+ static void do_clear(this_type &v) { clear(v.origin, begin(v), end(v)); }
+ static value_type access(const origin_type *o, const const_iterator &it,
+ const const_iterator &ite, size_type i)
+ { return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
+ static reference access(origin_type *o, const iterator &it,
+ const iterator &ite, size_type i)
+ { return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
+ };
+
+ template <typename PT, typename SUBI> std::ostream &operator <<
+ (std::ostream &o, const skyline_sub_vector<PT, SUBI>& m)
+ { gmm::write(o,m); return o; }
+
+ /* ******************************************************************** */
+ /* sub vector. */
+ /* ******************************************************************** */
+ /* sub_vector_type<PT, SUBI>::vector_type is the sub vector type */
+ /* returned by sub_vector(v, sub_index) */
+ /************************************************************************/
+
+ template <typename PT, typename SUBI, typename st_type> struct svrt_ir {
+ typedef abstract_null_type vector_type;
+ };
+
+ template <typename PT>
+ struct svrt_ir<PT, sub_index, abstract_dense> {
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef typename vect_ref_type<PT, V>::iterator iterator;
+ typedef tab_ref_index_ref_with_origin<iterator,
+ sub_index::const_iterator, V> vector_type;
+ };
+
+ template <typename PT>
+ struct svrt_ir<PT, unsorted_sub_index, abstract_dense> {
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef typename vect_ref_type<PT, V>::iterator iterator;
+ typedef tab_ref_index_ref_with_origin<iterator,
+ unsorted_sub_index::const_iterator, V> vector_type;
+ };
+
+ template <typename PT>
+ struct svrt_ir<PT, sub_interval, abstract_dense> {
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef typename vect_ref_type<PT, V>::iterator iterator;
+ typedef tab_ref_with_origin<iterator, V> vector_type;
+ };
+
+ template <typename PT>
+ struct svrt_ir<PT, sub_slice, abstract_dense> {
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef typename vect_ref_type<PT, V>::iterator iterator;
+ typedef tab_ref_reg_spaced_with_origin<iterator, V> vector_type;
+ };
+
+ template <typename PT, typename SUBI>
+ struct svrt_ir<PT, SUBI, abstract_skyline> {
+ typedef skyline_sub_vector<PT, SUBI> vector_type;
+ };
+
+ template <typename PT>
+ struct svrt_ir<PT, sub_index, abstract_skyline> {
+ typedef sparse_sub_vector<PT, sub_index> vector_type;
+ };
+
+ template <typename PT>
+ struct svrt_ir<PT, unsorted_sub_index, abstract_skyline> {
+ typedef sparse_sub_vector<PT, unsorted_sub_index> vector_type;
+ };
+
+
+ template <typename PT, typename SUBI>
+ struct svrt_ir<PT, SUBI, abstract_sparse> {
+ typedef sparse_sub_vector<PT, SUBI> vector_type;
+ };
+
+ template <typename PT, typename SUBI>
+ struct sub_vector_type {
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef typename svrt_ir<PT, SUBI,
+ typename linalg_traits<V>::storage_type>::vector_type vector_type;
+ };
+
+ template <typename V, typename SUBI>
+ typename select_return<
+ typename sub_vector_type<const V *, SUBI>::vector_type,
+ typename sub_vector_type<V *, SUBI>::vector_type, const V *>::return_type
+ sub_vector(const V &v, const SUBI &si) {
+ GMM_ASSERT2(si.last() <= vect_size(v), "sub vector too large");
+ return typename select_return<
+ typename sub_vector_type<const V *, SUBI>::vector_type,
+ typename sub_vector_type<V *, SUBI>::vector_type, const V *>::return_type
+ (linalg_cast(v), si);
+ }
+
+ template <typename V, typename SUBI>
+ typename select_return<
+ typename sub_vector_type<const V *, SUBI>::vector_type,
+ typename sub_vector_type<V *, SUBI>::vector_type, V *>::return_type
+ sub_vector(V &v, const SUBI &si) {
+ GMM_ASSERT2(si.last() <= vect_size(v), "sub vector too large");
+ return typename select_return<
+ typename sub_vector_type<const V *, SUBI>::vector_type,
+ typename sub_vector_type<V *, SUBI>::vector_type, V *>::return_type
+ (linalg_cast(v), si);
+ }
+
+}
+
+#endif // GMM_SUB_VECTOR_H__
diff --git a/Contrib/gmm/gmm_superlu_interface.h b/Contrib/gmm/gmm_superlu_interface.h
new file mode 100755
index 0000000..eb32435
--- /dev/null
+++ b/Contrib/gmm/gmm_superlu_interface.h
@@ -0,0 +1,406 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_superlu_interface.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 17, 2003.
+ @brief Interface with SuperLU (LU direct solver for sparse matrices).
+*/
+#if defined(GMM_USES_SUPERLU) && !defined(GETFEM_VERSION)
+
+#ifndef GMM_SUPERLU_INTERFACE_H
+#define GMM_SUPERLU_INTERFACE_H
+
+#include "gmm_kernel.h"
+
+typedef int int_t;
+
+/* because SRC/util.h defines TRUE and FALSE ... */
+#ifdef TRUE
+# undef TRUE
+#endif
+#ifdef FALSE
+# undef FALSE
+#endif
+
+#include "SRC/slu_Cnames.h"
+#include "SRC/supermatrix.h"
+#include "SRC/slu_util.h"
+
+namespace SuperLU_S {
+#include "SRC/slu_sdefs.h"
+}
+namespace SuperLU_D {
+#include "SRC/slu_ddefs.h"
+}
+namespace SuperLU_C {
+#include "SRC/slu_cdefs.h"
+}
+namespace SuperLU_Z {
+#include "SRC/slu_zdefs.h"
+}
+
+
+
+namespace gmm {
+
+ /* interface for Create_CompCol_Matrix */
+
+ inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
+ float *a, int *ir, int *jc) {
+ SuperLU_S::sCreate_CompCol_Matrix(A, m, n, nnz, a, ir, jc,
+ SLU_NC, SLU_S, SLU_GE);
+ }
+
+ inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
+ double *a, int *ir, int *jc) {
+ SuperLU_D::dCreate_CompCol_Matrix(A, m, n, nnz, a, ir, jc,
+ SLU_NC, SLU_D, SLU_GE);
+ }
+
+ inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
+ std::complex<float> *a, int *ir, int *jc) {
+ SuperLU_C::cCreate_CompCol_Matrix(A, m, n, nnz, (SuperLU_C::complex *)(a),
+ ir, jc, SLU_NC, SLU_C, SLU_GE);
+ }
+
+ inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
+ std::complex<double> *a, int *ir, int *jc) {
+ SuperLU_Z::zCreate_CompCol_Matrix(A, m, n, nnz,
+ (SuperLU_Z::doublecomplex *)(a), ir, jc,
+ SLU_NC, SLU_Z, SLU_GE);
+ }
+
+ /* interface for Create_Dense_Matrix */
+
+ inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n, float *a, int k)
+ { SuperLU_S::sCreate_Dense_Matrix(A, m, n, a, k, SLU_DN, SLU_S, SLU_GE); }
+ inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n, double *a, int k)
+ { SuperLU_D::dCreate_Dense_Matrix(A, m, n, a, k, SLU_DN, SLU_D, SLU_GE); }
+ inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n,
+ std::complex<float> *a, int k) {
+ SuperLU_C::cCreate_Dense_Matrix(A, m, n, (SuperLU_C::complex *)(a),
+ k, SLU_DN, SLU_C, SLU_GE);
+ }
+ inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n,
+ std::complex<double> *a, int k) {
+ SuperLU_Z::zCreate_Dense_Matrix(A, m, n, (SuperLU_Z::doublecomplex *)(a),
+ k, SLU_DN, SLU_Z, SLU_GE);
+ }
+
+ /* interface for gssv */
+
+#define DECL_GSSV(NAMESPACE,FNAME,FLOATTYPE,KEYTYPE) \
+ inline void SuperLU_gssv(superlu_options_t *options, SuperMatrix *A, int *p, \
+ int *q, SuperMatrix *L, SuperMatrix *U, SuperMatrix *B, \
+ SuperLUStat_t *stats, int *info, KEYTYPE) { \
+ NAMESPACE::FNAME(options, A, p, q, L, U, B, stats, info); \
+ }
+
+ DECL_GSSV(SuperLU_S,sgssv,float,float)
+ DECL_GSSV(SuperLU_C,cgssv,float,std::complex<float>)
+ DECL_GSSV(SuperLU_D,dgssv,double,double)
+ DECL_GSSV(SuperLU_Z,zgssv,double,std::complex<double>)
+
+ /* interface for gssvx */
+
+#define DECL_GSSVX(NAMESPACE,FNAME,FLOATTYPE,KEYTYPE) \
+ inline float SuperLU_gssvx(superlu_options_t *options, SuperMatrix *A, \
+ int *perm_c, int *perm_r, int *etree, char *equed, \
+ FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, \
+ SuperMatrix *U, void *work, int lwork, \
+ SuperMatrix *B, SuperMatrix *X, \
+ FLOATTYPE *recip_pivot_growth, \
+ FLOATTYPE *rcond, FLOATTYPE *ferr, FLOATTYPE *berr, \
+ SuperLUStat_t *stats, int *info, KEYTYPE) { \
+ NAMESPACE::mem_usage_t mem_usage; \
+ NAMESPACE::FNAME(options, A, perm_c, perm_r, etree, equed, R, C, L, \
+ U, work, lwork, B, X, recip_pivot_growth, rcond, \
+ ferr, berr, &mem_usage, stats, info); \
+ return mem_usage.for_lu; /* bytes used by the factor storage */ \
+ }
+
+ DECL_GSSVX(SuperLU_S,sgssvx,float,float)
+ DECL_GSSVX(SuperLU_C,cgssvx,float,std::complex<float>)
+ DECL_GSSVX(SuperLU_D,dgssvx,double,double)
+ DECL_GSSVX(SuperLU_Z,zgssvx,double,std::complex<double>)
+
+ /* ********************************************************************* */
+ /* SuperLU solve interface */
+ /* ********************************************************************* */
+
+ template <typename MAT, typename VECTX, typename VECTB>
+ void SuperLU_solve(const MAT &A, const VECTX &X_, const VECTB &B,
+ double& rcond_, int permc_spec = 3) {
+ VECTX &X = const_cast<VECTX &>(X_);
+ /*
+ * Get column permutation vector perm_c[], according to permc_spec:
+ * permc_spec = 0: use the natural ordering
+ * permc_spec = 1: use minimum degree ordering on structure of A'*A
+ * permc_spec = 2: use minimum degree ordering on structure of A'+A
+ * permc_spec = 3: use approximate minimum degree column ordering
+ */
+ typedef typename linalg_traits<MAT>::value_type T;
+ typedef typename number_traits<T>::magnitude_type R;
+
+ int m = mat_nrows(A), n = mat_ncols(A), nrhs = 1, info = 0;
+
+ csc_matrix<T> csc_A(m, n); gmm::copy(A, csc_A);
+ std::vector<T> rhs(m), sol(m);
+ gmm::copy(B, rhs);
+
+ int nz = nnz(csc_A);
+ if ((2 * nz / n) >= m)
+ GMM_WARNING2("CAUTION : it seems that SuperLU has a problem"
+ " for nearly dense sparse matrices");
+
+ superlu_options_t options;
+ set_default_options(&options);
+ options.ColPerm = NATURAL;
+ options.PrintStat = NO;
+ options.ConditionNumber = YES;
+ switch (permc_spec) {
+ case 1 : options.ColPerm = MMD_ATA; break;
+ case 2 : options.ColPerm = MMD_AT_PLUS_A; break;
+ case 3 : options.ColPerm = COLAMD; break;
+ }
+ SuperLUStat_t stat;
+ StatInit(&stat);
+
+ SuperMatrix SA, SL, SU, SB, SX; // SuperLU format.
+ Create_CompCol_Matrix(&SA, m, n, nz, csc_A.pr,
+ (int *)(csc_A.ir), (int *)(csc_A.jc));
+ Create_Dense_Matrix(&SB, m, nrhs, &rhs[0], m);
+ Create_Dense_Matrix(&SX, m, nrhs, &sol[0], m);
+ memset(&SL,0,sizeof SL);
+ memset(&SU,0,sizeof SU);
+
+ std::vector<int> etree(n);
+ char equed[] = "B";
+ std::vector<R> Rscale(m),Cscale(n); // row scale factors
+ std::vector<R> ferr(nrhs), berr(nrhs);
+ R recip_pivot_gross, rcond;
+ std::vector<int> perm_r(m), perm_c(n);
+
+ SuperLU_gssvx(&options, &SA, &perm_c[0], &perm_r[0],
+ &etree[0] /* output */, equed /* output */,
+ &Rscale[0] /* row scale factors (output) */,
+ &Cscale[0] /* col scale factors (output) */,
+ &SL /* fact L (output)*/, &SU /* fact U (output)*/,
+ NULL /* work */,
+ 0 /* lwork: superlu auto allocates (input) */,
+ &SB /* rhs */, &SX /* solution */,
+ &recip_pivot_gross /* reciprocal pivot growth */
+ /* factor max_j( norm(A_j)/norm(U_j) ). */,
+ &rcond /*estimate of the reciprocal condition */
+ /* number of the matrix A after equilibration */,
+ &ferr[0] /* estimated forward error */,
+ &berr[0] /* relative backward error */,
+ &stat, &info, T());
+ rcond_ = rcond;
+ Destroy_SuperMatrix_Store(&SB);
+ Destroy_SuperMatrix_Store(&SX);
+ Destroy_SuperMatrix_Store(&SA);
+ Destroy_SuperNode_Matrix(&SL);
+ Destroy_CompCol_Matrix(&SU);
+ StatFree(&stat);
+ GMM_ASSERT1(info == 0, "SuperLU solve failed: info=" << info);
+ gmm::copy(sol, X);
+ }
+
+ template <class T> class SuperLU_factor {
+ typedef typename number_traits<T>::magnitude_type R;
+
+ csc_matrix<T> csc_A;
+ mutable SuperMatrix SA, SL, SB, SU, SX;
+ mutable SuperLUStat_t stat;
+ mutable superlu_options_t options;
+ float memory_used;
+ mutable std::vector<int> etree, perm_r, perm_c;
+ mutable std::vector<R> Rscale, Cscale;
+ mutable std::vector<R> ferr, berr;
+ mutable std::vector<T> rhs;
+ mutable std::vector<T> sol;
+ mutable bool is_init;
+ mutable char equed;
+
+ public :
+ enum { LU_NOTRANSP, LU_TRANSP, LU_CONJUGATED };
+ void free_supermatrix(void);
+ template <class MAT> void build_with(const MAT &A, int permc_spec = 3);
+ template <typename VECTX, typename VECTB>
+ /* transp = LU_NOTRANSP -> solves Ax = B
+ transp = LU_TRANSP -> solves A'x = B
+ transp = LU_CONJUGATED -> solves conj(A)X = B */
+ void solve(const VECTX &X_, const VECTB &B, int transp=LU_NOTRANSP) const;
+ SuperLU_factor(void) { is_init = false; }
+ SuperLU_factor(const SuperLU_factor& other) {
+ GMM_ASSERT2(!(other.is_init),
+ "copy of initialized SuperLU_factor is forbidden");
+ is_init = false;
+ }
+ SuperLU_factor& operator=(const SuperLU_factor& other) {
+ GMM_ASSERT2(!(other.is_init) && !is_init,
+ "assignment of initialized SuperLU_factor is forbidden");
+ return *this;
+ }
+ ~SuperLU_factor() { free_supermatrix(); }
+ float memsize() { return memory_used; }
+ };
+
+
+ template <class T> void SuperLU_factor<T>::free_supermatrix(void) {
+ if (is_init) {
+ if (SB.Store) Destroy_SuperMatrix_Store(&SB);
+ if (SX.Store) Destroy_SuperMatrix_Store(&SX);
+ if (SA.Store) Destroy_SuperMatrix_Store(&SA);
+ if (SL.Store) Destroy_SuperNode_Matrix(&SL);
+ if (SU.Store) Destroy_CompCol_Matrix(&SU);
+ }
+ }
+
+
+ template <class T> template <class MAT>
+ void SuperLU_factor<T>::build_with(const MAT &A, int permc_spec) {
+ /*
+ * Get column permutation vector perm_c[], according to permc_spec:
+ * permc_spec = 0: use the natural ordering
+ * permc_spec = 1: use minimum degree ordering on structure of A'*A
+ * permc_spec = 2: use minimum degree ordering on structure of A'+A
+ * permc_spec = 3: use approximate minimum degree column ordering
+ */
+ free_supermatrix();
+ int n = mat_nrows(A), m = mat_ncols(A), info = 0;
+ csc_A.init_with(A);
+
+ rhs.resize(m); sol.resize(m);
+ gmm::clear(rhs);
+ int nz = nnz(csc_A);
+
+ set_default_options(&options);
+ options.ColPerm = NATURAL;
+ options.PrintStat = NO;
+ options.ConditionNumber = NO;
+ switch (permc_spec) {
+ case 1 : options.ColPerm = MMD_ATA; break;
+ case 2 : options.ColPerm = MMD_AT_PLUS_A; break;
+ case 3 : options.ColPerm = COLAMD; break;
+ }
+ StatInit(&stat);
+
+ Create_CompCol_Matrix(&SA, m, n, nz, csc_A.pr,
+ (int *)(csc_A.ir), (int *)(csc_A.jc));
+ Create_Dense_Matrix(&SB, m, 0, &rhs[0], m);
+ Create_Dense_Matrix(&SX, m, 0, &sol[0], m);
+ memset(&SL,0,sizeof SL);
+ memset(&SU,0,sizeof SU);
+ equed = 'B';
+ Rscale.resize(m); Cscale.resize(n); etree.resize(n);
+ ferr.resize(1); berr.resize(1);
+ R recip_pivot_gross, rcond;
+ perm_r.resize(m); perm_c.resize(n);
+ memory_used = SuperLU_gssvx(&options, &SA, &perm_c[0], &perm_r[0],
+ &etree[0] /* output */, &equed /* output */,
+ &Rscale[0] /* row scale factors (output) */,
+ &Cscale[0] /* col scale factors (output) */,
+ &SL /* fact L (output)*/, &SU /* fact U (output)*/,
+ NULL /* work */,
+ 0 /* lwork: superlu auto allocates (input) */,
+ &SB /* rhs */, &SX /* solution */,
+ &recip_pivot_gross /* reciprocal pivot growth */
+ /* factor max_j( norm(A_j)/norm(U_j) ). */,
+ &rcond /*estimate of the reciprocal condition */
+ /* number of the matrix A after equilibration */,
+ &ferr[0] /* estimated forward error */,
+ &berr[0] /* relative backward error */,
+ &stat, &info, T());
+
+ Destroy_SuperMatrix_Store(&SB);
+ Destroy_SuperMatrix_Store(&SX);
+ Create_Dense_Matrix(&SB, m, 1, &rhs[0], m);
+ Create_Dense_Matrix(&SX, m, 1, &sol[0], m);
+ StatFree(&stat);
+
+ GMM_ASSERT1(info == 0, "SuperLU solve failed: info=" << info);
+ is_init = true;
+ }
+
+ template <class T> template <typename VECTX, typename VECTB>
+ void SuperLU_factor<T>::solve(const VECTX &X_, const VECTB &B,
+ int transp) const {
+ VECTX &X = const_cast<VECTX &>(X_);
+ gmm::copy(B, rhs);
+ options.Fact = FACTORED;
+ options.IterRefine = NOREFINE;
+ switch (transp) {
+ case LU_NOTRANSP: options.Trans = NOTRANS; break;
+ case LU_TRANSP: options.Trans = TRANS; break;
+ case LU_CONJUGATED: options.Trans = CONJ; break;
+ default: GMM_ASSERT1(false, "invalid value for transposition option");
+ }
+ StatInit(&stat);
+ int info = 0;
+ R recip_pivot_gross, rcond;
+ SuperLU_gssvx(&options, &SA, &perm_c[0], &perm_r[0],
+ &etree[0] /* output */, &equed /* output */,
+ &Rscale[0] /* row scale factors (output) */,
+ &Cscale[0] /* col scale factors (output) */,
+ &SL /* fact L (output)*/, &SU /* fact U (output)*/,
+ NULL /* work */,
+ 0 /* lwork: superlu auto allocates (input) */,
+ &SB /* rhs */, &SX /* solution */,
+ &recip_pivot_gross /* reciprocal pivot growth */
+ /* factor max_j( norm(A_j)/norm(U_j) ). */,
+ &rcond /*estimate of the reciprocal condition */
+ /* number of the matrix A after equilibration */,
+ &ferr[0] /* estimated forward error */,
+ &berr[0] /* relative backward error */,
+ &stat, &info, T());
+ StatFree(&stat);
+ GMM_ASSERT1(info == 0, "SuperLU solve failed: info=" << info);
+ gmm::copy(sol, X);
+ }
+
+ template <typename T, typename V1, typename V2> inline
+ void mult(const SuperLU_factor<T>& P, const V1 &v1, const V2 &v2) {
+ P.solve(v2,v1);
+ }
+
+ template <typename T, typename V1, typename V2> inline
+ void transposed_mult(const SuperLU_factor<T>& P,const V1 &v1,const V2 &v2) {
+ P.solve(v2, v1, SuperLU_factor<T>::LU_TRANSP);
+ }
+
+}
+
+
+#endif // GMM_SUPERLU_INTERFACE_H
+
+#endif // GMM_USES_SUPERLU
diff --git a/Contrib/gmm/gmm_transposed.h b/Contrib/gmm/gmm_transposed.h
new file mode 100755
index 0000000..b5da665
--- /dev/null
+++ b/Contrib/gmm/gmm_transposed.h
@@ -0,0 +1,243 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_transposed.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date November 10, 2002.
+ @brief Generic transposed matrices
+*/
+#ifndef GMM_TRANSPOSED_H__
+#define GMM_TRANSPOSED_H__
+
+#include "gmm_def.h"
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* transposed reference */
+ /* ********************************************************************* */
+
+ template <typename PT> struct transposed_row_ref {
+
+ typedef transposed_row_ref<PT> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef M * CPT;
+ typedef typename std::iterator_traits<PT>::reference ref_M;
+ typedef typename select_ref<typename linalg_traits<this_type>
+ ::const_col_iterator, typename linalg_traits<this_type>
+ ::col_iterator, PT>::ref_type iterator;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ iterator begin_, end_;
+ porigin_type origin;
+ size_type nr, nc;
+
+ transposed_row_ref(ref_M m)
+ : begin_(mat_row_begin(m)), end_(mat_row_end(m)),
+ origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
+
+ transposed_row_ref(const transposed_row_ref<CPT> &cr) :
+ begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
+
+ reference operator()(size_type i, size_type j) const
+ { return linalg_traits<M>::access(begin_+j, i); }
+ };
+
+ template <typename PT> struct linalg_traits<transposed_row_ref<PT> > {
+ typedef transposed_row_ref<PT> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef typename linalg_traits<M>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<M>::value_type value_type;
+ typedef typename select_ref<value_type,
+ typename linalg_traits<M>::reference, PT>::ref_type reference;
+ typedef typename linalg_traits<M>::storage_type storage_type;
+ typedef abstract_null_type sub_row_type;
+ typedef abstract_null_type const_sub_row_type;
+ typedef abstract_null_type row_iterator;
+ typedef abstract_null_type const_row_iterator;
+ typedef typename linalg_traits<M>::const_sub_row_type const_sub_col_type;
+ typedef typename select_ref<abstract_null_type, typename
+ linalg_traits<M>::sub_row_type, PT>::ref_type sub_col_type;
+ typedef typename linalg_traits<M>::const_row_iterator const_col_iterator;
+ typedef typename select_ref<abstract_null_type, typename
+ linalg_traits<M>::row_iterator, PT>::ref_type col_iterator;
+ typedef col_major sub_orientation;
+ typedef typename linalg_traits<M>::index_sorted index_sorted;
+ static size_type ncols(const this_type &v) { return v.nc; }
+ static size_type nrows(const this_type &v) { return v.nr; }
+ static const_sub_col_type col(const const_col_iterator &it)
+ { return linalg_traits<M>::row(it); }
+ static sub_col_type col(const col_iterator &it)
+ { return linalg_traits<M>::row(it); }
+ static col_iterator col_begin(this_type &m) { return m.begin_; }
+ static col_iterator col_end(this_type &m) { return m.end_; }
+ static const_col_iterator col_begin(const this_type &m)
+ { return m.begin_; }
+ static const_col_iterator col_end(const this_type &m) { return m.end_; }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void do_clear(this_type &v);
+ static value_type access(const const_col_iterator &itcol, size_type i)
+ { return linalg_traits<M>::access(itcol, i); }
+ static reference access(const col_iterator &itcol, size_type i)
+ { return linalg_traits<M>::access(itcol, i); }
+ };
+
+ template <typename PT>
+ void linalg_traits<transposed_row_ref<PT> >::do_clear(this_type &v) {
+ col_iterator it = mat_col_begin(v), ite = mat_col_end(v);
+ for (; it != ite; ++it) clear(col(it));
+ }
+
+ template<typename PT> std::ostream &operator <<
+ (std::ostream &o, const transposed_row_ref<PT>& m)
+ { gmm::write(o,m); return o; }
+
+ template <typename PT> struct transposed_col_ref {
+
+ typedef transposed_col_ref<PT> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef M * CPT;
+ typedef typename std::iterator_traits<PT>::reference ref_M;
+ typedef typename select_ref<typename linalg_traits<this_type>
+ ::const_row_iterator, typename linalg_traits<this_type>
+ ::row_iterator, PT>::ref_type iterator;
+ typedef typename linalg_traits<this_type>::reference reference;
+ typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+ iterator begin_, end_;
+ porigin_type origin;
+ size_type nr, nc;
+
+ transposed_col_ref(ref_M m)
+ : begin_(mat_col_begin(m)), end_(mat_col_end(m)),
+ origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
+
+ transposed_col_ref(const transposed_col_ref<CPT> &cr) :
+ begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
+
+ reference operator()(size_type i, size_type j) const
+ { return linalg_traits<M>::access(begin_+i, j); }
+ };
+
+ template <typename PT> struct linalg_traits<transposed_col_ref<PT> > {
+ typedef transposed_col_ref<PT> this_type;
+ typedef typename std::iterator_traits<PT>::value_type M;
+ typedef typename linalg_traits<M>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<M>::value_type value_type;
+ typedef typename select_ref<value_type,
+ typename linalg_traits<M>::reference, PT>::ref_type reference;
+ typedef typename linalg_traits<M>::storage_type storage_type;
+ typedef abstract_null_type sub_col_type;
+ typedef abstract_null_type const_sub_col_type;
+ typedef abstract_null_type col_iterator;
+ typedef abstract_null_type const_col_iterator;
+ typedef typename linalg_traits<M>::const_sub_col_type const_sub_row_type;
+ typedef typename select_ref<abstract_null_type, typename
+ linalg_traits<M>::sub_col_type, PT>::ref_type sub_row_type;
+ typedef typename linalg_traits<M>::const_col_iterator const_row_iterator;
+ typedef typename select_ref<abstract_null_type, typename
+ linalg_traits<M>::col_iterator, PT>::ref_type row_iterator;
+ typedef row_major sub_orientation;
+ typedef typename linalg_traits<M>::index_sorted index_sorted;
+ static size_type nrows(const this_type &v)
+ { return v.nr; }
+ static size_type ncols(const this_type &v)
+ { return v.nc; }
+ static const_sub_row_type row(const const_row_iterator &it)
+ { return linalg_traits<M>::col(it); }
+ static sub_row_type row(const row_iterator &it)
+ { return linalg_traits<M>::col(it); }
+ static row_iterator row_begin(this_type &m) { return m.begin_; }
+ static row_iterator row_end(this_type &m) { return m.end_; }
+ static const_row_iterator row_begin(const this_type &m)
+ { return m.begin_; }
+ static const_row_iterator row_end(const this_type &m) { return m.end_; }
+ static origin_type* origin(this_type &v) { return v.origin; }
+ static const origin_type* origin(const this_type &v) { return v.origin; }
+ static void do_clear(this_type &m);
+ static value_type access(const const_row_iterator &itrow, size_type i)
+ { return linalg_traits<M>::access(itrow, i); }
+ static reference access(const row_iterator &itrow, size_type i)
+ { return linalg_traits<M>::access(itrow, i); }
+ };
+
+ template <typename PT>
+ void linalg_traits<transposed_col_ref<PT> >::do_clear(this_type &v) {
+ row_iterator it = mat_row_begin(v), ite = mat_row_end(v);
+ for (; it != ite; ++it) clear(row(it));
+ }
+
+ template<typename PT> std::ostream &operator <<
+ (std::ostream &o, const transposed_col_ref<PT>& m)
+ { gmm::write(o,m); return o; }
+
+ template <typename TYPE, typename PT> struct transposed_return_ {
+ typedef abstract_null_type return_type;
+ };
+ template <typename PT> struct transposed_return_<row_major, PT> {
+ typedef typename std::iterator_traits<PT>::value_type L;
+ typedef typename select_return<transposed_row_ref<const L *>,
+ transposed_row_ref< L *>, PT>::return_type return_type;
+ };
+ template <typename PT> struct transposed_return_<col_major, PT> {
+ typedef typename std::iterator_traits<PT>::value_type L;
+ typedef typename select_return<transposed_col_ref<const L *>,
+ transposed_col_ref< L *>, PT>::return_type return_type;
+ };
+ template <typename PT> struct transposed_return {
+ typedef typename std::iterator_traits<PT>::value_type L;
+ typedef typename transposed_return_<typename principal_orientation_type<
+ typename linalg_traits<L>::sub_orientation>::potype,
+ PT>::return_type return_type;
+ };
+
+ template <typename L> inline
+ typename transposed_return<const L *>::return_type transposed(const L &l) {
+ return typename transposed_return<const L *>::return_type
+ (linalg_cast(const_cast<L &>(l)));
+ }
+
+ template <typename L> inline
+ typename transposed_return<L *>::return_type transposed(L &l)
+ { return typename transposed_return<L *>::return_type(linalg_cast(l)); }
+
+}
+
+#endif // GMM_TRANSPOSED_H__
diff --git a/Contrib/gmm/gmm_tri_solve.h b/Contrib/gmm/gmm_tri_solve.h
new file mode 100755
index 0000000..2f7acf2
--- /dev/null
+++ b/Contrib/gmm/gmm_tri_solve.h
@@ -0,0 +1,221 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_tri_solve.h
+ @author Yves Renard
+ @date October 13, 2002.
+ @brief Solve triangular linear system for dense matrices.
+*/
+
+#ifndef GMM_TRI_SOLVE_H__
+#define GMM_TRI_SOLVE_H__
+
+#include "gmm_interface.h"
+
+namespace gmm {
+
+ template <typename TriMatrix, typename VecX>
+ void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+ col_major, abstract_sparse, bool is_unit) {
+ typename linalg_traits<TriMatrix>::value_type x_j;
+ for (int j = int(k) - 1; j >= 0; --j) {
+ typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
+ COL c = mat_const_col(T, j);
+ typename linalg_traits<COL>::const_iterator
+ it = vect_const_begin(c), ite = vect_const_end(c);
+ if (!is_unit) x[j] /= c[j];
+ for (x_j = x[j]; it != ite ; ++it)
+ if (int(it.index()) < j) x[it.index()] -= x_j * (*it);
+ }
+ }
+
+ template <typename TriMatrix, typename VecX>
+ void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+ col_major, abstract_dense, bool is_unit) {
+ typename linalg_traits<TriMatrix>::value_type x_j;
+ for (int j = int(k) - 1; j >= 0; --j) {
+ typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
+ COL c = mat_const_col(T, j);
+ typename linalg_traits<COL>::const_iterator
+ it = vect_const_begin(c), ite = it + j;
+ typename linalg_traits<VecX>::iterator itx = vect_begin(x);
+ if (!is_unit) x[j] /= c[j];
+ for (x_j = x[j]; it != ite ; ++it, ++itx) *itx -= x_j * (*it);
+ }
+ }
+
+ template <typename TriMatrix, typename VecX>
+ void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+ col_major, abstract_sparse, bool is_unit) {
+ typename linalg_traits<TriMatrix>::value_type x_j;
+ // cout << "(lower col)The Tri Matrix = " << T << endl;
+ // cout << "k = " << endl;
+ for (int j = 0; j < int(k); ++j) {
+ typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
+ COL c = mat_const_col(T, j);
+ typename linalg_traits<COL>::const_iterator
+ it = vect_const_begin(c), ite = vect_const_end(c);
+ if (!is_unit) x[j] /= c[j];
+ for (x_j = x[j]; it != ite ; ++it)
+ if (int(it.index()) > j && it.index() < k) x[it.index()] -= x_j*(*it);
+ }
+ }
+
+ template <typename TriMatrix, typename VecX>
+ void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+ col_major, abstract_dense, bool is_unit) {
+ typename linalg_traits<TriMatrix>::value_type x_j;
+ for (int j = 0; j < int(k); ++j) {
+ typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
+ COL c = mat_const_col(T, j);
+ typename linalg_traits<COL>::const_iterator
+ it = vect_const_begin(c) + (j+1), ite = vect_const_begin(c) + k;
+ typename linalg_traits<VecX>::iterator itx = vect_begin(x) + (j+1);
+ if (!is_unit) x[j] /= c[j];
+ for (x_j = x[j]; it != ite ; ++it, ++itx) *itx -= x_j * (*it);
+ }
+ }
+
+
+ template <typename TriMatrix, typename VecX>
+ void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+ row_major, abstract_sparse, bool is_unit) {
+ typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
+ typename linalg_traits<TriMatrix>::value_type t;
+ typename linalg_traits<TriMatrix>::const_row_iterator
+ itr = mat_row_const_end(T);
+ for (int i = int(k) - 1; i >= 0; --i) {
+ --itr;
+ ROW c = linalg_traits<TriMatrix>::row(itr);
+ typename linalg_traits<ROW>::const_iterator
+ it = vect_const_begin(c), ite = vect_const_end(c);
+ for (t = x[i]; it != ite; ++it)
+ if (int(it.index()) > i && it.index() < k) t -= (*it) * x[it.index()];
+ if (!is_unit) x[i] = t / c[i]; else x[i] = t;
+ }
+ }
+
+ template <typename TriMatrix, typename VecX>
+ void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+ row_major, abstract_dense, bool is_unit) {
+ typename linalg_traits<TriMatrix>::value_type t;
+
+ for (int i = int(k) - 1; i >= 0; --i) {
+ typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
+ ROW c = mat_const_row(T, i);
+ typename linalg_traits<ROW>::const_iterator
+ it = vect_const_begin(c) + (i + 1), ite = vect_const_begin(c) + k;
+ typename linalg_traits<VecX>::iterator itx = vect_begin(x) + (i+1);
+
+ for (t = x[i]; it != ite; ++it, ++itx) t -= (*it) * (*itx);
+ if (!is_unit) x[i] = t / c[i]; else x[i] = t;
+ }
+ }
+
+ template <typename TriMatrix, typename VecX>
+ void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+ row_major, abstract_sparse, bool is_unit) {
+ typename linalg_traits<TriMatrix>::value_type t;
+
+ for (int i = 0; i < int(k); ++i) {
+ typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
+ ROW c = mat_const_row(T, i);
+ typename linalg_traits<ROW>::const_iterator
+ it = vect_const_begin(c), ite = vect_const_end(c);
+
+ for (t = x[i]; it != ite; ++it)
+ if (int(it.index()) < i) t -= (*it) * x[it.index()];
+ if (!is_unit) x[i] = t / c[i]; else x[i] = t;
+ }
+ }
+
+ template <typename TriMatrix, typename VecX>
+ void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+ row_major, abstract_dense, bool is_unit) {
+ typename linalg_traits<TriMatrix>::value_type t;
+
+ for (int i = 0; i < int(k); ++i) {
+ typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
+ ROW c = mat_const_row(T, i);
+ typename linalg_traits<ROW>::const_iterator
+ it = vect_const_begin(c), ite = it + i;
+ typename linalg_traits<VecX>::iterator itx = vect_begin(x);
+
+ for (t = x[i]; it != ite; ++it, ++itx) t -= (*it) * (*itx);
+ if (!is_unit) x[i] = t / c[i]; else x[i] = t;
+ }
+ }
+
+
+// Triangular Solve: x <-- T^{-1} * x
+
+ template <typename TriMatrix, typename VecX> inline
+ void upper_tri_solve(const TriMatrix& T, VecX &x_, bool is_unit = false)
+ { upper_tri_solve(T, x_, mat_nrows(T), is_unit); }
+
+ template <typename TriMatrix, typename VecX> inline
+ void lower_tri_solve(const TriMatrix& T, VecX &x_, bool is_unit = false)
+ { lower_tri_solve(T, x_, mat_nrows(T), is_unit); }
+
+ template <typename TriMatrix, typename VecX> inline
+ void upper_tri_solve(const TriMatrix& T, VecX &x_, size_t k,
+ bool is_unit) {
+ VecX& x = const_cast<VecX&>(x_);
+ GMM_ASSERT2(mat_nrows(T) >= k && vect_size(x) >= k
+ && mat_ncols(T) >= k && !is_sparse(x_), "dimensions mismatch");
+ upper_tri_solve__(T, x, k,
+ typename principal_orientation_type<typename
+ linalg_traits<TriMatrix>::sub_orientation>::potype(),
+ typename linalg_traits<TriMatrix>::storage_type(),
+ is_unit);
+ }
+
+ template <typename TriMatrix, typename VecX> inline
+ void lower_tri_solve(const TriMatrix& T, VecX &x_, size_t k,
+ bool is_unit) {
+ VecX& x = const_cast<VecX&>(x_);
+ GMM_ASSERT2(mat_nrows(T) >= k && vect_size(x) >= k
+ && mat_ncols(T) >= k && !is_sparse(x_), "dimensions mismatch");
+ lower_tri_solve__(T, x, k,
+ typename principal_orientation_type<typename
+ linalg_traits<TriMatrix>::sub_orientation>::potype(),
+ typename linalg_traits<TriMatrix>::storage_type(),
+ is_unit);
+ }
+
+
+
+
+
+
+}
+
+
+#endif // GMM_TRI_SOLVE_H__
diff --git a/Contrib/gmm/gmm_vector.h b/Contrib/gmm/gmm_vector.h
new file mode 100755
index 0000000..f114a32
--- /dev/null
+++ b/Contrib/gmm/gmm_vector.h
@@ -0,0 +1,968 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+/**@file gmm_vector.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date October 13, 2002.
+ @brief Declaration of the vector types (gmm::rsvector, gmm::wsvector,
+ gmm::slvector ,..)
+*/
+#ifndef GMM_VECTOR_H__
+#define GMM_VECTOR_H__
+
+#include <map>
+#include "gmm_interface.h"
+
+namespace gmm {
+
+ /*************************************************************************/
+ /* */
+ /* Class ref_elt_vector: reference on a vector component. */
+ /* */
+ /*************************************************************************/
+
+
+ template<typename T, typename V> class ref_elt_vector {
+
+ V *pm;
+ size_type l;
+
+ public :
+
+ operator T() const { return pm->r(l); }
+ ref_elt_vector(V *p, size_type ll) : pm(p), l(ll) {}
+ inline ref_elt_vector &operator =(T v)
+ { (*pm).w(l,v); return *this; }
+ inline bool operator ==(T v) const { return ((*pm).r(l) == v); }
+ inline bool operator !=(T v) const { return ((*pm).r(l) != v); }
+ inline ref_elt_vector &operator +=(T v)
+ { (*pm).w(l,(*pm).r(l) + v); return *this; }
+ inline ref_elt_vector &operator -=(T v)
+ { (*pm).w(l,(*pm).r(l) - v); return *this; }
+ inline ref_elt_vector &operator /=(T v)
+ { (*pm).w(l,(*pm).r(l) / v); return *this; }
+ inline ref_elt_vector &operator *=(T v)
+ { (*pm).w(l,(*pm).r(l) * v); return *this; }
+ inline ref_elt_vector &operator =(const ref_elt_vector &re)
+ { *this = T(re); return *this; }
+ T operator +() { return T(*this); } // necessary for unknow reason
+ T operator -() { return -T(*this); } // necessary for unknow reason
+ T operator +(T v) { return T(*this)+ v; } // necessary for unknow reason
+ T operator -(T v) { return T(*this)- v; } // necessary for unknow reason
+ T operator *(T v) { return T(*this)* v; } // necessary for unknow reason
+ T operator /(T v) { return T(*this)/ v; } // necessary for unknow reason
+ };
+
+
+ template<typename T, typename V> inline
+ bool operator ==(T v, const ref_elt_vector<T, V> &re) { return (v==T(re)); }
+ template<typename T, typename V> inline
+ bool operator !=(T v, const ref_elt_vector<T, V> &re) { return (v!=T(re)); }
+ template<typename T, typename V> inline
+ T &operator +=(T &v, const ref_elt_vector<T, V> &re)
+ { v += T(re); return v; }
+ template<typename T, typename V> inline
+ T &operator -=(T &v, const ref_elt_vector<T, V> &re)
+ { v -= T(re); return v; }
+ template<typename T, typename V> inline
+ T &operator *=(T &v, const ref_elt_vector<T, V> &re)
+ { v *= T(re); return v; }
+ template<typename T, typename V> inline
+ T &operator /=(T &v, const ref_elt_vector<T, V> &re)
+ { v /= T(re); return v; }
+ template<typename T, typename V> inline
+ T operator +(const ref_elt_vector<T, V> &re) { return T(re); }
+ template<typename T, typename V> inline
+ T operator -(const ref_elt_vector<T, V> &re) { return -T(re); }
+ template<typename T, typename V> inline
+ T operator +(const ref_elt_vector<T, V> &re, T v) { return T(re)+ v; }
+ template<typename T, typename V> inline
+ T operator +(T v, const ref_elt_vector<T, V> &re) { return v+ T(re); }
+ template<typename T, typename V> inline
+ T operator -(const ref_elt_vector<T, V> &re, T v) { return T(re)- v; }
+ template<typename T, typename V> inline
+ T operator -(T v, const ref_elt_vector<T, V> &re) { return v- T(re); }
+ template<typename T, typename V> inline
+ T operator *(const ref_elt_vector<T, V> &re, T v) { return T(re)* v; }
+ template<typename T, typename V> inline
+ T operator *(T v, const ref_elt_vector<T, V> &re) { return v* T(re); }
+ template<typename T, typename V> inline
+ T operator /(const ref_elt_vector<T, V> &re, T v) { return T(re)/ v; }
+ template<typename T, typename V> inline
+ T operator /(T v, const ref_elt_vector<T, V> &re) { return v/ T(re); }
+ template<typename T, typename V> inline
+ typename number_traits<T>::magnitude_type
+ abs(const ref_elt_vector<T, V> &re) { return gmm::abs(T(re)); }
+ template<typename T, typename V> inline
+ T sqr(const ref_elt_vector<T, V> &re) { return gmm::sqr(T(re)); }
+ template<typename T, typename V> inline
+ typename number_traits<T>::magnitude_type
+ abs_sqr(const ref_elt_vector<T, V> &re) { return gmm::abs_sqr(T(re)); }
+ template<typename T, typename V> inline
+ T conj(const ref_elt_vector<T, V> &re) { return gmm::conj(T(re)); }
+ template<typename T, typename V> std::ostream &operator <<
+ (std::ostream &o, const ref_elt_vector<T, V> &re) { o << T(re); return o; }
+ template<typename T, typename V> inline
+ typename number_traits<T>::magnitude_type
+ real(const ref_elt_vector<T, V> &re) { return gmm::real(T(re)); }
+ template<typename T, typename V> inline
+ typename number_traits<T>::magnitude_type
+ imag(const ref_elt_vector<T, V> &re) { return gmm::imag(T(re)); }
+
+
+
+ /*************************************************************************/
+ /* */
+ /* Class wsvector: sparse vector optimized for random write operations. */
+ /* */
+ /*************************************************************************/
+
+ template<typename T> struct wsvector_iterator
+ : public std::map<size_type, T>::iterator {
+ typedef typename std::map<size_type, T>::iterator base_it_type;
+ typedef T value_type;
+ typedef value_type* pointer;
+ typedef value_type& reference;
+ // typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+
+ reference operator *() const { return (base_it_type::operator*()).second; }
+ pointer operator->() const { return &(operator*()); }
+ size_type index(void) const { return (base_it_type::operator*()).first; }
+
+ wsvector_iterator(void) {}
+ wsvector_iterator(const base_it_type &it) : base_it_type(it) {}
+ };
+
+ template<typename T> struct wsvector_const_iterator
+ : public std::map<size_type, T>::const_iterator {
+ typedef typename std::map<size_type, T>::const_iterator base_it_type;
+ typedef T value_type;
+ typedef const value_type* pointer;
+ typedef const value_type& reference;
+ // typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+
+ reference operator *() const { return (base_it_type::operator*()).second; }
+ pointer operator->() const { return &(operator*()); }
+ size_type index(void) const { return (base_it_type::operator*()).first; }
+
+ wsvector_const_iterator(void) {}
+ wsvector_const_iterator(const wsvector_iterator<T> &it)
+ : base_it_type(it) {}
+ wsvector_const_iterator(const base_it_type &it) : base_it_type(it) {}
+ };
+
+
+ /**
+ sparse vector built upon std::map.
+ Read and write access are quite fast (log n)
+ */
+ template<typename T> class wsvector : public std::map<size_type, T> {
+ public:
+
+ typedef typename std::map<int, T>::size_type size_type;
+ typedef std::map<size_type, T> base_type;
+ typedef typename base_type::iterator iterator;
+ typedef typename base_type::const_iterator const_iterator;
+
+ protected:
+ size_type nbl;
+
+ public:
+ void clean(double eps);
+ void resize(size_type);
+
+ inline ref_elt_vector<T, wsvector<T> > operator [](size_type c)
+ { return ref_elt_vector<T, wsvector<T> >(this, c); }
+
+ inline void w(size_type c, const T &e) {
+ GMM_ASSERT2(c < nbl, "out of range");
+ if (e == T(0)) { base_type::erase(c); }
+ else base_type::operator [](c) = e;
+ }
+
+ inline T r(size_type c) const {
+ GMM_ASSERT2(c < nbl, "out of range");
+ const_iterator it = this->lower_bound(c);
+ if (it != this->end() && c == it->first) return it->second;
+ else return T(0);
+ }
+
+ inline T operator [](size_type c) const { return r(c); }
+
+ size_type nb_stored(void) const { return base_type::size(); }
+ size_type size(void) const { return nbl; }
+
+ void swap(wsvector<T> &v)
+ { std::swap(nbl, v.nbl); std::map<size_type, T>::swap(v); }
+
+
+ /* Constructeurs */
+ void init(size_type l) { nbl = l; this->clear(); }
+ explicit wsvector(size_type l){ init(l); }
+ wsvector(void) { init(0); }
+ };
+
+ template<typename T> void wsvector<T>::clean(double eps) {
+ iterator it = this->begin(), itf = it, ite = this->end();
+ while (it != ite) {
+ ++itf; if (gmm::abs(it->second) <= eps) erase(it); it = itf;
+ }
+ }
+
+ template<typename T> void wsvector<T>::resize(size_type n) {
+ if (n < nbl) {
+ iterator it = this->begin(), itf = it, ite = this->end();
+ while (it != ite) { ++itf; if (it->first >= n) erase(it); it = itf; }
+ }
+ nbl = n;
+ }
+
+ template <typename T> struct linalg_traits<wsvector<T> > {
+ typedef wsvector<T> this_type;
+ typedef this_type origin_type;
+ typedef linalg_false is_reference;
+ typedef abstract_vector linalg_type;
+ typedef T value_type;
+ typedef ref_elt_vector<T, wsvector<T> > reference;
+ typedef wsvector_iterator<T> iterator;
+ typedef wsvector_const_iterator<T> const_iterator;
+ typedef abstract_sparse storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v) { return v.begin(); }
+ static const_iterator begin(const this_type &v) { return v.begin(); }
+ static iterator end(this_type &v) { return v.end(); }
+ static const_iterator end(const this_type &v) { return v.end(); }
+ static origin_type* origin(this_type &v) { return &v; }
+ static const origin_type* origin(const this_type &v) { return &v; }
+ static void clear(origin_type* o, const iterator &, const iterator &)
+ { o->clear(); }
+ static void do_clear(this_type &v) { v.clear(); }
+ static value_type access(const origin_type *o, const const_iterator &,
+ const const_iterator &, size_type i)
+ { return (*o)[i]; }
+ static reference access(origin_type *o, const iterator &, const iterator &,
+ size_type i)
+ { return (*o)[i]; }
+ static void resize(this_type &v, size_type n) { v.resize(n); }
+ };
+
+ template<typename T> std::ostream &operator <<
+ (std::ostream &o, const wsvector<T>& v) { gmm::write(o,v); return o; }
+
+ /******* Optimized BLAS for wsvector<T> **********************************/
+
+ template <typename T> inline void copy(const wsvector<T> &v1,
+ wsvector<T> &v2) {
+ GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+ v2 = v1;
+ }
+ template <typename T> inline
+ void copy(const wsvector<T> &v1, const simple_vector_ref<wsvector<T> *> &v2){
+ simple_vector_ref<wsvector<T> *>
+ *svr = const_cast<simple_vector_ref<wsvector<T> *> *>(&v2);
+ wsvector<T>
+ *pv = const_cast<wsvector<T> *>(v2.origin);
+ GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+ *pv = v1; svr->begin_ = vect_begin(*pv); svr->end_ = vect_end(*pv);
+ }
+ template <typename T> inline
+ void copy(const simple_vector_ref<const wsvector<T> *> &v1,
+ wsvector<T> &v2)
+ { copy(*(v1.origin), v2); }
+ template <typename T> inline
+ void copy(const simple_vector_ref<wsvector<T> *> &v1, wsvector<T> &v2)
+ { copy(*(v1.origin), v2); }
+
+ template <typename T> inline void clean(wsvector<T> &v, double eps) {
+ typedef typename number_traits<T>::magnitude_type R;
+ typename wsvector<T>::iterator it = v.begin(), ite = v.end(), itc;
+ while (it != ite)
+ if (gmm::abs((*it).second) <= R(eps))
+ { itc=it; ++it; v.erase(itc); } else ++it;
+ }
+
+ template <typename T>
+ inline void clean(const simple_vector_ref<wsvector<T> *> &l, double eps) {
+ simple_vector_ref<wsvector<T> *>
+ *svr = const_cast<simple_vector_ref<wsvector<T> *> *>(&l);
+ wsvector<T>
+ *pv = const_cast<wsvector<T> *>((l.origin));
+ clean(*pv, eps);
+ svr->begin_ = vect_begin(*pv); svr->end_ = vect_end(*pv);
+ }
+
+ template <typename T>
+ inline size_type nnz(const wsvector<T>& l) { return l.nb_stored(); }
+
+ /*************************************************************************/
+ /* */
+ /* rsvector: sparse vector optimized for linear algebra operations. */
+ /* */
+ /*************************************************************************/
+
+ template<typename T> struct elt_rsvector_ {
+ size_type c; T e;
+ /* e is initialized by default to avoid some false warnings of valgrind..
+ (from http://valgrind.org/docs/manual/mc-manual.html:
+
+ When memory is read into the CPU's floating point registers, the
+ relevant V bits are read from memory and they are immediately
+ checked. If any are invalid, an uninitialised value error is
+ emitted. This precludes using the floating-point registers to copy
+ possibly-uninitialised memory, but simplifies Valgrind in that it
+ does not have to track the validity status of the floating-point
+ registers.
+ */
+ elt_rsvector_(void) : e(0) {}
+ elt_rsvector_(size_type cc) : c(cc), e(0) {}
+ elt_rsvector_(size_type cc, const T &ee) : c(cc), e(ee) {}
+ bool operator < (const elt_rsvector_ &a) const { return c < a.c; }
+ bool operator == (const elt_rsvector_ &a) const { return c == a.c; }
+ bool operator != (const elt_rsvector_ &a) const { return c != a.c; }
+ };
+
+ template<typename T> struct rsvector_iterator {
+ typedef typename std::vector<elt_rsvector_<T> >::iterator IT;
+ typedef T value_type;
+ typedef value_type* pointer;
+ typedef value_type& reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef rsvector_iterator<T> iterator;
+
+ IT it;
+
+ reference operator *() const { return it->e; }
+ pointer operator->() const { return &(operator*()); }
+
+ iterator &operator ++() { ++it; return *this; }
+ iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+ iterator &operator --() { --it; return *this; }
+ iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+
+ bool operator ==(const iterator &i) const { return it == i.it; }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+
+ size_type index(void) const { return it->c; }
+ rsvector_iterator(void) {}
+ rsvector_iterator(const IT &i) : it(i) {}
+ };
+
+ template<typename T> struct rsvector_const_iterator {
+ typedef typename std::vector<elt_rsvector_<T> >::const_iterator IT;
+ typedef T value_type;
+ typedef const value_type* pointer;
+ typedef const value_type& reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef rsvector_const_iterator<T> iterator;
+
+ IT it;
+
+ reference operator *() const { return it->e; }
+ pointer operator->() const { return &(operator*()); }
+ size_type index(void) const { return it->c; }
+
+ iterator &operator ++() { ++it; return *this; }
+ iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+ iterator &operator --() { --it; return *this; }
+ iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+
+ bool operator ==(const iterator &i) const { return it == i.it; }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+
+ rsvector_const_iterator(void) {}
+ rsvector_const_iterator(const rsvector_iterator<T> &i) : it(i.it) {}
+ rsvector_const_iterator(const IT &i) : it(i) {}
+ };
+
+ /**
+ sparse vector built upon std::vector. Read access is fast,
+ but insertion is O(n)
+ */
+ template<typename T> class rsvector : public std::vector<elt_rsvector_<T> > {
+ public:
+
+ typedef std::vector<elt_rsvector_<T> > base_type_;
+ typedef typename base_type_::iterator iterator;
+ typedef typename base_type_::const_iterator const_iterator;
+ typedef typename base_type_::size_type size_type;
+ typedef T value_type;
+
+ protected:
+ size_type nbl; /* size of the vector. */
+
+ public:
+
+ void sup(size_type j);
+ void base_resize(size_type n) { base_type_::resize(n); }
+ void resize(size_type);
+
+ ref_elt_vector<T, rsvector<T> > operator [](size_type c)
+ { return ref_elt_vector<T, rsvector<T> >(this, c); }
+
+ void w(size_type c, const T &e);
+ T r(size_type c) const;
+ void swap_indices(size_type i, size_type j);
+
+ inline T operator [](size_type c) const { return r(c); }
+
+ size_type nb_stored(void) const { return base_type_::size(); }
+ size_type size(void) const { return nbl; }
+ void clear(void) { base_type_::resize(0); }
+ void swap(rsvector<T> &v)
+ { std::swap(nbl, v.nbl); std::vector<elt_rsvector_<T> >::swap(v); }
+
+ /* Constructeurs */
+ explicit rsvector(size_type l) : nbl(l) { }
+ rsvector(void) : nbl(0) { }
+ };
+
+ template <typename T>
+ void rsvector<T>::swap_indices(size_type i, size_type j) {
+ if (i > j) std::swap(i, j);
+ if (i != j) {
+ int situation = 0;
+ elt_rsvector_<T> ei(i), ej(j), a;
+ iterator it, ite, iti, itj;
+ iti = std::lower_bound(this->begin(), this->end(), ei);
+ if (iti != this->end() && iti->c == i) situation += 1;
+ itj = std::lower_bound(this->begin(), this->end(), ej);
+ if (itj != this->end() && itj->c == j) situation += 2;
+
+ switch (situation) {
+ case 1 : a = *iti; a.c = j; it = iti; ++it; ite = this->end();
+ for (; it != ite && it->c <= j; ++it, ++iti) *iti = *it;
+ *iti = a;
+ break;
+ case 2 : a = *itj; a.c = i; it = itj; ite = this->begin();
+ if (it != ite) {
+ --it;
+ while (it->c >= i) { *itj = *it; --itj; if (it==ite) break; --it; }
+ }
+ *itj = a;
+ break;
+ case 3 : std::swap(iti->e, itj->e);
+ break;
+ }
+ }
+ }
+
+ template <typename T> void rsvector<T>::sup(size_type j) {
+ if (nb_stored() != 0) {
+ elt_rsvector_<T> ev(j);
+ iterator it = std::lower_bound(this->begin(), this->end(), ev);
+ if (it != this->end() && it->c == j) {
+ for (iterator ite = this->end() - 1; it != ite; ++it) *it = *(it+1);
+ base_type_::resize(nb_stored()-1);
+ }
+ }
+ }
+
+ template<typename T> void rsvector<T>::resize(size_type n) {
+ if (n < nbl) {
+ for (size_type i = 0; i < nb_stored(); ++i)
+ if (base_type_::operator[](i).c >= n) { base_resize(i); break; }
+ }
+ nbl = n;
+ }
+
+ template <typename T> void rsvector<T>::w(size_type c, const T &e) {
+ GMM_ASSERT2(c < nbl, "out of range");
+ if (e == T(0)) sup(c);
+ else {
+ elt_rsvector_<T> ev(c, e);
+ if (nb_stored() == 0) {
+ base_type_::resize(1,ev);
+ }
+ else {
+ iterator it = std::lower_bound(this->begin(), this->end(), ev);
+ if (it != this->end() && it->c == c) it->e = e;
+ else {
+ size_type ind = it - this->begin();
+ base_type_::resize(nb_stored()+1, ev);
+ if (ind != nb_stored() - 1) {
+ it = this->begin() + ind;
+ for (iterator ite = this->end() - 1; ite != it; --ite)
+ *ite = *(ite-1);
+ *it = ev;
+ }
+ }
+ }
+ }
+ }
+
+ template <typename T> T rsvector<T>::r(size_type c) const {
+ GMM_ASSERT2(c < nbl, "out of range");
+ if (nb_stored() != 0) {
+ elt_rsvector_<T> ev(c);
+ const_iterator it = std::lower_bound(this->begin(), this->end(), ev);
+ if (it != this->end() && it->c == c) return it->e;
+ }
+ return T(0);
+ }
+
+ template <typename T> struct linalg_traits<rsvector<T> > {
+ typedef rsvector<T> this_type;
+ typedef this_type origin_type;
+ typedef linalg_false is_reference;
+ typedef abstract_vector linalg_type;
+ typedef T value_type;
+ typedef ref_elt_vector<T, rsvector<T> > reference;
+ typedef rsvector_iterator<T> iterator;
+ typedef rsvector_const_iterator<T> const_iterator;
+ typedef abstract_sparse storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v) { return iterator(v.begin()); }
+ static const_iterator begin(const this_type &v)
+ { return const_iterator(v.begin()); }
+ static iterator end(this_type &v) { return iterator(v.end()); }
+ static const_iterator end(const this_type &v)
+ { return const_iterator(v.end()); }
+ static origin_type* origin(this_type &v) { return &v; }
+ static const origin_type* origin(const this_type &v) { return &v; }
+ static void clear(origin_type* o, const iterator &, const iterator &)
+ { o->clear(); }
+ static void do_clear(this_type &v) { v.clear(); }
+ static value_type access(const origin_type *o, const const_iterator &,
+ const const_iterator &, size_type i)
+ { return (*o)[i]; }
+ static reference access(origin_type *o, const iterator &, const iterator &,
+ size_type i)
+ { return (*o)[i]; }
+ static void resize(this_type &v, size_type n) { v.resize(n); }
+ };
+
+ template<typename T> std::ostream &operator <<
+ (std::ostream &o, const rsvector<T>& v) { gmm::write(o,v); return o; }
+
+ /******* Optimized operations for rsvector<T> ****************************/
+
+ template <typename T> inline void copy(const rsvector<T> &v1,
+ rsvector<T> &v2) {
+ GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+ v2 = v1;
+ }
+ template <typename T> inline
+ void copy(const rsvector<T> &v1, const simple_vector_ref<rsvector<T> *> &v2){
+ simple_vector_ref<rsvector<T> *>
+ *svr = const_cast<simple_vector_ref<rsvector<T> *> *>(&v2);
+ rsvector<T>
+ *pv = const_cast<rsvector<T> *>((v2.origin));
+ GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+ *pv = v1; svr->begin_ = vect_begin(*pv); svr->end_ = vect_end(*pv);
+ }
+ template <typename T> inline
+ void copy(const simple_vector_ref<const rsvector<T> *> &v1,
+ rsvector<T> &v2)
+ { copy(*(v1.origin), v2); }
+ template <typename T> inline
+ void copy(const simple_vector_ref<rsvector<T> *> &v1, rsvector<T> &v2)
+ { copy(*(v1.origin), v2); }
+
+ template <typename V, typename T> inline void add(const V &v1,
+ rsvector<T> &v2) {
+ if ((const void *)(&v1) != (const void *)(&v2)) {
+ GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+ add_rsvector(v1, v2, typename linalg_traits<V>::storage_type());
+ }
+ }
+
+ template <typename V, typename T>
+ inline void add_rsvector(const V &v1, rsvector<T> &v2, abstract_dense)
+ { add(v1, v2, abstract_dense(), abstract_sparse()); }
+
+ template <typename V, typename T>
+ inline void add_rsvector(const V &v1, rsvector<T> &v2, abstract_skyline)
+ { add(v1, v2, abstract_skyline(), abstract_sparse()); }
+
+ template <typename V, typename T>
+ void add_rsvector(const V &v1, rsvector<T> &v2, abstract_sparse) {
+ add_rsvector(v1, v2, typename linalg_traits<V>::index_sorted());
+ }
+
+ template <typename V, typename T>
+ void add_rsvector(const V &v1, rsvector<T> &v2, linalg_false) {
+ add(v1, v2, abstract_sparse(), abstract_sparse());
+ }
+
+ template <typename V, typename T>
+ void add_rsvector(const V &v1, rsvector<T> &v2, linalg_true) {
+ typename linalg_traits<V>::const_iterator it1 = vect_const_begin(v1),
+ ite1 = vect_const_end(v1);
+ typename rsvector<T>::iterator it2 = v2.begin(), ite2 = v2.end(), it3;
+ size_type nbc = 0, old_nbc = v2.nb_stored();
+ for (; it1 != ite1 && it2 != ite2 ; ++nbc)
+ if (it1.index() == it2->c) { ++it1; ++it2; }
+ else if (it1.index() < it2->c) ++it1; else ++it2;
+ for (; it1 != ite1; ++it1) ++nbc;
+ for (; it2 != ite2; ++it2) ++nbc;
+
+ v2.base_resize(nbc);
+ it3 = v2.begin() + old_nbc;
+ it2 = v2.end(); ite2 = v2.begin();
+ it1 = vect_end(v1); ite1 = vect_const_begin(v1);
+ while (it1 != ite1 && it3 != ite2) {
+ --it3; --it1; --it2;
+ if (it3->c > it1.index()) { *it2 = *it3; ++it1; }
+ else if (it3->c == it1.index()) { *it2=*it3; it2->e+=*it1; }
+ else { it2->c = it1.index(); it2->e = *it1; ++it3; }
+ }
+ while (it1 != ite1) { --it1; --it2; it2->c = it1.index(); it2->e = *it1; }
+ }
+
+ template <typename V, typename T> void copy(const V &v1, rsvector<T> &v2) {
+ if ((const void *)(&v1) != (const void *)(&v2)) {
+ GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+ if (same_origin(v1, v2))
+ GMM_WARNING2("a conflict is possible in vector copy\n");
+ copy_rsvector(v1, v2, typename linalg_traits<V>::storage_type());
+ }
+ }
+
+ template <typename V, typename T>
+ void copy_rsvector(const V &v1, rsvector<T> &v2, abstract_dense)
+ { copy_vect(v1, v2, abstract_dense(), abstract_sparse()); }
+
+ template <typename V, typename T>
+ void copy_rsvector(const V &v1, rsvector<T> &v2, abstract_skyline)
+ { copy_vect(v1, v2, abstract_skyline(), abstract_sparse()); }
+
+ template <typename V, typename T>
+ void copy_rsvector(const V &v1, rsvector<T> &v2, abstract_sparse) {
+ copy_rsvector(v1, v2, typename linalg_traits<V>::index_sorted());
+ }
+
+ template <typename V, typename T2>
+ void copy_rsvector(const V &v1, rsvector<T2> &v2, linalg_true) {
+ typedef typename linalg_traits<V>::value_type T1;
+ typename linalg_traits<V>::const_iterator it = vect_const_begin(v1),
+ ite = vect_const_end(v1);
+ v2.base_resize(nnz(v1));
+ typename rsvector<T2>::iterator it2 = v2.begin();
+ size_type nn = 0;
+ for (; it != ite; ++it)
+ if ((*it) != T1(0)) { it2->c = it.index(); it2->e = *it; ++it2; ++nn; }
+ v2.base_resize(nn);
+ }
+
+ template <typename V, typename T2>
+ void copy_rsvector(const V &v1, rsvector<T2> &v2, linalg_false) {
+ typedef typename linalg_traits<V>::value_type T1;
+ typename linalg_traits<V>::const_iterator it = vect_const_begin(v1),
+ ite = vect_const_end(v1);
+ v2.base_resize(nnz(v1));
+ typename rsvector<T2>::iterator it2 = v2.begin();
+ size_type nn = 0;
+ for (; it != ite; ++it)
+ if ((*it) != T1(0)) { it2->c = it.index(); it2->e = *it; ++it2; ++nn; }
+ v2.base_resize(nn);
+ std::sort(v2.begin(), v2.end());
+ }
+
+ template <typename T> inline void clean(rsvector<T> &v, double eps) {
+ typedef typename number_traits<T>::magnitude_type R;
+ typename rsvector<T>::iterator it = v.begin(), ite = v.end();
+ for (; it != ite; ++it) if (gmm::abs((*it).e) <= eps) break;
+ if (it != ite) {
+ typename rsvector<T>::iterator itc = it;
+ size_type erased = 1;
+ for (++it; it != ite; ++it)
+ { *itc = *it; if (gmm::abs((*it).e) <= R(eps)) ++erased; else ++itc; }
+ v.base_resize(v.nb_stored() - erased);
+ }
+ }
+
+ template <typename T>
+ inline void clean(const simple_vector_ref<rsvector<T> *> &l, double eps) {
+ simple_vector_ref<rsvector<T> *>
+ *svr = const_cast<simple_vector_ref<rsvector<T> *> *>(&l);
+ rsvector<T>
+ *pv = const_cast<rsvector<T> *>((l.origin));
+ clean(*pv, eps);
+ svr->begin_ = vect_begin(*pv); svr->end_ = vect_end(*pv);
+ }
+
+ template <typename T>
+ inline size_type nnz(const rsvector<T>& l) { return l.nb_stored(); }
+
+ /*************************************************************************/
+ /* */
+ /* Class slvector: 'sky-line' vector. */
+ /* */
+ /*************************************************************************/
+
+ template<typename T> struct slvector_iterator {
+ typedef T value_type;
+ typedef T *pointer;
+ typedef T &reference;
+ typedef ptrdiff_t difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef slvector_iterator<T> iterator;
+ typedef typename std::vector<T>::iterator base_iterator;
+
+ base_iterator it;
+ size_type shift;
+
+
+ iterator &operator ++()
+ { ++it; ++shift; return *this; }
+ iterator &operator --()
+ { --it; --shift; return *this; }
+ iterator operator ++(int)
+ { iterator tmp = *this; ++(*(this)); return tmp; }
+ iterator operator --(int)
+ { iterator tmp = *this; --(*(this)); return tmp; }
+ iterator &operator +=(difference_type i)
+ { it += i; shift += i; return *this; }
+ iterator &operator -=(difference_type i)
+ { it -= i; shift -= i; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator tmp = *this; return (tmp += i); }
+ iterator operator -(difference_type i) const
+ { iterator tmp = *this; return (tmp -= i); }
+ difference_type operator -(const iterator &i) const
+ { return it - i.it; }
+
+ reference operator *() const
+ { return *it; }
+ reference operator [](int ii)
+ { return *(it + ii); }
+
+ bool operator ==(const iterator &i) const
+ { return it == i.it; }
+ bool operator !=(const iterator &i) const
+ { return !(i == *this); }
+ bool operator < (const iterator &i) const
+ { return it < i.it; }
+ size_type index(void) const { return shift; }
+
+ slvector_iterator(void) {}
+ slvector_iterator(const base_iterator &iter, size_type s)
+ : it(iter), shift(s) {}
+ };
+
+ template<typename T> struct slvector_const_iterator {
+ typedef T value_type;
+ typedef const T *pointer;
+ typedef value_type reference;
+ typedef ptrdiff_t difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef size_t size_type;
+ typedef slvector_const_iterator<T> iterator;
+ typedef typename std::vector<T>::const_iterator base_iterator;
+
+ base_iterator it;
+ size_type shift;
+
+
+ iterator &operator ++()
+ { ++it; ++shift; return *this; }
+ iterator &operator --()
+ { --it; --shift; return *this; }
+ iterator operator ++(int)
+ { iterator tmp = *this; ++(*(this)); return tmp; }
+ iterator operator --(int)
+ { iterator tmp = *this; --(*(this)); return tmp; }
+ iterator &operator +=(difference_type i)
+ { it += i; shift += i; return *this; }
+ iterator &operator -=(difference_type i)
+ { it -= i; shift -= i; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator tmp = *this; return (tmp += i); }
+ iterator operator -(difference_type i) const
+ { iterator tmp = *this; return (tmp -= i); }
+ difference_type operator -(const iterator &i) const
+ { return it - i.it; }
+
+ value_type operator *() const
+ { return *it; }
+ value_type operator [](int ii)
+ { return *(it + ii); }
+
+ bool operator ==(const iterator &i) const
+ { return it == i.it; }
+ bool operator !=(const iterator &i) const
+ { return !(i == *this); }
+ bool operator < (const iterator &i) const
+ { return it < i.it; }
+ size_type index(void) const { return shift; }
+
+ slvector_const_iterator(void) {}
+ slvector_const_iterator(const slvector_iterator<T>& iter)
+ : it(iter.it), shift(iter.shift) {}
+ slvector_const_iterator(const base_iterator &iter, size_type s)
+ : it(iter), shift(s) {}
+ };
+
+
+ /** skyline vector.
+ */
+ template <typename T> class slvector {
+
+ public :
+ typedef slvector_iterator<T> iterators;
+ typedef slvector_const_iterator<T> const_iterators;
+ typedef typename std::vector<T>::size_type size_type;
+ typedef T value_type;
+
+ protected :
+ std::vector<T> data;
+ size_type shift;
+ size_type size_;
+
+
+ public :
+
+ size_type size(void) const { return size_; }
+ size_type first(void) const { return shift; }
+ size_type last(void) const { return shift + data.size(); }
+ ref_elt_vector<T, slvector<T> > operator [](size_type c)
+ { return ref_elt_vector<T, slvector<T> >(this, c); }
+
+ typename std::vector<T>::iterator data_begin(void) { return data.begin(); }
+ typename std::vector<T>::iterator data_end(void) { return data.end(); }
+ typename std::vector<T>::const_iterator data_begin(void) const
+ { return data.begin(); }
+ typename std::vector<T>::const_iterator data_end(void) const
+ { return data.end(); }
+
+ void w(size_type c, const T &e);
+ T r(size_type c) const {
+ GMM_ASSERT2(c < size_, "out of range");
+ if (c < shift || c >= shift + data.size()) return T(0);
+ return data[c - shift];
+ }
+
+ inline T operator [](size_type c) const { return r(c); }
+ void resize(size_type);
+ void clear(void) { data.resize(0); shift = 0; }
+ void swap(slvector<T> &v) {
+ std::swap(data, v.data);
+ std::swap(shift, v.shift);
+ std::swap(size_, v.size_);
+ }
+
+
+ slvector(void) : data(0), shift(0), size_(0) {}
+ explicit slvector(size_type l) : data(0), shift(0), size_(l) {}
+ slvector(size_type l, size_type d, size_type s)
+ : data(d), shift(s), size_(l) {}
+
+ };
+
+ template<typename T> void slvector<T>::resize(size_type n) {
+ if (n < last()) {
+ if (shift >= n) clear(); else { data.resize(n-shift); }
+ }
+ size_ = n;
+ }
+
+ template<typename T> void slvector<T>::w(size_type c, const T &e) {
+ GMM_ASSERT2(c < size_, "out of range");
+ size_type s = data.size();
+ if (!s) { data.resize(1); shift = c; }
+ else if (c < shift) {
+ data.resize(s + shift - c);
+ typename std::vector<T>::iterator it = data.begin(),it2=data.end()-1;
+ typename std::vector<T>::iterator it3 = it2 - shift + c;
+ for (; it3 >= it; --it3, --it2) *it2 = *it3;
+ std::fill(it, it + shift - c, T(0));
+ shift = c;
+ }
+ else if (c >= shift + s) {
+ data.resize(c - shift + 1);
+ std::fill(data.begin() + s, data.end(), T(0));
+ }
+ data[c - shift] = e;
+ }
+
+ template <typename T> struct linalg_traits<slvector<T> > {
+ typedef slvector<T> this_type;
+ typedef this_type origin_type;
+ typedef linalg_false is_reference;
+ typedef abstract_vector linalg_type;
+ typedef T value_type;
+ typedef ref_elt_vector<T, slvector<T> > reference;
+ typedef slvector_iterator<T> iterator;
+ typedef slvector_const_iterator<T> const_iterator;
+ typedef abstract_skyline storage_type;
+ typedef linalg_true index_sorted;
+ static size_type size(const this_type &v) { return v.size(); }
+ static iterator begin(this_type &v)
+ { return iterator(v.data_begin(), v.first()); }
+ static const_iterator begin(const this_type &v)
+ { return const_iterator(v.data_begin(), v.first()); }
+ static iterator end(this_type &v)
+ { return iterator(v.data_end(), v.last()); }
+ static const_iterator end(const this_type &v)
+ { return const_iterator(v.data_end(), v.last()); }
+ static origin_type* origin(this_type &v) { return &v; }
+ static const origin_type* origin(const this_type &v) { return &v; }
+ static void clear(origin_type* o, const iterator &, const iterator &)
+ { o->clear(); }
+ static void do_clear(this_type &v) { v.clear(); }
+ static value_type access(const origin_type *o, const const_iterator &,
+ const const_iterator &, size_type i)
+ { return (*o)[i]; }
+ static reference access(origin_type *o, const iterator &, const iterator &,
+ size_type i)
+ { return (*o)[i]; }
+ static void resize(this_type &v, size_type n) { v.resize(n); }
+ };
+
+ template<typename T> std::ostream &operator <<
+ (std::ostream &o, const slvector<T>& v) { gmm::write(o,v); return o; }
+
+ template <typename T>
+ inline size_type nnz(const slvector<T>& l) { return l.last() - l.first(); }
+
+}
+
+namespace std {
+ template <typename T> void swap(gmm::wsvector<T> &v, gmm::wsvector<T> &w)
+ { v.swap(w);}
+ template <typename T> void swap(gmm::rsvector<T> &v, gmm::rsvector<T> &w)
+ { v.swap(w);}
+ template <typename T> void swap(gmm::slvector<T> &v, gmm::slvector<T> &w)
+ { v.swap(w);}
+}
+
+
+
+#endif /* GMM_VECTOR_H__ */
diff --git a/Contrib/gmm/gmm_vector_to_matrix.h b/Contrib/gmm/gmm_vector_to_matrix.h
new file mode 100755
index 0000000..50036fc
--- /dev/null
+++ b/Contrib/gmm/gmm_vector_to_matrix.h
@@ -0,0 +1,339 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++ 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 program 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 program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_vector_to_matrix.h
+ @author Yves Renard <Yves.Renard at insa-lyon.fr>
+ @date December 6, 2003.
+ @brief View vectors as row or column matrices. */
+#ifndef GMM_VECTOR_TO_MATRIX_H__
+#define GMM_VECTOR_TO_MATRIX_H__
+
+#include "gmm_interface.h"
+
+namespace gmm {
+
+ /* ********************************************************************* */
+ /* row vector -> transform a vector in a (1, n) matrix. */
+ /* ********************************************************************* */
+
+ template <typename PT> struct gen_row_vector {
+ typedef gen_row_vector<PT> this_type;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef V * CPT;
+ typedef typename std::iterator_traits<PT>::reference ref_V;
+ typedef typename linalg_traits<this_type>::reference reference;
+
+ simple_vector_ref<PT> vec;
+
+ reference operator()(size_type, size_type j) const { return vec[j]; }
+
+ size_type nrows(void) const { return 1; }
+ size_type ncols(void) const { return vect_size(vec); }
+
+ gen_row_vector(ref_V v) : vec(v) {}
+ gen_row_vector() {}
+ gen_row_vector(const gen_row_vector<CPT> &cr) : vec(cr.vec) {}
+ };
+
+ template <typename PT>
+ struct gen_row_vector_iterator {
+ typedef gen_row_vector<PT> this_type;
+ typedef typename modifiable_pointer<PT>::pointer MPT;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef simple_vector_ref<PT> value_type;
+ typedef const simple_vector_ref<PT> *pointer;
+ typedef const simple_vector_ref<PT> &reference;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef gen_row_vector_iterator<PT> iterator;
+
+ simple_vector_ref<PT> vec;
+ bool isend;
+
+ iterator &operator ++() { isend = true; return *this; }
+ iterator &operator --() { isend = false; return *this; }
+ iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+ iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+ iterator &operator +=(difference_type i)
+ { if (i) isend = false; return *this; }
+ iterator &operator -=(difference_type i)
+ { if (i) isend = true; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator itt = *this; return (itt += i); }
+ iterator operator -(difference_type i) const
+ { iterator itt = *this; return (itt -= i); }
+ difference_type operator -(const iterator &i) const {
+ return (isend == true) ? ((i.isend == true) ? 0 : 1)
+ : ((i.isend == true) ? -1 : 0);
+ }
+
+ const simple_vector_ref<PT>& operator *() const { return vec; }
+ const simple_vector_ref<PT>& operator [](int i) { return vec; }
+
+ bool operator ==(const iterator &i) const { return (isend == i.isend); }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+ bool operator < (const iterator &i) const { return (*this - i < 0); }
+
+ gen_row_vector_iterator(void) {}
+ gen_row_vector_iterator(const gen_row_vector_iterator<MPT> &itm)
+ : vec(itm.vec), isend(itm.isend) {}
+ gen_row_vector_iterator(const gen_row_vector<PT> &m, bool iis_end)
+ : vec(m.vec), isend(iis_end) { }
+
+ };
+
+ template <typename PT>
+ struct linalg_traits<gen_row_vector<PT> > {
+ typedef gen_row_vector<PT> this_type;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename linalg_traits<V>::value_type value_type;
+ typedef typename select_ref<value_type,
+ typename linalg_traits<V>::reference, PT>::ref_type reference;
+ typedef abstract_null_type sub_col_type;
+ typedef abstract_null_type col_iterator;
+ typedef abstract_null_type const_sub_col_type;
+ typedef abstract_null_type const_col_iterator;
+ typedef simple_vector_ref<const V *> const_sub_row_type;
+ typedef typename select_ref<abstract_null_type,
+ simple_vector_ref<V *>, PT>::ref_type sub_row_type;
+ typedef gen_row_vector_iterator<typename const_pointer<PT>::pointer>
+ const_row_iterator;
+ typedef typename select_ref<abstract_null_type,
+ gen_row_vector_iterator<PT>, PT>::ref_type row_iterator;
+ typedef typename linalg_traits<V>::storage_type storage_type;
+ typedef row_major sub_orientation;
+ typedef typename linalg_traits<V>::index_sorted index_sorted;
+ static size_type nrows(const this_type &) { return 1; }
+ static size_type ncols(const this_type &m) { return m.ncols(); }
+ static const_sub_row_type row(const const_row_iterator &it) { return *it; }
+ static sub_row_type row(const row_iterator &it) { return *it; }
+ static const_row_iterator row_begin(const this_type &m)
+ { return const_row_iterator(m, false); }
+ static row_iterator row_begin(this_type &m)
+ { return row_iterator(m, false); }
+ static const_row_iterator row_end(const this_type &m)
+ { return const_row_iterator(m, true); }
+ static row_iterator row_end(this_type &m)
+ { return row_iterator(m, true); }
+ static origin_type* origin(this_type &m) { return m.vec.origin; }
+ static const origin_type* origin(const this_type &m)
+ { return m.vec.origin; }
+ static void do_clear(this_type &m)
+ { clear(row(mat_row_begin(m))); }
+ static value_type access(const const_row_iterator &itrow, size_type i)
+ { return itrow.vec[i]; }
+ static reference access(const row_iterator &itrow, size_type i)
+ { return itrow.vec[i]; }
+ };
+
+ template <typename PT>
+ std::ostream &operator <<(std::ostream &o, const gen_row_vector<PT>& m)
+ { gmm::write(o,m); return o; }
+
+ /* ********************************************************************* */
+ /* col vector -> transform a vector in a (n, 1) matrix. */
+ /* ********************************************************************* */
+
+ template <typename PT> struct gen_col_vector {
+ typedef gen_col_vector<PT> this_type;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef V * CPT;
+ typedef typename std::iterator_traits<PT>::reference ref_V;
+ typedef typename linalg_traits<this_type>::reference reference;
+
+ simple_vector_ref<PT> vec;
+
+ reference operator()(size_type i, size_type) const { return vec[i]; }
+
+ size_type ncols(void) const { return 1; }
+ size_type nrows(void) const { return vect_size(vec); }
+
+ gen_col_vector(ref_V v) : vec(v) {}
+ gen_col_vector() {}
+ gen_col_vector(const gen_col_vector<CPT> &cr) : vec(cr.vec) {}
+ };
+
+ template <typename PT>
+ struct gen_col_vector_iterator {
+ typedef gen_col_vector<PT> this_type;
+ typedef typename modifiable_pointer<PT>::pointer MPT;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef simple_vector_ref<PT> value_type;
+ typedef const simple_vector_ref<PT> *pointer;
+ typedef const simple_vector_ref<PT> &reference;
+ typedef ptrdiff_t difference_type;
+ typedef size_t size_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef gen_col_vector_iterator<PT> iterator;
+
+ simple_vector_ref<PT> vec;
+ bool isend;
+
+ iterator &operator ++() { isend = true; return *this; }
+ iterator &operator --() { isend = false; return *this; }
+ iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+ iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+ iterator &operator +=(difference_type i)
+ { if (i) isend = false; return *this; }
+ iterator &operator -=(difference_type i)
+ { if (i) isend = true; return *this; }
+ iterator operator +(difference_type i) const
+ { iterator itt = *this; return (itt += i); }
+ iterator operator -(difference_type i) const
+ { iterator itt = *this; return (itt -= i); }
+ difference_type operator -(const iterator &i) const {
+ return (isend == true) ? ((i.isend == true) ? 0 : 1)
+ : ((i.isend == true) ? -1 : 0);
+ }
+
+ const simple_vector_ref<PT>& operator *() const { return vec; }
+ const simple_vector_ref<PT>& operator [](int i) { return vec; }
+
+ bool operator ==(const iterator &i) const { return (isend == i.isend); }
+ bool operator !=(const iterator &i) const { return !(i == *this); }
+ bool operator < (const iterator &i) const { return (*this - i < 0); }
+
+ gen_col_vector_iterator(void) {}
+ gen_col_vector_iterator(const gen_col_vector_iterator<MPT> &itm)
+ : vec(itm.vec), isend(itm.isend) {}
+ gen_col_vector_iterator(const gen_col_vector<PT> &m, bool iis_end)
+ : vec(m.vec), isend(iis_end) { }
+
+ };
+
+ template <typename PT>
+ struct linalg_traits<gen_col_vector<PT> > {
+ typedef gen_col_vector<PT> this_type;
+ typedef typename std::iterator_traits<PT>::value_type V;
+ typedef typename which_reference<PT>::is_reference is_reference;
+ typedef abstract_matrix linalg_type;
+ typedef typename linalg_traits<V>::origin_type origin_type;
+ typedef typename select_ref<const origin_type *, origin_type *,
+ PT>::ref_type porigin_type;
+ typedef typename linalg_traits<V>::value_type value_type;
+ typedef typename select_ref<value_type,
+ typename linalg_traits<V>::reference, PT>::ref_type reference;
+ typedef abstract_null_type sub_row_type;
+ typedef abstract_null_type row_iterator;
+ typedef abstract_null_type const_sub_row_type;
+ typedef abstract_null_type const_row_iterator;
+ typedef simple_vector_ref<const V *> const_sub_col_type;
+ typedef typename select_ref<abstract_null_type,
+ simple_vector_ref<V *>, PT>::ref_type sub_col_type;
+ typedef gen_col_vector_iterator<typename const_pointer<PT>::pointer>
+ const_col_iterator;
+ typedef typename select_ref<abstract_null_type,
+ gen_col_vector_iterator<PT>, PT>::ref_type col_iterator;
+ typedef typename linalg_traits<V>::storage_type storage_type;
+ typedef col_major sub_orientation;
+ typedef typename linalg_traits<V>::index_sorted index_sorted;
+ static size_type ncols(const this_type &) { return 1; }
+ static size_type nrows(const this_type &m) { return m.nrows(); }
+ static const_sub_col_type col(const const_col_iterator &it) { return *it; }
+ static sub_col_type col(const col_iterator &it) { return *it; }
+ static const_col_iterator col_begin(const this_type &m)
+ { return const_col_iterator(m, false); }
+ static col_iterator col_begin(this_type &m)
+ { return col_iterator(m, false); }
+ static const_col_iterator col_end(const this_type &m)
+ { return const_col_iterator(m, true); }
+ static col_iterator col_end(this_type &m)
+ { return col_iterator(m, true); }
+ static origin_type* origin(this_type &m) { return m.vec.origin; }
+ static const origin_type* origin(const this_type &m)
+ { return m.vec.origin; }
+ static void do_clear(this_type &m)
+ { clear(col(mat_col_begin(m))); }
+ static value_type access(const const_col_iterator &itcol, size_type i)
+ { return itcol.vec[i]; }
+ static reference access(const col_iterator &itcol, size_type i)
+ { return itcol.vec[i]; }
+ };
+
+ template <typename PT>
+ std::ostream &operator <<(std::ostream &o, const gen_col_vector<PT>& m)
+ { gmm::write(o,m); return o; }
+
+ /* ******************************************************************** */
+ /* col and row vectors */
+ /* ******************************************************************** */
+
+
+ template <class V> inline
+ typename select_return< gen_row_vector<const V *>, gen_row_vector<V *>,
+ const V *>::return_type
+ row_vector(const V& v) {
+ return typename select_return< gen_row_vector<const V *>,
+ gen_row_vector<V *>, const V *>::return_type(linalg_cast(v));
+ }
+
+ template <class V> inline
+ typename select_return< gen_row_vector<const V *>, gen_row_vector<V *>,
+ V *>::return_type
+ row_vector(V& v) {
+ return typename select_return< gen_row_vector<const V *>,
+ gen_row_vector<V *>, V *>::return_type(linalg_cast(v));
+ }
+
+ template <class V> inline gen_row_vector<const V *>
+ const_row_vector(V& v)
+ { return gen_row_vector<const V *>(v); }
+
+
+ template <class V> inline
+ typename select_return< gen_col_vector<const V *>, gen_col_vector<V *>,
+ const V *>::return_type
+ col_vector(const V& v) {
+ return typename select_return< gen_col_vector<const V *>,
+ gen_col_vector<V *>, const V *>::return_type(linalg_cast(v));
+ }
+
+ template <class V> inline
+ typename select_return< gen_col_vector<const V *>, gen_col_vector<V *>,
+ V *>::return_type
+ col_vector(V& v) {
+ return typename select_return< gen_col_vector<const V *>,
+ gen_col_vector<V *>, V *>::return_type(linalg_cast(v));
+ }
+
+ template <class V> inline gen_col_vector<const V *>
+ const_col_vector(V& v)
+ { return gen_col_vector<const V *>(v); }
+
+
+}
+
+#endif // GMM_VECTOR_TO_MATRIX_H__
diff --git a/Contrib/mathex/lesser.txt b/Contrib/mathex/lesser.txt
new file mode 100644
index 0000000..3f50d04
--- /dev/null
+++ b/Contrib/mathex/lesser.txt
@@ -0,0 +1,506 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
+
+
diff --git a/Contrib/mathex/license.txt b/Contrib/mathex/license.txt
new file mode 100644
index 0000000..1bc4194
--- /dev/null
+++ b/Contrib/mathex/license.txt
@@ -0,0 +1,35 @@
+BMP libray License
+------------------
+
+The MathEx library and included programs are part of SSCILIB and provided under
+the terms of the GNU Library/Lesser General Public License (LGPL) 2.1 or latter,
+with following static linking exceptions:
+
+ 1. The combined work statically linked with unmodified MathEx library will
+distributed under your own license.
+
+ 2. The application or libraries statically linked with MathEx library must identify
+their use of SSCILIB library. For example, text like
+"[application/library] is based in part on the work of the SSCILIB Library
+ (http://sscilib.sourceforge.net/)"
+will included in document or help to satisfy this requirement.
+
+ 3. The folowing five modifications on MathEx library in way to fit your
+requirement does not implies in modification of source code:
+ i. Modification of the MathEx config script, makefiles or instalation tools.
+ ii. change of name space definition
+using namespace smlib
+to other one (need if it conflict with other library)
+
+ 4. The modifications of source code implies in the GNU Library/Lesser General Public License 2.1 or latter, without this static linking exceptions.
+
+End of license term
+-------------------
+
+For GNU Library/lesser General Public License, see the lesser.txt or visit
+http://www.gnu.org/
+
+June of 2003.
+
+Sadao Massago
+http://www2.dm.ufscar.br/~sadao
diff --git a/Contrib/mathex/mathex.cpp b/Contrib/mathex/mathex.cpp
new file mode 100644
index 0000000..3231891
--- /dev/null
+++ b/Contrib/mathex/mathex.cpp
@@ -0,0 +1,1019 @@
+///////////////////////////////////////////////////////////////////////////
+// mathex 0.2.3 (beta) - Copyright (C) 2000-2003, by Sadao Massago //
+// file: mathex.h (math expression evaluator header file) //
+// requires: none //
+// project web page: http://sscilib.sourceforge.net/ //
+// ----------------------------------------------------------------------//
+// The mathex library and related files is licenced under the term of //
+// GNU LGPL (Lesser General Public License) version 2.1 or latter //
+// with exceptions that allow for static linking. //
+// See license.txt for detail. //
+// For GNU LGPL, see lesser.txt. //
+// For information over GNU or GNU compatible license, visit the site //
+// http://www.gnu.org. //
+///////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////
+// references:
+//-------------------------------------------------------------------------
+// title: Algoritms and Data Structures
+// author: Niklaus Wirth
+// publisher: Prentice-Hall
+// year: 1989
+//-------------------------------------------------------------------------
+// title: The C++ Programming Language
+// edition: thrird
+// author: Bjarne Stroustrup
+// publisher: Addilson-Wesley
+// year: 1997
+//-------------------------------------------------------------------------
+// title: building your own C interpreter
+// author: Schildt, Helbert
+// journal: Dr. Dobb's Jornal (http://www.ddj.com)
+// number: August/1989
+// pages: 38-49, 110-122
+///////////////////////////////////////////////////////////////////////////
+
+// #define _DEBUG_
+
+#include "mathex.h"
+
+#include <string.h>
+#include <string>
+#include <vector>
+#include <cmath>
+#include <cctype>
+#include <math.h>
+#include <cstdlib>
+
+// debug purpose
+#ifdef _DEBUG_
+ #include <iostream>
+#endif
+
+ namespace smlib {
+ using namespace std;
+
+
+ ////////////////////////////////////
+ // local variables, functions, etc
+ ////////////////////////////////////
+ namespace {
+
+ //////////////////////////////////
+ // C function with one parameter
+ //--------------------------------
+
+ double fac(double x)
+ // Function return the factorial of integer belong to range 0..170.
+ // in future, will implement aproximation for gamma function to evaluate for x > 170
+ {
+ double p;
+ unsigned n;
+
+ if((x <0) || (x>170)) // maximum admited where
+ throw mathex::error("Error [fac()]: range error");
+ else {
+ n = static_cast<unsigned>(x+0.5);
+ if(x < 2)
+ return 1;
+ else if(n == 2)
+ return(2);
+ for(p=1;1<n;n--)
+ p *= n;
+ return p;
+ }
+ } // fac()
+
+ // convert radian to degree
+ double deg(double x)
+ {
+ return( x * 180.0 / M_PI);
+ } // deg()
+
+ // convert degree to radian
+ double rad(double x)
+ {
+ return(x * M_PI / 180.0);
+ } // rad()
+
+ // return square
+ /* double sqr(double x)
+ {
+ return (x*x);
+ } */
+ // sqr()
+
+ // return real part
+ double trunc(double x)
+ {
+ return static_cast<long>(x);
+ } // trunc()
+
+ // return rounded value to int
+ double round(double x)
+ {
+ return static_cast<long>(x+0.5);
+ } // round
+
+ // return 0 if x negative, 1 otherwise
+ double step(double x)
+ {
+ if ( x < 0 ) return static_cast<long>(0.);
+ return static_cast<long>(1.);
+ } // step
+
+ // return -1 if x negative, 1 otherwise
+ double sign(double x)
+ {
+ if ( x < 0 ) return static_cast<long>(-1.);
+ return static_cast<long>(1.);
+ } // sign
+
+ //////////////////////////////////////////////////////////
+ // arithmetic operators
+ //////////////////////////////////////////////////////////
+ // operators was treated in Parsingr time, to check the
+ // operator level.
+ // unary operator is the function double op(double) and
+ // binary operator is function double op(double,double)
+ //--------------------------------------------------------
+ // unary:
+ // "+" -> none
+ // "-" -> unary_minus
+ // binary:
+ // "+" -> binary_plus
+ // "-" -> binary_minus
+ // "*" -> binary_times
+ // "/" -> binary_divide
+ // "^" -> binary_power
+ // "%" -> fmod (defined in math.h)
+ ///////////////////////////////////////////////////////////
+
+ //////////////////////
+ // C unary operator
+
+ double unary_minus(double x)
+ {
+ return -x;
+ } // unary_minus()
+
+ //////////////////////////////////////////
+ // C binary operators
+ //----------------------------------------
+
+ double binary_plus(double x, double y)
+ {
+ return x + y;
+ } // binary_plus()
+
+ double binary_minus(double x, double y)
+ {
+ return x - y;
+ } // binary_minus()
+
+ double binary_times(double x, double y)
+ {
+ return x * y;
+ } // binary_timess()
+
+ double binary_divide(double x, double y)
+ // in future, put more precisery checking, for overflow ?
+ {
+ if (y == 0)
+ throw mathex::error("Error [binary_divide()]: divisin by zero");
+ else
+ return (x/y);
+ } // binary_divide()
+
+ double binary_power(double x, double y)
+ {
+ return pow(x,y);
+ } // binary_power()
+
+ /////////////////////////////////////////
+ // pre-defined user defined functions
+ //---------------------------------------
+
+ double p_rand(vector <double> const &x)
+ // rand() return value between [0,1)
+ {
+ if(x.size() != 0)
+ throw mathex::error("Error [p_rand()]: can not use argument");
+ return rand()/(RAND_MAX+1.0);
+ } // p_rand()
+
+ // maximum
+ double p_max(vector <double> const & x)
+ {
+
+ double maxval=0;
+
+ if(x.size() == 0)
+ throw mathex::error("Error [p_max()]: No arguments");
+ maxval = x[0];
+ for(unsigned i=0; i<x.size(); i++)
+ if(x[i] > maxval)
+ maxval = x[i];
+
+ return maxval;
+ } // p_max
+
+ // minimum
+ double p_min(vector <double> const & x)
+ {
+
+ double minval=0;
+
+ if(x.size() == 0)
+ throw mathex::error("Error [p_min()]: No arguments");
+ minval = x[0];
+ for(unsigned i=0; i<x.size(); i++)
+ if(x[i] < minval)
+ minval = x[i];
+
+ return minval;
+ } // p_min
+
+ // sum
+ double p_sum(vector <double> const & x)
+ {
+
+ double sumval=0;
+
+ if(x.size() == 0)
+ throw mathex::error("Error [p_sum()]: No arguments");
+ for(unsigned i=0; i<x.size(); i++)
+ sumval += x[i];
+
+ return sumval;
+ } // p_sum
+
+ // average
+ double p_med(vector <double> const & x)
+ {
+ if(x.size() == 0)
+ throw mathex::error("Error [p_med()]: No arguments");
+ return p_sum(x)/x.size();
+ } // p_med()
+
+ ////////////////////////////////
+ // function/constant tables
+ ////////////////////////////////
+
+ //////////////////////////////////
+ // One parameter C function table
+
+ // Record for one parameter C functions
+ typedef
+ struct
+ {
+ const char *name;
+ double (*f)(double x); // one parameter function
+ } CFUNCREC;
+
+ ///////////////////////////////////////////////////////////
+ // One parameter internal C defined functions
+ // the unary operator are stored on first part of table
+ //---------------------------------------------------------
+ // CAUTION:
+ // if add unary operator, adjust the definiftion of NUM_UNARY_OP
+ #define NUM_UNARY_OP 1
+ CFUNCREC cfunctable[] =
+ {
+ // name and funtion pointer
+ // first part of table is unary operators
+ {"-", unary_minus}, // unary operator
+ // seccond part of table is functions
+ { "abs", fabs },
+ { "Abs", fabs },
+ { "acos", acos },
+ { "Acos", acos },
+ { "asin", asin },
+ { "Asin", asin },
+ { "atan", atan },
+ { "Atan", atan },
+ { "cos", cos },
+ { "Cos", cos },
+ { "cosh", cosh },
+ { "Cosh", cosh },
+ { "deg", deg }, // added
+ { "Deg", deg }, // added
+ { "exp", exp },
+ { "Exp", exp },
+ { "fac", fac }, // added
+ { "Fac", fac }, // added
+ { "log", log },
+ { "Log", log },
+ { "log10", log10 },
+ { "Log10", log10 },
+ // { "pow10", pow10 } // in future, add it?
+ { "rad", rad }, // added
+ { "Rad", rad }, // added
+ { "round", round }, // added
+ { "Round", round }, // added
+ { "sign", sign },
+ { "Sign", sign },
+ { "sin", sin },
+ { "Sin", sin },
+ { "sinh", sinh },
+ { "Sinh", sinh },
+ // { "sqr", sqr }, // added
+ { "sqrt", sqrt },
+ { "Sqrt", sqrt },
+ { "step", step },
+ { "Step", step },
+ { "tan", tan },
+ { "Tan", tan },
+ { "tanh", tanh },
+ { "Tanh", tanh },
+ { "trunc", trunc }, // added
+ { "Trunc", trunc }, // added
+ { "floor", floor }, // largest integer not grather than x
+ { "Floor", floor }, // largest integer not grather than x
+ { "ceil", ceil }, // smallest integer not less than x
+ { "Ceil", ceil }, // smallest integer not less than x
+
+ { 0, 0 } // 0 mark the end of table
+ };
+
+ /////////////////////
+ // binary operators
+
+ // binary operator's record
+ class BINOPREC {
+ public:
+ char name;
+ double (*f)(double, double);
+ };
+
+ ////////////////////
+ // binary operators
+ BINOPREC binoptable[] =
+ {
+ // name, value
+ { '+', binary_plus},
+ { '-', binary_minus},
+ { '*', binary_times},
+ { '/', binary_divide},
+ { '^', binary_power},
+ { '%', fmod},
+
+ { '\0' , 0 } // '\0' mark the end of table
+ };
+
+ //////////////
+ // constants
+
+ // constants record
+ class CONSTREC {
+ public:
+ const char *name;
+ double value;
+ };
+
+ /////////////
+ // constants
+ CONSTREC consttable[] =
+ {
+ // name, value
+ { "pi", M_PI },
+ { "e", M_E },
+
+ { NULL, 0 } // NULL mark the end of table
+ };
+
+ } // namespace {
+
+
+ ////////////////////////////
+ // implementations
+ ///////////////////////////
+
+ ///////////////
+ // constatnts
+ /// undefined number of arguments (for user defined functions
+ const int mathex::UNDEFARGS = -1; // for user function arguments
+
+ ////////////////
+ // methods
+ void mathex::addstdfunc()
+ {
+ addfunc("rand", p_rand, 0);
+ addfunc("sum", p_sum, UNDEFARGS);
+ addfunc("max", p_max, UNDEFARGS);
+ addfunc("min", p_min, UNDEFARGS);
+ addfunc("med", p_med, UNDEFARGS);
+ } // addstdfunc()
+
+ void mathex::reset()
+ {
+ delvar();
+ delfunc();
+ status = notparsed;
+ expr = "";
+ bytecode.clear();
+ pos = 0;
+ addstdfunc();
+ } // reset
+
+ /////////////////////////////////
+ // varibles table manipulations
+
+ bool mathex::addvar(string const &name, double *var)
+ // register the program internal variable
+ {
+ unsigned i;
+
+ for(i=0; (i<vartable.size()) && (vartable[i].name != name);i++);
+ if(i<vartable.size()) { // found! overwrite
+ vartable[i].var = var;
+ return true;
+ }
+ else if(!isnewvalidname(name))
+ return false;
+ vartable.push_back(VARREC(name, var));
+ return true;
+ } // addvar()
+
+ bool mathex::delvar(string const &name)
+ // delete one variable
+ {
+ unsigned i;
+
+ for(i=0; (i<vartable.size()) && (vartable[i].name != name);i++);
+ if(i < vartable.size()) {
+ // how to use erase?
+ // vartable.erase(&vartable[i],&vartable[i+1]);
+ for(unsigned j=0; j<vartable.size()-1; j++)
+ vartable[j] = vartable[j+1];
+ vartable.pop_back(); // delete last
+ status = notparsed;
+ return true;
+ }
+ else
+ return false;
+ } // delvar()
+
+ //////////////////////////////////////////////
+ // user defined function table manipulation
+ //////////////////////////////////////////////
+
+ bool mathex::addfunc(string const &name, double (*f)(vector<double> const &), int NumArgs)
+ // register the user defined function
+ {
+ unsigned i;
+
+ for(i=0; (i<functable.size()) && (functable[i].name != name);i++);
+ if(i<functable.size()) { // found! overwrite
+ functable[i].f = f;
+ functable[i].numargs = NumArgs;
+ return true;
+ }
+ else if(!isnewvalidname(name))
+ return false;
+ functable.push_back(FUNCREC(name, f, NumArgs));
+ return true;
+ } // addfunc()
+
+ bool mathex::delfunc(string const &name)
+ // delete the user defined function
+ {
+ unsigned i;
+
+ for(i=0; (i<functable.size()) && (functable[i].name != name);i++);
+ if(i < functable.size()) {
+ // how to use erase?
+ // functable.erase(&vartable[i],&vartable[i+1]);
+ for(unsigned j=0; j<vartable.size()-1; j++)
+ functable[j] = functable[j+1];
+ functable.pop_back(); // delete last
+ return true;
+ }
+ else
+ return false;
+ } // delfunc()
+
+ ////////////////////////////////////////////////////
+ // get the index of variables/constants/functions/
+ // binary operator/user defined functions
+ //--------------------------------------------------
+ // return -1 if not found
+ ////////////////////////////////////////////////////
+
+ int mathex::getconst(string const &name)
+ // get index of const
+ // return -1 if not found
+ {
+ unsigned i;
+ // look up the constants
+ for(i=0;consttable[i].name && strcmp(name.c_str(), consttable[i].name);i++);
+ if(consttable[i].name != NULL) // if found
+ return i;
+ else
+ return -1;
+ } // getconst
+
+
+ int mathex::getvar(string const &name)
+ // get index of variable
+ // return -1 if not found
+ {
+ unsigned i;
+
+ // look up the table
+ for(i=0;(i<vartable.size()) && strcmp(name.c_str(), vartable[i].name.c_str());i++);
+ if(i<vartable.size()) // if found
+ return i;
+ else
+ return -1;
+ } // getvar
+
+
+ int mathex::getcfunc(string const &name)
+ // get index of one parameter function
+ // return -1 if not found
+ {
+ unsigned i;
+ // look up the constants
+ for(i=NUM_UNARY_OP;cfunctable[i].name && strcmp(name.c_str(), cfunctable[i].name);i++);
+ if(cfunctable[i].name != NULL) // if found
+ return i;
+ else
+ return -1;
+ } // getcfunc
+
+ int mathex::getunaryop(string const &name)
+ // get index of unary operator
+ // return -1 if not found
+ {
+ unsigned i;
+ // look up the constants
+ for(i=0; cfunctable[i].name && strcmp(name.c_str(), cfunctable[i].name);i++);
+ if(cfunctable[i].name != NULL) // if found
+ return i;
+ else
+ return -1;
+ } // getunaryop
+
+ int mathex::getbinop(char name)
+ // get index of one parameter function
+ // return -1 if not found
+ {
+ unsigned i;
+ // look up the constants
+ for(i=0;binoptable[i].name && (name != binoptable[i].name);i++);
+ if(binoptable[i].name != '\0') // if found
+ return i;
+ else
+ return -1;
+ } // getbinop
+
+
+ int mathex::getuserfunc(string const &name)
+ // get index of variable
+ // return -1 if not found
+ {
+ unsigned i;
+ // look up the constants
+ for(i=0;(i<functable.size()) && strcmp(name.c_str(), functable[i].name.c_str());i++);
+ if(i<functable.size()) // if found
+ return i;
+ else
+ return -1;
+ } // getuserfunc
+
+
+ bool mathex::isnewvalidname(string const &name)
+ // Name validation.
+ {
+ if(name.empty() || (!isalpha(name[0]) && (name[0] != '_')))
+ return false;
+ // check for rest of characters
+ for(unsigned j=0; j<name.size(); j++)
+ if(!isalnum(name[j]) && (name[j] != '-'))
+ return false;
+ return (getcfunc(name) < 0) && (getconst(name) < 0)
+ && (getuserfunc(name) < 0) && (getvar(name) < 0);
+ } // isnewvalidname
+
+
+ //////////////////
+ // Evaluation
+
+ // main evaluator: internal use only
+
+ // main evaluation function
+ double mathex::eval()
+ // Eval the parsed stack and return
+ {
+ static vector <double> x; // suppose that eval does not eval
+ evalstack.clear();
+
+ if(status == notparsed) parse();
+ if(status == invalid) throw error("eval()", "invalid expression");
+
+ for(unsigned i=0; i<bytecode.size(); i++)
+ {
+ switch(bytecode[i].state) {
+ case CODETOKEN::VALUE: evalstack.push_back(bytecode[i].value);
+ break;
+ case CODETOKEN::VARIABLE:
+ // get value of variable as value
+ evalstack.push_back(*vartable[bytecode[i].idx].var);
+ break;
+ case CODETOKEN::FUNCTION: // Call the C internal functions with one parameter
+ #ifdef _DEBUG_
+ if(evalstack.size()<1) // error: It does not to occur if currect parsed.
+ throw error("eval()", "stack error");
+ #endif
+ evalstack.back() = cfunctable[bytecode[i].idx].f(evalstack.back());
+ break;
+ case CODETOKEN::BINOP: // Call the intern C function with two parameters
+ #ifdef _DEBUG_
+ if(evalstack.size() < 2) // error: It does not to occur if currect parsed.
+ throw error("eval()", "stack error");
+ #endif
+ evalstack[evalstack.size()-2] = binoptable[bytecode[i].idx].f
+ (evalstack[evalstack.size()-2], evalstack.back());
+ evalstack.pop_back(); // delete last
+ break;
+ case CODETOKEN::USERFUNC: // Call the user defined functions
+ #ifdef _DEBUG_
+ if(bytecode[i].numargs > evalstack.size())
+ throw error("eval()", "stack error");
+ #endif
+ if(bytecode[i].numargs > 0) {
+ x.resize(bytecode[i].numargs);
+ for(unsigned j=0; j<static_cast<unsigned>(bytecode[i].numargs); j++)
+ x[bytecode[i].numargs-1-j] = evalstack[evalstack.size()-1-j];
+ evalstack.resize(evalstack.size()-bytecode[i].numargs+1);
+
+ evalstack.back() = functable[bytecode[i].idx].f(x);
+ }
+ else // Fixing bug pointed by Hugh Denman <denmanh at tcd.ie> November 06, 2003
+ evalstack.push_back(functable[bytecode[i].idx].f(x));
+ break;
+ default: // invarid stack. It does not occur if currect parsed
+ throw error("eval()", "invalid code token");
+ }
+ } // for(i=0; ByteCode[i].state != EMPTY;i++);
+
+ #ifdef _DEBUG_
+ if(evalstack.size() != 1)
+ throw error("eval()", "stack error");
+ #endif
+ return evalstack[0];
+ } // eval()
+
+ /////////////////
+ // parser
+ //---------------
+
+ /////////////////
+ // get the token
+
+ // get the number token
+ bool mathex::getnumber(double &x)
+ {
+ unsigned long i = pos;
+ bool decimal;
+
+ // is a number?
+ if((i >= expr.size()) || !strchr("0123456789.", expr[i])) // not a number
+ return false;
+
+ // getting the number
+ for(decimal=false; i<expr.size(); i++) {
+ if(!isdigit(expr[i]) && ((expr[i] != '.') || decimal) )
+ break;
+ if(expr[i] == '.') decimal = true;
+ }
+
+ if((i==(pos+1)) && (expr[i]=='.')) // is not a number
+ return false;
+
+ // if scientific notation
+ if((toupper(expr[i])=='E') && (i<expr.size())) { // cientific notation
+ // decimal = true; // turn on to detect that are double
+ i++; // skip this
+ if((i<expr.size()) && ((expr[i]=='+') || (expr[i]=='-')) ) { // if sign
+ i++;
+ }
+ // get the expoent
+ while((i<expr.size()) && isdigit(expr[i]))
+ i++;
+ }
+ // now, copy the token and conter to number
+ // if decimal is true, the number is double. otherwise, number is integer
+ // for this detection, cientific notation need to enable decimal too.
+ // The integer value are not used for this package
+
+ x = strtod(expr.substr(pos, i-pos).c_str(), 0);
+ pos = i;
+ return true;
+ } // getnumber()
+
+ bool mathex::getidentifier(string &name)
+ {
+ unsigned i = pos;
+
+ name.erase();
+ if((i>=expr.size()) || (!isalpha(expr[i]) && (expr[i] != '_'))) // not a identifier
+ return false;
+
+ // identifier
+ for(;(i<expr.size()) &&(isalnum(expr[i]) || (expr[i] == '_')); i++);
+
+ name = expr.substr(pos, i-pos);
+ pos = i; // advance the input
+
+ return true;
+ } // getidentifier()
+
+
+ mathex::PARSERTOKEN::type mathex::nexttoken()
+ // Gets the next token from the expr
+ {
+ string identifier;
+
+ while((pos<expr.size()) && isspace(expr[pos]) )
+ pos++;
+
+ if(pos == expr.size()) {
+ curtok.state = PARSERTOKEN::END;
+ return curtok.state;
+ }
+
+ if(getnumber(curtok.value)) {
+ curtok.state = PARSERTOKEN::VALUE;
+ return curtok.state;
+ }
+ else if(getidentifier(identifier)) { // if identifier
+ // checking the identifier type
+ if((curtok.idx = getcfunc(identifier))>=0) // internal C functions
+ curtok.state = PARSERTOKEN::FUNCTION;
+ else if((curtok.idx=getuserfunc(identifier))>=0) { // user defined functions
+ curtok.numargs = functable[curtok.idx].numargs;
+ curtok.state = PARSERTOKEN::USERFUNC;
+ }
+ else if((curtok.idx=getvar(identifier))>=0) // variable
+ curtok.state = PARSERTOKEN::VARIABLE;
+ else if((curtok.idx=getconst(identifier))>=0) { // constant are treated as NUMBER
+ curtok.state = PARSERTOKEN::VALUE;
+ curtok.value = consttable[curtok.idx].value;
+ }
+ else { // new identifier: not supported
+ curtok.state = PARSERTOKEN::INVALID;
+ }
+ }
+ else { // will be operators or delimiters
+ switch(expr[pos]) {
+ case '+' : curtok.state = PARSERTOKEN::PLUS;
+ break;
+ case '-' : curtok.state = PARSERTOKEN::MINUS;
+ break;
+ case '*' : curtok.state = PARSERTOKEN::TIMES;
+ break;
+ case '/' : curtok.state = PARSERTOKEN::DIVIDE;
+ break;
+ case '%' : curtok.state = PARSERTOKEN::MODULE;
+ break;
+ case '^' : curtok.state = PARSERTOKEN::POWER;
+ break;
+ case ',' : curtok.state = PARSERTOKEN::COMMA;
+ break;
+ case '(' : curtok.state = PARSERTOKEN::OPAREN;
+ break;
+ case ')' : curtok.state = PARSERTOKEN::CPAREN;
+ break;
+ default : curtok.state = PARSERTOKEN::INVALID;
+ } // switch
+ if(curtok.state != PARSERTOKEN::INVALID) {
+ curtok.idx = getbinop(expr[pos]);
+ pos++;
+ }
+ } // else
+
+ return curtok.state;
+ } // nexttoken()
+
+ ////////////////////////////
+ // CodeStack operations
+ ////////////////////////////
+ #ifdef _DEBUG_
+ void mathex::printcoderec(CODETOKEN const &token)
+ // print the Code Stack status
+ {
+ switch(token.state) {
+ // case CODETOKEN::EMPTY: cout << "EMPTY\n";
+ // break;
+ case CODETOKEN::VALUE:
+ cout << "VALUE: " << token.value << endl;
+ break;
+ case CODETOKEN::VARIABLE:
+ cout << "VARIABLE: " << vartable[token.idx].name << endl;
+ break;
+ case CODETOKEN::FUNCTION:
+ if(token.idx <NUM_UNARY_OP)
+ cout << "unary operator: " << cfunctable[token.idx].name << endl;
+ else
+ cout << "FUNCTION: " << cfunctable[token.idx].name << endl;
+ break;
+ case CODETOKEN::BINOP:
+ cout << "binary operator: " << binoptable[token.idx].name << endl;
+ break;
+ case CODETOKEN::USERFUNC:
+ cout << "USERFUNC: " << functable[token.idx].name << endl;
+ break;
+ default: printf("INVALID\n");
+ }
+
+ } // printcoderec()
+
+ void mathex::printbytecode()
+ {
+ cout << "codesize = "<< bytecode.size() << endl;
+ for(unsigned i=0; i<bytecode.size(); i++)
+ printcoderec(bytecode[i]);
+ }
+ #endif
+
+ void mathex::parse()
+ // Parse the expression
+ {
+ // parserstatus = true;
+ bytecode.clear();
+ status = invalid;
+ pos=0;
+ nexttoken();
+ parsearithmetic1();
+ #ifdef _DEBUG_
+ printbytecode();
+ #endif
+ if(curtok.state != PARSERTOKEN::END) // if remain token
+ throw error("parse()", "End of expression expected");
+ status = parsed;
+ } // parse()
+
+ void mathex::parsearithmetic1(void)
+ // level 1 arithmetic operator: binary plus/minus
+ {
+ unsigned savedidx;
+ parsearithmetic2();
+ while((curtok.state == PARSERTOKEN::PLUS) || (curtok.state == PARSERTOKEN::MINUS)) {
+ savedidx = curtok.idx;
+ nexttoken();
+ if((curtok.state == PARSERTOKEN::PLUS) || (curtok.state == PARSERTOKEN::MINUS))
+ throw error("parse()", "Invalid expression");
+ parsearithmetic2();
+ bytecode.push_back(CODETOKEN(CODETOKEN::BINOP, savedidx));
+ } // while
+ } // parsearithmetic1
+
+
+ void mathex::parsearithmetic2(void)
+ // level 2 arithmetic operator: multiplication, division, module
+ {
+ unsigned savedidx;
+ parsearithmetic3();
+ while( (curtok.state == PARSERTOKEN::TIMES) || (curtok.state == PARSERTOKEN::DIVIDE)
+ || (curtok.state == PARSERTOKEN::MODULE) ) {
+ savedidx = curtok.idx;
+ nexttoken();
+ if((curtok.state == PARSERTOKEN::PLUS) || (curtok.state == PARSERTOKEN::MINUS))
+ throw error("parse()", "Invalid expression");
+ parsearithmetic3();
+ bytecode.push_back(CODETOKEN(CODETOKEN::BINOP, savedidx));
+ }
+ } // parsearithmetic3
+
+ void mathex::parsearithmetic3(void)
+ // level 3 arithmetic operator: power
+ {
+ unsigned savedidx;
+ parsearithmetic4();
+ if(curtok.state == PARSERTOKEN::POWER) {
+ savedidx = curtok.idx;
+ nexttoken();
+ if((curtok.state == PARSERTOKEN::PLUS) || (curtok.state == PARSERTOKEN::MINUS))
+ throw error("parse()", "Invalid expression");
+ parsearithmetic4();
+ bytecode.push_back(CODETOKEN(CODETOKEN::BINOP, savedidx));
+ }
+ } // parsearithmetic3()
+
+ void mathex::parsearithmetic4(void)
+ // level 4 arithmetic operator: unary plus/minus
+ {
+ PARSERTOKEN::type state;
+ if(((state=curtok.state) == PARSERTOKEN::PLUS) || (state == PARSERTOKEN::MINUS))
+ nexttoken();
+ if((curtok.state == PARSERTOKEN::PLUS) || (curtok.state == PARSERTOKEN::MINUS))
+ throw error("parse()", "Invalid expression");
+ parseatom();
+
+ if(state == PARSERTOKEN::MINUS) // stored index are for binary operator. Get correct index
+ bytecode.push_back(CODETOKEN(CODETOKEN::FUNCTION, getunaryop("-")));
+ // unary minus are on function table
+ } // parsearithmetic5()
+
+ void mathex::parseatom(void)
+ // level 6: literal numbers, variables and functions
+ {
+ unsigned i;
+
+ // parentesis expression
+ if(curtok.state == PARSERTOKEN::OPAREN) {
+ nexttoken();
+ if(curtok.state == PARSERTOKEN::CPAREN)
+ throw error("parseatom()", "No expression inside parentesis");
+ parsearithmetic1();
+
+ if(curtok.state != PARSERTOKEN::CPAREN)
+ throw error("parseatom()", "\")\" expected");
+ nexttoken(); // Added by Hugh Denman (<denmanh at tcd.ie> or hdenman at cantab.net) Oct/03/2003
+ }
+ // Number
+ else if(curtok.state == PARSERTOKEN::VALUE) { // numbers
+ bytecode.push_back(CODETOKEN(curtok.value));
+ nexttoken();
+ }
+ // variables
+ else if(curtok.state == PARSERTOKEN::VARIABLE) { // variables
+ bytecode.push_back(CODETOKEN(CODETOKEN::VARIABLE, curtok.idx));
+ nexttoken();
+ }
+ // internal C function with one parameters
+ else if(curtok.state == PARSERTOKEN::FUNCTION) { // one parameter C functions
+ parserstack.push_back(curtok);
+ nexttoken();
+ if(curtok.state != PARSERTOKEN::OPAREN)
+ throw error("parseatom()", "\"(\" expected");
+ nexttoken();
+ if(curtok.state == PARSERTOKEN::CPAREN)
+ throw error("parseatom()", "invalid number of arguments");
+ parsearithmetic1();
+ if(curtok.state != PARSERTOKEN::CPAREN)
+ throw error("parseatom()", "\")\" expected");
+ curtok = parserstack.back();
+ parserstack.pop_back();
+ bytecode.push_back(CODETOKEN(CODETOKEN::FUNCTION, curtok.idx));
+ nexttoken();
+ }
+ // user defined functions
+ else if(curtok.state == PARSERTOKEN::USERFUNC) { // user defined function
+ parserstack.push_back(curtok);
+ nexttoken();
+ if(curtok.state != PARSERTOKEN::OPAREN)
+ throw error("parseatom()", "\"(\" expected");
+ nexttoken();
+ if(curtok.state == PARSERTOKEN::CPAREN)
+ i = 0;
+ else { // arguments exist
+ parsearithmetic1();
+ i = 1;
+ // while(parserstatus && (curtok.state != PARSERTOKEN::END)
+ // &&(curtok.state != PARSERTOKEN::CPAREN)) {
+ while((curtok.state != PARSERTOKEN::END) && (curtok.state != PARSERTOKEN::CPAREN)) {
+ if(curtok.state == PARSERTOKEN::COMMA) {
+ nexttoken();
+ i++;
+ }
+ else
+ throw error("parseatom()", "unknow error");
+ parsearithmetic1();
+ } // while
+ if(curtok.state != PARSERTOKEN::CPAREN)
+ throw error("parseatom()", "\")\" expected");
+ } // else
+ curtok = parserstack.back();
+ parserstack.pop_back();
+
+ if ((curtok.numargs != UNDEFARGS) && (i != static_cast<unsigned>(curtok.numargs)))
+ // i is current number of parameters
+ throw error("parseatom()", "invalid number of arguments");
+
+ // number of parameters is correct. Now, put the function
+ // i is number of arguments
+ bytecode.push_back(CODETOKEN(CODETOKEN::USERFUNC, curtok.idx, i));
+
+ nexttoken();
+ } // user defined functions
+ // End of buffer
+ else if (curtok.state == PARSERTOKEN::END)
+ throw error("parseatom()", "unexpected end of expression");
+ // invalid
+ else if (curtok.state == PARSERTOKEN::INVALID)
+ throw error("parseatom()", "invalid token on expression");
+ // unknow error
+ else // it not occur
+ throw error("parseatom()", "unknow error");
+ } // parseatom()
+
+
+
+ } // namespace smlib {
+
+
+// end of mathex.c
diff --git a/Contrib/mathex/mathex.h b/Contrib/mathex/mathex.h
new file mode 100644
index 0000000..56e9029
--- /dev/null
+++ b/Contrib/mathex/mathex.h
@@ -0,0 +1,270 @@
+///////////////////////////////////////////////////////////////////////////
+// mathex 0.2.3 (beta) - Copyright (C) 2000-2003, by Sadao Massago //
+// file: mathex.h (math expression evaluator header file) //
+// requires: none //
+// project web page: http://sscilib.sourceforge.net/ //
+//-----------------------------------------------------------------------//
+// The mathex library and related files is licensed under the term of //
+// GNU LGPL (Lesser General Public License) version 2.1 or latter //
+// with exceptions that allow for static linking. //
+// See license.txt for detail. //
+// For GNU LGPL, see lesser.txt. //
+// For information over GNU or GNU compatible license, visit the site //
+// http://www.gnu.org. //
+////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////
+// references:
+//-------------------------------------------------------------------------
+// title: Algoritms and Data Structures
+// author: Niklaus Wirth
+// publisher: Prentice-Hall
+// year: 1989
+//-------------------------------------------------------------------------
+// title: The C++ programming language
+// edition: thrird
+// author: Bjarne Stroustrup
+// publisher: Addilson-Wesley
+// year: 1997
+//-------------------------------------------------------------------------
+// title: building your own C interpreter
+// author: Schildt, Helbert
+// journal: Dr. Dobb's Jornal (http://www.ddj.com)
+// number: August/1989
+// pages: 38-49, 110-122
+///////////////////////////////////////////////////////////////////////////
+
+// example file listing for doxygen
+
+/// \example inttest.cpp
+/// integration test using Trapezoidal rule
+
+/// \example userfunctest.cpp
+/// user defined function testing
+
+/// \example tabletest.cpp
+/// making table of function
+
+/// \example curvetest.cpp
+/// making table of parametric curve
+
+// #define _DEBUG_
+
+#ifndef _MATHEX_H
+ #define _MATHEX_H
+
+#include <string>
+#include <vector>
+#include <cmath>
+// #include <cctype>
+// debug purpose
+#ifdef _DEBUG_
+ #include <iostream>
+#endif
+
+namespace smlib {
+
+using namespace std;
+
+/////////////////////////////////////
+// mathex main class
+// it contain several sub classes
+// to handle expressions
+/////////////////////////////////////
+
+ class mathex {
+ /////////////////////////
+ // private sub calsses
+ ////////////////////////
+
+ // code token used by evaluator
+ class CODETOKEN {
+ public:
+ // token type (code token type)
+ enum type {
+ VALUE=0, // numerical value stack
+ VARIABLE, // variable stack
+ FUNCTION, // internal C function with one parameters (include unary operators)
+ BINOP, // internal C binary opeartors (function with two parameters)
+ USERFUNC, // user defined functions
+ LASTTYPE=USERFUNC};
+
+ type state; // state of Token
+ unsigned numargs;
+ // The user defined function use it to pop values from stack
+ // In the undefined number of arguments case, it will not eliminated
+ double value; // numerical value
+ unsigned idx; // index of variable, function or user defined function on table
+ CODETOKEN(double x=0.0) // construct VALUE token
+ {
+ state = VALUE;
+ value = x;
+ }
+ CODETOKEN(type toktype, unsigned index, unsigned NumArgs=1) // construct token except VALUE
+ // in the used defined function case, num args need to set
+ {
+ state = toktype;
+ idx = index;
+ numargs = NumArgs;
+ }
+ }; // CODETOKEN
+
+ // parse token used by parser
+ class PARSERTOKEN {
+ public:
+ enum type {
+ VALUE, VARIABLE, FUNCTION, USERFUNC,
+ PLUS, MINUS, TIMES, DIVIDE, MODULE, POWER,
+ OPAREN, CPAREN, COMMA, END, INVALID, // invalid character on token
+ LASTTYPE=INVALID
+ };
+
+ type state;
+ int numargs; // number of parameters of functions
+ double value;
+ int idx; // it are signed because receive func/var search index that will be -1
+ // atom parsing cede optimization
+ }; // parsetoken
+
+
+ // function record
+
+ // Record for user defined functions
+ class FUNCREC {
+ public:
+ string name;
+ double (*f)(vector<double> const &x); // generic number of parameters
+ int numargs; // number of arguments
+ FUNCREC() // only for table (vector) operation
+ {name = ""; f = 0;}
+ FUNCREC(string const &funcname, double (*func)(vector<double> const &), int NumArgs)
+ {name = funcname; f = func; numargs = NumArgs; }
+ }; // FUNCREC
+
+
+ // variable record
+ class VARREC {
+ public:
+ string name;
+ double *var;
+ VARREC()
+ {name = ""; var = 0;}
+ VARREC(string const &varname, double *x)
+ {
+ if(x == NULL) throw error("Error [VARREC()]: variable without reference");
+ name = varname; var = x; }
+ }; // VARREC
+
+ /////////////////////
+ // evalmath start here
+ /////////////////////
+
+ vector<FUNCREC> functable; // used defined function table
+ vector<VARREC> vartable; // used defined variable table
+ vector<CODETOKEN> bytecode; // parsed code
+ vector<double> evalstack; // stack memory used by evaluator
+ string expr; // expression string
+ enum {invalid, notparsed, parsed} status; // prse status
+
+ // used by addvar/addfunc to validate new variable/functions name
+ bool isnewvalidname(string const &name); // check if new valid name
+
+ // table look up
+ int getconst(string const &name); // get index of constant
+ int getvar(string const &name); // get index of variable
+ int getcfunc(string const &name); // get index of one parameter internal C function
+ int getunaryop(string const &name); // get index of unary operator
+ int getbinop(char name); // get index of binary operator
+ int getuserfunc(string const &name); // get index of user defined functions
+ void addstdfunc(); // add standard user defined functions to table
+
+ // token operators
+ bool getnumber(double &x); // get number from input string
+ bool getidentifier(string &name); // get identifier from input string
+ PARSERTOKEN::type nexttoken(); // get next token from input string
+ vector<PARSERTOKEN> parserstack; // stack used by parser
+ PARSERTOKEN curtok; // current token. Used by parser
+ unsigned long pos; // expression parsing position
+
+ #ifdef _DEBUG_
+ void printcoderec(CODETOKEN const &token); // used by printbytecode()
+ #endif
+ // parser methods
+ // aritmethic operators
+ void parsearithmetic1(void); // binary plus/minus
+ void parsearithmetic2(void); // timed, divide, modulo
+ void parsearithmetic3(void); // power
+ void parsearithmetic4(void); // unary minus
+ void parseatom(void); // atom: functions, variables, numbers...
+
+ public:
+ ///////////////////////
+ // public sub classes
+ ///////////////////////
+
+ /// error class to hamdle exceptions
+ class error : public std::exception {
+ private:
+ string msg;
+ public:
+ /// with message only
+ error(string const &message)
+ { msg = "Error [eval]: " + message; }
+ /// error with identifier and messages
+ error(string const &id, string const &message)
+ { msg = "Error [mathex::" + id + "]: " + message; }
+ /// unkone error
+ error()
+ { msg = "Error [mathex]: unkonw error"; }
+ /// return error message
+ const char * what() const throw()
+ {
+ return msg.c_str(); }
+ ~error() throw() {}
+ }; // error
+
+ ////////////////////////////////////////////////////
+ // mathex public constants, variables and methods
+
+ #ifdef _DEBUG_
+ void printbytecode(); // output byte code to cout
+ #endif
+
+
+ // add/delete variables
+ bool addvar(string const &name, double *x); /// < add new variable
+ bool delvar(string const &name); /// < delete variable
+ void delvar() /// < delete all variables
+ {vartable.clear(); status = notparsed; }
+
+ /// undefined number of arguments (for user defined functions
+ static const int UNDEFARGS; // for user function arguments
+ // add/delete used defined functions
+ bool addfunc(string const &name, double (*f)(vector<double> const &), int NumArgs); /// < add new function
+ bool delfunc(string const &name); /// < delete variable
+ void delfunc() /// < delete all variable
+ {functable.clear(); addstdfunc(); status=notparsed; }
+ // expression string
+ string const &expression() /// < return expression string
+ {
+ return expr;}
+ void expression(string const &formula) /// < set expression string
+ { expr = formula; status = notparsed; pos=0; }
+ unsigned long stopposition() /// < return parser stoped position
+ {
+ return pos; }
+ void parse(); /// < parse expression
+ double eval(); /// < eval expression
+ void reset(); /// < reset all
+ mathex() /// < default constructor
+ {reset();}
+ mathex(string const &formula) /// < constructor that assign expression string
+ {reset(); expr = formula;}
+ }; /// mathex
+
+
+} // namespace smlib {
+
+#endif // #ifndef _MATHEX_H
+
+// end of mathex.c
diff --git a/Copyright.txt b/Copyright.txt
new file mode 100644
index 0000000..9ffb9ac
--- /dev/null
+++ b/Copyright.txt
@@ -0,0 +1,33 @@
+MAdLib: Mesh Adaptation Library
+Version: 1.0
+
+Copyright (C) 2008-2009 Universite catholique de Louvain, Belgium,
+<http://www.uclouvain.be>. All Rights Reserved.
+
+This program 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 3 of the
+License, or (at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program (License.txt). If not, see <http://www.gnu.org/licenses/>.
+
+Disclaimer
+----------
+The Universite catholique de Louvain and the authors make no
+representations about the suitability or fitness of this software
+for any purpose. It is provided "as is" without express or implied
+warranty.
+
+Report all bugs and problems to <contrib at madlib.be>
+Web site: http://www.madlib.be
+
+Authors
+-------
+
+See Credits.txt
diff --git a/Credits.txt b/Credits.txt
new file mode 100644
index 0000000..20fb364
--- /dev/null
+++ b/Credits.txt
@@ -0,0 +1,37 @@
+ MAdLib is copyright (C) 2008-2009
+
+ Universite catholique de Louvain
+ <http://www.uclouvain.be>
+
+The main authors are Gaetan Compere and Jean-Francois Remacle.
+
+Gaetan Compere
+Departement of Civil Engineering
+Universite catholique de Louvain
+Avenue Georges Lemaitre 4, 1348 Louvain-la-Neuve, Belgium
+gaetan.compere at uclouvain.be
+
+Jean-Francois Remacle
+Departement of Civil Engineering
+Universite catholique de Louvain
+Avenue Georges Lemaitre 4, 1348 Louvain-la-Neuve, Belgium
+jean-francois.remacle at uclouvain.be
+
+Major code contributions have been provided by Cecile Dobrzynski
+(parallel adaptation and periodic meshes) and Koen Hillewaert
+(high order elements and a lot of testing and bug reports/fixes).
+
+Other code contributors include: Arnaud Francois (edge swap operator),
+Olivier Pierard (DESC, edge split and face collapse operators),
+Richard Comblen (PETSc interface), Josue Barboza (parallel adaptation
+testing and debugging), Jonathan Lambrechts (bug fixes) and Paul-Emile
+Bernard (bug fixes).
+
+This version of MAdLib may contain code (in the Contrib/gmm
+subdirectory) copyright (C) 2002-2008 Yves Renard: check the
+configuration options.
+
+This version of MAdLib may contain code (in the Contrib/mathex
+subdirectory) copyright (C) 2000-2003 Sadao Massago: check the
+configuration options.
+
diff --git a/Geo/GM_Iterators.h b/Geo/GM_Iterators.h
new file mode 100644
index 0000000..7b63181
--- /dev/null
+++ b/Geo/GM_Iterators.h
@@ -0,0 +1,125 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_GM_ITERATORS
+#define _H_GM_ITERATORS
+
+#include "ModelInterface.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class GM_RegionIterator {
+
+ private:
+ MAdModel * model;
+ MAdModel::riter iter;
+
+ public:
+ GM_RegionIterator(MAdModel * _model):
+ model(_model)
+ { iter = model->firstRegion(); }
+ GM_RegionIterator(const GM_RegionIterator& it):
+ model(it.model),iter(it.iter) {}
+ ~GM_RegionIterator() {}
+
+ void reset() { iter = model->firstRegion(); }
+ MAdGRegion * next()
+ {
+ if ( iter == model->lastRegion() ) return NULL;
+ MAdGRegion * res = *iter;
+ iter++;
+ return res;
+ }
+ };
+
+ // -------------------------------------------------------------------
+ class GM_FaceIterator {
+
+ private:
+ MAdModel * model;
+ MAdModel::fiter iter;
+
+ public:
+ GM_FaceIterator(MAdModel * _model):
+ model(_model)
+ { iter = model->firstFace(); }
+ GM_FaceIterator(const GM_FaceIterator& it):
+ model(it.model),iter(it.iter) {}
+ ~GM_FaceIterator() {}
+
+ void reset() { iter = model->firstFace(); }
+ MAdGFace * next()
+ {
+ if ( iter == model->lastFace() ) return NULL;
+ MAdGFace * res = *iter;
+ iter++;
+ return res;
+ }
+ };
+
+ // -------------------------------------------------------------------
+ class GM_EdgeIterator {
+
+ private:
+ MAdModel * model;
+ MAdModel::eiter iter;
+
+ public:
+ GM_EdgeIterator(MAdModel * _model):
+ model(_model)
+ { iter = model->firstEdge(); }
+ GM_EdgeIterator(const GM_EdgeIterator& it):
+ model(it.model),iter(it.iter) {}
+ ~GM_EdgeIterator() {}
+
+ void reset() { iter = model->firstEdge(); }
+ MAdGEdge * next()
+ {
+ if ( iter == model->lastEdge() ) return NULL;
+ MAdGEdge * res = *iter;
+ iter++;
+ return res;
+ }
+ };
+
+ // -------------------------------------------------------------------
+ class GM_VertexIterator {
+
+ private:
+ MAdModel * model;
+ MAdModel::viter iter;
+
+ public:
+ GM_VertexIterator(MAdModel * _model):
+ model(_model)
+ { iter = model->firstVertex(); }
+ GM_VertexIterator(const GM_VertexIterator& it):
+ model(it.model),iter(it.iter) {}
+ ~GM_VertexIterator() {}
+
+ void reset() { iter = model->firstVertex(); }
+ MAdGVertex * next()
+ {
+ if ( iter == model->lastVertex() ) return NULL;
+ MAdGVertex * res = *iter;
+ iter++;
+ return res;
+ }
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Geo/GmshEntities.h b/Geo/GmshEntities.h
new file mode 100644
index 0000000..96c2ded
--- /dev/null
+++ b/Geo/GmshEntities.h
@@ -0,0 +1,34 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_MAD_GMSHENTITIES
+#define _H_MAD_GMSHENTITIES
+
+#ifdef _HAVE_GMSH_
+
+#include "gmsh/GEntity.h"
+
+namespace MAd {
+
+ typedef class GEntity MAdGEntity;
+ typedef class GEntityLessThan MAdGEntityLessThan;
+ typedef class GRegion MAdGRegion;
+ typedef class GFace MAdGFace;
+ typedef class GEdge MAdGEdge;
+ typedef class GVertex MAdGVertex;
+
+}
+
+#endif
+
+#endif
diff --git a/Geo/GmshModel.cc b/Geo/GmshModel.cc
new file mode 100644
index 0000000..74d754a
--- /dev/null
+++ b/Geo/GmshModel.cc
@@ -0,0 +1,82 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_GMSH_
+
+#include "GmshModel.h"
+
+#include "gmsh/discreteRegion.h"
+#include "gmsh/discreteFace.h"
+#include "gmsh/discreteEdge.h"
+#include "gmsh/discreteVertex.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ MAdGEntity * GmshModel::getEntityByTag(int dim, int tag)
+ {
+ switch(dim) {
+ case 3: return getRegionByTag(tag);
+ case 2: return getFaceByTag(tag);
+ case 1: return getEdgeByTag(tag);
+ case 0: return getVertexByTag(tag);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ MAdGRegion * GmshModel::getRegionByTag(int tag)
+ {
+ GRegion * pGR = model->getRegionByTag(tag);
+ if ( !pGR ) {
+ pGR = new discreteRegion(model,tag);
+ model->add(pGR);
+ }
+ return pGR;
+ }
+
+ // -------------------------------------------------------------------
+ MAdGFace * GmshModel::getFaceByTag(int tag)
+ {
+ GFace * pGF = model->getFaceByTag(tag);
+ if ( !pGF ) {
+ pGF = new discreteFace(model,tag);
+ model->add(pGF);
+ }
+ return pGF;
+ }
+
+ // -------------------------------------------------------------------
+ MAdGEdge * GmshModel::getEdgeByTag(int tag)
+ {
+ GEdge * pGE = model->getEdgeByTag(tag);
+ if ( !pGE ) {
+ pGE = new discreteEdge(model,tag,NULL,NULL);
+ model->add(pGE);
+ }
+ return pGE;
+ }
+
+ // -------------------------------------------------------------------
+ MAdGVertex * GmshModel::getVertexByTag(int tag)
+ {
+ GVertex * pGV = model->getVertexByTag(tag);
+ if ( !pGV ) {
+ pGV = new discreteVertex(model,tag);
+ model->add(pGV);
+ }
+ return pGV;
+ }
+
+ // -------------------------------------------------------------------
+}
+
+#endif
diff --git a/Geo/GmshModel.h b/Geo/GmshModel.h
new file mode 100644
index 0000000..63a6f40
--- /dev/null
+++ b/Geo/GmshModel.h
@@ -0,0 +1,90 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_GMSHMODEL
+#define _H_GMSHMODEL
+
+#ifdef _HAVE_GMSH_
+
+#include "MAdModel.h"
+#include "GmshEntities.h"
+
+#include "gmsh/GModel.h"
+#include <list>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class GmshModel : public MAdModel {
+
+ public:
+
+ GmshModel(std::string name=""):
+ MAdModel(name)
+ {
+ model = new GModel(_name);
+ GModel::current(GModel::list.size() - 1);
+ }
+ ~GmshModel() { if (model) delete model; }
+
+ ModelType type() const { return GMSHMODEL; }
+
+ // Gmsh mesh file format
+ int readMSH(const std::string &filename) { return model->readMSH(filename); }
+
+ // Gmsh native CAD format
+ int readGEO(const std::string &filename) { return model->readGEO(filename); }
+ int writeGEO(const std::string &filename) { return model->writeGEO(filename); }
+
+ // OCC formats
+ int readSTEP(const std::string &filename) { return model->readOCCSTEP(filename); }
+ int readBREP(const std::string &filename) { return model->readOCCBREP(filename); }
+ int readIGES(const std::string &filename) { return model->readOCCIGES(filename); }
+
+ GModel * getModel() { return model; }
+
+ // get the number of entities in this model
+ int getNumRegions() const { return model->getNumRegions(); }
+ int getNumFaces() const { return model->getNumFaces(); }
+ int getNumEdges() const { return model->getNumEdges(); }
+ int getNumVertices() const { return model->getNumVertices(); }
+
+ // find the entity with the given tag and create it if not found
+ MAdGEntity * getEntityByTag(int dim, int tag);
+ MAdGRegion * getRegionByTag(int);
+ MAdGFace * getFaceByTag (int);
+ MAdGEdge * getEdgeByTag (int);
+ MAdGVertex * getVertexByTag(int);
+
+ // get an iterator initialized to the first/last entity in this model.
+ riter firstRegion() { return model->firstRegion(); }
+ fiter firstFace() { return model->firstFace(); }
+ eiter firstEdge() { return model->firstEdge(); }
+ viter firstVertex() { return model->firstVertex(); }
+ riter lastRegion() { return model->lastRegion(); }
+ fiter lastFace() { return model->lastFace(); }
+ eiter lastEdge() { return model->lastEdge(); }
+ viter lastVertex() { return model->lastVertex(); }
+
+ private:
+ GModel * model;
+
+ };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
+
+#endif
diff --git a/Geo/MAdModel.h b/Geo/MAdModel.h
new file mode 100644
index 0000000..2027fd7
--- /dev/null
+++ b/Geo/MAdModel.h
@@ -0,0 +1,91 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_MADMODEL
+#define _H_MADMODEL
+
+#ifdef _HAVE_GMSH_
+#include "GmshEntities.h"
+#else
+#include "NullEntities.h"
+#endif
+#include <string>
+#include <set>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ enum ModelType {
+ NULLMODEL,
+ GMSHMODEL
+ };
+
+ // -------------------------------------------------------------------
+ class MAdModel {
+
+ public:
+
+ MAdModel(std::string name="") { _name = name; }
+ virtual ~MAdModel() {};
+
+ virtual ModelType type() const = 0;
+
+ // Gmsh mesh file format
+ virtual int readMSH(const std::string &name) = 0;
+
+ // Gmsh native CAD format
+ virtual int readGEO(const std::string &name) = 0;
+ virtual int writeGEO(const std::string &name) = 0;
+
+ // OCC formats
+ virtual int readSTEP(const std::string &name) = 0;
+ virtual int readBREP(const std::string &name) = 0;
+ virtual int readIGES(const std::string &name) = 0;
+
+ // get the number of entities in this model
+ virtual int getNumRegions() const = 0;
+ virtual int getNumFaces() const = 0;
+ virtual int getNumEdges() const = 0;
+ virtual int getNumVertices() const = 0;
+
+ // find the entity with the given tag and create it if not found
+ virtual MAdGEntity * getEntityByTag(int dim, int tag) = 0;
+ virtual MAdGRegion * getRegionByTag(int) = 0;
+ virtual MAdGFace * getFaceByTag (int) = 0;
+ virtual MAdGEdge * getEdgeByTag (int) = 0;
+ virtual MAdGVertex * getVertexByTag(int) = 0;
+
+ typedef std::set<MAdGRegion*, MAdGEntityLessThan>::iterator riter;
+ typedef std::set<MAdGFace*, MAdGEntityLessThan>::iterator fiter;
+ typedef std::set<MAdGEdge*, MAdGEntityLessThan>::iterator eiter;
+ typedef std::set<MAdGVertex*, MAdGEntityLessThan>::iterator viter;
+
+ // get an iterator initialized to the first/last entity in this model.
+ virtual riter firstRegion() = 0;
+ virtual fiter firstFace() = 0;
+ virtual eiter firstEdge() = 0;
+ virtual viter firstVertex() = 0;
+ virtual riter lastRegion() = 0;
+ virtual fiter lastFace() = 0;
+ virtual eiter lastEdge() = 0;
+ virtual viter lastVertex() = 0;
+
+ protected:
+ std::string _name;
+ };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
diff --git a/Geo/Makefile b/Geo/Makefile
new file mode 100644
index 0000000..7cabadf
--- /dev/null
+++ b/Geo/Makefile
@@ -0,0 +1,53 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../variables
+
+LIB = ../lib/libMAdGeo${LIBEXT}
+
+INC = ${MAdLib_INCLUDES}\
+ ${DASH}I$(MAdROOT)/Geo\
+ ${DASH}I$(MAdROOT)/Mesh\
+ ${DASH}I$(MAdROOT)/Common
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = GmshModel.cc\
+ ModelInterface.cc\
+ NullModel.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${LIB}: ${OBJ}
+ ${AR} ${ARFLAGS} ${LIB} ${OBJ}
+ ${RANLIB} ${LIB}
+
+cpobj: ${OBJ}
+ cp -f ${OBJ} ${MAdLib_TMPDIR}/.
+
+.cc${OBJEXT}:
+ ${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+ ${RM} */*.o *.o *.obj
+
+purge:
+
+depend:
+ (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+ ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+ ) > Makefile.new
+ cp Makefile Makefile.bak
+ cp Makefile.new Makefile
+ rm -f Makefile.new
\ No newline at end of file
diff --git a/Geo/ModelInterface.cc b/Geo/ModelInterface.cc
new file mode 100644
index 0000000..6f13763
--- /dev/null
+++ b/Geo/ModelInterface.cc
@@ -0,0 +1,649 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "ModelInterface.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+#include "MAdDefines.h"
+
+#include <string.h>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void GM_create(pGModel* model, std::string name)
+ {
+ if (*model) delete (*model);
+#ifdef _HAVE_GMSH_
+ *model = new GmshModel(name);
+#else
+ *model = new NullModel(name);
+#endif
+ }
+
+ // -------------------------------------------------------------------
+ void GM_delete(pGModel model)
+ {
+ if (model) { delete model; model=NULL; }
+ }
+
+ // -------------------------------------------------------------------
+ enum GeoFileFormat {
+ FORMAT_MSH,
+ FORMAT_GEO,
+ FORMAT_STEP,
+ FORMAT_BREP,
+ FORMAT_IGES,
+ FORMAT_UNKNOWN
+ };
+
+ // -------------------------------------------------------------------
+ std::vector<std::string> SplitFileName(std::string fileName)
+ {
+ // returns [path, baseName, extension]
+ int idot = fileName.find_last_of('.');
+ int islash = fileName.find_last_of("/\\");
+ if(idot == std::string::npos) idot = -1;
+ if(islash == std::string::npos) islash = -1;
+ std::vector<std::string> s(3);
+ if(idot > 0)
+ s[2] = fileName.substr(idot);
+ if(islash > 0)
+ s[0] = fileName.substr(0, islash + 1);
+ s[1] = fileName.substr(s[0].size(), fileName.size() - s[0].size() - s[2].size());
+ return s;
+ }
+
+ // -------------------------------------------------------------------
+ GeoFileFormat guessFormatFromExtension(const std::string fileName)
+ {
+ std::string ext = SplitFileName(fileName)[2];
+ if ( !strcmp(ext.c_str(),".msh" ) ) return FORMAT_MSH;
+ if ( !strcmp(ext.c_str(),".geo" ) ) return FORMAT_GEO;
+ if ( !strcmp(ext.c_str(),".stp" ) ) return FORMAT_STEP;
+ if ( !strcmp(ext.c_str(),".step") ) return FORMAT_STEP;
+ if ( !strcmp(ext.c_str(),".brep") ) return FORMAT_BREP;
+ if ( !strcmp(ext.c_str(),".iges") ) return FORMAT_IGES;
+ return FORMAT_UNKNOWN;
+ }
+
+ // -------------------------------------------------------------------
+ int GM_read(pGModel model, const std::string fileName)
+ {
+ GeoFileFormat format = guessFormatFromExtension(fileName);
+ if ( format == FORMAT_MSH ) return GM_readFromMSH (model,fileName);
+ if ( format == FORMAT_GEO ) return GM_readFromGEO (model,fileName);
+ if ( format == FORMAT_STEP ) return GM_readFromSTEP(model,fileName);
+ if ( format == FORMAT_BREP ) return GM_readFromBREP(model,fileName);
+ if ( format == FORMAT_IGES ) return GM_readFromIGES(model,fileName);
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Unknown geo file format %d",format);
+ return 0;
+ }
+
+ // -------------------------------------------------------------------
+ int GM_readFromMSH(pGModel model, const std::string name)
+ {
+ return (model->readMSH(name));
+ }
+
+ // -------------------------------------------------------------------
+ int GM_readFromGEO(pGModel model, const std::string name)
+ {
+ return (model->readGEO(name));
+ }
+
+ // -------------------------------------------------------------------
+ int GM_readFromSTEP(pGModel model, const std::string name)
+ {
+ return (model->readSTEP(name));
+ }
+
+ // -------------------------------------------------------------------
+ int GM_readFromBREP(pGModel model, const std::string name)
+ {
+ return (model->readBREP(name));
+ }
+
+ // -------------------------------------------------------------------
+ int GM_readFromIGES(pGModel model, const std::string name)
+ {
+ return (model->readIGES(name));
+ }
+
+ // -------------------------------------------------------------------
+ int GM_writeGEO(pGModel model, const std::string &name)
+ {
+ return (model->writeGEO(name));
+ }
+
+ // -------------------------------------------------------------------
+ pGEntity GM_entityByTag(pGModel model, int dim, int tag)
+ {
+ return model->getEntityByTag(dim,tag);
+ }
+ pGRegion GM_regionByTag(const pGModel model, int tag)
+ {
+ return model->getRegionByTag(tag);
+ }
+ pGFace GM_faceByTag(const pGModel model, int tag)
+ {
+ return model->getFaceByTag(tag);
+ }
+ pGEdge GM_edgeByTag(const pGModel model, int tag)
+ {
+ return model->getEdgeByTag(tag);
+ }
+ pGVertex GM_vertexByTag(const pGModel model, int tag)
+ {
+ return model->getVertexByTag(tag);
+ }
+
+ // -------------------------------------------------------------------
+ int GM_numVertices(const pGModel model)
+ {
+ return model->getNumVertices();
+ }
+ int GM_numEdges(const pGModel model)
+ {
+ return model->getNumEdges();
+ }
+ int GM_numFaces(const pGModel model)
+ {
+ return model->getNumFaces();
+ }
+ int GM_numRegions(const pGModel model)
+ {
+ return model->getNumRegions();
+ }
+
+ // -------------------------------------------------------------------
+ GRIter GM_regionIter(pGModel model)
+ {
+ return new GM_RegionIterator(model);
+ }
+ GFIter GM_faceIter(pGModel model)
+ {
+ return new GM_FaceIterator(model);
+ }
+ GEIter GM_edgeIter(pGModel model)
+ {
+ return new GM_EdgeIterator(model);
+ }
+ GVIter GM_vertexIter(pGModel model)
+ {
+ return new GM_VertexIterator(model);
+ }
+
+ pGRegion GRIter_next(GRIter iter) { return iter->next(); }
+ pGFace GFIter_next(GFIter iter) { return iter->next(); }
+ pGEdge GEIter_next(GEIter iter) { return iter->next(); }
+ pGVertex GVIter_next(GVIter iter) { return iter->next(); }
+
+ void GRIter_delete(GRIter iter) { delete (iter); }
+ void GFIter_delete(GFIter iter) { delete (iter); }
+ void GEIter_delete(GEIter iter) { delete (iter); }
+ void GVIter_delete(GVIter iter) { delete (iter); }
+
+ void GRIter_reset(GRIter iter) { iter->reset(); }
+ void GFIter_reset(GFIter iter) { iter->reset(); }
+ void GEIter_reset(GEIter iter) { iter->reset(); }
+ void GVIter_reset(GVIter iter) { iter->reset(); }
+
+ // -------------------------------------------------------------------
+ int GEN_tag(const pGEntity ent)
+ {
+ return ent->tag();
+ }
+
+ // -------------------------------------------------------------------
+ int GEN_type(const pGEntity ent)
+ {
+ return ent->dim();
+ }
+
+#ifdef _HAVE_GMSH_
+ // -------------------------------------------------------------------
+ std::list<pGEntity> GEN_closure(const pGEntity pGE)
+ {
+ std::list<pGEntity> theList;
+
+ int type = GEN_type(pGE);
+ switch (type) {
+ case 0: break;
+ case 1: {
+ std::list<pGVertex> vList = GE_vertices((pGEdge)pGE);
+ std::list<pGVertex>::const_iterator vIter = vList.begin();
+ for (; vIter != vList.end(); vIter++) {
+ theList.push_back(*vIter);
+ }
+ break;
+ }
+ case 2: {
+ std::list<pGEdge> eList = GF_edges((pGFace)pGE);
+ std::list<pGEdge>::const_iterator eIter = eList.begin();
+ for (; eIter != eList.end(); eIter++) {
+ theList.push_back(*eIter);
+ }
+ break;
+ }
+ case 3: {
+ std::list<pGFace> fList = GR_faces((pGRegion)pGE);
+ std::list<pGFace>::const_iterator fIter = fList.begin();
+ for (; fIter != fList.end(); fIter++) {
+ theList.push_back(*fIter);
+ }
+ break;
+ }
+ }
+
+ return theList;
+ }
+
+ // -------------------------------------------------------------------
+ std::list<pGFace> GR_faces(const pGRegion pGR)
+ {
+ return pGR->faces();
+ }
+
+ // -------------------------------------------------------------------
+ int GF_numRegions(const pGFace f)
+ {
+ return f->numRegions();
+ }
+
+ // -------------------------------------------------------------------
+ std::list<pGEdge> GF_edges(const pGFace pGF)
+ {
+ return pGF->edges();
+ }
+
+ // -------------------------------------------------------------------
+ //! Computes the parameter location of xyz in the surface.
+ //! Returns false if xyz is not in the surface.
+ bool GF_getParams(const pGFace pGF, const double xyz[3],
+ double params[2])
+ {
+ // SPoint2 sP = pGF->parFromPoint(SPoint3(xyz));
+ // params[0] = sP.x();
+ // params[1] = sP.y();
+
+ pGF->XYZtoUV( xyz[0], xyz[1], xyz[2],
+ params[0], params[1], 1.);
+
+ // throw;
+
+ // a test should be done to check that xyz was on the surface
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ //! Computes the coordinates of the point on the surface closest to xyz
+ void GF_closestPoint(const pGFace pGF, const double xyz[3],
+ const double initGuess[2], double xyzOnF[3])
+ {
+ // GPoint gP = pGF->closestPoint( SPoint3(xyz), initGuess );
+ // xyzOnF[0] = gP.x();
+ // xyzOnF[1] = gP.y();
+ // xyzOnF[2] = gP.z();
+ throw;
+ }
+
+ // -------------------------------------------------------------------
+ void GF_xyz(const pGFace pGF, double u, double v, double xyz[3])
+ {
+ GPoint gP = pGF->point(u,v);
+ xyz[0] = gP.x();
+ xyz[1] = gP.y();
+ xyz[2] = gP.z();
+ }
+
+ // -------------------------------------------------------------------
+ //! Gets the curvature of the surface computed as the divergence of its normal
+ //! Result is bounded by cMaxBound. NaN curvatures are turned into cMaxBound.
+ double GF_curvatureDiv(const pGFace surface, const double u[2],
+ double cMaxBound)
+ {
+ SPoint2 param(u[0],u[1]);
+ double curv = surface->curvatureDiv(param);
+ if ( isnan(curv) ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,"NaN curvature");
+ curv = cMaxBound;
+ }
+ return std::min(curv,cMaxBound);
+ }
+
+ // -------------------------------------------------------------------
+ //! Compute the min and max curvatures and the corresponding directions.
+ //! Returns the max curvature.
+ //! Min and max curvatures are bounded by cMaxBound.
+ //! NaN curvatures are turned into cMaxBound.
+ double GF_curvatures(const pGFace surface, const double u[2],
+ double dirMax[3], double dirMin[3],
+ double *curvMax, double *curvMin,
+ double cMaxBound)
+ {
+ SPoint2 param(u[0],u[1]);
+ SVector3 dirMaxTmp = SVector3();
+ SVector3 dirMinTmp = SVector3();
+
+ surface->curvatures(param, &dirMaxTmp, &dirMinTmp, curvMax, curvMin);
+
+ dirMax[0] = dirMaxTmp.x();
+ dirMax[1] = dirMaxTmp.y();
+ dirMax[2] = dirMaxTmp.z();
+ if ( ( dotProd(dirMax,dirMax) <= MAdTOL ) ||
+ ( isnan(dirMax[0]) || isnan(dirMax[1]) || isnan(dirMax[2]) ) )
+ {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "NaN direction for maximum curvature");
+ dirMax[0] = 0.36436431;
+ dirMax[1] = 0.76356436;
+ dirMax[2] = 0.96983673;
+ }
+
+ dirMin[0] = dirMinTmp.x();
+ dirMin[1] = dirMinTmp.y();
+ dirMin[2] = dirMinTmp.z();
+ if ( ( dotProd(dirMin,dirMin) <= MAdTOL ) ||
+ ( isnan(dirMin[0]) || isnan(dirMin[1]) || isnan(dirMin[2]) ) )
+ {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Inconsistent direction for minimum curvature (u,v)=(%f,%f), direction: %f, %f, %f, curvature: %f",
+ u[0],u[1],dirMin[0],dirMin[1],dirMin[2],*curvMin);
+ double tmp[3] = { 0.86684859, 0.69576964, 0.39876864 };
+ crossProd(tmp,dirMax,dirMin);
+ }
+
+ if ( isnan(*curvMax) ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,"NaN maximum curvature");
+ *curvMax = cMaxBound;
+ }
+ *curvMax = std::min(*curvMax,cMaxBound);
+ if ( isnan(*curvMin) ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,"NaN minimum curvature");
+ *curvMin = cMaxBound;
+ }
+ *curvMin = std::min(*curvMin,cMaxBound);
+
+ return *curvMax;
+ }
+
+ // -------------------------------------------------------------------
+ //! Computes the parametric coordinates of the point of an edge on
+ //! a geodesic of the surface. t is the location on the edge ( 0 <= t <= 1 ).
+ void GF_centerOnGeodesic(const pGFace face, double t,
+ const double e[2][2], double c[2])
+ {
+ SPoint2 pt1(e[0][0],e[0][1]);
+ SPoint2 pt2(e[1][0],e[1][1]);
+ SPoint2 res = face->geodesic(pt1,pt2,t);
+ c[0] = res.x();
+ c[1] = res.y();
+ }
+
+ // -------------------------------------------------------------------
+ std::list<pGVertex> GE_vertices(const pGEdge pGE)
+ {
+ return pGE->vertices();
+ }
+
+ // -------------------------------------------------------------------
+ //! Computes the coordinates of the point on the line closest to xyz
+ void GE_closestPoint(const pGEdge pGE, const double xyz[3],
+ double xyzOnE[3])
+ {
+ // GPoint gP = pGE->closestPoint( SPoint3(xyz) );
+ // xyzOnE[0] = gP.x();
+ // xyzOnE[1] = gP.y();
+ // xyzOnE[2] = gP.z();
+ throw;
+ }
+
+ // -------------------------------------------------------------------
+ void GE_xyz(const pGEdge pGE, double u, double xyz[3])
+ {
+ GPoint gP = pGE->point(u);
+ xyz[0] = gP.x();
+ xyz[1] = gP.y();
+ xyz[2] = gP.z();
+ }
+
+ // -------------------------------------------------------------------
+ //! Given an edge which is a seam of the face, and a point of
+ //! the edge with parametric coordinate uOnE on the edge,
+ //! find the parametric coordinates of the point on the face.
+ //! uClose are the parametric coordinates of a close point of
+ //! face used to determine the direction for the parametrization.
+ void GE_reparamOnFace(const pGEdge edge, const pGFace face,
+ double uOnE, double uOnF[2], double uClose[2])
+ {
+ // assert( edge->isSeam(face) );
+
+ SPoint2 pt = edge->reparamOnFace(face, uOnE, 0);
+ uOnF[0] = pt.x();
+ uOnF[1] = pt.y();
+
+ if ( uClose )
+ {
+ double dist =
+ ( uClose[0] - pt.x() ) * ( uClose[0] - pt.x() ) +
+ ( uClose[1] - pt.y() ) * ( uClose[1] - pt.y() );
+
+ SPoint2 pt2 = edge->reparamOnFace(face, uOnE, 1);
+ double dist2 =
+ ( uClose[0] - pt2.x() ) * ( uClose[0] - pt2.x() ) +
+ ( uClose[1] - pt2.y() ) * ( uClose[1] - pt2.y() );
+
+ if ( dist2 < dist ) {
+ uOnF[0] = pt2.x();
+ uOnF[1] = pt2.y();
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! true if the edge is a seam for the given face.
+ bool GE_isSeam(const pGEdge edge, const pGFace face)
+ {
+ return edge->isSeam(face);
+ }
+
+ // -------------------------------------------------------------------
+ //! gets the curvature of the line at that point bounded by cMaxBound
+ double GE_curvature(const pGEdge line, double u, double cMaxBound)
+ {
+ double curv = line->curvature(u);
+ if ( isnan(curv) ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,"NaN curvature");
+ curv = cMaxBound;
+ }
+ return std::min(curv,cMaxBound);
+ }
+
+ // -------------------------------------------------------------------
+ //! returns a list of the lines including the vertex
+ std::list<pGEdge> GV_edges(const pGVertex pGV)
+ {
+ return pGV->edges();
+ }
+
+ // -------------------------------------------------------------------
+ //! Given a geometric vertex which is on the face, find the parametric
+ //! coordinates of the vertex on the face.
+ //! uClose are the parametric coordinates of a close point of
+ //! face used to determine the direction for the parametrization.
+ void GV_reparamOnFace(const pGVertex vertex, const pGFace face,
+ double uOnF[2], double uClose[2])
+ {
+ SPoint2 pt = vertex->reparamOnFace(face, 0);
+ uOnF[0] = pt.x();
+ uOnF[1] = pt.y();
+
+ if ( uClose )
+ {
+ double dist =
+ ( uClose[0] - pt.x() ) * ( uClose[0] - pt.x() ) +
+ ( uClose[1] - pt.y() ) * ( uClose[1] - pt.y() );
+
+ SPoint2 pt2 = vertex->reparamOnFace(face, 1);
+ double dist2 =
+ ( uClose[0] - pt2.x() ) * ( uClose[0] - pt2.x() ) +
+ ( uClose[1] - pt2.y() ) * ( uClose[1] - pt2.y() );
+
+ if ( dist2 < dist ) {
+ uOnF[0] = pt2.x();
+ uOnF[1] = pt2.y();
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! Given a geometric vertex which is on the edge, find the parametric
+ //! coordinates of the vertex on the edge.
+ //! uClose is the parametric coordinate of a close point of
+ //! edge used to determine the direction for the parametrization.
+ void GV_reparamOnEdge(const pGVertex vertex, const pGEdge edge,
+ double * uOnE, double uClose)
+ {
+ Range<double> range = edge->parBounds(0);
+
+ if ( uClose >= 0. &&
+ vertex == edge->getBeginVertex() &&
+ vertex == edge->getEndVertex() ) {
+ *uOnE = range.low();
+ double dist = ( uClose - *uOnE ) * ( uClose - *uOnE );
+ double dist2 = ( uClose - range.high() ) * ( uClose - range.high() );
+ if ( dist2 < dist ) *uOnE = range.high();
+ return;
+ }
+
+ if ( vertex == edge->getBeginVertex() ) { *uOnE = range.low(); return; }
+ if ( vertex == edge->getEndVertex() ) { *uOnE = range.high(); return; }
+
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "GVertex not in the closure of the GEdge");
+ }
+
+ // -------------------------------------------------------------------
+ //! Return true if the vertex is on a seam of the given face
+ bool GV_isOnSeam(const pGVertex vert, const pGFace face)
+ {
+ return vert->isOnSeam(face);
+ }
+
+#else
+
+ // -------------------------------------------------------------------
+ void GF_centerOnGeodesic(const pGFace face, double t,
+ const double e[2][2], double c[2])
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Using geodesics requires Gmsh");
+ }
+
+#endif
+
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // PGList functions
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ PGList * PGList_new()
+ {
+ return new PGList();
+ }
+
+ // -------------------------------------------------------------------
+ void PGList_delete(PGList * lst)
+ {
+ if (lst) delete lst;
+ lst = NULL;
+ }
+
+ // -------------------------------------------------------------------
+ void PGList_clear(PGList * lst)
+ {
+ lst->clear();
+ }
+
+ // -------------------------------------------------------------------
+ PGList * PGList_appUnique(PGList * lst, pGEntity ent)
+ {
+ for ( unsigned int i=0; i<lst->entities.size(); i++ ) {
+ if ( lst->entities[i] == ent ) return lst;
+ }
+ lst->entities.push_back(ent);
+ return lst;
+ }
+
+ // -------------------------------------------------------------------
+ PGList * PGList_appPGListUnique(PGList * lst, PGList * source)
+ {
+ for ( unsigned int iSrc=0; iSrc<source->entities.size(); iSrc++ ) {
+ PGList_appUnique(lst,source->entities[iSrc]);
+ }
+ return lst;
+ }
+
+ // -------------------------------------------------------------------
+ PGList * PGList_append(PGList * lst, pGEntity ent)
+ {
+ lst->entities.push_back(ent);
+ return lst;
+ }
+
+ // -------------------------------------------------------------------
+ int PGList_size(PGList * lst)
+ {
+ return lst->entities.size();
+ }
+
+ // -------------------------------------------------------------------
+ pGEntity PGList_item(PGList * lst, int i)
+ {
+ return lst->entities[i];
+ }
+
+ // -------------------------------------------------------------------
+ pGEntity PGList_next(PGList * lst, void **restart)
+ {
+ if( *(int*)(restart) >= (int)lst->entities.size() ) return NULL;
+ return lst->entities[(*(int*)(restart))++];
+ }
+
+ // -------------------------------------------------------------------
+ int PGList_inList(PGList * lst, pGEntity ent)
+ {
+ for ( unsigned int i=0; i<lst->entities.size(); i++ ) {
+ if ( lst->entities[i] == ent ) return 1;
+ }
+ return 0;
+ }
+
+ // -------------------------------------------------------------------
+ void PGList_remItem(PGList * lst, pGEntity ent)
+ {
+ std::vector<pGEntity>::iterator eIter = lst->entities.begin();
+ for (; eIter != lst->entities.end() ; eIter++) {
+ if ( *eIter == ent ) lst->entities.erase(eIter);
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+
+}
+
diff --git a/Geo/ModelInterface.h b/Geo/ModelInterface.h
new file mode 100644
index 0000000..fb3b1e5
--- /dev/null
+++ b/Geo/ModelInterface.h
@@ -0,0 +1,178 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_MODELINTERFACE
+#define _H_MODELINTERFACE
+
+#include <string>
+#include <list>
+
+#ifdef _HAVE_GMSH_
+#include "GmshModel.h"
+#else
+#include "NullModel.h"
+#endif
+
+#include "GM_Iterators.h"
+#include "PGList.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ typedef MAdModel * pGModel;
+ typedef MAdGEntity * pGEntity;
+ typedef MAdGRegion * pGRegion;
+ typedef MAdGFace * pGFace;
+ typedef MAdGEdge * pGEdge;
+ typedef MAdGVertex * pGVertex;
+
+ typedef GM_RegionIterator * GRIter;
+ typedef GM_FaceIterator * GFIter;
+ typedef GM_EdgeIterator * GEIter;
+ typedef GM_VertexIterator * GVIter;
+
+ typedef PGList * pPGList;
+
+ // -------------------------------------------------------------------
+
+ // --- Model operators ---
+
+ // create an empty model
+ void GM_create(pGModel * model, std::string name="");
+
+ // delete the model
+ void GM_delete(pGModel model);
+
+ // read a model, guess file format from extension
+ int GM_read(pGModel model, const std::string name);
+
+ // read particular file formats
+ int GM_readFromMSH(pGModel model, const std::string name);
+ int GM_readFromGEO(pGModel model, const std::string name);
+ int GM_readFromSTEP(pGModel model, const std::string name);
+ int GM_readFromBREP(pGModel model, const std::string name);
+ int GM_readFromIGES(pGModel model, const std::string name);
+
+ // write geometry in a GEO format file (Gmsh native CAD format)
+ int GM_writeGEO(pGModel model, const std::string &name);
+ // void GM_diagnostics(const pGModel model);
+
+ // Find the entity with the given tag.
+ // Create it if it doesn't exist.
+ pGEntity GM_entityByTag(const pGModel model, int type, int tag);
+ pGRegion GM_regionByTag(const pGModel model, int tag);
+ pGFace GM_faceByTag (const pGModel model, int tag);
+ pGEdge GM_edgeByTag (const pGModel model, int tag);
+ pGVertex GM_vertexByTag(const pGModel model, int tag);
+
+ int GM_numVertices(const pGModel);
+ int GM_numEdges(const pGModel);
+ int GM_numFaces(const pGModel);
+ int GM_numRegions(const pGModel);
+
+ // --- Iterators ---
+
+ GRIter GM_regionIter(pGModel);
+ GFIter GM_faceIter(pGModel);
+ GEIter GM_edgeIter(pGModel);
+ GVIter GM_vertexIter(pGModel);
+
+ pGRegion GRIter_next(GRIter);
+ pGFace GFIter_next(GFIter);
+ pGEdge GEIter_next(GEIter);
+ pGVertex GVIter_next(GVIter);
+
+ void GRIter_delete(GRIter);
+ void GFIter_delete(GFIter);
+ void GEIter_delete(GEIter);
+ void GVIter_delete(GVIter);
+
+ void GRIter_reset(GRIter);
+ void GFIter_reset(GFIter);
+ void GEIter_reset(GEIter);
+ void GVIter_reset(GVIter);
+
+ // --- Entity operators ---
+
+ int GEN_tag(const pGEntity);
+ int GEN_type(const pGEntity);
+
+#ifdef _HAVE_GMSH_
+ std::list<pGEntity> GEN_closure(const pGEntity);
+
+ // --- Region operators ---
+
+ std::list<pGFace> GR_faces(const pGRegion);
+
+ // --- Face operators ---
+
+ int GF_numRegions(const pGFace);
+ std::list<pGEdge> GF_edges(const pGFace);
+ bool GF_getParams(const pGFace, const double[3], double[2]);
+ void GF_closestPoint(const pGFace, const double[3],
+ const double[2], double[3]);
+ void GF_xyz(const pGFace, double, double, double[3]);
+ double GF_curvatureDiv(const pGFace, const double[2],
+ double cMaxBound);
+ double GF_curvatures(const pGFace, const double[2],
+ double dirMax[3], double dirMin[3],
+ double *curvMax, double *curvMin,
+ double cMaxBound);
+ void GF_centerOnGeodesic(const pGFace face, double t,
+ const double e[2][2], double c[2]);
+
+ // --- Edge operators ---
+
+ std::list<pGVertex> GE_vertices(const pGEdge);
+ void GE_closestPoint(const pGEdge, const double[3], double[3]);
+ void GE_xyz(const pGEdge, double, double[3]);
+ void GE_reparamOnFace(const pGEdge, const pGFace,
+ double, double[2], double uClose[2]=NULL);
+ bool GE_isSeam(const pGEdge, const pGFace);
+ double GE_curvature(const pGEdge, double, double);
+
+ // --- Vertex operators ---
+
+ std::list<pGEdge> GV_edges(const pGVertex);
+
+ void GV_reparamOnFace(const pGVertex, const pGFace, double [2],
+ double uClose[2]=NULL);
+ void GV_reparamOnEdge(const pGVertex, const pGEdge, double *,
+ double uClose=-1.);
+ bool GV_isOnSeam(const pGVertex, const pGFace);
+#else
+ void GF_centerOnGeodesic(const pGFace face, double t,
+ const double e[2][2], double c[2]);
+#endif
+
+ // --- pGList operators ---
+
+ pPGList PGList_new();
+ pPGList PGList_allocate();
+ void PGList_delete (pPGList);
+ void PGList_deallocate (pPGList);
+ void PGList_clear (pPGList);
+ pPGList PGList_appPGListUnique (pPGList, pPGList source);
+ pPGList PGList_appUnique (pPGList, pGEntity);
+ pPGList PGList_append (pPGList, pGEntity);
+ int PGList_size (pPGList);
+ pGEntity PGList_item (pPGList, int n);
+ pGEntity PGList_next (pPGList, void ** restart);
+ int PGList_inList (pPGList, pGEntity);
+ void PGList_remItem (pPGList, pGEntity);
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Geo/NullEntities.h b/Geo/NullEntities.h
new file mode 100644
index 0000000..9eaf244
--- /dev/null
+++ b/Geo/NullEntities.h
@@ -0,0 +1,102 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_NULLENTITIES
+#define _H_NULLENTITIES
+
+#ifndef _HAVE_GMSH_
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class NullGEntity {
+
+ public:
+ NullGEntity(): _tag(-1) {}
+ NullGEntity(int tag): _tag(tag) {}
+ NullGEntity(const NullGEntity& ge): _tag(ge._tag) {}
+ virtual ~NullGEntity() {}
+
+ virtual int dim() const { return -1; }
+ virtual int tag() const { return _tag; }
+
+ private:
+ int _tag;
+ };
+
+ // -------------------------------------------------------------------
+ class NullGEntityLessThan {
+ public:
+ bool operator()(const NullGEntity *ent1, const NullGEntity *ent2) const
+ { return ent1->tag() < ent2->tag(); }
+ };
+
+ // -------------------------------------------------------------------
+ class NullGRegion : public NullGEntity {
+
+ public:
+ NullGRegion() : NullGEntity() {}
+ NullGRegion(int tag) : NullGEntity(tag) {}
+ NullGRegion(const NullGRegion& gr) : NullGEntity(gr) {}
+ virtual ~NullGRegion() {}
+ int dim() const { return 3; }
+ };
+
+ // -------------------------------------------------------------------
+ class NullGFace : public NullGEntity {
+
+ public:
+ NullGFace() : NullGEntity() {}
+ NullGFace(int tag) : NullGEntity(tag) {}
+ NullGFace(const NullGFace& gf) : NullGEntity(gf) {}
+ virtual ~NullGFace() {}
+ int dim() const { return 2; }
+ };
+
+ // -------------------------------------------------------------------
+ class NullGEdge : public NullGEntity {
+
+ public:
+ NullGEdge() : NullGEntity() {}
+ NullGEdge(int tag) : NullGEntity(tag) {}
+ NullGEdge(const NullGEdge& ge) : NullGEntity(ge) {}
+ virtual ~NullGEdge() {}
+ int dim() const { return 1; }
+ };
+
+ // -------------------------------------------------------------------
+ class NullGVertex : public NullGEntity {
+
+ public:
+ NullGVertex() : NullGEntity() {}
+ NullGVertex(int tag) : NullGEntity(tag) {}
+ NullGVertex(const NullGVertex& gv) : NullGEntity(gv) {}
+ virtual ~NullGVertex() {}
+ int dim() const { return 0; }
+ };
+
+ // -------------------------------------------------------------------
+ typedef class NullGEntity MAdGEntity;
+ typedef class NullGEntityLessThan MAdGEntityLessThan;
+ typedef class NullGRegion MAdGRegion;
+ typedef class NullGFace MAdGFace;
+ typedef class NullGEdge MAdGEdge;
+ typedef class NullGVertex MAdGVertex;
+
+ // -------------------------------------------------------------------
+}
+
+#endif
+
+#endif
+
diff --git a/Geo/NullModel.cc b/Geo/NullModel.cc
new file mode 100644
index 0000000..9c8bd56
--- /dev/null
+++ b/Geo/NullModel.cc
@@ -0,0 +1,288 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _HAVE_GMSH_
+
+#include "NullModel.h"
+
+#include "MAdMessage.h"
+#include "MshTags.h"
+
+#include <stdio.h>
+#include <set>
+using std::set;
+#include <string.h>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ NullModel::~NullModel()
+ {
+ clean();
+ }
+
+ // -------------------------------------------------------------------
+ void NullModel::clean()
+ {
+ riter itR = regions.begin();
+ for (; itR != regions.end(); itR++) delete (*itR);
+ regions.clear();
+ fiter itF = faces.begin();
+ for (; itF != faces.end(); itF++) delete (*itF);
+ faces.clear();
+ eiter itE = edges.begin();
+ for (; itE != edges.end(); itE++) delete (*itE);
+ edges.clear();
+ viter itV = vertices.begin();
+ for (; itV != vertices.end(); itV++) delete (*itV);
+ vertices.clear();
+ }
+
+ // -------------------------------------------------------------------
+ MAdGEntity * NullModel::getEntityByTag(int dim, int tag)
+ {
+ switch(dim) {
+ case 3: return getRegionByTag(tag);
+ case 2: return getFaceByTag(tag);
+ case 1: return getEdgeByTag(tag);
+ case 0: return getVertexByTag(tag);
+ }
+ return NULL;
+ }
+
+ // -------------------------------------------------------------------
+ MAdGRegion *NullModel::getRegionByTag(int tag)
+ {
+ set<MAdGRegion *,MAdGEntityLessThan>::const_iterator it = regions.begin();
+ for (; it != regions.end(); it++) {
+ if ( (*it)->tag() == tag ) return *it;
+ }
+ MAdGRegion * newRegion = new MAdGRegion(tag);
+ regions.insert(newRegion);
+ return newRegion;
+ }
+
+ // -------------------------------------------------------------------
+ MAdGFace *NullModel::getFaceByTag(int tag)
+ {
+ set<MAdGFace *,MAdGEntityLessThan>::const_iterator it = faces.begin();
+ for (; it != faces.end(); it++) {
+ if ( (*it)->tag() == tag ) return *it;
+ }
+ MAdGFace * newFace = new MAdGFace(tag);
+ faces.insert(newFace);
+ return newFace;
+ }
+
+ // -------------------------------------------------------------------
+ MAdGEdge *NullModel::getEdgeByTag(int tag)
+ {
+ set<MAdGEdge *,MAdGEntityLessThan>::const_iterator it = edges.begin();
+ for (; it != edges.end(); it++) {
+ if ( (*it)->tag() == tag ) return *it;
+ }
+ MAdGEdge * newEdge = new MAdGEdge(tag);
+ edges.insert(newEdge);
+ return newEdge;
+ }
+
+ // -------------------------------------------------------------------
+ MAdGVertex *NullModel::getVertexByTag(int tag)
+ {
+ set<MAdGVertex *,MAdGEntityLessThan>::const_iterator it = vertices.begin();
+ for (; it != vertices.end(); it++) {
+ if ( (*it)->tag() == tag ) return *it;
+ }
+ MAdGVertex * newVertex = new MAdGVertex(tag);
+ vertices.insert(newVertex);
+ return newVertex;
+ }
+
+ // -------------------------------------------------------------------
+ int NullModel::readGEO(const std::string &filename)
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Reading a model from a .geo file not implemented in NullModel");
+ }
+
+ // -------------------------------------------------------------------
+ void SwapBytes(char *array, int size, int n)
+ {
+ char *x = new char[size];
+ for(int i = 0; i < n; i++) {
+ char *a = &array[i * size];
+ memcpy(x, a, size);
+ for(int c = 0; c < size; c++)
+ a[size - 1 - c] = x[c];
+ }
+ delete [] x;
+ }
+
+ // -------------------------------------------------------------------
+ int NullModel::readMSH(const std::string &filename)
+ {
+ FILE *fp = fopen(filename.c_str(), "rb");
+ if(!fp){
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Unable to open file '%s'", filename.c_str());
+ return 0;
+ }
+
+ char str[256] = "XXX";
+ double version = 1.0;
+ bool binary = false, swap = false;
+
+ while(1) {
+
+ while(str[0] != '$'){
+ if(!fgets(str, sizeof(str), fp) || feof(fp))
+ break;
+ }
+
+ if(feof(fp))
+ break;
+
+ if(!strncmp(&str[1], "MeshFormat", 10)) {
+
+ if(!fgets(str, sizeof(str), fp)) return 0;
+ int format, size;
+ if(sscanf(str, "%lf %d %d", &version, &format, &size) != 3) return 0;
+ if(format){
+ binary = true;
+ MAdMsgSgl::instance().info(__LINE__,__FILE__,
+ "Mesh is in binary format");
+ int one;
+ if(fread(&one, sizeof(int), 1, fp) != 1) return 0;
+ if(one != 1){
+ swap = true;
+ MAdMsgSgl::instance().info(__LINE__,__FILE__,
+ "Swapping bytes from binary file");
+ }
+ }
+
+ }
+ else if(!strncmp(&str[1], "PhysicalNames", 13)) {
+ }
+ else if(!strncmp(&str[1], "NO", 2) || !strncmp(&str[1], "Nodes", 5) ||
+ !strncmp(&str[1], "ParametricNodes", 15)) {
+ }
+ else if(!strncmp(&str[1], "ELM", 3) || !strncmp(&str[1], "Elements", 8)) {
+
+ if(!fgets(str, sizeof(str), fp)) return 0;
+ int numElements;
+ sscanf(str, "%d", &numElements);
+ MAdMsgSgl::instance().info(__LINE__,__FILE__,
+ "%d elements", numElements);
+ if(!binary){
+ for(int i = 0; i < numElements; i++) {
+ int num, type, physical = -1, elementary = -1, partition = 0, numVertices;
+ if(version <= 1.0){
+ fscanf(fp, "%d %d %d %d %d", &num, &type, &physical, &elementary, &numVertices);
+ }
+ else{
+ int numTags;
+ fscanf(fp, "%d %d %d", &num, &type, &numTags);
+ for(int j = 0; j < numTags; j++){
+ int tag;
+ fscanf(fp, "%d", &tag);
+ if(j == 0) physical = tag;
+ else if(j == 1) elementary = tag;
+ else if(j == 2) partition = tag;
+ // ignore any other tags for now
+ numVertices = getNumVerticesForElementTypeMSH(type);
+ }
+ }
+ int tmp;
+ for(int j = 0; j < numVertices; j++) fscanf(fp, "%d", &tmp);
+
+ int gTag = elementary;
+ if ( physical != -1 ) gTag = physical;
+ int gDim = getDimForElementTypeMSH(type);
+ getEntityByTag(gDim,gTag);
+ }
+ }
+ else{
+ int numElementsPartial = 0;
+ while(numElementsPartial < numElements){
+ int header[3];
+ if(fread(header, sizeof(int), 3, fp) != 3) return 0;
+ if(swap) SwapBytes((char*)header, sizeof(int), 3);
+ int type = header[0];
+ int numElms = header[1];
+ int numTags = header[2];
+ int numVertices = getNumVerticesForElementTypeMSH(type);
+ unsigned int n = 1 + numTags + numVertices;
+ int *data = new int[n];
+ for(int i = 0; i < numElms; i++) {
+ if(fread(data, sizeof(int), n, fp) != n) return 0;
+ if(swap) SwapBytes((char*)data, sizeof(int), n);
+ int num = data[0];
+ int physical = (numTags > 0) ? data[4 - numTags] : -1;
+ int elementary = (numTags > 1) ? data[4 - numTags + 1] : -1;
+ int partition = (numTags > 2) ? data[4 - numTags + 2] : 0;
+ int *indices = &data[numTags + 1];
+ int gTag = elementary;
+ if ( physical != -1 ) gTag = physical;
+ int gDim = getDimForElementTypeMSH(type);
+ getEntityByTag(gDim,gTag);
+ }
+ delete [] data;
+ numElementsPartial += numElms;
+ }
+ }
+
+ }
+
+ do {
+ if(!fgets(str, sizeof(str), fp) || feof(fp))
+ break;
+ } while(str[0] != '$');
+ }
+
+ fclose(fp);
+ return 1;
+ }
+
+ // -------------------------------------------------------------------
+ int NullModel::writeGEO(const std::string &filename)
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Null model cannot write a GEO file");
+ }
+
+ // -------------------------------------------------------------------
+ int NullModel::readSTEP(const std::string &filename)
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Null model cannot read STEP format");
+ }
+
+ // -------------------------------------------------------------------
+ int NullModel::readBREP(const std::string &filename)
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Null model cannot read BREP format");
+ }
+
+ // -------------------------------------------------------------------
+ int NullModel::readIGES(const std::string &filename)
+ {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Null model cannot read IGES format");
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
+
diff --git a/Geo/NullModel.h b/Geo/NullModel.h
new file mode 100644
index 0000000..045d729
--- /dev/null
+++ b/Geo/NullModel.h
@@ -0,0 +1,88 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_NULLMODEL
+#define _H_NULLMODEL
+
+#ifndef _HAVE_GMSH_
+
+#include "MAdModel.h"
+#include "NullEntities.h"
+#include <set>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class NullModel : public MAdModel {
+
+ public:
+
+ NullModel(std::string name=""): MAdModel(name) {}
+ ~NullModel();
+
+ ModelType type() const { return NULLMODEL; }
+
+ // Gmsh mesh file format
+ int readMSH(const std::string &filename);
+
+ // Gmsh native CAD format
+ int readGEO(const std::string &filename);
+ int writeGEO(const std::string &filename);
+
+ // OCC formats
+ int readSTEP(const std::string &filename);
+ int readBREP(const std::string &filename);
+ int readIGES(const std::string &filename);
+
+ // get the number of entities in this model
+ int getNumRegions() const { return regions.size(); }
+ int getNumFaces() const { return faces.size(); }
+ int getNumEdges() const { return edges.size(); }
+ int getNumVertices() const { return vertices.size(); }
+
+ // find the entity with the given tag and create it if not found
+ MAdGEntity * getEntityByTag(int dim, int tag);
+ MAdGRegion * getRegionByTag(int);
+ MAdGFace * getFaceByTag (int);
+ MAdGEdge * getEdgeByTag (int);
+ MAdGVertex * getVertexByTag(int);
+
+ // get an iterator initialized to the first/last entity in this model.
+ riter firstRegion() { return regions.begin(); }
+ fiter firstFace() { return faces.begin(); }
+ eiter firstEdge() { return edges.begin(); }
+ viter firstVertex() { return vertices.begin(); }
+ riter lastRegion() { return regions.end(); }
+ fiter lastFace() { return faces.end(); }
+ eiter lastEdge() { return edges.end(); }
+ viter lastVertex() { return vertices.end(); }
+
+ private:
+
+ // delete all geometric entities
+ void clean();
+
+ std::set<MAdGRegion *,MAdGEntityLessThan> regions;
+ std::set<MAdGFace *,MAdGEntityLessThan> faces;
+ std::set<MAdGEdge *,MAdGEntityLessThan> edges;
+ std::set<MAdGVertex *,MAdGEntityLessThan> vertices;
+
+ };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
+
+#endif
diff --git a/Geo/PGList.h b/Geo/PGList.h
new file mode 100644
index 0000000..bf65068
--- /dev/null
+++ b/Geo/PGList.h
@@ -0,0 +1,60 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+/*
+ Store a list of pointers to geometric entities
+
+ The list is stored as a standart vector:
+ - allow fast random access
+ - allow fast iterating
+ - can be allocated to a particular size
+ - slow at randomly adding/removing elements but not useful here
+*/
+
+#ifndef _H_PGLIST
+#define _H_PGLIST
+
+#include "ModelInterface.h"
+
+#include <vector>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class PGList {
+
+ public:
+
+ PGList() {};
+ PGList(const PGList& ori)
+ {
+ entities = ori.entities;
+ };
+
+ ~PGList() {};
+
+ public:
+
+ void clear() { entities.clear(); };
+
+ public:
+
+ std::vector<MAdGEntity *> entities;
+
+ };
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/License.txt b/License.txt
new file mode 100644
index 0000000..8da168b
--- /dev/null
+++ b/License.txt
@@ -0,0 +1,850 @@
+This file contains:
+ - the terms of the GNU Lesser General Public License Version 3,
+ - the terms of the GNU General Public License Version 3.
+
+//-----------------------------------------------------------------------
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+
+
+
+//-----------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/MAdConfig.h.in b/MAdConfig.h.in
new file mode 100644
index 0000000..28c7fff
--- /dev/null
+++ b/MAdConfig.h.in
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+#ifndef _H_MADCONFIG_MAD_
+#define _H_MADCONFIG_MAD_
+
+#undef HAVE_64BIT_SIZE_T
+#undef _HAVE_ANN_
+#undef HAVE_BLAS
+#undef _HAVE_BLAS_
+#undef HAVE_CBLAS
+#undef _HAVE_CBLAS_
+#undef _HAVE_GMM_
+#undef _HAVE_GMSH_
+#undef _HAVE_GSL_
+#undef HAVE_LAPACK
+#undef _HAVE_LAPACK_
+#undef _HAVE_METIS_
+#undef _HAVE_MPI_
+#undef HAVE_NO_DLL
+#undef HAVE_NO_SOCKLEN_T
+#undef _HAVE_OCC_
+#undef _HAVE_PARMETIS_
+#undef _HAVE_PARSER_
+#undef _HAVE_PETSC_
+#undef PARALLEL
+
+#endif
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e89a239
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,403 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include variables
+
+MADLIB_MAJOR_VERSION = 1
+MADLIB_MINOR_VERSION = 2
+MADLIB_PATCH_VERSION = 3
+MADLIB_EXTRA_VERSION =
+
+MADLIB_VERSION = ${MADLIB_MAJOR_VERSION}.${MADLIB_MINOR_VERSION}.${MADLIB_PATCH_VERSION}${MADLIB_EXTRA_VERSION}
+
+MADLIB_SHORT_LICENSE = "GNU Lesser General Public License"
+
+MADLIB_VERSION_FILE = Common/MAdLibVersion.h
+MADLIB_DATE = `date "+%Y%m%d"`
+MADLIB_PCFILE = MAdLib.pc
+
+MADLIB_API = \
+Adapt/AdaptInterface.h\
+Adapt/constraint/ModelConstraintManager.h\
+Adapt/constraint/Constraint.h\
+Adapt/MeshParametersManager.h\
+Adapt/operator/VertexMoveOp.h\
+Adapt/operator/SliverRegionHandler.h\
+Adapt/operator/FaceSwapOp.h\
+Adapt/operator/DESCOp.h\
+Adapt/operator/EdgeCollapseOp.h\
+Adapt/operator/EdgeSplitOp.h\
+Adapt/operator/EdgeSwapConfig.h\
+Adapt/operator/EdgeSwapOp.h\
+Adapt/operator/FaceCollapseOp.h\
+Adapt/operator/OperatorTools.h\
+Adapt/operator/SliverFaceHandler.h\
+Adapt/operator/RegionRemoveOp.h\
+Adapt/operator/MAdOperatorBase.h\
+Adapt/output/MAdOutput.h\
+Adapt/quality/ElementEvaluatorBase.h\
+Adapt/quality/ElementStatistics.h\
+Adapt/quality/MeshQualityManager.h\
+Adapt/quality/MeanRatioEvaluator.h\
+Adapt/quality/OrientedMeanRatioEvaluator.h\
+Adapt/repositioning/NodesRepositioningOp.h\
+Adapt/repositioning/GeoMatcher.h\
+Adapt/repositioning/MobileObject.h\
+Adapt/repositioning/LaplaceSmoothingOp.h\
+Adapt/repositioning/MAdElasticityOp.h\
+Adapt/sizeField/NullSField.h\
+Adapt/sizeField/MeshSizeBase.h\
+Adapt/sizeField/IsoMeshSize.h\
+Adapt/sizeField/LocalSizeField.h\
+Adapt/sizeField/AnalyticalSField.h\
+Adapt/sizeField/PWLinearSField.h\
+Adapt/sizeField/AnisoMeshSize.h\
+Adapt/sizeField/SizeFieldBase.h\
+Adapt/sizeField/SizeFieldManager.h\
+Adapt/sizeField/DiscreteSF.h\
+Adapt/utils/MAdStatistics.h\
+Adapt/utils/MAdLinearSystemSparskit.h\
+Adapt/utils/DistanceToPoints.h\
+Adapt/utils/DistanceFunction.h\
+Adapt/utils/MAdLinearSystemPETSc.h\
+Adapt/utils/MAdTimeManager.h\
+Adapt/utils/MAdLinearSystemGmm.h\
+Adapt/utils/NodalDataManager.h\
+Adapt/utils/CallBackManager.h\
+Adapt/utils/MAdLinearSystem.h\
+Adapt/utils/History.h\
+Geo/GM_Iterators.h\
+Geo/GmshEntities.h\
+Geo/GmshModel.h\
+Geo/MAdModel.h\
+Geo/ModelInterface.h\
+Geo/NullEntities.h\
+Geo/NullModel.h\
+Geo/PGList.h\
+Mesh/CheckMesh.h\
+Mesh/CheckOrientation.h\
+Mesh/Mark.h\
+Mesh/MeshDataBaseAttachable.h\
+Mesh/MeshDataBaseCommCheck.h\
+Mesh/MeshDataBaseComm.h\
+Mesh/MeshDataBaseCommPeriodic.h\
+Mesh/MeshDataBaseGEntity2Physical.h\
+Mesh/MeshDataBase.h\
+Mesh/MeshDataBaseInterface.h\
+Mesh/MeshDataBaseIO.h\
+Mesh/MeshDataBaseIterators.h\
+Mesh/MeshDataBaseLoadBalancing.h\
+Mesh/MeshDataBaseMessage.h\
+Mesh/MeshDataBaseMiniMesh.h\
+Mesh/MeshDataBaseParallelInterface.h\
+Mesh/MeshDataBaseParallelIO.h\
+Mesh/metisAdaptiveRepart.h\
+Mesh/MshTags.h\
+Mesh/MSops.h\
+Mesh/ParallelUtils.h\
+Mesh/PList.h\
+Common/MAdDefines.h\
+Common/MAdFieldEvaluator.h\
+Common/MAdMatrix.h\
+Common/MAdMessage.h\
+Common/MAdResourceManager.h\
+Common/MAdSingleton.h\
+Common/MAdStringFieldEvaluator.h\
+Common/MathUtils.h\
+Common/MAdLib.h\
+Common/MAdMetric.h\
+Common/MAdVector3.h\
+Common/MAdLibVersion.h\
+Contrib/mathex/mathex.h\
+Contrib/ANN/include/ANN/ANN.h
+
+docdir=${prefix}/doc
+
+# Main building rules
+
+#all: link
+
+#link: compile
+# ${LINKER} ${OPTIM} ${DASH}o bin/MAdLib${EXEEXT} ${MAdLib_LIBS}
+
+default: lib
+
+all: bench
+
+compile: variables initialtag dirs
+ifneq (${UNAME},WIN32MSVC)
+ @for i in ${MAdLib_DIRS}; do (cd $$i && ${MAKE}); done
+else
+ for %%i in (${MAdLib_DIRS}) do ${MAKE} -C %%i
+endif
+
+bench: lib
+ifneq (${UNAME},WIN32MSVC)
+ cd Benchmarks/moveIt; ln -s examples/tube/MyParams.h; cd -;
+ @for i in ${MAdLib_BENCHDIRS}; do (cd $$i && ${MAKE}); done
+else
+ for %%i in (${MAdLib_BENCHDIRS}) do ${MAKE} -C %%i
+endif
+
+tag:
+ifneq (${UNAME},WIN32MSVC)
+ echo "#define MADLIB_MAJOR_VERSION ${MADLIB_MAJOR_VERSION}" > ${MADLIB_VERSION_FILE}
+ echo "#define MADLIB_MINOR_VERSION ${MADLIB_MINOR_VERSION}" >> ${MADLIB_VERSION_FILE}
+ echo "#define MADLIB_PATCH_VERSION ${MADLIB_PATCH_VERSION}" >> ${MADLIB_VERSION_FILE}
+ echo "#define MADLIB_EXTRA_VERSION \"${MADLIB_EXTRA_VERSION}\"" >> ${MADLIB_VERSION_FILE}
+ echo "#define MADLIB_VERSION \"${MADLIB_VERSION}\"" >> ${MADLIB_VERSION_FILE}
+ echo "#define MADLIB_DATE \"`date`\"" >> ${MADLIB_VERSION_FILE}
+ echo "#define MADLIB_HOST \"${HOSTNAME}\"" >> ${MADLIB_VERSION_FILE}
+ echo "#define MADLIB_PACKAGER \"`whoami`\"" >> ${MADLIB_VERSION_FILE}
+ echo "#define MADLIB_OS \"${UNAME}\"" >> ${MADLIB_VERSION_FILE}
+ echo "#define MADLIB_SHORT_LICENSE \"${MADLIB_SHORT_LICENSE}\"" >> ${MADLIB_VERSION_FILE}
+else
+ echo #define MADLIB_MAJOR_VERSION ${MADLIB_MAJOR_VERSION} > ${MADLIB_VERSION_FILE}
+ echo #define MADLIB_MINOR_VERSION ${MADLIB_MINOR_VERSION} >> ${MADLIB_VERSION_FILE}
+ echo #define MADLIB_PATCH_VERSION ${MADLIB_PATCH_VERSION} >> ${MADLIB_VERSION_FILE}
+ echo #define MADLIB_EXTRA_VERSION "${MADLIB_EXTRA_VERSION}" >> ${MADLIB_VERSION_FILE}
+ echo #define MADLIB_VERSION "${MADLIB_VERSION}" >> ${MADLIB_VERSION_FILE}
+ echo #define MADLIB_DATE "" >> ${MADLIB_VERSION_FILE}
+ echo #define MADLIB_HOST "${HOSTNAME}" >> ${MADLIB_VERSION_FILE}
+ echo #define MADLIB_PACKAGER "" >> ${MADLIB_VERSION_FILE}
+ echo #define MADLIB_OS "${UNAME}" >> ${MADLIB_VERSION_FILE}
+ echo #define MADLIB_SHORT_LICENSE ${MADLIB_SHORT_LICENSE} >> ${MADLIB_VERSION_FILE}
+endif
+
+# Rules to build the MAdLib library
+
+.PHONY: lib
+lib: variables initialtag compile
+ifneq (${UNAME},WIN32MSVC)
+ @for i in ${MAdLib_DIRS}; do (cd $$i && ${MAKE} cpobj); done
+ ${AR} ${ARFLAGS}lib/libMAdLib${LIBEXT} ${MAdLib_TMPDIR}/*${OBJEXT}
+ ${RANLIB} lib/libMAdLib${LIBEXT}
+ rm -f lib/*${OBJEXT}
+else
+ for %%i in (${MAdLib_DIRS}); do ${MAKE} -C %%i
+ ${AR} ${ARFLAGS}bin\libMAdLib${LIBEXT} lib\*${LIBEXT}
+ erase lib\*${LIBEXT}
+ move bin\libMAdLib${LIBEXT} "lib"
+endif
+
+install: lib pc doc
+ifneq (${UNAME},WIN32MSVC)
+ mkdir -p ${includedir}/MAdLib
+ rm -f ${includedir}/MAdLib/*
+ cp -f ${MADLIB_API} ${includedir}/MAdLib
+ mkdir -p ${libdir}
+ cp -f lib/* ${libdir}/.
+ifneq (${DOXYGEN},)
+ mkdir -p ${docdir}
+ cp -rf doc/html ${docdir}/.
+ @echo "*********************************************************************"
+ @echo "MAdLib has been installed to the following locations:"
+ @echo " * Libraries: ${libdir}"
+ @echo " * Header files: ${includedir}"
+ @echo " * Documentation: ${docdir}"
+ @echo "Note that the libraries location should be found by the LD process."
+ @echo "*********************************************************************"
+else
+ @echo "*********************************************************************"
+ @echo "MAdLib has been installed to the following locations:"
+ @echo " * Libraries: ${libdir}"
+ @echo " * Header files: ${includedir}"
+ @echo "Note that the libraries location should be found by the LD process."
+ @echo "*********************************************************************"
+endif
+else
+ if not exist ${includedir}\MAdLib mkdir ${includedir}\MAdLib
+ if not exist ${libdir} mkdir ${libdir}
+ erase /q ${includedir}\MAdLib\*.h
+ for %%i in (${subst /,\,${MADLIB_API}}) do copy %%i ${includedir}\MAdLib
+ copy /y lib\libMAdLib${LIBEXT} ${libdir}\libMAdLib${LIBSUFFIX}${LIBEXT}
+endif
+
+install-bench: bench pc doc
+ifneq (${UNAME},WIN32MSVC)
+ mkdir -p ${includedir}/MAdLib
+ rm -f ${includedir}/MAdLib/*
+ cp -f ${MADLIB_API} ${includedir}/MAdLib
+ mkdir -p ${libdir}
+ cp -f lib/* ${libdir}/.
+ mkdir -p ${bindir}
+ -cp -f bin/* ${bindir}/.
+ifneq (${DOXYGEN},)
+ mkdir -p ${docdir}
+ cp -rf doc/html ${docdir}/.
+ @echo "*********************************************************************"
+ @echo "MAdLib has been installed to the following locations:"
+ @echo " * Libraries: ${libdir}"
+ @echo " * Header files: ${includedir}"
+ @echo " * Executables: ${bindir}"
+ @echo " * Documentation: ${docdir}"
+ @echo "Note that the libraries location should be found by the LD process."
+ @echo "*********************************************************************"
+else
+ @echo "*********************************************************************"
+ @echo "MAdLib has been installed to the following locations:"
+ @echo " * Libraries: ${libdir}"
+ @echo " * Header files: ${includedir}"
+ @echo " * Executables: ${bindir}"
+ @echo "Note that the libraries location should be found by the LD process."
+ @echo "*********************************************************************"
+endif
+# cp -f lib/libMAdLib${LIBEXT} ${libdir}/libMAdLib${LIBSUFFIX}${LIBEXT}
+else
+ if not exist ${includedir}\MAdLib mkdir ${includedir}\MAdLib
+ if not exist ${libdir} mkdir ${libdir}
+ erase /q ${includedir}\MAdLib\*.h
+ for %%i in (${subst /,\,${MADLIB_API}}) do copy %%i ${includedir}\MAdLib
+ copy /y lib\libMAdLib${LIBEXT} ${libdir}\libMAdLib${LIBSUFFIX}${LIBEXT}
+endif
+
+uninstall:
+ rm -rf ${includedir}/MAdLib
+ rm -rf ${libdir}/libMAdLib${LIBSUFFIX}${LIBEXT}
+ rm -rf ${docdir}
+ rm -rf ${bindir}
+ rm ${MADLIB_PCFILE}
+
+# Utilities
+
+variables: configure
+ @echo "********************************************************************"
+ @echo "Please configure MAdLib by running ./configure"
+ @echo "For help, type ./configure --help"
+ @echo "********************************************************************"
+ @exit 1
+
+dirs:
+ -mkdir -p bin lib ${MAdLib_TMPDIR}
+
+purge:
+ifneq (${UNAME},WIN32MSVC)
+ for i in ${MAdLib_DIRS}; do (cd $$i && ${MAKE} purge); done
+ for i in ${MAdLib_BENCHDIRS}; do (cd $$i && ${MAKE} purge); done
+else
+ for %%i in (${MAdLib_DIRS}) do ${MAKE} -C %%i purge
+ for %%i in (${MAdLib_BENCHDIRS}) do ${MAKE} -C %%i purge
+endif
+
+clean:
+ifneq (${UNAME},WIN32MSVC)
+ for i in ${MAdLib_DIRS}; do (cd $$i && ${MAKE} clean); done
+ for i in ${MAdLib_BENCHDIRS}; do (cd $$i && ${MAKE} clean); done
+ rm -f ${MADLIB_VERSION_FILE}
+ rm -rf bin lib ${MAdLib_TMPDIR} doc
+else
+ for %%i in (${MAdLib_DIRS}) do ${MAKE} -C %%i clean
+ for %%i in (${MAdLib_BENCHDIRS}) do ${MAKE} -C %%i clean
+ erase ${MADLIB_VERSION_FILE}
+ rm -rf bin lib ${MAdLib_TMPDIR} doc
+endif
+
+depend: initialtag
+ mv -f Common/MAdLibConfig.h .
+ cp -f MAdLibConfig.depend Common/MAdLibConfig.h
+ for i in ${MAdLib_DIRS}; do (cd $$i && ${MAKE} depend); done
+ mv -f MAdLibConfig.h Common/
+
+nodepend:
+ for i in ${MAdLib_DIRS} ; do \
+ (cd $$i && (sed '/^# DO NOT DELETE THIS LINE/q' Makefile) > Makefile.new \
+ && cp Makefile Makefile.bak \
+ && cp Makefile.new Makefile \
+ && rm -f Makefile.new); \
+ done
+
+initialtag:
+ifneq (${UNAME},WIN32MSVC)
+ @if [ ! -r ${MADLIB_VERSION_FILE} ]; then ${MAKE} tag ; fi
+else
+ ${MAKE} tag
+endif
+
+tags:
+ gtags
+ htags
+
+etags:
+ etags `find . \( -name "*.cpp" -o -name "*.c" -o -name "*.h"\
+ -o -name "*.y" -o -name "*.l" \)`
+
+# Rules to package the sources
+
+source-tree: purge
+ rm -rf MAdLib-${MADLIB_VERSION}
+ tar zcf MAdLib.tgz --exclude "*.o" --exclude "*.a" --exclude "libMAdLib*"\
+ --exclude "variables" --exclude "config.log" --exclude "config.status"\
+ --exclude "autom4*" --exclude "Makefile.distrib" --exclude "*.bak"\
+ --exclude "HTML" --exclude "*TAGS*" --exclude ".svn" --exclude "*.pos"\
+ --exclude "*.msh" --exclude "toPort" --exclude "poubelle"\
+ --exclude "Makefile.buildconfig"\
+ Geo Mesh Adapt Common Copyright.txt License.txt Credits.txt\
+ README *.in Contrib Makefile configure Tutorial doxygen.config
+ mkdir MAdLib-${MADLIB_VERSION}
+ cd MAdLib-${MADLIB_VERSION} && tar zxf ../MAdLib.tgz
+ rm -f MAdLib.tgz
+ tar zcf MAdLib_Benchmarks.tgz\
+ --exclude "*.bak"\
+ --exclude "*.msh"\
+ --exclude "*.pos"\
+ --exclude ".svn"\
+ --exclude "cpu" --exclude "*tmp*" --exclude "statistics"\
+ --exclude "slivers" --exclude "cpuinfo" --exclude "journal" --exclude "meshSize"\
+ Benchmarks/meshInfo Benchmarks/optimize\
+ Benchmarks/moveIt/*.h Benchmarks/moveIt/*.cc Benchmarks/moveIt/Makefile\
+ Benchmarks/moveIt/README\
+ Benchmarks/moveIt/examples/tube
+ cd MAdLib-${MADLIB_VERSION} && tar zxf ../MAdLib_Benchmarks.tgz
+ rm -f MAdLib_Benchmarks.tgz
+
+source: source-tree
+ cd MAdLib-${MADLIB_VERSION} && rm -rf ${MADLIB_VERSION_FILE}\
+ Common/MAdLibConfig.h
+ tar zcf MAdLib-${MADLIB_VERSION}-source.tgz MAdLib-${MADLIB_VERSION}
+
+# Configuration file to include MAdLib within a pkg-config compilation
+
+pc:
+ifneq (${UNAME},WIN32MSVC)
+ echo "prefix=${prefix}" > ${MADLIB_PCFILE}
+ echo "exec_prefix=${prefix}/bin" >> ${MADLIB_PCFILE}
+ echo "libdir=${libdir}" >> ${MADLIB_PCFILE}
+ echo "includedir=${includedir}" >> ${MADLIB_PCFILE}
+ echo "">> ${MADLIB_PCFILE}
+ echo "Name: MAdLib" >> ${MADLIB_PCFILE}
+ echo "Version: ${MADLIB_VERSION}" >> ${MADLIB_PCFILE}
+ echo "Description: Mesh adaptation library" >> ${MADLIB_PCFILE}
+ echo "Libs: -L${libdir} -lMAdLib" >> ${MADLIB_PCFILE}
+ echo "Cflags: -I${includedir}" >> ${MADLIB_PCFILE}
+else
+ echo prefix=${prefix} > ${MADLIB_PCFILE}
+ echo exec_prefix=${prefix}/bin >> ${MADLIB_PCFILE}
+ echo libdir=${libdir} >> ${MADLIB_PCFILE}
+ echo includedir=${includedir} >> ${MADLIB_PCFILE}
+ echo >> ${MADLIB_PCFILE}
+ echo Name: MAdLib >> ${MADLIB_PCFILE}
+ echo Version: ${MADLIB_VERSION} >> ${MADLIB_PCFILE}
+ echo Description: Mesh adaptation library >> ${MADLIB_PCFILE}
+ echo Libs: -L${libdir} -lMAdLib >> ${MADLIB_PCFILE}
+ echo Cflags: -I${includedir} >> ${MADLIB_PCFILE}
+endif
+
+doc:
+ifneq (${DOXYGEN},)
+ ${DOXYGEN} doxygen.config
+else
+ifneq (${UNAME},WIN32MSVC)
+ echo "Doxygen not found during configure process: documentation will not be generated"
+else
+ echo Doxygen not found during configure process: documentation will not be generated
+endif
+endif
diff --git a/Mesh/Balance.cc b/Mesh/Balance.cc
new file mode 100644
index 0000000..02aaa03
--- /dev/null
+++ b/Mesh/Balance.cc
@@ -0,0 +1,194 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseComm.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "Mark.h"
+#include "MAdMessage.h"
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#ifdef _HAVE_PARMETIS_
+#include "metisAdaptiveRepart.h"
+#endif
+#endif
+
+#include <stdio.h>
+
+using namespace MAd;
+
+namespace MAd {
+
+#ifdef PARALLEL
+ // -------------------------------------------------------------------
+ void Balance(pMesh mesh,MDB_DataExchanger &de) {
+
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+ pMeshDataId tagElt= MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+
+ // --- Mark the elements to be moved and their destination ---
+ if(dim==2) MarkTriangles (mesh, tagElt);
+ else MarkTets (mesh, tagElt);
+ // if(dim==2) MarkTrianglesSmooth (mesh, tagElt);
+ // else MarkTetsSmooth (mesh, tagElt);
+
+ // --- Move marked elements ---
+ loadBalancing(mesh, tagElt, de);
+
+ // --- Check that the mesh is not empty (debug) ---
+ if ( dim==2 ) assert( !( mesh->triangles.empty() ) );
+ if ( dim==3 ) assert( !( mesh->tets.empty() ) );
+
+ // ----------------------------------------------
+ // ------ Tagging inter-partition nodes
+ // ----------------------------------------------
+
+ pMeshDataId tag = MD_lookupMeshDataId("RemotePoint");
+
+ V_createInfoInterface(mesh,tag);
+ E_createInfoInterface(mesh,tag);
+ F_createInfoInterface(mesh,tag);
+
+ return;
+ }
+ // -------------------------------------------------------------------
+ void Balance2(pMesh mesh,MDB_DataExchanger &de) {
+
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+ pMeshDataId tagElt= MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+
+ // --- Mark the elements to be moved and their destination ---
+ if(dim==2) MarkTriangles (mesh, tagElt);
+ else MarkTets (mesh, tagElt);
+
+ // --- Move marked elements ---
+ loadBalancing2(mesh, tagElt, de);
+
+ // --- Check that the mesh is not empty (debug) ---
+ if ( dim==2 ) assert( !( mesh->triangles.empty() ) );
+ if ( dim==3 ) assert( !( mesh->tets.empty() ) );
+ // ----------------------------------------------
+ // ------ Tagging inter-partition nodes
+ // ----------------------------------------------
+
+ pMeshDataId tag = MD_lookupMeshDataId("RemotePoint");
+
+ V_createInfoInterface(mesh,tag);
+ E_createInfoInterface(mesh,tag);
+ F_createInfoInterface(mesh,tag);
+
+ return;
+ }
+
+ // -------------------------------------------------------------------
+ int BalanceManifold(pMesh mesh,MDB_DataExchanger &de) {
+
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+ pMeshDataId tagElt= MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+
+ int nmanifold = MarkTetsManifold(mesh,tagElt);
+
+ loadBalancing(mesh,tagElt,de);
+
+ if ( dim==3 ) assert( !(mesh->tets.empty()) );
+
+ return(nmanifold);
+ }
+
+ // -------------------------------------------------------------------
+ void BalanceRandom(pMesh mesh, MDB_DataExchanger &de) {
+
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+ pMeshDataId tagElt = MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+
+ if(dim==2) MarkTrianglesRandom(mesh,tagElt);
+ else MarkTetsRandom(mesh,tagElt);
+
+ loadBalancing(mesh,tagElt,de);
+
+ if ( dim==3 ) assert( !(mesh->tets.empty()) );
+ }
+
+ // -------------------------------------------------------------------
+#ifdef _HAVE_PARMETIS_
+ void BalanceMetis(pMesh mesh,MDB_DataExchanger &de) {
+
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+
+ //std::cout<<"metisAdaptiveRepart"<<mesh->nbPoints<<" "<<mesh->nbTets<<std::endl;
+ pMeshDataId tagElt = MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+ std::cout <<"USING PARMETIS"<<std::endl;
+ metisAdaptiveRepart(mesh,tagElt);
+
+ loadBalancing(mesh,tagElt,de);
+
+ //std::cout<<"end metisAdaptiveRepart"<<mesh->nbPoints<<" "<<mesh->nbTets<<std::endl;
+
+ if ( dim==3 ) assert( !(mesh->tets.empty()) );
+
+ return;
+ }
+#endif
+
+ // -------------------------------------------------------------------
+#ifdef _HAVE_PARMETIS_
+ void BalanceMetis2(pMesh mesh, MDB_DataExchanger &de) {
+
+ int dim = M_dim(mesh);
+
+ pMeshDataId tagElt = MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+ metisAdaptiveRepart(mesh,tagElt);
+ loadBalancing2(mesh,tagElt,de);
+
+ if ( M_dim(mesh) != dim ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "The dimension of the mesh has been reduced from %d to %d during a balancing operation",
+ dim, M_dim(mesh));
+ }
+
+ pMeshDataId tag = MD_lookupMeshDataId("RemotePoint");
+ V_createInfoInterface(mesh,tag);
+ E_createInfoInterface(mesh,tag);
+ F_createInfoInterface(mesh,tag);
+ }
+#endif
+
+ // -------------------------------------------------------------------
+#endif
+
+ // -------------------------------------------------------------------
+ void BalancePeriodic(pMesh mesh,int dim,MDB_DataExchanger &de,
+ MDB_DataExchangerPeriodic &deperiodic,std::vector<std::vector<int> >& transfo) {
+ pMeshDataId tagMove = MD_newMeshDataId("TagMovePeriodic");
+ pMeshDataId tagElt = MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+ /*for 3-periodic cases*/
+ pMeshDataId tagTransfo = MD_newMeshDataId("Transformation");
+
+ if(dim==2) MarkPeriodicTriangles(mesh,transfo,tagElt,tagMove,tagTransfo);
+ else MarkPeriodicTets(mesh,transfo,tagElt,tagMove,tagTransfo);
+
+ PeriodicInterfaceMigration(mesh,tagElt,tagMove,tagTransfo,de,deperiodic);
+
+ MD_deleteMeshDataId(tagMove);
+ MD_deleteMeshDataId(tagElt);
+ MD_deleteMeshDataId(tagTransfo);
+
+ return;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Mesh/CheckMesh.cc b/Mesh/CheckMesh.cc
new file mode 100644
index 0000000..d34835f
--- /dev/null
+++ b/Mesh/CheckMesh.cc
@@ -0,0 +1,825 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "CheckMesh.h"
+#include "MAdMessage.h"
+
+#include <stdio.h>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // checkGeometricalCompatibility:
+
+ // *** For 2D meshes ***
+
+ // --- Faces ---
+ // - check every face is classified on a surface
+
+ // --- Edges ---
+ // For every edge:
+ // - if is classified on a surface: the edge is used by exactly
+ // 2 faces with the same classification as the edge,
+ // - if classified on a line: the edge is used by exactly 1 face.
+ // - is not classified on a point
+
+ // --- Vertices ---
+ // For every vertex:
+ // - if classified on a surface: all edges using it have to be
+ // classified on the same surface,
+ // - if classified on a line: exactly two edges classified on the
+ // same line use it. No other edge classified on a line use it.
+ // - if classified on a point, at least two edges classified
+ // on different lines use it.
+
+ // *** For 3D meshes ***
+
+ // --- Regions ---
+ // - check every mesh region is classified on a model region
+
+ // --- Faces ---
+ // For every face:
+ // - if classified on a model region: the face is used by exactly
+ // 2 mesh regions with the same classification as the face,
+ // - if classified on a surface: the face is used by exactly 1
+ // mesh region.
+ // - is not classified on a line
+ // - is not classified on a point
+
+ // --- Edges ---
+ // For every edge:
+ // - if classified on a model region: check that all faces using
+ // it are classified on the same model region,
+ // - if classified on a surface: check that exactly 2 faces using it
+ // are classified on the same surface, and that no face is classified
+ // on a different surface,
+ // - if classified on a line: check that at least two faces using it
+ // are classified on surfaces (it can be the same surface: revoluted
+ // cylinder).
+ // - is not classified on a point
+
+ // --- Vertices ---
+ // For every vertex:
+ // - if classified on a model region: all edges using it have to be
+ // classified on the same model region,
+ // - if classified on a surface: at least 3 edges using it are
+ // classified on the same surface, and no edge can be classified
+ // on a line or on a different surface.
+ // - if classified on a line: exactly 2 edges using it are
+ // classified on the same line and no other edge is classified
+ // on a line,
+ // - if classified on a point: at least 1 edge using it is
+ // classified on a line (only 1: for revoluted cones).
+
+ int checkGeomCompatibility(MDB_Mesh * mesh, int verbose, std::ostream& out)
+ {
+#ifdef PARALLEL
+ // In a mesh partitioned with MDB, the parallel boundary
+ // faces are not classified on a model face and the following
+ // check fails
+ return 1;
+#endif
+
+// #warning "check geometric compatibility not implemented for 2D meshes"
+ if ( M_dim(mesh) < 3 ) return 1;
+
+ int gDim;
+
+ int flag = 1;
+
+ // --- Regions ---
+
+ pRegion pr;
+ RIter rIt= M_regionIter(mesh);
+ while ( ( pr = RIter_next(rIt) ) )
+ {
+ gDim = R_whatInType(pr);
+ if ( gDim != 3 ) {
+ flag = 0;
+ if (verbose) {
+ out << "Mesh region not classified on a model region\n";
+ R_info_topology(pr,out);
+ }
+ break;
+ }
+ }
+ RIter_delete(rIt);
+ if ( !flag ) return 0;
+
+ // -- Faces ---
+
+ pFace pf;
+ FIter fIt= M_faceIter(mesh);
+ while ( flag && ( pf = FIter_next(fIt) ) )
+ {
+ gDim = F_whatInType(pf);
+ switch (gDim) {
+ case 3: {
+ int nRgn = F_numRegions(pf);
+ if ( nRgn != 2 ) {
+ flag = 0;
+ if (verbose) {
+ out << "Face classif on dim 3 with not exactly 2 regions\n";
+ F_info(pf,"",out);
+ }
+ }
+ if ( ( F_whatIn(pf) != R_whatIn( F_region(pf,0) ) ) ||
+ ( F_whatIn(pf) != R_whatIn( F_region(pf,1) ) ) ) {
+ flag = 0;
+ if (verbose) {
+ out << "Face classif on dim 3 used by regions classif on different entities\n";
+ F_info(pf,"",out);
+ }
+ }
+ break;
+ }
+ case 2: {
+ int nRgn = F_numRegions(pf);
+ if ( nRgn != 1 ) {
+ flag = 0;
+ if (verbose) {
+ out << "Face classif on dim 2 with not exactly 1 region\n";
+ F_info(pf,"",out);
+ }
+ }
+ break;
+ }
+ default: {
+ flag = 0;
+ if (verbose) {
+ out << "Face classif on wrong dimension\n";
+ F_info(pf,"",out);
+ }
+ }
+ }
+ }
+ FIter_delete(fIt);
+ if ( !flag ) return 0;
+
+ // -- Edges ---
+
+ pEdge pe;
+ pGEntity pge;
+ pPList eFaces;
+ void * temp;
+ EIter eIt = M_edgeIter(mesh);
+ while ( flag && ( pe = EIter_next(eIt) ) )
+ {
+ pge = E_whatIn(pe);
+ gDim = GEN_type(pge);
+ switch (gDim) {
+ case 3: {
+ eFaces = E_faces(pe);
+ temp = NULL;
+ while ( ( pf = (pFace) PList_next(eFaces,&temp) ) ) {
+ if ( F_whatIn(pf) != pge ) {
+ flag = 0;
+ if (verbose) {
+ out << "Edge classif on a region but used by faces "
+ << "not classif on the same region\n";
+ E_info(pe,"",out);
+ }
+ }
+ }
+ PList_delete(eFaces);
+ break;
+ }
+ case 2: {
+ int nbBF = 0;
+ eFaces = E_faces(pe);
+ temp = NULL;
+ while ( ( pf = (pFace) PList_next(eFaces,&temp) ) ) {
+ if ( F_whatInType(pf) == 2 ) {
+ if ( F_whatIn(pf) != pge ) {
+ flag = 0;
+ if (verbose) {
+ out << "Edge classif on a surface used by a face classif "
+ << "on another surface\n";
+ E_info(pe,"",out);
+ }
+ }
+ nbBF++;
+ }
+ }
+ PList_delete(eFaces);
+ if ( nbBF != 2 ) {
+ flag = 0;
+ if (verbose) {
+ out << "Edge classif on a surface and not used by exactly "
+ << "2 faces classif on surfaces\n";
+ E_info(pe,"",out);
+ }
+ }
+ break;
+ }
+ case 1: {
+ int nbBF = 0;
+ eFaces = E_faces(pe);
+ temp = NULL;
+ while ( ( pf = (pFace) PList_next(eFaces,&temp) ) ) {
+ if ( F_whatInType(pf) == 2 ) nbBF++;
+ }
+ PList_delete(eFaces);
+ if ( nbBF < 2 ) {
+ flag = 0;
+ if (verbose) {
+ out << "Edge classif on a line and not used by at least"
+ << " 2 faces classif on surfaces\n";
+ E_info(pe,"",out);
+ }
+ }
+ break;
+ }
+ default: {
+ flag = 0;
+ if (verbose) {
+ out << "Edge classif on wrong dimension\n";
+ E_info(pe,"",out);
+ }
+ }
+ }
+ }
+ EIter_delete(eIt);
+ if ( !flag ) return 0;
+
+ // -- Vertices ---
+
+ pPList vEdges;
+ pVertex pv;
+ VIter vIt = M_vertexIter(mesh);
+ while ( flag && ( pv = VIter_next(vIt) ) )
+ {
+ pge = V_whatIn(pv);
+ gDim = GEN_type(pge);
+ switch (gDim) {
+ case 3: {
+ vEdges = V_edges(pv);
+ temp = NULL;
+ while ( ( pe = (pEdge) PList_next(vEdges,&temp) ) ) {
+ if ( E_whatIn(pe) != pge ) {
+ flag = 0;
+ if (verbose) {
+ out << "Vertex classif on a region but used by edges "
+ << "not classif on the same region\n";
+ V_info(pv,"",out);
+ }
+ }
+ }
+ PList_delete(vEdges);
+ break;
+ }
+ case 2: {
+ int nbE = 0;
+ vEdges = V_edges(pv);
+ temp = NULL;
+ while ( ( pe = (pEdge) PList_next(vEdges,&temp) ) ) {
+ if ( E_whatInType(pe) == 3 ) continue;
+ if ( E_whatIn(pe) != pge ) {
+ flag = 0;
+ if (verbose) {
+ out << "Vertex classif on a surface but used by edges "
+ << "not classif on the same surface or on a region\n";
+ V_info(pv,"",out);
+ }
+ }
+ nbE++;
+ }
+ PList_delete(vEdges);
+ if ( nbE < 3 ) {
+ flag = 0;
+ if (verbose) {
+ out << "Vertex classif on a surface and not used by at least"
+ << " 3 edges classif on surfaces\n";
+ V_info(pv,"",out);
+ }
+ }
+ break;
+ }
+ case 1: {
+ int nbE = 0;
+ vEdges = V_edges(pv);
+ temp = NULL;
+ while ( ( pe = (pEdge) PList_next(vEdges,&temp) ) ) {
+ if ( E_whatInType(pe) > 1 ) continue;
+ if ( E_whatIn(pe) != pge ) {
+ flag = 0;
+ if (verbose) {
+ out << "Vertex classif on a line and used by an edge "
+ << "classif on another line\n";
+ V_info(pv,"",out);
+ }
+ }
+ nbE++;
+ }
+ PList_delete(vEdges);
+ if ( nbE != 2 ) {
+ flag = 0;
+ if (verbose) {
+ out << "Vertex classif on a line and not used by exactly"
+ << " 2 edges classif on the same line\n";
+ V_info(pv,"",out);
+ }
+ }
+ break;
+ }
+ case 0: {
+ int nbE = 0;
+ std::set<pGEntity> glines;
+ vEdges = V_edges(pv);
+ temp = NULL;
+ while ( ( pe = (pEdge) PList_next(vEdges,&temp) ) ) {
+ if ( E_whatInType(pe) > 1 ) continue;
+ nbE++;
+ glines.insert(E_whatIn(pe));
+ }
+ PList_delete(vEdges);
+ if ( nbE == 0 ) {
+ flag = 0;
+ if (verbose) {
+ out << "Vertex classif on a point and not used by an"
+ << " edge classif on a line\n";
+ V_info(pv,"",out);
+ }
+ }
+// if ( nbE < 2 ) {
+// flag = 0;
+// if (verbose) {
+// out << "Vertex classif on a point and used by less than"
+// << " 2 edges classif on lines\n";
+// V_info(pv,"",out);
+// }
+// }
+// if ( glines.size() < 2 ) {
+// flag = 0;
+// if (verbose) {
+// out << "Vertex classif on a point and not used by edges"
+// << " classified on different lines\n";
+// V_info(pv,"",out);
+// }
+// }
+ break;
+ }
+ default: {
+ flag = 0;
+ if (verbose) {
+ out << "Vertex classif on non-existing dimension\n";
+ V_info(pv,"",out);
+ }
+ }
+ }
+ }
+ VIter_delete(vIt);
+ if ( !flag ) return 0;
+
+ return flag;
+
+ }
+
+ // -------------------------------------------------------------------
+ int checkRegionsVolume(MDB_Mesh * mesh, int verbose, std::ostream& out)
+ {
+ int flag = 1;
+ pRegion r;
+ RIter rIt= M_regionIter(mesh);
+ while ( ( r = RIter_next(rIt) ) ) {
+ if (R_volume(r) < 0.) {
+ flag = 0;
+ if (verbose) {
+ out << "Negative volume found !\n";
+ R_info_topology(r,out);
+ }
+ break;
+ }
+ }
+ RIter_delete(rIt);
+ return flag;
+ }
+
+ // -------------------------------------------------------------------
+ int checkEdgeToRegionConnectivity(MDB_Mesh * mesh, int verbose,
+ std::ostream& out)
+ {
+#ifdef PARALLEL
+ // In a mesh partitioned with MDB, the parallel boundary
+ // faces are not classified on a model face and the following
+ // check fails
+ return 1;
+#endif
+
+ if ( M_dim(mesh) <= 2 ) return 1;
+
+ int flag = 1;
+ pEdge edge;
+ EIter eIt = M_edgeIter(mesh);
+ while ( ( edge = EIter_next(eIt) ) ) {
+
+ if ( E_whatInType(edge) != 3 ) continue;
+
+ pFace face = E_face(edge,0);
+ pRegion start_region = F_region(face,0);
+
+ pFace current_face = face;
+ pRegion current_region = start_region;
+ pFace next_face;
+ pRegion next_region = NULL;
+ while ( next_region != start_region )
+ {
+ next_face = E_otherFace(edge, current_face, current_region);
+ next_region = F_region(next_face, 0);
+ if( next_region == current_region ) {
+ next_region = F_region(next_face, 1);
+ }
+ current_face = next_face;
+ current_region = next_region;
+
+ if ( !next_region ) {
+ flag = 0;
+ if (verbose) {
+ out << "Found a wrong edge to region connectivity !\n";
+ E_info(edge,"",out);
+ }
+ break;
+ }
+ }
+ }
+ EIter_delete(eIt);
+ return flag;
+ }
+
+ // -------------------------------------------------------------------
+ // Obsolete: included in checkGeomCompatibility()
+ int checkFaceToRegionConnectivity(MDB_Mesh * mesh, int verbose, std::ostream& out) {
+
+#ifdef PARALLEL
+ // In a mesh partitioned with MDB, the parallel boundary
+ // faces are not classified on a model face and the following
+ // check fails
+ return 1;
+#endif
+
+ if ( M_dim(mesh) <= 2 ) return 1;
+
+ int flag = 1;
+ pFace f;
+ FIter fIt= M_faceIter(mesh);
+ while ( ( f = FIter_next(fIt) ) ) {
+ int ok = 1;
+ int nRgn = F_numRegions(f);
+ if (nRgn==0) out << "nRgn: " << nRgn << "\n";
+ int type = F_whatInType(f);
+ if ( nRgn == 0 ) ok = 0;
+ if ( type == 2 && nRgn != 1 ) ok = 0;
+ if ( type == 3 && nRgn != 2 ) ok = 0;
+ if (!ok) {
+ flag = 0;
+ if (verbose) {
+ out << "Found a wrong face to region connectivity !\n";
+ F_info(f,"",out);
+ }
+ break;
+ }
+ }
+ FIter_delete(fIt);
+ return flag;
+ }
+
+ // -------------------------------------------------------------------
+ int checkFaceToVertexConnectivity(MDB_Mesh * mesh, int verbose, std::ostream& out)
+ {
+ int flag = 1;
+ pFace f;
+ pVertex v0,v1,v2;
+ FIter fIt = M_faceIter(mesh);
+ while ( ( f = FIter_next(fIt) ) ) {
+ v0 = F_vertex(f,0);
+ v1 = F_vertex(f,1);
+ v2 = F_vertex(f,2);
+ if ( v0 == v1 || v0 == v2 || v1 == v2 ) {
+ flag = 0;
+ if (verbose) {
+ out << "Found a wrong face to vertex connectivity !\n";
+ F_info(f,"",out);
+ }
+ break;
+ }
+ }
+ FIter_delete(fIt);
+ return flag;
+ }
+
+ // -------------------------------------------------------------------
+ // Check that there is at least one face attached to each edge in 2D,
+ // one region and two faces in 3D.
+ int checkEdgeConnectivity(MDB_Mesh * mesh, int verbose, std::ostream& out) {
+
+#ifdef PARALLEL
+ // In a mesh partitioned with MDB, the parallel boundary
+ // edges are not classified on a model line and the following
+ // check fails
+ return 1;
+#endif
+
+ int dim = M_dim(mesh);
+ if ( dim <= 1 ) return 1;
+
+ int flag = 1;
+ pEdge e;
+ EIter eIt= M_edgeIter(mesh);
+ while ( ( e = EIter_next(eIt) ) ) {
+ int nFace = E_numFaces(e);
+ int nRgn = E_numRegions(e);
+ if ( dim == 2 ) {
+ if ( (nRgn != 0) || (nFace < 1) ) {
+ flag = 0; break;
+ }
+ }
+ else if ( dim == 3 ) {
+ if ( (nRgn < 1) || (nFace < 2) ) {
+ flag = 0; break;
+ }
+ }
+ }
+ EIter_delete(eIt);
+ if ( (!flag) && verbose ) {
+ out << "Found an ill-connected edge !\n";
+ E_info(e,"",out);
+ }
+ return flag;
+ }
+
+ // -------------------------------------------------------------------
+ int checkEntityPointers(MDB_Mesh * mesh, int verbose, std::ostream& out) {
+
+ int flag = 1;
+
+ VIter vIt = M_vertexIter(mesh);
+ pVertex pv;
+ while ( ( pv = VIter_next(vIt) ) ) {
+ if ( !pv ) {
+ flag = 0;
+ if (verbose) out << "Found a null pointer when iterating on vertices\n";
+ }
+ }
+ VIter_delete(vIt);
+
+ EIter eIt = M_edgeIter(mesh);
+ pEdge pe;
+ while ( ( pe = EIter_next(eIt) ) ) {
+ if ( !pe ) {
+ flag = 0;
+ if (verbose) out << "Found a null pointer when iterating on edges\n";
+ }
+ }
+ EIter_delete(eIt);
+
+ FIter fIt = M_faceIter(mesh);
+ pFace pf;
+ while ( ( pf = FIter_next(fIt) ) ) {
+ if ( !pf ) {
+ flag = 0;
+ if (verbose) out << "Found a null pointer when iterating on faces\n";
+ }
+ }
+ FIter_delete(fIt);
+
+ RIter rIt = M_regionIter(mesh);
+ pRegion pr;
+ while ( ( pr = RIter_next(rIt) ) ) {
+ if ( !pr ) {
+ flag = 0;
+ if (verbose) out << "Found a null pointer when iterating on regions\n";
+ }
+ }
+ RIter_delete(rIt);
+
+ return flag;
+ }
+
+ // -------------------------------------------------------------------
+ int checkIterators(MDB_Mesh * mesh, int verbose, std::ostream& out) {
+
+ int flag = 1;
+
+ int nbMeshV = M_numVertices(mesh);
+ int nbIterV = 0;
+ VIter vIt= M_vertexIter(mesh);
+ while ( VIter_next(vIt) ) nbIterV++;
+ VIter_delete(vIt);
+ if ( nbMeshV != nbIterV ) {
+ flag = 0;
+ if (verbose) {
+ out << "Incoherent number of vertices: "
+ << nbMeshV << " in mesh, "
+ << nbIterV << " in iterator\n";
+ }
+ }
+
+ int nbMeshE = M_numEdges(mesh);
+ int nbIterE = 0;
+ EIter eIt= M_edgeIter(mesh);
+ while ( EIter_next(eIt) ) nbIterE++;
+ EIter_delete(eIt);
+ if ( nbMeshE != nbIterE ) {
+ flag = 0;
+ if (verbose) {
+ out << "Incoherent number of edges: "
+ << nbMeshE << " in mesh, "
+ << nbIterE << " in iterator\n";
+ }
+ }
+
+ int nbMeshF = M_numFaces(mesh);
+ int nbIterF = 0;
+ FIter fIt= M_faceIter(mesh);
+ while ( FIter_next(fIt) ) nbIterF++;
+ FIter_delete(fIt);
+ if ( nbMeshF != nbIterF ) {
+ flag = 0;
+ if (verbose) {
+ out << "Incoherent number of faces: "
+ << nbMeshF << " in mesh, "
+ << nbIterF << " in iterator\n";
+ }
+ }
+
+ int nbMeshR = M_numRegions(mesh);
+ int nbIterR = 0;
+ RIter rIt= M_regionIter(mesh);
+ while ( RIter_next(rIt) ) nbIterR++;
+ RIter_delete(rIt);
+ if ( nbMeshR != nbIterR ) {
+ flag = 0;
+ if (verbose) {
+ out << "Incoherent number of regions: "
+ << nbMeshR << " in mesh, "
+ << nbIterR << " in iterator\n";
+ }
+ }
+
+ return flag;
+ }
+
+ // -------------------------------------------------------------------
+ int checkParameters(MDB_Mesh * mesh, int verbose, std::ostream& out)
+ {
+ if ( !M_isParametric(mesh) ) return 1;
+
+ int flag = 1;
+
+ pVertex pv;
+ double tmp0,tmp1;
+ VIter vIt= M_vertexIter(mesh);
+ while ( ( pv = VIter_next(vIt) ) ) {
+ int gDim = V_whatInType(pv);
+ bool param = V_params(pv,&tmp0,&tmp1);
+ if ( ( gDim==0 || gDim==1 || gDim==2 ) && !param ) {
+ flag = 0;
+ if (verbose) {
+ out << "Non parametric point classified on geo entity with dim " <<gDim<<"\n";
+ V_info(pv,"",out);
+ }
+ }
+ if ( ( gDim==3 ) && param ) {
+ flag = 0;
+ if (verbose) {
+ out << "Parametric point classified on geo entity with dim " <<gDim<<"\n";
+ V_info(pv,"",out);
+ }
+ }
+ }
+ VIter_delete(vIt);
+
+ return flag;
+ }
+
+ // -------------------------------------------------------------------
+ bool checkMesh(MDB_Mesh * mesh, checkType type, int verbose,
+ std::ostream& out, MeshStatus * status) {
+
+ switch (type) {
+ case CHECK_ALL: {
+ if ( !checkRegionsVolume(mesh, verbose, out) ) {
+ if(status) *status = NEGATIVE_VOLUME;
+ return false;
+ }
+ if ( !checkGeomCompatibility(mesh, verbose, out) ) {
+ if(status) *status = GEOM_INCOMPATIBILITY;
+ return false;
+ }
+ if ( !checkEdgeToRegionConnectivity(mesh, verbose, out) ) {
+ if(status) *status = WRONG_EDGE_TO_RGN_CONN;
+ return false;
+ }
+ if ( !checkFaceToRegionConnectivity(mesh, verbose, out) ) {
+ if(status) *status = WRONG_FACE_TO_RGN_CONN;
+ return false;
+ }
+ if ( !checkFaceToVertexConnectivity(mesh, verbose, out) ) {
+ if(status) *status = WRONG_FACE_TO_VTX_CONN;
+ return false;
+ }
+ if ( !checkEdgeConnectivity(mesh, verbose, out) ) {
+ if(status) *status = WRONG_EDGE_CONN;
+ return false;
+ }
+ if ( !checkEntityPointers(mesh, verbose, out) ) {
+ if(status) *status = WRONG_ENTITY_POINTERS;
+ return false;
+ }
+ if ( !checkIterators(mesh, verbose, out) ) {
+ if(status) *status = WRONG_ITERATORS;
+ return false;
+ }
+ if ( !checkParameters(mesh, verbose, out) ) {
+ if(status) *status = WRONG_PARAMETERS;
+ return false;
+ }
+ break;
+ }
+ case CHECK_VOLUME: {
+ if ( !checkRegionsVolume(mesh, verbose, out) ) {
+ if(status) *status = NEGATIVE_VOLUME;
+ return false;
+ }
+ break;
+ }
+ case CHECK_GEOM_COMPATIBILITY: {
+ if ( !checkGeomCompatibility(mesh, verbose, out) ) {
+ if(status) *status = GEOM_INCOMPATIBILITY;
+ return false;
+ }
+ break;
+ }
+ case CHECK_EDGE_TO_RGN_CONN: {
+ if ( !checkEdgeToRegionConnectivity(mesh, verbose, out) ) {
+ if(status) *status = WRONG_EDGE_TO_RGN_CONN;
+ return false;
+ }
+ break;
+ }
+ case CHECK_FACE_TO_RGN_CONN: {
+ if ( !checkFaceToRegionConnectivity(mesh, verbose, out) ) {
+ if(status) *status = WRONG_FACE_TO_RGN_CONN;
+ return false;
+ }
+ break;
+ }
+ case CHECK_FACE_TO_VTX_CONN: {
+ if ( !checkFaceToVertexConnectivity(mesh, verbose, out) ) {
+ if(status) *status = WRONG_FACE_TO_VTX_CONN;
+ return false;
+ }
+ break;
+ }
+ case CHECK_EDGE_CONN: {
+ if ( !checkEdgeConnectivity(mesh, verbose, out) ) {
+ if(status) *status = WRONG_EDGE_CONN;
+ return false;
+ }
+ break;
+ }
+ case CHECK_ENTITY_POINTERS: {
+ if ( !checkEntityPointers(mesh, verbose, out) ) {
+ if(status) *status = WRONG_ENTITY_POINTERS;
+ return false;
+ }
+ break;
+ }
+ case CHECK_ITERATORS: {
+ if ( !checkIterators(mesh, verbose, out) ) {
+ if(status) *status = WRONG_ITERATORS;
+ return false;
+ }
+ break;
+ }
+ case CHECK_PARAMETERS: {
+ if ( !checkParameters(mesh, verbose, out) ) {
+ if(status) *status = WRONG_PARAMETERS;
+ return false;
+ }
+ break;
+ }
+ default: {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Not a valid checkType: %d",type);
+ return false;
+ }
+ }
+
+ if(status) *status = VALID;
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Mesh/CheckMesh.h b/Mesh/CheckMesh.h
new file mode 100644
index 0000000..fcf46b7
--- /dev/null
+++ b/Mesh/CheckMesh.h
@@ -0,0 +1,58 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _CHECKMESH_H_
+#define _CHECKMESH_H_
+
+#include "MeshDataBaseInterface.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ typedef enum MeshStatus {
+ VALID = 0,
+ NEGATIVE_VOLUME = 1,
+ GEOM_INCOMPATIBILITY = 2,
+ WRONG_EDGE_TO_RGN_CONN = 3,
+ WRONG_FACE_TO_RGN_CONN = 4,
+ WRONG_FACE_TO_VTX_CONN = 5,
+ WRONG_EDGE_CONN = 6,
+ WRONG_ENTITY_POINTERS = 7,
+ WRONG_ITERATORS = 8,
+ WRONG_PARAMETERS = 9
+ } MeshStatus;
+
+ // -------------------------------------------------------------------
+ typedef enum checkType {
+ CHECK_ALL,
+ CHECK_VOLUME,
+ CHECK_GEOM_COMPATIBILITY,
+ CHECK_EDGE_TO_RGN_CONN,
+ CHECK_FACE_TO_RGN_CONN,
+ CHECK_FACE_TO_VTX_CONN,
+ CHECK_EDGE_CONN,
+ CHECK_ENTITY_POINTERS,
+ CHECK_ITERATORS,
+ CHECK_PARAMETERS
+ } checkType;
+
+ // -------------------------------------------------------------------
+ // return 1 if the mesh passes the test successfully, 0 otherwise
+ bool checkMesh(MDB_Mesh * mesh, checkType type, int verbose,
+ std::ostream& out=std::cout, MeshStatus * status=NULL);
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Mesh/CheckOrientation.cc b/Mesh/CheckOrientation.cc
new file mode 100644
index 0000000..94269c8
--- /dev/null
+++ b/Mesh/CheckOrientation.cc
@@ -0,0 +1,415 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MSops.h"
+
+#ifdef PARALLEL
+#include <cassert>
+
+#include "mpi.h"
+#include "autopack.h"
+
+#include "MeshDataBase.h"
+
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseParallelInterface.h"
+
+#include "CheckOrientation.h"
+
+namespace MAd {
+
+ struct edge_comm
+ {
+ pVertex p1,p2; //pointer in dest
+ int sendID;
+ };
+
+ struct face_comm {
+ pVertex pdest[3];
+ };
+
+ int CheckEdgesOrientation(pMesh mesh){
+#ifdef DEBUG
+ int norient = 0;
+#endif
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ EIter eit = M_edgeIter(mesh);
+ pEdge pedge;
+ while ((pedge = EIter_next(eit))) {
+ pVertex p[2];
+ p[0] = E_vertex(pedge,0);
+ p[1] = E_vertex(pedge,1);
+ int tmp1;
+ int isInterface1 = EN_getDataInt((pEntity) p[0] ,tagData, &tmp1);
+ int tmp2;
+ int isInterface2 = EN_getDataInt((pEntity) p[1] ,tagData, &tmp2);
+ if(!isInterface1 || !isInterface2) continue;
+ const std::vector<std::pair<int , pVertex> > *recup1 = (std::vector<std::pair<int , pVertex> > *) tmp1;
+ const std::vector<std::pair<int , pVertex> > *recup2 = (std::vector<std::pair<int , pVertex> > *) tmp2;
+ int size1 = (*recup1).size();
+ int size2 = (*recup2).size();
+ assert(size1);assert(size2);
+ int *tab=new int[size1];
+ for(int i=0 ; i< size1 ; i++) tab[i] = (*recup1)[i].first;
+ //check if myrank must send
+ int nSender = myrank;
+ for(int j=0 ; j< size2 ; j++) {
+ int iProc = (*recup2)[j].first;
+ int i;
+ for(i=0 ; i<size1 ; i++) {
+ if(iProc == tab[i]) break;
+ }
+ if(i<size1) {
+ if(iProc < nSender) nSender = iProc;
+ }
+ }
+ if(nSender != myrank) continue;
+ for(int j=0 ; j< size2 ; j++) {
+ int iProc = (*recup2)[j].first;
+ int i;
+ for(i=0 ; i<size1 ; i++) {
+ if(iProc == tab[i]) break;
+ }
+ if(i < size1) {
+ pVertex remote1 = (*recup1)[i].second;
+ pVertex remote2 = (*recup2)[j].second;
+ assert(iProc != myrank);
+ assert(iProc > myrank);
+ void *buf = AP_alloc(iProc,444,sizeof(edge_comm));
+ edge_comm *castbuf = (edge_comm *) buf;
+ castbuf->p1 = remote1;
+ castbuf->p2 = remote2,
+ castbuf->sendID = myrank;
+ AP_send(buf);
+ sendcounts[iProc]++;
+ }
+ }
+ delete []tab;
+ }
+ EIter_delete(eit);
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ int message=0;
+ int count;
+
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int rc;
+ rc=AP_recv(MPI_ANY_SOURCE,444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if (rc) {
+ message++;
+ edge_comm * castbuf = (edge_comm*) msg;
+ pVertex p1recv,p2recv;
+ p1recv = castbuf -> p1;
+ p2recv = castbuf -> p2;
+ assert(p1recv);assert(p2recv);
+ int nprocrecv = castbuf->sendID;
+ assert(nprocrecv==from);
+ pEdge pe = E_exist(p1recv,p2recv);
+ if(pe) {
+ //check orientation
+ if(E_vertex(pe,0) != p1recv) {
+#ifdef DEBUG
+ norient++;
+#endif
+ pe->p1 = p1recv;
+ pe->p2 = p2recv;
+ assert(E_vertex(pe,0) == p1recv);
+ }
+ }
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+#ifdef DEBUG
+ return norient;
+#else
+ return 0;
+#endif
+ }
+
+
+ int CheckFacesOrientation(pMesh mesh){
+#ifdef DEBUG
+ int norient = 0;
+#endif
+ int mysize,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[mysize];
+ for(int i=0;i<mysize;i++) sendcounts[i]=0;
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ pVertex p1 = F_vertex(pface,0);
+ pVertex p2 = F_vertex(pface,1);
+ pVertex p3 = F_vertex(pface,2);
+ void *temp_ptr1,*temp_ptr2,*temp_ptr3;
+ int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+ int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+ int isInterface3 = EN_getDataPtr((pEntity) p3 , tagData, &temp_ptr3);
+ if(!(isInterface1 && isInterface2 && isInterface3)) continue;
+
+ const std::vector<std::pair<int , pVertex> > *recup1 = (std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+ const std::vector<std::pair<int , pVertex> > *recup2 = (std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+ const std::vector<std::pair<int , pVertex> > *recup3 = (std::vector<std::pair<int , pVertex> > *) temp_ptr3;
+ int size = (*recup1).size();
+ int *tab=new int[size];
+ for(int i=0 ; i< size ; i++) tab[i] = (*recup1)[i].first;
+
+ int size2 = (*recup2).size();
+ int *tab2=new int[size2];
+ for(int i=0 ; i< size2 ; i++) tab2[i] = (*recup2)[i].first;
+
+ // check if I must send
+ int nSender = myrank;
+ for(unsigned int k=0 ; k<(*recup3).size() ; k++) {
+ int iProc = (*recup3)[k].first;
+ int i;
+ for(i=0 ; i<size ; i++) {
+ if(iProc == tab[i]) break;
+ }
+ int j;
+ for(j=0 ; j<size2 ; j++) {
+ if(iProc == tab2[j]) break;
+ }
+ if(i < size && j < size2) {
+ if(iProc < nSender) nSender = iProc;
+ }
+ }
+
+ if(nSender != myrank) continue;
+
+ for(unsigned int k=0 ; k<(*recup3).size() ; k++) {
+ int iProc = (*recup3)[k].first;
+ int i;
+ for(i=0 ; i<size ; i++) {
+ if(iProc == tab[i]) break;
+ }
+ int j;
+ for(j=0 ; j<size2 ; j++) {
+ if(iProc == tab2[j]) break;
+ }
+ if(i < size && j < size2) {
+ assert(tab[i]==iProc);
+ assert(tab2[j]==iProc);
+
+ pVertex remote1 = (*recup1)[i].second;
+ pVertex remote2 = (*recup2)[j].second;
+ pVertex remote3 = (*recup3)[k].second;
+
+ void *buf = AP_alloc(iProc,444,sizeof(face_comm));
+ face_comm *castbuf = (face_comm *) buf;
+ castbuf->pdest[0] = remote1;
+ castbuf->pdest[1] = remote2,
+ castbuf->pdest[2] = remote3,
+ AP_send(buf);
+ sendcounts[iProc]++;
+ }
+ }
+ delete []tab;
+ delete []tab2;
+ }
+ FIter_delete(fit);
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ face_comm * facecom = (face_comm * ) msg;
+ pVertex p1 = facecom->pdest[0];
+ pVertex p2 = facecom->pdest[1];
+ pVertex p3 = facecom->pdest[2];
+ pEdge pe[3];
+ pe[0] = E_exist(p1,p2);
+ pe[1] = E_exist(p2,p3);
+ pe[2] = E_exist(p1,p3);
+
+ if(pe[0] && pe[1] && pe[2]) {
+ // pFace pface = F_exist(2,p1,p2,p3,0);
+ pFace pface = F_exist(p1,p2,p3,0);
+ assert(pface);
+
+ //check orientation
+ if(F_edge(pface,0) != pe[0] || F_edge(pface,1) != pe[1]) {
+ ((MDB_Triangle*)pface)->e1 = pe[0];
+ ((MDB_Triangle*)pface)->e2 = pe[1];
+ ((MDB_Triangle*)pface)->e3 = pe[2];
+#ifdef DEBUG
+ norient++;
+#endif
+ }
+ }
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+#ifdef DEBUG
+ return norient;
+#else
+ return 0;
+#endif
+ }
+
+/*
+// version with sets for the parallel nodes
+int CheckEdgesOrientation(pMesh mesh){
+#ifdef DEBUG
+int norient = 0;
+#endif
+int nproc,myrank;
+MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+int *sendcounts = new int[nproc];
+for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+EIter eit = M_edgeIter(mesh);
+pEdge pedge;
+while ((pedge = EIter_next(eit))) {
+pVertex p[2];
+p[0] = E_vertex(pedge,0);
+p[1] = E_vertex(pedge,1);
+int tmp1;
+int isInterface1 = EN_getDataInt((pEntity) p[0] ,tagData, &tmp1);
+int tmp2;
+int isInterface2 = EN_getDataInt((pEntity) p[1] ,tagData, &tmp2);
+if(!isInterface1 || !isInterface2) continue;
+const std::set<std::pair<int, MDB_Point*> > *recup1 = (std::set<std::pair<int, MDB_Point*> > *) temp_ptr1;
+const std::set<std::pair<int, MDB_Point*> > *recup2 = (std::set<std::pair<int, MDB_Point*> > *) temp_ptr2;
+int size1 = (*recup1).size();
+int size2 = (*recup2).size();
+assert(size1);assert(size2);
+int *tab=new int[size1];
+std::set<std::pair<int, MDB_Point*> >::const_iterator rIter1 = recup1->begin();
+for (int i=0; rIter1 != recup1->end(); rIter1++, i++) tab[i] = (*rIter1).first;
+int nSender = myrank;
+std::set<std::pair<int, MDB_Point*> >::const_iterator rIter2 = recup2->begin();
+for (int j=0; rIter2 != recup2->end(); rIter2++, j++) {
+int iProc = (*rIter2).first;
+int i;
+for(i=0 ; i<size1 ; i++) {
+if(iProc == tab[i]) break;
+}
+if(i<size1) {
+if(iProc < nSender) nSender = iProc;
+}
+}
+if(nSender != myrank) continue;
+rIter2 = recup2->begin();
+for (int j=0; rIter2 != recup2->end(); rIter2++, j++) {
+int iProc = (*rIter2).first;
+int i;
+rIter1 = recup1->begin();
+for (i=0; rIter1 != recup1->end(), i<size1; rIter1++, i++) {
+if(iProc == tab[i]) break;
+}
+if(i < size1) {
+pVertex remote1 = (*rIter1).second;
+pVertex remote2 = (*rIter2).second;
+assert(iProc != myrank);
+assert(iProc > myrank);
+void *buf = AP_alloc(iProc,444,sizeof(edge_comm));
+edge_comm *castbuf = (edge_comm *) buf;
+castbuf->p1 = remote1;
+castbuf->p2 = remote2,
+castbuf->sendID = myrank;
+AP_send(buf);
+sendcounts[iProc]++;
+}
+}
+delete []tab;
+}
+EIter_delete(eit);
+AP_check_sends(AP_NOFLAGS);
+AP_reduce_nsends(sendcounts);
+
+int message=0;
+int count;
+
+while (!AP_recv_count(&count) || message<count) {
+void *msg;
+int from;
+int tag;
+int size;
+int rc;
+rc=AP_recv(MPI_ANY_SOURCE,444, AP_BLOCKING|AP_DROPOUT,
+&msg, &size, &from, &tag);
+if (rc) {
+message++;
+edge_comm * castbuf = (edge_comm*) msg;
+pVertex p1recv,p2recv;
+p1recv = castbuf -> p1;
+p2recv = castbuf -> p2;
+assert(p1recv);assert(p2recv);
+int nprocrecv = castbuf->sendID;
+assert(nprocrecv==from);
+pEdge pe = E_exist(p1recv,p2recv);
+if(pe) {
+//check orientation
+if(E_vertex(pe,0) != p1recv) {
+#ifdef DEBUG
+norient++;
+#endif
+pe->p1 = p1recv;
+pe->p2 = p2recv;
+assert(E_vertex(pe,0) == p1recv);
+}
+}
+AP_free(msg);
+}
+}
+AP_check_sends(AP_WAITALL);
+MPI_Barrier(MPI_COMM_WORLD);
+delete [] sendcounts;
+#ifdef DEBUG
+return norient;
+#else
+return 0;
+#endif
+}
+*/
+
+}
+
+#endif
diff --git a/Mesh/CheckOrientation.h b/Mesh/CheckOrientation.h
new file mode 100644
index 0000000..35d4bea
--- /dev/null
+++ b/Mesh/CheckOrientation.h
@@ -0,0 +1,28 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _CHECKORIENTATION_H_
+#define _CHECKORIENTATION_H_
+
+#ifdef PARALLEL
+
+#include "MeshDataBaseInterface.h"
+
+namespace MAd {
+ int CheckEdgesOrientation(pMesh mesh);
+ int CheckFacesOrientation(pMesh mesh);
+}
+
+#endif
+
+#endif
diff --git a/Mesh/MSops.h b/Mesh/MSops.h
new file mode 100644
index 0000000..77ef95f
--- /dev/null
+++ b/Mesh/MSops.h
@@ -0,0 +1,18 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MESHDATABASE_OPS
+#define _MESHDATABASE_OPS
+#include "ModelInterface.h"
+#include "MeshDataBaseInterface.h"
+#endif
diff --git a/Mesh/Makefile b/Mesh/Makefile
new file mode 100644
index 0000000..055132f
--- /dev/null
+++ b/Mesh/Makefile
@@ -0,0 +1,69 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../variables
+
+LIB = ../lib/libMAdMesh${LIBEXT}
+
+INC = ${MAdLib_INCLUDES}\
+ ${DASH}I$(MAdROOT)/Geo\
+ ${DASH}I$(MAdROOT)/Mesh\
+ ${DASH}I$(MAdROOT)/Common
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = Balance.cc\
+ CheckMesh.cc\
+ CheckOrientation.cc\
+ Mark.cc\
+ MeshDataBase.cc\
+ MeshDataBaseComm.cc\
+ MeshDataBaseCommCheck.cc\
+ MeshDataBaseGEntity2Physical.cc\
+ MeshDataBaseInterface.cc\
+ MeshDataBaseIO.cc\
+ MeshDataBaseLoadBalancing.cc\
+ MeshDataBaseMessage.cc\
+ MeshDataBaseMigration.cc\
+ MeshDataBaseMiniMesh.cc\
+ MeshDataBaseParallelInterface.cc\
+ MeshDataBaseParallelIO.cc\
+ metisAdaptiveRepart.cc\
+ ParallelUtils.cc\
+ PeriodicInterfaceMigration.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${LIB}: ${OBJ}
+ ${AR} ${ARFLAGS} ${LIB} ${OBJ}
+ ${RANLIB} ${LIB}
+
+cpobj: ${OBJ}
+ cp -f ${OBJ} ${MAdLib_TMPDIR}/.
+
+.cc${OBJEXT}:
+ ${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+ ${RM} */*.o *.o *.obj
+
+purge:
+
+depend:
+ (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+ ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+ ) > Makefile.new
+ cp Makefile Makefile.bak
+ cp Makefile.new Makefile
+ rm -f Makefile.new
\ No newline at end of file
diff --git a/Mesh/Mark.cc b/Mesh/Mark.cc
new file mode 100644
index 0000000..9828ea6
--- /dev/null
+++ b/Mesh/Mark.cc
@@ -0,0 +1,1332 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "Mark.h"
+#include "MSops.h"
+#include "MeshDataBase.h"
+
+#include "assert.h"
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+namespace MAd {
+
+#ifdef PARALLEL
+ // -------------------------------------------------------------------
+ void MarkTets(pMesh mesh,pMeshDataId tagElt)
+ {
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+
+ int * tab = new int[nproc];
+ int sendnum = mesh->nbPoints;
+ if(myrank) {
+ MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);
+ } else {
+ MPI_Status status;
+ tab[0] = sendnum;
+ for(int i=1 ; i<nproc ; i++) {
+ MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+ }
+ }
+
+ MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ int npGlob = 0;
+ for(int i=0 ; i<nproc ; i++) npGlob +=tab[i];
+
+ /* 1) marked regions*/
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ //int dest = rand()%nproc;
+
+ int dest = myrank;// = rand()%nproc;
+ pVertex nod[4];
+ for(int i=0 ; i<4 ; i++) {
+ nod[i] = R_vertex(pr,i);
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+ int maxproc = myrank;
+ if(isInterface) {
+ const std::vector<std::pair<int , pVertex> > *recup = (std::vector<std::pair<int , pVertex> > *) temp_ptr;
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+ int numproc = (*recup)[j].first;
+ if(tab[numproc] < tab[maxproc]) {
+ maxproc = numproc;
+ }
+ }
+ }
+ if(tab[maxproc] < tab[dest]) dest = maxproc;
+ }
+ assert(dest<nproc);
+ assert(dest>=0);
+ if(dest == myrank) continue;
+ EN_attachDataInt((pEntity) pr ,tagElt, dest + 1);
+ }
+ RIter_delete(rit);
+ delete []tab;
+ }
+
+
+ // -------------------------------------------------------------------
+ void MarkTetsSmooth(pMesh mesh,pMeshDataId tagElt)
+ {
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+
+ int *tab=new int[nproc];
+ int sendnum = mesh->nbPoints;
+ if(myrank) {
+ MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);
+ } else {
+ MPI_Status status;
+ tab[0] = sendnum;
+ for(int i=1 ; i<nproc ; i++) {
+ MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+ }
+ }
+
+ MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ int npGlob = 0;
+ for(int i=0 ; i<nproc ; i++) npGlob +=tab[i];
+
+ /* 1) marked regions*/
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ //int dest = rand()%nproc;
+
+ int dest = myrank;// = rand()%nproc;
+ pVertex nod[4];
+ for(int i=0 ; i<4 ; i++) {
+ nod[i] = R_vertex(pr,i);
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+ int maxproc = myrank;
+ if(isInterface) {
+ const std::vector<std::pair<int , pVertex> > *recup = (std::vector<std::pair<int , pVertex> > *) temp_ptr;
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+ int numproc = (*recup)[j].first;
+ if(tab[numproc] < tab[maxproc]) {
+ maxproc = numproc;
+ }
+ }
+ }
+ if(tab[maxproc] < tab[dest]) dest = maxproc;
+ }
+ assert(dest<nproc);
+ assert(dest>=0);
+ if(dest == myrank) continue;
+ EN_attachDataInt((pEntity) pr ,tagElt, dest + 1);
+ }
+ RIter_delete(rit);
+
+ //mark neighboor of interface tetras
+ int iter = 0;
+ int maxiter = 1;
+ int tetmove = 10;
+ while(iter<maxiter) {
+ tetmove = 0;
+ rit = M_regionIter(mesh);
+ while ((pr = RIter_next(rit))) {
+ int dest;
+ int isMove = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+ if(!isMove) continue;
+ if(iter%2)
+ if(dest < 0) continue;
+ else
+ if(dest > 0) continue;
+ EN_attachDataInt((pEntity) pr ,tagElt, -dest) ;
+ for(int i = 0 ; i<4 ; i++) {
+ pFace pface = R_face(pr,i);
+ pRegion prother;
+ int k =0;
+ for(k = 0; k < F_numRegions(pface); k++) {
+ prother = F_region(pface,k);
+ if(prother != pr) break;
+ }
+ if(k == F_numRegions(pface)) continue;
+ int destother;
+ int is = EN_getDataInt((pEntity) prother ,tagElt, &destother);
+ if(!is) EN_attachDataInt((pEntity) prother ,tagElt, -dest) ;
+ }
+ }
+ RIter_delete(rit);
+ //printf("iter neigh %d : %d\n",iter,trmove);
+ iter++;
+ }
+ //smooth new interfaces
+ iter = 0;
+ maxiter = 10;
+ tetmove = 10;
+ while(tetmove && iter<maxiter) {
+ tetmove = 0;
+ rit = M_regionIter(mesh);
+ while ((pr = RIter_next(rit))) {
+ int dest;
+ int isMove = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+ if(!isMove) continue;
+ if(dest < 0) EN_attachDataInt((pEntity) pr ,tagElt, abs(dest));
+ dest = abs(dest);
+ if((dest-1)== myrank) continue;
+ //how many neighboors in dest-1?
+ int nbN = 0;
+ int destreal = dest;
+ int nb = 0;
+ for(int i = 0 ; i < 4 ; i++) {
+ pFace pface = R_face(pr,i);
+ pRegion prother;
+ int k =0;
+ for(k = 0; k < F_numRegions(pface); k++) {
+ prother = F_region(pface,k);
+ if(prother != pr) break;
+ }
+ if(k == F_numRegions(pface)) continue;
+ int destother;
+ int is = EN_getDataInt((pEntity) prother ,tagElt, &destother);
+ if(!is) continue;
+ if(destother == dest) nb++;
+ else destreal = destother;
+ }
+ int nbGood = 4 - nbN + nb;
+ if(nbGood==1 || nbGood==2) {
+ tetmove++;
+ //printf("smoothing new interfaces : %d\n",pface->iD);
+ if(destreal == dest) {
+ //printf("nbGood : %d %d\n",nbN,nb);
+ EN_deleteData((pEntity) pr ,tagElt);
+ } else {
+ EN_attachDataInt((pEntity) pr ,tagElt, abs(destreal));
+ }
+ }
+ }
+ RIter_delete(rit);
+ //printf("iter smoothing %d : %d\n",iter,tetmove);
+ iter++;
+ }
+
+ //attach positive destination
+ rit = M_regionIter(mesh);
+ while ((pr = RIter_next(rit))) {
+ int dest;
+ int isMove = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+ if(isMove) {
+ if(dest < 0) EN_attachDataInt((pEntity) pr ,tagElt, abs(dest));
+ //assert(dest > 0);
+ }
+ }
+ RIter_delete(rit);
+ delete []tab;
+ }
+
+ // -------------------------------------------------------------------
+ void MarkTetsRandom(pMesh mesh, pMeshDataId tagElt) {
+
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ int dest = rand() % nproc;
+ if(dest == myrank) continue;
+ EN_attachDataInt((pEntity) pr, tagElt, dest + 1);
+ }
+ RIter_delete(rit);
+ }
+
+ // -------------------------------------------------------------------
+ int MarkTetsManifold(pMesh mesh,pMeshDataId tagElt) {
+
+ int nmanifold = 0;
+
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ EIter eit = M_edgeIter(mesh);
+ pEdge ped;
+ while ((ped = EIter_next(eit))) {
+ pVertex p1 = E_vertex(ped,0);
+ pVertex p2 = E_vertex(ped,1);
+ void *temp_ptr1,*temp_ptr2;
+ int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+ int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+ if(!(isInterface1 && isInterface2)) continue;
+ int nFace = 0;
+ int dest = myrank;// = rand()%nproc;
+ int maxproc = myrank;
+ for(int i=0 ; i<E_numFaces(ped) ; i++) {
+ pFace pface = E_face(ped,i);
+ for(int j=0 ; j<F_numRegions(pface) ; j++) {
+ pRegion pr = F_region(pface,j);
+ pVertex nod[4];
+ for(int i=0 ; i<4 ; i++) {
+ nod[i] = R_vertex(pr,i);
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+ int maxproc = myrank;
+ if(isInterface) {
+ const std::vector<std::pair<int , pVertex> > *recup = (std::vector<std::pair<int , pVertex> > *) temp_ptr;
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+ int numproc = (*recup)[j].first;
+ if(numproc < maxproc) {
+ maxproc = numproc;
+ }
+ }
+ }
+ }
+ if(maxproc < dest) dest = maxproc;
+ }
+ if(F_numRegions(pface)==2) continue;
+ int j;
+ for(j=0 ; j<3 ; j++) {
+ pVertex pp = F_vertex(pface,j);
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pp , tagData, &temp_ptr);
+ if(!isInterface) break;
+ }
+ if(j==3) nFace++;
+ }
+ if(nFace<=2) continue;
+ nmanifold++;
+ //printf("nFace %d non manifold edge\n",nFace);
+ if(dest == myrank) continue;
+ for(int i=0 ; i<E_numFaces(ped) ; i++) {
+ pFace pface = E_face(ped,i);
+ for(int j=0 ; j<F_numRegions(pface) ; j++) {
+ pRegion pr = F_region(pface,j);
+ EN_attachDataInt((pEntity) pr ,tagElt, dest + 1);
+ }
+ }
+ }
+ EIter_delete(eit);
+
+ return(nmanifold);
+ }
+
+ // -------------------------------------------------------------------
+ void MarkTriangles(pMesh mesh, pMeshDataId tagElt)
+ {
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+
+ // --- Every proc send its number of nodes -> collected in tab ---
+ int * tab = new int[nproc];
+ int sendnum = M_numVertices(mesh);
+ if(myrank) {
+ MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);
+ } else {
+ MPI_Status status;
+ tab[0] = sendnum;
+ for(int i=1 ; i<nproc ; i++) {
+ MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+ }
+ }
+ MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ int npGlob = 0;
+ for(int i=0 ; i<nproc ; i++) npGlob +=tab[i];
+
+ // --- Mark the triangles which have at least one vertex on an interface
+ // with a distant mesh that has less nodes than the current one ---
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ( (pface = FIter_next(fit)) ) {
+ pVertex nod[3];
+ pface->getNodes(nod);
+ int dest = myrank;
+ for(int i=0; i<3; i++) {
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) nod[i], tagData, &temp_ptr);
+ int maxproc = myrank;
+ if(isInterface) {
+ const std::vector<std::pair<int, pVertex> > *recup = (const std::vector<std::pair<int, pVertex> > *) temp_ptr;
+ for(int j=0; j<(int)((*recup).size()); j++) {
+ int numproc = (*recup)[j].first;
+ if(tab[numproc] < tab[maxproc]) maxproc = numproc;
+ }
+ }
+ if(tab[maxproc] < tab[dest]) dest = maxproc;
+ }
+ assert(dest<nproc);
+ assert(dest>=0);
+ if(dest == myrank) continue;
+ EN_attachDataInt((pEntity) pface, tagElt, dest + 1);
+ }
+ FIter_delete(fit);
+ delete []tab;
+ }
+
+
+
+ // -------------------------------------------------------------------
+ void MarkTrianglesSmooth(pMesh mesh,pMeshDataId tagElt)
+ {
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+
+ // --- Every proc send its number of nodes -> collected in tab ---
+ int * tab = new int[nproc];
+ int sendnum = M_numVertices(mesh);
+ if(myrank) {
+ MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);
+ } else {
+ MPI_Status status;
+ tab[0] = sendnum;
+ for(int i=1 ; i<nproc ; i++) {
+ MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+ }
+ }
+ MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ int npGlob = 0;
+ for(int i=0 ; i<nproc ; i++) npGlob += tab[i];
+
+ // --- Mark the triangles which have at least one vertex on an interface
+ // with a distant mesh that has less nodes than the current one ---
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ( (pface = FIter_next(fit)) ) {
+ pVertex nod[3];
+ pface->getNodes(nod);
+ int dest = myrank;
+ for(int i=0; i<3; i++) {
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) nod[i], tagData, &temp_ptr);
+ int maxproc = myrank;
+ if(isInterface) {
+ const std::vector<std::pair<int, pVertex> > *recup = (const std::vector<std::pair<int, pVertex> > *) temp_ptr;
+ for(int j=0; j<(int)((*recup).size()); j++) {
+ int numproc = (*recup)[j].first;
+ if(tab[numproc] < tab[maxproc]) maxproc = numproc;
+ }
+ }
+ if(tab[maxproc] < tab[dest]) dest = maxproc;
+ }
+ assert(dest<nproc);
+ assert(dest>=0);
+ if(dest == myrank) continue;
+ EN_attachDataInt((pEntity) pface, tagElt, dest + 1);
+ }
+ FIter_delete(fit);
+
+ // --- Mark the neighbour triangles of the marked triangles (do it n times) ---
+ // GCREMARK: why not apply the same principle as for the first marking -> mark around nodes ?
+ int iter = 0;
+ int maxiter = 1;
+ int trmove = 10;
+ while(iter<maxiter) {
+ trmove = 0;
+ fit = M_faceIter(mesh);
+ while ((pface = FIter_next(fit))) {
+ int dest;
+ int isMove = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+ if(!isMove) continue;
+ if(iter%2)
+ if(dest < 0) continue;
+ else
+ if(dest > 0) continue;
+ EN_attachDataInt((pEntity) pface ,tagElt, -dest) ;
+ for(int i = 0 ; i<3 ; i++) {
+ pEdge ped = F_edge(pface,i);
+ pFace pfother;
+ int k =0;
+ for(k = 0; k < E_numFaces(ped); k++) {
+ pfother = E_face(ped,k);
+ if(pfother != pface) break;
+ }
+ if(k == E_numFaces(ped)) continue;
+ int destother;
+ int is = EN_getDataInt((pEntity) pfother ,tagElt, &destother);
+ if(!is) EN_attachDataInt((pEntity) pfother ,tagElt, -dest) ;
+ }
+ }
+ FIter_delete(fit);
+ //printf("iter neigh %d : %d\n",iter,trmove);
+ iter++;
+ }
+
+ // --- Smooth new interfaces ---
+ iter = 0;
+ maxiter = 10;
+ trmove = 10;
+ while(trmove && iter<maxiter) {
+ trmove = 0;
+ fit = M_faceIter(mesh);
+ while ((pface = FIter_next(fit))) {
+ int dest;
+ int isMove = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+ if(!isMove) continue;
+ if(dest < 0) EN_attachDataInt((pEntity) pface ,tagElt, abs(dest));
+ dest = abs(dest);
+ if((dest-1)== myrank) continue;
+ //how many neighbours in dest-1?
+ int nbN = 0;
+ int destreal = dest;
+ int nb = 0;
+ for(int i = 0 ; i < 3 ; i++) {
+ pEdge ped = F_edge(pface,i);
+ pFace pfother;
+ int k =0;
+ for(k = 0; k < E_numFaces(ped); k++) {
+ pfother = E_face(ped,k);
+ if(pfother != pface) break;
+ }
+ if(k == E_numFaces(ped)) continue;
+ int destother;
+ int is = EN_getDataInt((pEntity) pfother ,tagElt, &destother);
+ if(!is) continue;
+ if(destother == dest) nb++;
+ else destreal = destother;
+ }
+ int nbGood = 3 - nbN + nb;
+ if(nbGood==1) {
+ trmove++;
+ //printf("smoothing new interfaces : %d\n",pface->iD);
+ if(destreal == dest) {
+ //printf("nbGood : %d %d\n",nbN,nb);
+ EN_deleteData((pEntity) pface ,tagElt);
+ } else {
+ EN_attachDataInt((pEntity) pface ,tagElt, abs(destreal));
+ }
+ }
+ }
+ FIter_delete(fit);
+ printf("iter smoothing %d : %d\n",iter,trmove);
+ iter++;
+ }
+
+ // --- Attach positive destination ---
+ fit = M_faceIter(mesh);
+ while ((pface = FIter_next(fit))) {
+ int dest;
+ int isMove = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+ if(isMove) {
+ if(dest < 0) EN_attachDataInt((pEntity) pface ,tagElt, abs(dest));
+ //assert(dest > 0);
+ }
+ }
+ FIter_delete(fit);
+ delete []tab;
+ }
+
+ // -------------------------------------------------------------------
+ void MarkTrianglesRandom(pMesh mesh, pMeshDataId tagElt) {
+
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ FIter fit = M_faceIter(mesh);
+ pFace pf;
+ while ((pf = FIter_next(fit))) {
+ int dest = rand() % nproc;
+ if(dest == myrank) continue;
+ EN_attachDataInt((pEntity) pf, tagElt, dest + 1);
+ }
+ FIter_delete(fit);
+ }
+#endif
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ /*loop on an edges list for 3-periodic cases*/
+ bool compare(pEdge p1, pEdge p2) {
+ pVertex p10 = E_vertex(p1,0);
+ pVertex p11 = E_vertex(p1,1);
+ pVertex p20 = E_vertex(p2,0);
+ pVertex p21 = E_vertex(p2,1);
+
+ double len1 = (p10->X-p11->X)*(p10->X-p11->X) + (p10->Y-p11->Y)*(p10->Y-p11->Y) +(p10->Z-p11->Z)*(p10->Z-p11->Z);
+ double len2 = (p20->X-p21->X)*(p20->X-p21->X) + (p20->Y-p21->Y)*(p20->Y-p21->Y) +(p20->Z-p21->Z)*(p20->Z-p21->Z);
+ // printf(" edge %d %d : %e\n",EN_id((pEntity) p10),EN_id((pEntity) p11),len1) ;
+ // printf(" et edge %d %d : %e\n",EN_id((pEntity) p20),EN_id((pEntity) p21),len2) ;
+ int num11 = EN_id((pEntity) p10);
+ int num12 = EN_id((pEntity) p11);
+ int num21 = EN_id((pEntity) p20);
+ int num22 = EN_id((pEntity) p21);
+ // printf("egal %d %d %d\n",len1==len2,num11==num21,num12<num22) ;
+
+ if(len1==len2) {
+ if(num11==num21) {
+ return(num12>num22);
+ } else {
+ return(num11>num21);
+ }
+ }
+ return ((len1 > len2));
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ void VertexTagMoveList(pMesh mesh, std::vector<std::vector<int> >& transforef,
+ pMeshDataId tagMove,pMeshDataId tagTransfo) {
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+
+ /*building list*/
+ std::list<pEdge> listedge;
+ EIter eit = M_edgeIter(mesh);
+ pEdge ped;
+ while ((ped = EIter_next(eit))) {
+ // pVertex p0 = E_vertex(ped,0);
+ // pVertex p1 = E_vertex(ped,1);
+ //printf("adding %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1));
+ listedge.push_back(ped);
+ }
+ EIter_delete(eit);
+ //GCRMK: anisotropic case!!
+ listedge.sort(compare);
+
+ /*favorite direction ?*/
+ int direct = 0;
+ int refsize = transforef.size();
+ for(unsigned int kt = 0 ; kt < transforef[0].size(); kt++) {
+ direct += transforef[0][kt]*transforef[0][kt];
+ }
+ //printf("********** favorite direction ??? %d\n",direct);
+
+
+ for(std::list<pEdge>::iterator it = listedge.begin() ; it!=listedge.end() ; it++) {
+ pEdge ped = (*it);
+ /*summits of edge ped*/
+ pVertex p0 = E_vertex(ped,0);
+ pVertex p1 = E_vertex(ped,1);
+ if(it==listedge.begin()) printf("the longest is %d %d\n",EN_id(p0),EN_id(p1));
+ pVertex pFix0,pFix1;
+ std::vector<int> vectnod;
+ int find = 0;
+ /*sommets periodics ?*/
+ void *temp_ptr0;
+ int isP0 = EN_getDataPtr((pEntity) p0 , tagPeriodic, &temp_ptr0);
+ if(!isP0) continue;
+ void *temp_ptr1;
+ int isP1 = EN_getDataPtr((pEntity) p1 , tagPeriodic, &temp_ptr1);
+ if(!isP1) continue;
+ /*sommets deja tagges ?*/
+ int move0;
+ int isM0 = EN_getDataInt((pEntity) p0 ,tagMove, &move0);
+ if(!(!isM0 || (move0 == -2))) continue;
+ int move1;
+ int isM1 = EN_getDataInt((pEntity) p1 ,tagMove, &move1);
+ if(!(!isM1 || (move1 == -2))) continue;
+
+ //printf("treat edge %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1));
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup0 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr0;
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup1 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+
+ /*a-t-on deja une direction privilegiee ?*/
+ if(1/*!direct*/) {
+ unsigned int j=0;
+ for(j=0 ; j<(*recup0).size() ; j++) {
+ std::vector<int> transfo0 = (*recup0)[j].first;
+ pVertex pImg0 = (*recup0)[j].second;
+ //if(pImg0==p1) continue;
+ unsigned int j1;
+ for(j1=0 ; j1<(*recup1).size() ; j1++) {
+ std::vector<int> transfo1 = (*recup1)[j1].first;
+ pVertex pImg1 = (*recup1)[j1].second;
+ //if(pImg1==p0) continue;
+
+ /*transfo0 == transfo1 ?*/
+ assert(transfo1.size()==transfo0.size());
+ unsigned int kt = 0;
+ for(kt = 0 ; kt < transfo0.size(); kt++) {
+ if(transfo0[kt] != transfo1[kt]) break;
+ }
+ if(kt!=transfo0.size()) continue;
+ /* pImg1-pImg0 existe ?*/
+ if ( !E_exist(pImg0,pImg1) && !E_exist(pImg1,pImg0) ) continue;
+ /* a-t-on deja trouve une arete img ?*/
+ //printf("img edge %d %d\n",EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));
+ if(!find) {
+ //if(it==listedge.begin()) printf("c'est bon on bouge\n");
+ /*si le point img bouge, on bouge pas!*/
+ int moveI0;
+ int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+ int moveI1;
+ int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+ if (isMI0 && (moveI0==1) ) continue;
+ if (isMI1 && (moveI1==1) ) continue;
+ if(!direct) {
+ find = 1;
+ int move = 1;
+ EN_attachDataInt((pEntity) p0 ,tagMove, move);
+ EN_attachDataInt((pEntity) p1 ,tagMove, move);
+ move = -1;
+ EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+ EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+
+ /*on garde les deux points img*/
+ pFix0 = pImg0;
+ pFix1 = pImg1;
+ /*rajout de la transfo avec laquelle bouger les points*/
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vectnod.push_back(transfo0[kt]);
+ transforef[0][kt] = transfo0[kt];
+ }
+ EN_attachDataPtr((pEntity) p0 , tagTransfo,new std::vector<int>(vectnod));
+ EN_attachDataPtr((pEntity) p1 , tagTransfo,new std::vector<int>(vectnod));
+ for(unsigned int kt = 0 ; kt < transforef[0].size(); kt++) {
+ direct += transforef[0][kt]*transforef[0][kt];
+ }
+ //printf("on a une direct %d : %d %d\n",direct,transforef.size(),refsize);
+ } else { /*on a deja une direction privilegiee*/
+ double pds = 0;
+ for(int st = 0 ; st < refsize; st++) {
+ for(unsigned int kt = 0 ; kt < transforef[st].size(); kt++) {
+ pds += transforef[st][kt]*transfo0[kt];
+ }
+ if(pds!=0) break;
+ }
+ if(pds>=0) {
+ //printf("direction ok : %d %d %d (%d)\n",transfo0[0],transfo0[1],transfo0[2],transforef.size());
+ if(pds==0) {/*on rajoute une direction privilegiee*/
+ transforef.push_back(transfo0);
+ refsize++;
+ //printf("on rajoute la direction au ref : %d \n",refsize);
+ }
+ find = 1;
+ int move = 1;
+ EN_attachDataInt((pEntity) p0 ,tagMove, move);
+ EN_attachDataInt((pEntity) p1 ,tagMove, move);
+ move = -1;
+ EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+ EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+
+ /*on garde les deux points img*/
+ pFix0 = pImg0;
+ pFix1 = pImg1;
+ /*rajout de la transfo avec laquelle bouger les points*/
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vectnod.push_back(transfo0[kt]);
+ }
+ EN_attachDataPtr((pEntity) p0 , tagTransfo,new std::vector<int>(vectnod));
+ EN_attachDataPtr((pEntity) p1 , tagTransfo,new std::vector<int>(vectnod));
+ } else {/*la direction est opposee a celle souhaitee --> on fait l'inverse*/
+ //printf("bad direction : %d %d %d (%d %d)\n",transfo0[0],transfo0[1],transfo0[2],transforef.size(),refsize);
+ /*****INUTILE ????????******/
+ int moveI0;
+ int isMI0 = EN_getDataInt((pEntity) p0 ,tagMove, &moveI0);
+ int moveI1;
+ int isMI1 = EN_getDataInt((pEntity) p1 ,tagMove, &moveI1);
+ if (isMI0 && (moveI0==1) ) break;
+ if (isMI1 && (moveI1==1) ) break;
+ if(!(!isMI0 || (moveI0 == -2))) break;
+ if(!(!isMI0 || (moveI0 == -2))) break;
+ /*****FIN INUTILE ????????******/
+ find = 1;
+ int move = -1;
+ EN_attachDataInt((pEntity) p0 ,tagMove, move);
+ EN_attachDataInt((pEntity) p1 ,tagMove, move);
+ move = 1;
+ EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+ EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+
+ /*on garde les deux points img*/
+ pFix0 = p0;
+ pFix1 = p1;
+ /*rajout de la transfo avec laquelle bouger les points*/
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vectnod.push_back((-1)*transfo0[kt]);
+ }
+ EN_attachDataPtr((pEntity) pImg0 , tagTransfo,new std::vector<int>(vectnod));
+ EN_attachDataPtr((pEntity) pImg1 , tagTransfo,new std::vector<int>(vectnod));
+ }
+ } /*end if direct*/
+ break;
+ } else {
+ /*si le point bouge deja, on veut pas chger sa destination!!!*/
+ int moveI0;
+ int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+ int moveI1;
+ int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+ if (isMI0 && (moveI0==1) ) continue;
+ if (isMI1 && (moveI1==1) ) continue;
+
+ int move = 1;
+ EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+ EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+
+ /*on sait que pImg0pImg1 doit aller sur pFix0pFix1 il faut trouver la transfo*/
+ /*si PFix0==p0 transfo = -transfo0*/
+ /*sinon transfo = -transfo0 + vecnod */
+ std::vector<int> vecttrans;
+ if(pFix0==p0) {
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vecttrans.push_back(-transfo0[kt]);
+ }
+ } else {
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vecttrans.push_back(-transfo0[kt]);
+ }
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vecttrans[kt] += vectnod[kt];
+ }
+ }
+ EN_attachDataPtr((pEntity) pImg0 , tagTransfo,new std::vector<int>(vecttrans));
+ EN_attachDataPtr((pEntity) pImg1 , tagTransfo,new std::vector<int>(vecttrans));
+ break;
+ }
+ } /*end j1*/
+ if(j1==(*recup1).size()){
+ //printf("arete not found\n");
+ /* int move = -2;
+ EN_attachDataInt((pEntity) pImg0 ,tagMove, move); */
+ }
+ } /*end j*/
+ //if(!find) {printf("on n'a pas trouve d'arete img donc on tag pas\n"); exit(0);}
+ } else {/*if direct*/
+
+ }
+ }
+ return;
+ }
+
+
+ // -------------------------------------------------------------------
+ /*boucle sur les aretes pour traiter les cas 3-periodic*/
+ void VertexTagMove(pMesh mesh,pMeshDataId tagMove,pMeshDataId tagTransfo) {
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+
+ EIter eit = M_edgeIter(mesh);
+ pEdge ped,pedla;
+ double lenla = 0;
+ while ((ped = EIter_next(eit))) {
+ /*les deux sommets de l'arete ped*/
+ pVertex p0 = E_vertex(ped,0);
+ pVertex p1 = E_vertex(ped,1);
+
+ /*sommets periodics ?*/
+ void *temp_ptr0;
+ int isP0 = EN_getDataPtr((pEntity) p0 , tagPeriodic, &temp_ptr0);
+ if(!isP0) continue;
+ void *temp_ptr1;
+ int isP1 = EN_getDataPtr((pEntity) p1 , tagPeriodic, &temp_ptr1);
+ if(!isP1) continue;
+
+ double len = (p0->X-p1->X)*(p0->X-p1->X) + (p0->Y-p1->Y)*(p0->Y-p1->Y) +(p0->Z-p1->Z)*(p0->Z-p1->Z);
+ if(len > lenla) {
+ lenla = len;
+ pedla = ped;
+ }
+
+ }
+ //printf("lenla %e %p : %d %d\n",lenla,pedla,EN_id((pEntity) E_vertex(pedla,0)),EN_id((pEntity) E_vertex(pedla,1)));
+ EIter_delete(eit);
+ eit = M_edgeIter(mesh);
+ while ((ped = EIter_next(eit))) {
+ if(ped!=pedla) continue;
+ /*les deux sommets de l'arete ped*/
+ pVertex p0 = E_vertex(ped,0);
+ pVertex p1 = E_vertex(ped,1);
+ pVertex pFix0,pFix1;
+ std::vector<int> vectnod;
+ int find = 0;
+ /*sommets periodics ?*/
+ void *temp_ptr0;
+ int isP0 = EN_getDataPtr((pEntity) p0 , tagPeriodic, &temp_ptr0);
+ if(!isP0) continue;
+ void *temp_ptr1;
+ int isP1 = EN_getDataPtr((pEntity) p1 , tagPeriodic, &temp_ptr1);
+ if(!isP1) continue;
+ /*sommets deja tagges ?*/
+ int move0;
+ int isM0 = EN_getDataInt((pEntity) p0 ,tagMove, &move0);
+ if(!(!isM0 || (move0 == -2))) continue;
+ int move1;
+ int isM1 = EN_getDataInt((pEntity) p1 ,tagMove, &move1);
+ if(!(!isM1 || (move1 == -2))) continue;
+
+ //printf("treat edge %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1));
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup0 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr0;
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup1 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+
+ unsigned int j=0;
+ for(j=0 ; j<(*recup0).size() ; j++) {
+ std::vector<int> transfo0 = (*recup0)[j].first;
+ pVertex pImg0 = (*recup0)[j].second;
+ if(pImg0==p1) continue;
+ unsigned int j1;
+ for(j1=0 ; j1<(*recup1).size() ; j1++) {
+ std::vector<int> transfo1 = (*recup1)[j1].first;
+ pVertex pImg1 = (*recup1)[j1].second;
+ if(pImg1==p0) continue;
+
+ /*transfo0 == transfo1 ?*/
+ assert(transfo1.size()==transfo0.size());
+ unsigned int kt = 0;
+ for(kt = 0 ; kt < transfo0.size(); kt++) {
+ if(transfo0[kt] != transfo1[kt]) break;
+ }
+ if(kt!=transfo0.size()) continue;
+ /* pImg1-pImg0 existe ?*/
+ if ( !E_exist(pImg0,pImg1) && !E_exist(pImg1,pImg0) ) continue;
+ /* a-t-on deja trouve une arete img ?*/
+ //printf("img edge %d %d\n",EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));
+ if(!find) {
+ /*si le point img bouge, on bouge pas!*/
+ int moveI0;
+ int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+ int moveI1;
+ int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+ if (isMI0 && (moveI0==1) ) continue;
+ if (isMI1 && (moveI1==1) ) continue;
+ find = 1;
+ int move = 1;
+ EN_attachDataInt((pEntity) p0 ,tagMove, move);
+ EN_attachDataInt((pEntity) p1 ,tagMove, move);
+ move = -1;
+ EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+ EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+
+ /*on garde les deux points img*/
+ pFix0 = pImg0;
+ pFix1 = pImg1;
+
+ /*rajout de la transfo avec laquelle bouger les points*/
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vectnod.push_back(transfo0[kt]);
+ }
+ EN_attachDataPtr((pEntity) p0 , tagTransfo,new std::vector<int>(vectnod));
+ EN_attachDataPtr((pEntity) p1 , tagTransfo,new std::vector<int>(vectnod));
+ //printf("mark vertex : %d %d -- %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1),EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));
+ //printf("transfo : %d %d %d\n",transfo0[0],transfo0[1],transfo0[2]);
+ break;
+ } else {
+ /*si le point bouge deja, on veut pas chger sa destination!!!*/
+ int moveI0;
+ int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+ int moveI1;
+ int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+ if (isMI0 && (moveI0==1) ) continue;
+ if (isMI1 && (moveI1==1) ) continue;
+
+ int move = 1;
+ EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+ EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+
+ /*on sait que pImg0pImg1 doit aller sur pFix0pFix1 il faut trouver la transfo*/
+ /*transfo = -transfo0 + vecnod */
+ std::vector<int> vecttrans;
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vecttrans.push_back(-transfo0[kt]);
+ }
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vecttrans[kt] += vectnod[kt];
+ }
+ //printf("on applique la transfo %d %d %d\n",vecttrans[0],vecttrans[1],vecttrans[2]);
+ //printf("mark vertex : %d %d \n",EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));
+ EN_attachDataPtr((pEntity) pImg0 , tagTransfo,new std::vector<int>(vecttrans));
+ EN_attachDataPtr((pEntity) pImg1 , tagTransfo,new std::vector<int>(vecttrans));
+ break;
+ }
+ } /*end j1*/
+ if(j1==(*recup1).size()){
+ //printf("arete not found\n");
+ /* int move = -2;
+ EN_attachDataInt((pEntity) pImg0 ,tagMove, move); */
+ }
+ } /*end j*/
+ //if(!find) {printf("on n'a pas trouve d'arete img donc on tag pas\n"); exit(0);}
+ }
+ EIter_delete(eit);
+ eit = M_edgeIter(mesh);
+ while ((ped = EIter_next(eit))) {
+ /*les deux sommets de l'arete ped*/
+ pVertex p0 = E_vertex(ped,0);
+ pVertex p1 = E_vertex(ped,1);
+ pVertex pFix0,pFix1;
+ std::vector<int> vectnod;
+ int find = 0;
+
+ /*sommets periodics ?*/
+ void *temp_ptr0;
+ int isP0 = EN_getDataPtr((pEntity) p0 , tagPeriodic, &temp_ptr0);
+ if(!isP0) continue;
+ void *temp_ptr1;
+ int isP1 = EN_getDataPtr((pEntity) p1 , tagPeriodic, &temp_ptr1);
+ if(!isP1) continue;
+ /*sommets deja tagges ?*/
+ int move0;
+ int isM0 = EN_getDataInt((pEntity) p0 ,tagMove, &move0);
+ if(!(!isM0 || (move0 == -2))) continue;
+ int move1;
+ int isM1 = EN_getDataInt((pEntity) p1 ,tagMove, &move1);
+ if(!(!isM1 || (move1 == -2))) continue;
+
+ //printf("treat edge %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1));
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup0 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr0;
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup1 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+ unsigned int j=0;
+ for(j=0 ; j<(*recup0).size() ; j++) {
+ std::vector<int> transfo0 = (*recup0)[j].first;
+ pVertex pImg0 = (*recup0)[j].second;
+ if(pImg0==p1) continue;
+ unsigned int j1;
+ for(j1=0 ; j1<(*recup1).size() ; j1++) {
+ std::vector<int> transfo1 = (*recup1)[j1].first;
+ pVertex pImg1 = (*recup1)[j1].second;
+ if(pImg1==p0) continue;
+
+ /*transfo0 == transfo1 ?*/
+ assert(transfo1.size()==transfo0.size());
+ unsigned int kt = 0;
+ for(kt = 0 ; kt < transfo0.size(); kt++) {
+ if(transfo0[kt] != transfo1[kt]) break;
+ }
+ if(kt!=transfo0.size()) continue;
+ /* pImg1-pImg0 existe ?*/
+ if ( !E_exist(pImg0,pImg1) && !E_exist(pImg1,pImg0) ) continue;
+ /* a-t-on deja trouve une arete img ?*/
+ //printf("img edge %d %d\n",EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));
+ if(!find) {
+ /*si le point img bouge, on bouge pas!*/
+ int moveI0;
+ int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+ int moveI1;
+ int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+ if (isMI0 && (moveI0==1) ) continue;
+ if (isMI1 && (moveI1==1) ) continue;
+ find = 1;
+ int move = 1;
+ EN_attachDataInt((pEntity) p0 ,tagMove, move);
+ EN_attachDataInt((pEntity) p1 ,tagMove, move);
+ move = -1;
+ EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+ EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+
+ /*on garde les deux points img*/
+ pFix0 = pImg0;
+ pFix1 = pImg1;
+
+ /*rajout de la transfo avec laquelle bouger les points*/
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vectnod.push_back(transfo0[kt]);
+ }
+ EN_attachDataPtr((pEntity) p0 , tagTransfo,new std::vector<int>(vectnod));
+ EN_attachDataPtr((pEntity) p1 , tagTransfo,new std::vector<int>(vectnod));
+ //printf("mark vertex : %d %d -- %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1),EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));
+ break;
+ } else {
+ /*si le point bouge deja, on veut pas chger sa destination!!!*/
+ int moveI0;
+ int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+ int moveI1;
+ int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+ if (isMI0 && (moveI0==1) ) continue;
+ if (isMI1 && (moveI1==1) ) continue;
+ int move = 1;
+ EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+ EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+
+ /*on sait que pImg0pImg1 doit aller sur pFix0pFix1 il faut trouver la transfo*/
+ /*transfo = -transfo0 + vecnod */
+ std::vector<int> vecttrans;
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vecttrans.push_back(-transfo0[kt]);
+ }
+ for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+ vecttrans[kt] += vectnod[kt];
+ }
+ //printf("on applique la transfo %d %d %d\n",vecttrans[0],vecttrans[1],vecttrans[2]);
+ //printf("mark vertex : %d %d \n",EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));
+ EN_attachDataPtr((pEntity) pImg0 , tagTransfo,new std::vector<int>(vecttrans));
+ EN_attachDataPtr((pEntity) pImg1 , tagTransfo,new std::vector<int>(vecttrans));
+ break;
+ }
+ } /*end j1*/
+ if(j1==(*recup1).size()){
+ //printf("arete not found\n");
+ /* int move = -2;
+ EN_attachDataInt((pEntity) pImg0 ,tagMove, move); */
+ }
+ } /*end j*/
+ //if(!find) {printf("on n'a pas trouve d'arete img donc on tag pas\n"); exit(0);}
+ }
+ EIter_delete(eit);
+ return;
+ }
+
+ // -------------------------------------------------------------------
+ void VertexTagMove_old(pMesh mesh,pMeshDataId tagMove,int imove) {
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ /*****************************************************************************/
+ /********nouvelle facon de bouger (sans pbs pour les tri-periodicite)*********/
+ /*****************************************************************************/
+ int move;
+ int isMove = EN_getDataInt((pEntity) pv ,tagMove, &move);
+ if((isMove && move==-1) || (isMove && move==1)) continue;
+ /*****************************************************************************/
+ /*****************************************************************************/
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ move = -1;
+ unsigned int j=0;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ std::vector<int> transfo = (*recup)[j].first;
+ /*****************************************************************************/
+ /********************ancienne facon*******************************************/
+ /*****************************************************************************/
+ /*unsigned int k=0;
+ for(k = 0 ; k<transfo.size() ; k++) {
+ if(transfo[k]< 0) break;
+ }
+ if(k==transfo.size()) move=1;*/
+ /*****************************************************************************/
+
+ /*on bouge que par rapport à x*/
+ /* int somme = 0;
+ for(int kk = 0 ; kk<transfo.size() ; kk++) {
+ //if(kk==imove) continue;
+ somme += abs(transfo[kk] );
+ }
+ int inv = (imove>=0) ? 1 : -1;
+ if(inv < 0) imove = abs(imove)-1;
+ for(k = imove ; k<imove+1 ; k++) {
+ if((transfo[k] == 0) || (inv * transfo[k] < 0)) break;
+ }
+ if(k==imove+1 && somme < 2) move=1; */
+ /*****************************************************************************/
+ /********nouvelle facon de bouger (sans pbs pour les tri-periodicite)*********/
+ /*****************************************************************************/
+ pVertex pImg = (*recup)[j].second;
+ int movimg;
+ int isM = EN_getDataInt((pEntity) pImg ,tagMove, &movimg);
+ if(isM && movimg==1) continue;
+
+ /*unsigned int k=0;
+ for(k = 0 ; k<transfo.size() ; k++) {
+ if(transfo[k]< 0) break;
+ }
+ if(k==transfo.size()) {
+ move=1;
+ break;
+ } */
+ move=1;
+ break;
+ /*****************************************************************************/
+ /*****************************************************************************/
+ }
+ /*****************************************************************************/
+ /********nouvelle facon de bouger (sans pbs pour les tri-periodicite)*********/
+ /*****************************************************************************/
+ if(move==1) {
+ //printf("on traite le point %d -> %d: j = %d / %d\n",EN_id((pEntity) pv),EN_id((pEntity) (*recup)[j].second),j,(*recup).size());
+ unsigned int j2=0;
+ for(j2=0 ; j2<(*recup).size() ; j2++) {
+ std::vector<int> transfo = (*recup)[j2].first;
+ pVertex pImg = (*recup)[j2].second;
+ if(j2==j) {
+ int movimg;
+ int isM = EN_getDataInt((pEntity) pImg ,tagMove, &movimg);
+ assert(!isM || (isM && movimg==-1) || (isM && movimg==-2));
+ movimg = -1;
+ if(!isM) EN_attachDataInt((pEntity) pImg ,tagMove, movimg);
+ continue;
+ }
+ /*le point pImg doit bouger sur le meme point que pv*/
+ int movimg;
+ int isM = EN_getDataInt((pEntity) pImg ,tagMove, &movimg);
+ if(!(!isM || (isM && movimg==-2) || (isM && movimg==1))) printf("point %d : %d %d\n",EN_id((pEntity) pImg),isM,movimg);
+ assert(!isM || (isM && movimg==-2) || (isM && movimg==1));
+ movimg = 1;
+ if(!isM) EN_attachDataInt((pEntity) pImg ,tagMove, movimg);
+ // GCRMK: remove this part
+ /****verifier que (*recup)[j].second existe dans les img de pImg*/
+ pVertex pcheck = (*recup)[j].second;
+ void *temp_ptrimg;
+ int isP = EN_getDataPtr((pEntity) pImg , tagPeriodic, &temp_ptrimg);
+ assert(isP);
+ std::vector<std::pair<std::vector<int> , pVertex> > *recupimg = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptrimg;
+ unsigned int j3=0;
+ for(j3=0 ; j3<(*recupimg).size() ; j3++) {
+ pVertex pI2 = (*recup)[j3].second;
+ if(pI2==pcheck) break;
+ }
+ assert(j3!=(*recupimg).size());
+ /****end check*/
+ }
+ } else {
+ move=-2;
+ }
+ /*****************************************************************************/
+ /*****************************************************************************/
+ //printf("on traite le point %d : %d\n",EN_id((pEntity) pv),move);
+ EN_attachDataInt((pEntity) pv ,tagMove, move);
+ }
+ }
+ VIter_delete(vit);
+
+ return;
+ }
+
+ // -------------------------------------------------------------------
+ void VertexTagMoveInverse(pMesh mesh,pMeshDataId tagMove) {
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ int move = -1;
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+ std::vector<int> transfo = (*recup)[j].first;
+ unsigned int k=0;
+ for(k = 0 ; k<transfo.size() ; k++) {
+ if(pv->X > 1) printf("%e %e %d\n",pv->X,pv->Y,transfo[k]);
+ if(transfo[k] >= -1) break;
+ //if((transfo[k] >= 0) || (transfo[k] >= -1 && transfo[k] <= 1)) break;
+ printf("tr %d\n",transfo[k]);
+ }
+ if(k==transfo.size()) move=1;
+ }
+ EN_attachDataInt((pEntity) pv ,tagMove, move);
+ }
+ }
+ VIter_delete(vit);
+
+ return;
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ void MarkPeriodicTets(pMesh mesh,std::vector<std::vector<int> >& transfo,
+ pMeshDataId tagElt,pMeshDataId tagMove,pMeshDataId tagTransfo) {
+
+ /* 1) define if periodic vertex can move : 1 : yes / -1 : no*/
+ VertexTagMoveList(mesh,transfo,tagMove,tagTransfo);
+ /*ancienne version*/
+ //VertexTagMove_old(mesh,tagMove,1);
+
+ /* 2) marked tetras and vertex*/
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ pVertex nod[4];
+ pr->getNodes(nod);
+ int dest = 0;
+ for(int i=0 ; i<4 ; i++) {
+ int move;
+ int isPeriodic = EN_getDataInt((pEntity) nod[i] , tagMove, &move);
+ //GCRMK: remove this check
+ if(isPeriodic && move==-2) printf("point %d argggg \n",EN_id((pEntity) nod[i])) ;
+ if(isPeriodic) assert(move!=-2);
+ if(isPeriodic && (move==1)) {
+ dest = 1;
+ }
+ }
+ if(dest) EN_attachDataInt((pEntity) pr ,tagElt, dest);
+ }
+ RIter_delete(rit);
+
+ }
+
+
+ // -------------------------------------------------------------------
+ int MarkGroupPeriodicTets(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove) {
+
+ int mark = 0;
+
+ /* 1) define if periodic vertex can move : 1 : yes / -1 : no*/
+ VertexTagMoveInverse(mesh,tagMove);
+
+ /* 2) marked tetras and vertex*/
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ pVertex nod[4];
+ pr->getNodes(nod);
+ int dest = 0;
+ for(int i=0 ; i<4 ; i++) {
+ int move;
+ int isPeriodic = EN_getDataInt((pEntity) nod[i] , tagMove, &move);
+ if(isPeriodic && (move==1)) {
+ dest = 1;
+ }
+ }
+ if(dest) {
+ EN_attachDataInt((pEntity) pr ,tagElt, dest);
+ mark++;
+ }
+ }
+ RIter_delete(rit);
+ return mark;
+
+ }
+
+ // -------------------------------------------------------------------
+ void MarkPeriodicTriangles(pMesh mesh,std::vector<std::vector<int> >& transfo,pMeshDataId tagElt,pMeshDataId tagMove,pMeshDataId tagTransfo) {
+
+
+ /* 1) define if periodic vertex can move : 1 : yes / -1 : no*/
+ //VertexTagMove(mesh,tagMove,tagTransfo);
+ VertexTagMoveList(mesh,transfo,tagMove,tagTransfo);
+
+ /* 2) marked faces and vertex*/
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ pVertex nod[3];
+ pface->getNodes(nod);
+ int dest = 0;
+ for(int i=0 ; i<3 ; i++) {
+ int move;
+ int isPeriodic = EN_getDataInt((pEntity) nod[i] , tagMove, &move);
+ if(isPeriodic && (move==1)) {
+ dest = 1;
+ }
+ }
+ if(dest) EN_attachDataInt((pEntity) pface ,tagElt, dest);
+ }
+ FIter_delete(fit);
+ }
+
+ // -------------------------------------------------------------------
+
+}
+
diff --git a/Mesh/Mark.h b/Mesh/Mark.h
new file mode 100644
index 0000000..0b3f6e7
--- /dev/null
+++ b/Mesh/Mark.h
@@ -0,0 +1,51 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MARK_H_
+#define _MARK_H_
+
+#include "MSops.h"
+
+#include <vector>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+#ifdef PARALLEL
+ void MarkTriangles (pMesh mesh, pMeshDataId tagElt);
+ void MarkTrianglesSmooth (pMesh mesh, pMeshDataId tagElt);
+ void MarkTrianglesRandom (pMesh mesh, pMeshDataId tagElt);
+ void MarkTets (pMesh mesh, pMeshDataId tagElt);
+ void MarkTetsSmooth (pMesh mesh, pMeshDataId tagElt);
+ void MarkTetsRandom (pMesh mesh, pMeshDataId tagElt);
+ int MarkTetsManifold (pMesh mesh, pMeshDataId tagElt);
+#endif
+
+ // -------------------------------------------------------------------
+ void VertexTagMove (pMesh mesh, pMeshDataId tagMove);
+ void VertexTagMoveList (pMesh mesh, std::vector<std::vector<int> >& transfo,
+ pMeshDataId tagMove, pMeshDataId tagTransfo);
+ void VertexTagMoveInverse (pMesh mesh, pMeshDataId tagMove);
+
+ // -------------------------------------------------------------------
+ void MarkPeriodicTriangles (pMesh mesh, std::vector<std::vector<int> >& transfo,
+ pMeshDataId tagElt, pMeshDataId tagMove, pMeshDataId tagTransfo);
+ void MarkPeriodicTets (pMesh mesh, std::vector<std::vector<int> >& transfo,
+ pMeshDataId tagElt, pMeshDataId tagMove, pMeshDataId tagTransfo);
+ int MarkGroupPeriodicTets (pMesh mesh, pMeshDataId tagElt, pMeshDataId tagMove);
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBase.cc b/Mesh/MeshDataBase.cc
new file mode 100644
index 0000000..839d1d2
--- /dev/null
+++ b/Mesh/MeshDataBase.cc
@@ -0,0 +1,2144 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere, Koen Hillewaert
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MeshDataBaseGEntity2Physical.h"
+#include "MSops.h"
+#include "MeshDataBaseMessage.h"
+#include "MAdMessage.h"
+#include "MAdDefines.h"
+#include "MathUtils.h"
+
+#include <set>
+using std::set;
+using std::cout;
+
+#ifdef PARALLEL
+#include "mpi.h"
+#endif
+
+namespace MAd {
+
+ MDB_Mesh::MDB_Mesh (int _MAXX)
+ : parametric(false), shrinked(false), maxId(_MAXX), idIncrement(1),
+ nbPoints(0), nbEdges(0), nbTriangles(0), nbQuads(0), nbTets(0),
+ nbHexes(0), nbPrisms(0)
+ {
+ initializeIdData();
+ }
+
+ void MDB_Mesh::initializeIdData( )
+ {
+#ifdef PARALLEL
+ int myRank = 0, nbProc = 0;
+ MPI_Comm_size(MPI_COMM_WORLD, &nbProc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
+
+ int maxIdGlob = -1;
+ MPI_Allreduce(&maxId,&maxIdGlob,1,MPI_INT,MPI_MAX,MPI_COMM_WORLD);
+ maxId = maxIdGlob + myRank;
+ idIncrement = nbProc;
+ MPI_Barrier(MPI_COMM_WORLD);
+#else
+ idIncrement = 1;
+#endif
+ }
+
+ void MDB_Mesh::deleteTheHighOrderPoint(std::set < MDB_Point *, PointLessThan >::iterator it){
+ MDB_Point *pt;
+ if (it != points.end())
+ {
+ pt = *it;
+ points.erase(it);
+ nbPoints--;
+ }
+ else throw;
+ }
+
+ void MDB_Point::getTriangles(MDB_ListF&t) const
+ {
+ t.clear();
+ MDB_VectorE::const_iterator it = edges.begin();
+ MDB_VectorE::const_iterator ite = edges.end();
+ while(it != ite) {
+ int NF = (*it)->numfaces();
+ for(int i = 0; i < NF; ++i) {
+ MDB_Triangle *tt = (*it)->faces(i);
+ if(tt) {
+ MDB_ListF::iterator tit = t.begin();
+ MDB_ListF::iterator tite = t.end();
+ int found = 0;
+ while(tit != tite) {
+ if(tt == *tit)
+ found = 1;
+ ++tit;
+ }
+ if(!found)
+ t.push_back(tt);
+ }
+ }
+ ++it;
+ }
+ }
+
+ void MDB_Point::getQuads(MDB_ListQ&q) const
+ {
+ q.clear();
+ MDB_VectorE::const_iterator it = edges.begin();
+ MDB_VectorE::const_iterator ite = edges.end();
+ while(it != ite) {
+ int NF = (*it)->numquads();
+ for(int i = 0; i < NF; ++i) {
+ MDB_Quad *qq = (*it)->quads(i);
+ if(qq) {
+ MDB_ListQ::iterator qit = q.begin();
+ MDB_ListQ::iterator qite = q.end();
+ int found = 0;
+ while(qit != qite) {
+ if(qq == *qit)
+ found = 1;
+ ++qit;
+ }
+ if(!found)
+ q.push_back(qq);
+ }
+ }
+ ++it;
+ }
+ }
+
+
+ MDB_Point * MDB_Mesh::add_point(int num, double x, double y, double z, pGEntity pg)
+ {
+ int newId = num;
+ if ( newId < 0 ) {
+ maxId += idIncrement;
+ newId = maxId;
+ }
+
+ MDB_Point *pp = new MDB_Point(newId, x, y, z);
+ pp->g = pg;
+ points.insert(pp);
+ maxId = (maxId < newId) ? newId : maxId;
+ nbPoints++;
+ return pp;
+ }
+
+ MDB_PointParam * MDB_Mesh::add_pointParam(int num , double x, double y, double z,
+ double u, double v, pGEntity pg)
+ {
+ int newId = num;
+ if ( newId < 0 ) {
+ maxId += idIncrement;
+ newId = maxId;
+ }
+
+ MDB_PointParam *pp = new MDB_PointParam(newId, x, y, z, u, v);
+ pp->g = pg;
+ points.insert(pp);
+ maxId = (maxId < newId) ? newId : maxId;
+ nbPoints++;
+ parametric = true;
+ return pp;
+ }
+
+ MDB_Point *MDB_Mesh::find_point(int p)
+ {
+ MDB_Point P(p);
+ std::set < MDB_Point *, PointLessThan >::iterator it = points.find(&P);
+ if(it != points.end()) return (MDB_Point *) (*it);
+ return 0;
+
+ // MDB_PointParam VP(p);
+ // it = points.find(&VP);
+ // if(it != points.end()) return (MDB_Point *) (*it);
+ // else return 0;
+ }
+
+ MDB_Edge *MDB_Mesh::find_edge(int num1, int num2)
+ {
+ MDB_Point *p = find_point(num1);
+ MDB_VectorE::iterator eit = p->edges.begin();
+ while(eit != p->edges.end()) {
+ if((*eit)->p1 == p && (*eit)->p2->iD == num2)
+ return (*eit);
+ if((*eit)->p2 == p && (*eit)->p1->iD == num2)
+ return (*eit);
+ ++eit;
+ }
+ return 0;
+ }
+
+ MDB_Edge *MDB_Mesh::find_edge(MDB_Point * p1, MDB_Point * p2) const
+ {
+ const int nbe1 = p1->edges.size();
+ const int nbe2 = p2->edges.size();
+ if (nbe1 < nbe2)
+ {
+ for (int i=0;i<nbe1;i++)
+ {
+ MDB_Edge *e = p1->edges [i];
+ if (e->p1 == p1 && e->p2 == p2)return e;
+ if (e->p2 == p1 && e->p1 == p2)return e;
+ }
+ }
+ else
+ {
+ for (int i=0;i<nbe2;i++)
+ {
+ MDB_Edge *e = p2->edges [i];
+ if (e->p1 == p1 && e->p2 == p2)return e;
+ if (e->p2 == p1 && e->p1 == p2)return e;
+ }
+ }
+ return 0;
+ }
+
+
+ MDB_Edge *MDB_Mesh::find_edge(MDB_Point * p1, MDB_Point * p2,
+ MDB_Triangle * t) const
+ {
+ if((t->e1->p1->iD == p1->iD && t->e1->p2->iD == p2->iD) ||
+ (t->e1->p1->iD == p2->iD && t->e1->p2->iD == p1->iD))
+ return t->e1;
+ if((t->e2->p1->iD == p1->iD && t->e2->p2->iD == p2->iD) ||
+ (t->e2->p1->iD == p2->iD && t->e2->p2->iD == p1->iD))
+ return t->e2;
+ if((t->e3->p1->iD == p1->iD && t->e3->p2->iD == p2->iD)||
+ (t->e3->p1->iD == p2->iD && t->e3->p2->iD == p1->iD))
+ return t->e3;
+ return 0;
+ }
+
+ MDB_Edge *MDB_Mesh::find_clone_edge(MDB_Edge * edge) const
+ {
+ double xyz[3];
+ double eXYZ[2][3];
+ MDB_Point * P = edge->p1;
+ eXYZ[0][0] = P->X; eXYZ[0][1] = P->Y; eXYZ[0][2] = P->Z;
+ P = edge->p2;
+ eXYZ[1][0] = P->X; eXYZ[1][1] = P->Y; eXYZ[1][2] = P->Z;
+
+ MDB_ListE::const_iterator eit = edges.begin();
+ for(; eit != edges.end(); ++eit) {
+
+ if ( (*eit) == edge ) continue;
+
+ P = (*eit)->p1;
+ xyz[0] = P->X; xyz[1] = P->Y; xyz[2] = P->Z;
+ if ( distanceSq(xyz,eXYZ[0]) < MAdTOL ) {
+ P = (*eit)->p2;
+ xyz[0] = P->X; xyz[1] = P->Y; xyz[2] = P->Z;
+ if ( distanceSq(xyz,eXYZ[1]) < MAdTOL ) {
+ return (*eit);
+ }
+ }
+
+ P = (*eit)->p2;
+ xyz[0] = P->X; xyz[1] = P->Y; xyz[2] = P->Z;
+ if ( distanceSq(xyz,eXYZ[0]) < MAdTOL ) {
+ P = (*eit)->p1;
+ xyz[0] = P->X; xyz[1] = P->Y; xyz[2] = P->Z;
+ if ( distanceSq(xyz,eXYZ[1]) < MAdTOL ) {
+ return (*eit);
+ }
+ }
+ }
+ return NULL;
+ }
+
+ MDB_Triangle *MDB_Mesh::find_triangle(MDB_Edge * e1, MDB_Edge * e2,
+ MDB_Edge * e3)
+ {
+ int i;
+ for(i = 0; i < e1->numfaces(); i++) {
+ MDB_Triangle *t = e1->faces(i);
+ MDB_Edge *o1 = t->e1;
+ MDB_Edge *o2 = t->e2;
+ MDB_Edge *o3 = t->e3;
+ if((o1 == e1 && o2 == e2 && o3 == e3) ||
+ (o1 == e1 && o2 == e3 && o3 == e2) ||
+ (o1 == e2 && o2 == e1 && o3 == e3) ||
+ (o1 == e2 && o2 == e3 && o3 == e1) ||
+ (o1 == e3 && o2 == e1 && o3 == e2) ||
+ (o1 == e3 && o2 == e2 && o3 == e1))
+ return t;
+ }
+
+ return 0;
+ }
+
+
+ MDB_Quad *MDB_Mesh::find_quad(MDB_Edge * e1, MDB_Edge * e2,
+ MDB_Edge * e3, MDB_Edge * e4)
+ {
+ MDB_Edge *eds[4] = {e1,e2,e3,e4};
+ std::sort(eds,eds+4);
+ for(int i = 0; i < e1->numquads(); i++) {
+ MDB_Quad *q = e1->quads(i);
+ MDB_Edge *edsb[4] = {q->e1,q->e2,q->e3,q->e4};
+ std::sort(edsb,edsb+4);
+ if (edsb[0] == eds[0] && edsb[1] == eds[1] && edsb[2] == eds[2] && edsb[3] == eds[3])
+ return q;
+ }
+ return 0;
+ }
+
+ MDB_Edge *MDB_Mesh::add_edge(int p1, int p2, pGEntity pg)
+ {
+ MDB_Edge *efound = find_edge(p1, p2);
+ if(efound)
+ {
+ if (efound->g == 0 || ( pg && GEN_type(pg) < GEN_type(efound->g )))
+ {
+ efound->g = pg;
+ }
+ return efound;
+ }
+
+ MDB_Point *pp1 = find_point(p1);
+ MDB_Point *pp2 = find_point(p2);
+ if(!pp1 || !pp2)
+ throw;
+ return add_edge (pp1,pp2,pg);
+ }
+
+ /*MDB_Edge *MDB_Mesh::add_edge(int p1, int p2, int p3, pGEntity pg)
+ {
+ MDB_Edge *efound = find_edge(p1, p3);
+
+ if(efound)
+ return efound;
+ MDB_Point *pp1 = find_point(p1);
+ MDB_Point *pp2 = find_point(p2);
+ MDB_Point *pp3 = find_point(p3);
+
+ if(!pp1 || !pp2 || !pp3)
+ throw;
+ return add_edge (pp1,pp2,pp3,pg);
+ }*/
+
+ MDB_Edge *MDB_Mesh::add_edge(int numberOfPoints, pGEntity pg, int p1, ...)
+ {
+ va_list ap;
+ // va_start(ap,numberOfPoints);
+ va_start(ap,p1);
+
+ int p2=0;int p3=0;int p4=0;int p5=0;
+ if (numberOfPoints>=3){
+ p2 = va_arg(ap,int);
+ if (numberOfPoints>=4){
+ p3 = va_arg(ap,int);
+ if (numberOfPoints>=5){
+ p4 = va_arg(ap,int);
+ if (numberOfPoints>=6){
+ p5 = va_arg(ap,int);
+ }
+ }
+ }
+ }
+ int pend = va_arg(ap,int);
+ va_end(ap);
+
+ MDB_Edge *efound = find_edge(p1, pend);
+
+ if(efound)
+ return efound;
+ MDB_Point *pp1 = find_point(p1);
+ MDB_Point *pp2=NULL;
+ MDB_Point *pp3=NULL;
+ MDB_Point *pp4=NULL;
+ MDB_Point *pp5=NULL;// = find_point(p2);
+ MDB_Point *ppend = find_point(pend);
+ switch(numberOfPoints){
+ case 3:
+ pp2 = find_point(p2);
+ assert(pp1 && pp2 && ppend);
+ return add_edge (3,pg,pp1,pp2,ppend);
+ case 4:
+ pp2 = find_point(p2);
+ pp3 = find_point(p3);
+ assert(pp1 && pp2 && pp3 && ppend);
+ return add_edge (4,pg,pp1,pp2,pp3,ppend);
+ case 5:
+ pp2 = find_point(p2);
+ pp3 = find_point(p3);
+ pp4 = find_point(p4);
+ assert(pp1 && pp2 && pp3 && pp4 && ppend);
+ return add_edge (5,pg,pp1,pp2,pp3,pp4,ppend);
+ case 6:
+ pp2 = find_point(p2);
+ pp3 = find_point(p3);
+ pp4 = find_point(p4);
+ pp5 = find_point(p5);
+ assert(pp1 && pp2 && pp3 && pp4 && pp5 && ppend);
+ return add_edge (6,pg,pp1,pp2,pp3,pp4,pp5,ppend);
+ default:
+ Msg(MDB_FATAL,"add_edge only implemented up to order 5 (this edge has %d nodes)\n",numberOfPoints);
+ }
+ throw;
+ }
+
+ MDB_Edge *MDB_Mesh::add_edge(MDB_Point *pp1 , MDB_Point *pp2, pGEntity pg)
+ {
+ MDB_Edge *e = new MDB_Edge(pp1, pp2);
+ e->g = pg;
+ edges.push_back(e);
+ nbEdges++;
+ return e;
+ }
+
+ MDB_Edge *MDB_Mesh::add_edge(MDB_Point* pp1,MDB_Point *pp2,pGEntity pg,int order,MDB_Point** pp)
+ {
+ // int numberOfPoints = order + 1;
+
+ MDB_Edge *e = NULL;
+ switch(order){
+ case 1:
+ e = new MDB_Edge(pp1,pp2);
+ break;
+ case 2:
+ e = new MDB_EdgeP2(pp1, pp[0], pp2);
+ break;
+ case 3:
+ e = new MDB_EdgeP3(pp1, pp[0], pp[1], pp2);
+ break;
+ case 4:
+ e = new MDB_EdgeP4(pp1, pp[0], pp[1], pp[2], pp2);
+ break;
+ case 5:
+ e = new MDB_EdgeP5(pp1, pp[0], pp[1], pp[2], pp[3] , pp2);
+ break;
+ default:
+ Msg(MDB_FATAL,"add_edge only implemented up to order 5\n");
+ }
+ e->g = pg;
+
+ for (int i=0;i<order-1;i++) {
+ if (pp[i]->g == NULL) pp[i]->g = pg;
+ std::set < MDB_Point *, PointLessThan >::iterator it = points.find(pp[i]);
+ deleteTheHighOrderPoint(it);
+ }
+
+ edges .push_back(e);
+ nbEdges++;
+ return e;
+ }
+
+
+
+ MDB_Edge *MDB_Mesh::add_edge(int numberOfPoints, pGEntity pg, MDB_Point *firstPoint, ...)
+ {
+ va_list ap;
+ // va_start(ap,numberOfPoints);
+ va_start(ap,firstPoint);
+
+ MDB_Point *pp2 = NULL;
+ MDB_Point *pp3 = NULL;
+ MDB_Point *pp4 = NULL;
+ MDB_Point *pp5 = NULL;
+
+ if (numberOfPoints>=3){
+ pp2 = va_arg(ap,MDB_Point*);
+ if (numberOfPoints>=4){
+ pp3 = va_arg(ap,MDB_Point*);
+ if (numberOfPoints>=5){
+ pp4 = va_arg(ap,MDB_Point*);
+ if (numberOfPoints>=6){
+ pp5 = va_arg(ap,MDB_Point*);
+ }
+ }
+ }
+ }
+ MDB_Point *ppend = va_arg(ap,MDB_Point*);
+ va_end(ap);
+
+ MDB_Edge *e = NULL;
+ switch(numberOfPoints){
+ case 2:
+ break;
+ case 3:
+ e = new MDB_EdgeP2(firstPoint, pp2, ppend);
+ break;
+ case 4:
+ e = new MDB_EdgeP3(firstPoint, pp2, pp3, ppend);
+ break;
+ case 5:
+ e = new MDB_EdgeP4(firstPoint, pp2, pp3, pp4, ppend);
+ break;
+ case 6:
+ e = new MDB_EdgeP5(firstPoint, pp2, pp3, pp4, pp5, ppend);
+ break;
+ default:
+ Msg(MDB_FATAL,"add_edge only implemented up to order 5\n");
+ }
+ e->g = pg;
+ edges.push_back(e);
+ nbEdges++;
+
+ if (numberOfPoints==2) return e;
+
+ std::set < MDB_Point *, PointLessThan >::iterator it1 = points.find(pp2);
+ deleteTheHighOrderPoint(it1);
+
+ std::set < MDB_Point *, PointLessThan >::iterator it2;
+ std::set < MDB_Point *, PointLessThan >::iterator it3;
+ std::set < MDB_Point *, PointLessThan >::iterator it4;
+ switch(numberOfPoints){
+ case 4:
+ it2 = points.find(pp3);
+ deleteTheHighOrderPoint(it2);
+ break;
+ case 5:
+ it2 = points.find(pp3);
+ it3 = points.find(pp4);
+ deleteTheHighOrderPoint(it2);
+ deleteTheHighOrderPoint(it3);
+ break;
+ case 6:
+ it2 = points.find(pp3);
+ it3 = points.find(pp4);
+ it4 = points.find(pp5);
+ deleteTheHighOrderPoint(it2);
+ deleteTheHighOrderPoint(it3);
+ deleteTheHighOrderPoint(it4);
+ break;
+ }
+ return e;
+ }
+
+ /*MDB_Edge *MDB_Mesh::add_edge(MDB_Point *pp1 , MDB_Point *pp2, MDB_Point *pp3, pGEntity pg)
+ {
+ MDB_Edge *e = new MDB_EdgeP2(pp1, pp2,pp3);
+ e->g = pg;
+ edges.push_back(e);
+ nbEdges++;
+
+ std::set < MDB_Point *, PointLessThan >::iterator it = points.find(pp2);
+ MDB_Point *pt;
+ if (it != points.end())
+ {
+ pt = *it;
+ points.erase(it);
+ nbPoints--;
+ }
+ else throw;
+ return e;
+ }*/
+
+ MDB_Triangle *MDB_Mesh::add_triangle(int p1, int p2, int p3, pGEntity pg)
+ {
+ MDB_Edge *e1 = add_edge(p1, p2);
+ MDB_Edge *e2 = add_edge(p2, p3);
+ MDB_Edge *e3 = add_edge(p3, p1);
+
+
+ MDB_Triangle *efound = find_triangle(e1, e2, e3);
+ if(efound)
+ {
+ if (efound->g == 0 || ( pg && GEN_type(pg) < GEN_type(efound->g )))
+ {
+ efound->g = pg;
+ }
+ return efound;
+ }
+
+ return add_triangle(e1, e2, e3,pg);
+ }
+
+ /*MDB_Triangle *MDB_Mesh::add_triangle(int numberOfPoints, pGEntity pg, int p1, int p2, ...)
+ {
+ va_list ap;
+ // va_start(ap,numberOfPoints);
+ va_start(ap,p2);
+ int p3=0;int p4=0;int p5=0;
+ int p6=0;int p7=0;int p8=0;int p9=0;
+ int p10=0;int p11=0;int p12=0;int p13=0;
+ int p14=0;int p15=0;
+ if (numberOfPoints>=6){
+ p3 = va_arg(ap,int);
+ p4 = va_arg(ap,int);
+ p5 = va_arg(ap,int);
+ p6 = va_arg(ap,int);
+ if (numberOfPoints>=9){
+ p7 = va_arg(ap,int);
+ p8 = va_arg(ap,int);
+ p9 = va_arg(ap,int);
+ if (numberOfPoints>=12){
+ p10 = va_arg(ap,int);
+ p11 = va_arg(ap,int);
+ p12 = va_arg(ap,int);
+ if (numberOfPoints>=15){
+ p13 = va_arg(ap,int);
+ p14 = va_arg(ap,int);
+ p15 = va_arg(ap,int);
+ }
+ }
+ }
+ }
+ va_end(ap);
+
+ MDB_Edge *e1,*e2,*e3;
+ switch(numberOfPoints){
+ case 3:
+ e1 = add_edge(2,0,p1, p2);
+ e2 = add_edge(2,0,p2, p3);
+ e3 = add_edge(2,0,p3, p1);
+ break;
+ case 6:
+ e1 = add_edge(3,0,p1, p2, p3);
+ e2 = add_edge(3,0,p3, p4, p5);
+ e3 = add_edge(3,0,p5, p6, p1);
+ break;
+ case 9:
+ e1 = add_edge(4,0,p1, p2, p3, p4);
+ e2 = add_edge(4,0,p4, p5, p6, p7);
+ e3 = add_edge(4,0,p7, p8, p9, p1);
+ break;
+ case 12:
+ e1 = add_edge(5,0,p1, p2, p3, p4, p5);
+ e2 = add_edge(5,0,p5, p6, p7, p8, p9);
+ e3 = add_edge(5,0,p9, p10,p11,p12,p1);
+ break;
+ case 15:
+ e1 = add_edge(6,0,p1, p2, p3, p4, p5, p6);
+ e2 = add_edge(6,0,p6, p7, p8, p9, p10,p11);
+ e3 = add_edge(6,0,p11,p12,p13,p14,p15,p1);
+ break;
+ }
+
+ MDB_Triangle *efound = find_triangle(e1, e2, e3);
+ if(efound)
+ {
+ if (efound->g == 0 || ( pg && GEN_type(pg) < GEN_type(efound->g )))
+ {
+ efound->g = pg;
+ }
+ return efound;
+ }
+ return add_triangle(e1, e2, e3,pg);
+ }*/
+
+ // high order triangle ...
+ // template is the following v0 ho[v0->v1] v1 ho[v1->v2] v2 ho[v2->v0]
+ MDB_Triangle *MDB_Mesh::add_triangle(int order, bool complete, pGEntity pg, int p1, int p2, ...)
+ {
+ // int numberOfPoints = complete ? (order+2)*(order+1)/2 : 3*order;
+ va_list ap;
+ // va_start(ap,numberOfPoints);
+ va_start(ap,p2);
+ int p3=0;int p4=0;int p5=0;
+ int p6=0;int p7=0;int p8=0;int p9=0;
+ int p10=0;int p11=0;int p12=0;int p13=0;
+ int p14=0;int p15=0;
+ if (order>=2){
+ p3 = va_arg(ap,int);
+ p4 = va_arg(ap,int);
+ p5 = va_arg(ap,int);
+ p6 = va_arg(ap,int);
+ if (order>=3){
+ p7 = va_arg(ap,int);
+ p8 = va_arg(ap,int);
+ p9 = va_arg(ap,int);
+ if (order>=4){
+ p10 = va_arg(ap,int);
+ p11 = va_arg(ap,int);
+ p12 = va_arg(ap,int);
+ if (order>=5){
+ p13 = va_arg(ap,int);
+ p14 = va_arg(ap,int);
+ p15 = va_arg(ap,int);
+ }
+ }
+ }
+ }
+ if (complete && order>2){
+ switch(order){
+ case 3:
+ p10 = va_arg(ap,int);
+ break;
+ case 4:
+ p13 = va_arg(ap,int);
+ p14 = va_arg(ap,int);
+ p15 = va_arg(ap,int);
+ break;
+ default:
+ Msg(MDB_FATAL,"Complete triangles not defined for order %d\n",order);
+ }
+ }
+ va_end(ap);
+
+ MDB_Edge *e1 = NULL;
+ MDB_Edge *e2 = NULL;
+ MDB_Edge *e3 = NULL;
+
+ switch(order){
+ case 1:
+ e1 = add_edge(2,0,p1, p2);
+ e2 = add_edge(2,0,p2, p3);
+ e3 = add_edge(2,0,p3, p1);
+ break;
+ case 2:
+ e1 = add_edge(3,0,p1, p2, p3);
+ e2 = add_edge(3,0,p3, p4, p5);
+ e3 = add_edge(3,0,p5, p6, p1);
+ break;
+ case 3:
+ e1 = add_edge(4,0,p1, p2, p3, p4);
+ e2 = add_edge(4,0,p4, p5, p6, p7);
+ e3 = add_edge(4,0,p7, p8, p9, p1);
+ break;
+ case 4:
+ e1 = add_edge(5,0,p1, p2, p3, p4, p5);
+ e2 = add_edge(5,0,p5, p6, p7, p8, p9);
+ e3 = add_edge(5,0,p9, p10,p11,p12,p1);
+ break;
+ case 5:
+ e1 = add_edge(6,0,p1, p2, p3, p4, p5, p6);
+ e2 = add_edge(6,0,p6, p7, p8, p9, p10,p11);
+ e3 = add_edge(6,0,p11,p12,p13,p14,p15,p1);
+ break;
+ }
+ MDB_Point** innerPoints = NULL;
+ if (complete && order>2){
+ int nbFacePoints = (order-1) * (order-2)/2;
+ innerPoints = new MDB_Point*[nbFacePoints];
+ switch (order){
+ case 3:
+ innerPoints[0] = find_point(p10);
+ break;
+ case 4:
+ innerPoints[0] = find_point(p13);
+ innerPoints[1] = find_point(p14);
+ innerPoints[2] = find_point(p15);
+ break;
+ default:
+ Msg(MDB_FATAL,"Complete triangles not defined for order %d\n",order);
+ }
+ }
+
+ MDB_Triangle *efound = find_triangle(e1, e2, e3);
+ if(efound)
+ {
+ if (efound->g == 0 || ( pg && GEN_type(pg) < GEN_type(efound->g )))
+ {
+ efound->g = pg;
+ }
+ return efound;
+ }
+ return add_triangle(e1,e2,e3,pg,order,!complete,innerPoints);
+ //return add_triangle(e1, e2, e3,pg);
+ }
+
+ // template for higher order triangle, following gmsh template
+ // v0 v1 v2
+ // higher order points
+ // edges loop following edge direction E0(V0-V1) E1(V1->V2) E2(V2->V0)
+ // face loop (eta(ksi)), ksi=e0, eta=-e2
+
+ /*MDB_Triangle *MDB_Mesh::add_triangle(pGEntity pg,int order,bool serendip,int* p) {
+
+
+ int nbEdgePoints = (order-1);
+ int nbFacePoints = (order+1) * (order+2)/2 - (serendip ? std::max(0,(order-2)*(order-1)/2) : 0);
+
+ MDB_Point** point = new MDB_Point*[nbFacePoints];
+
+ for (int i=0;i<nbFacePoints;i++) point[i] = find_point(p[i]);
+
+ MDB_Point** pp = point + 3;
+
+ // create edges
+
+ MDB_Edge* e1 = add_edge(point[0],point[1],pg,order,pp);
+ pp += nbEdgePoints;
+
+ MDB_Edge* e2 = add_edge(point[1],point[2],pg,order,pp);
+ pp += nbEdgePoints;
+
+ MDB_Edge* e3 = add_edge(point[2],point[0],pg,order,pp);
+ pp += nbEdgePoints;
+
+ //
+
+ return add_triangle(e1,e2,e3,pg,order,serendip,pp);
+ }*/
+
+ MDB_Triangle *MDB_Mesh::add_triangle(MDB_Edge * e1, MDB_Edge * e2,
+ MDB_Edge * e3, pGEntity pg)
+ {
+ MDB_Triangle *t = new MDB_Triangle(e1, e2, e3);
+ t->g = pg;
+ triangles.push_back(t);
+ nbTriangles++;
+ return t;
+ }
+
+ MDB_Triangle *MDB_Mesh::add_triangle(MDB_Edge *e1,MDB_Edge* e2,
+ MDB_Edge *e3,pGEntity pg,
+ int order,bool serendip,
+ MDB_Point** point) {
+
+
+
+
+ MDB_Triangle *t = NULL;
+ if (serendip || order <= 2) t = new MDB_Triangle(e1,e2,e3);
+ else {
+ switch (order) {
+
+ case 3:
+ t = new MDB_CompleteTriangle<3>(e1,e2,e3,point);
+ break;
+ case 4:
+ t = new MDB_CompleteTriangle<4>(e1,e2,e3,point);
+ break;
+ /* case 5:
+ t = new MDB_CompleteTriangle<5>(e1,e2,e3,point);
+ break;*/
+ default:
+ Msg(MDB_FATAL,"Complete triangle of order %d\n",order);
+ }
+
+ int nbPoints = (order-2)*(order-1)/2;
+
+ for (int i=0;i<nbPoints;i++) {
+ std::set<MDB_Point*,PointLessThan>::iterator it = points.find(point[i]);
+ deleteTheHighOrderPoint(it);
+ }
+ }
+
+ if (t) {
+ t->g = pg;
+ triangles.push_back(t);
+ nbTriangles++;
+ }
+ return t;
+ }
+
+
+
+ MDB_Quad *MDB_Mesh::add_quad(int p1, int p2, int p3, int p4, pGEntity pg)
+ {
+ MDB_Edge *e1 = add_edge(p1, p2);
+ MDB_Edge *e2 = add_edge(p2, p3);
+ MDB_Edge *e3 = add_edge(p3, p4);
+ MDB_Edge *e4 = add_edge(p4, p1);
+
+ MDB_Quad *efound = find_quad(e1, e2, e3, e4);
+ if(efound)
+ {
+ if (efound->g == 0 || ( pg && GEN_type(pg) < GEN_type(efound->g )))
+ {
+ efound->g = pg;
+ }
+ return efound;
+ }
+
+ return add_quad(e1, e2, e3, e4,pg);
+ }
+
+ MDB_Quad *MDB_Mesh::add_quad(MDB_Edge * e1, MDB_Edge * e2,
+ MDB_Edge * e3, MDB_Edge * e4, pGEntity pg)
+ {
+ MDB_Quad *q = new MDB_Quad(e1, e2, e3, e4);
+ q->g = pg;
+ quads.push_back(q);
+ nbQuads++;
+ return q;
+ }
+
+
+ static double VOLUME ( MDB_Tet *t )
+ {
+ pVertex v1 = R_vertex (t,0);
+ pVertex v2 = R_vertex (t,1);
+ pVertex v3 = R_vertex (t,2);
+ pVertex v4 = R_vertex (t,3);
+
+ double v12[3] = { v2->X - v1->X, v2->Y - v1->Y, v2->Z - v1->Z};
+ double v13[3] = { v3->X - v1->X, v3->Y - v1->Y, v3->Z - v1->Z};
+ double v14[3] = { v4->X - v1->X, v4->Y - v1->Y, v4->Z - v1->Z};
+
+ double pv[3] = { v12[1]*v13[2]-v12[2]*v13[1],
+ v12[2]*v13[0]-v12[0]*v13[2],
+ v12[0]*v13[1]-v12[1]*v13[0]};
+ double v =
+ pv[0] * v14[0]
+ + pv[1] * v14[1]
+ + pv[2] * v14[2];
+
+ return v/6;
+ }
+
+ static double VOLUME ( MDB_Hex *h )
+ {
+ pVertex v1 = R_vertex (h,0);
+ pVertex v2 = R_vertex (h,1);
+ pVertex v3 = R_vertex (h,2);
+ pVertex v4 = R_vertex (h,3);
+ pVertex v5 = R_vertex (h,4);
+ pVertex v6 = R_vertex (h,5);
+ pVertex v7 = R_vertex (h,6);
+ pVertex v8 = R_vertex (h,7);
+
+ double v21[3] = { v1->X - v2->X, v1->Y - v2->Y, v1->Z - v2->Z};
+ double v23[3] = { v3->X - v2->X, v3->Y - v2->Y, v3->Z - v2->Z};
+ double v24[3] = { v4->X - v2->X, v4->Y - v2->Y, v4->Z - v2->Z};
+ double v25[3] = { v5->X - v2->X, v5->Y - v2->Y, v5->Z - v2->Z};
+ double v26[3] = { v6->X - v2->X, v6->Y - v2->Y, v6->Z - v2->Z};
+ double v27[3] = { v7->X - v2->X, v7->Y - v2->Y, v7->Z - v2->Z};
+ double v28[3] = { v8->X - v2->X, v8->Y - v2->Y, v8->Z - v2->Z};
+
+ double pv248[3] = { v24[1]*v28[2]-v24[2]*v28[1], v24[2]*v28[0]-v24[0]*v28[2], v24[0]*v28[1]-v24[1]*v28[0]};
+ double pv258[3] = { v25[1]*v28[2]-v25[2]*v28[1], v25[2]*v28[0]-v25[0]*v28[2], v25[0]*v28[1]-v25[1]*v28[0]};
+ double pv278[3] = { v27[1]*v28[2]-v27[2]*v28[1], v27[2]*v28[0]-v27[0]*v28[2], v27[0]*v28[1]-v27[1]*v28[0]};
+
+ double vo1 = pv248[0] * v21[0] + pv248[1] * v21[1] + pv248[2] * v21[2];
+ double vo2 = pv258[0] * v21[0] + pv258[1] * v21[1] + pv258[2] * v21[2];
+ double vo3 = pv258[0] * v26[0] + pv258[1] * v26[1] + pv258[2] * v26[2];
+ double vo4 = pv248[0] * v23[0] + pv248[1] * v23[1] + pv248[2] * v23[2];
+ double vo5 = pv278[0] * v23[0] + pv278[1] * v23[1] + pv278[2] * v23[2];
+ double vo6 = pv278[0] * v26[0] + pv278[1] * v26[1] + pv278[2] * v26[2];
+
+ //NP The volume of hex was 0, I think there is an error in the tet volume formula.
+ // I fix the problem by changing the following line.
+ // return (vo1+vo2+vo3+vo4+vo5+vo6)/6;
+ return (-vo1+vo2-vo3+vo4-vo5+vo6)/6;
+ }
+
+
+ // -----------------------------------------------------------------------------
+ // template tet
+ // -----------------------------------------------------------------------------
+ //
+ // gmsh template
+ // V0 V1 V2 V3
+ // higher order points
+ //
+ // edges:
+ // ------
+ //
+ // E0 : V0 V1
+ // E1 : V1 V2
+ // E2 : V2 V0
+ // E3 : V0 V3
+ // E5 : V2 V3
+ // E4 : V1 V3
+ //
+ // faces:
+ // ------
+ //
+ // loop (eta(ksi)), ksi e0 (v0-v1) , eta -e2 (v0-v2)
+ // orientation such that rotation axis points inward
+ // face starts at vertex with corresponding index
+ //
+ // | e0 e1 e2 | v0 v1 v2 |
+ // -----------------------------
+ // F0 | +E0 +E1 +E2 | V0 V1 V2 |
+ // F1 | -E0 +E3 -E4 | V1 V0 V3 |
+ // F2 | +E5 -E3 -E2 | V2 V3 V0 |
+ // F3 | -E5 -E1 +E4 | V3 V2 V1 |
+ //
+ //
+ // volume:
+ // -------
+ //
+ // loop (zeta(eta(ksi))), ksi (V0-V1), eta (V0-V2), zeta (V0-V3)
+ //
+ // -----------------------------------------------------------------------------
+
+
+
+ MDB_Tet *MDB_Mesh::add_tet(pGEntity pg,int order,bool serendip,int* pointID) {
+
+ int nbEdgePoints = order > 1 ? order - 1 : 0;
+ int nbFacePoints = order > 2 ? (order-2)*(order-1)/2 : 0;
+ int nbVolPoints = ((serendip || order < 4) ? 0 : (order-3)*(order-2)*(order-1)/6);
+
+ int nb = 4 + 6 * nbEdgePoints + 4 * nbFacePoints + nbVolPoints;
+
+ MDB_Point** point = new MDB_Point*[nb];
+ for (int i=0;i<nb;i++) point[i] = find_point(pointID[i]);
+
+ MDB_Point** pp = point + 4;
+
+ // create edges
+ // to be tested : ordering of higher order nodes ...
+
+ MDB_Edge *e1 = find_edge(point[0],point[1]);
+ if (!e1) e1 = add_edge(point[0], point[1],pg,order,pp);
+ pp += nbEdgePoints;
+
+ MDB_Edge *e2 = find_edge(point[1],point[2]);
+ if (!e2) e2 = add_edge(point[1], point[2],pg,order,pp);
+ pp += nbEdgePoints;
+
+ MDB_Edge *e3 = find_edge(point[2],point[0]);
+ if (!e3) e3 = add_edge(point[2], point[0],pg,order,pp);
+ pp += nbEdgePoints;
+
+ // KH: edges 4,5 and 6 have opposite orientation in gmsh
+
+ MDB_Edge *e4 = find_edge(point[0],point[3]);
+ if (!e4) e4 = add_edge(point[3], point[0],pg,order,pp);
+ pp += nbEdgePoints;
+
+ // KH: edges 5 and 6 switched wrt gmsh, opposite direction
+
+ MDB_Edge *e6 = find_edge(point[2],point[3]);
+ if (!e6) e6 = add_edge(point[3], point[2],pg,order,pp);
+ pp += nbEdgePoints;
+
+ MDB_Edge *e5 = find_edge(point[1],point[3]);
+ if (!e5) e5 = add_edge(point[3], point[1],pg,order,pp);
+ pp += nbEdgePoints;
+
+ // create faces - complete
+
+ // face 1 is face 1 in Gmsh, the latter is oriented as v0-v2-v1
+
+ MDB_Triangle *t1 = find_triangle(e1, e2, e3);
+ // if(!t1) t1 = add_triangle(e1, e2, e3,pg,order,false,pp);
+ if(!t1) t1 = add_triangle(e3, e2, e1,pg,order,false,pp);
+ pp += nbFacePoints;
+
+ // face 2 is the same as in Gmsh
+
+ MDB_Triangle *t2 = find_triangle(e1, e4, e5);
+ if(!t2) t2 = add_triangle(e1, e5, e4,pg,order,false,pp);
+ pp += nbFacePoints;
+
+ // face 4 is face 3 in gmsh, the latter is oriented as v0-v3-v2
+
+ MDB_Triangle *t4 = find_triangle(e3, e4, e6);
+ // if(!t4)t4 = add_triangle (e3, e4, e6,pg,order,false,pp);
+ if(!t4) t4 = add_triangle (e4, e6, e3,pg,order,false,pp);
+ pp += nbFacePoints;
+
+ // face 3 in mdb is face 4 in gmsh, the latter is oriented as v3-v1-v2
+
+ MDB_Triangle *t3 = find_triangle(e2, e6, e5);
+ // if(!t3) t3 = add_triangle(e2, e6, e5,pg,order,false,pp);
+ if(!t3) t3 = add_triangle(e5, e2, e6,pg,order,false,pp);
+ pp += nbFacePoints;
+
+ // create tets
+
+ MDB_Tet* t = serendip ? add_tet(t1,t2,t3,t4,pg) : add_tet(t1,t2,t3,t4,pg,order,serendip,pp);
+
+ // clean up
+
+ delete [] point;
+ return t;
+ }
+
+
+
+
+ MDB_Tet *MDB_Mesh::add_tet(MDB_Triangle *t1,MDB_Triangle *t2,
+ MDB_Triangle *t3,MDB_Triangle *t4,
+ pGEntity pg,int order,bool serendip,MDB_Point** pp) {
+
+
+ MDB_Tet* t = NULL;
+
+ if (serendip || order <= 2) {
+ t = new MDB_Tet(t1,t2,t3,t4);
+ }
+ else {
+ switch (order){
+
+ case 3:
+ t = new MDB_CompleteTet<3> (t1,t2,t3,t4,pp);
+ break;
+ case 4:
+ t = new MDB_CompleteTet<4> (t1,t2,t3,t4,pp);
+ break;
+ case 5:
+ t = new MDB_CompleteTet<5> (t1,t2,t3,t4,pp);
+ break;
+ default:
+ Msg(MDB_FATAL,"Complete tetrahedron of order %d not yet implemented ",order);
+ break;
+ }
+
+ int nbPoints = std::max(0,(order-3)*(order-2)*(order-1)/6);
+
+ for (int i=0;i<nbPoints;i++) {
+ std::set<MDB_Point*,PointLessThan>::iterator it = points.find(pp[i]);
+ deleteTheHighOrderPoint(it);
+ }
+ }
+
+ if (t) {
+ t->g = pg;
+ tets.push_back(t);
+ nbTets++;
+ }
+ return t;
+ }
+
+
+ MDB_Tet *MDB_Mesh::add_tet(MDB_Triangle *t1,
+ MDB_Triangle *t2,
+ MDB_Triangle *t3,
+ MDB_Triangle *t4,
+ pGEntity pg)
+ {
+ MDB_Tet *t = new MDB_Tet(t1, t2, t3, t4);
+
+ double v = VOLUME (t);
+ if (v < 0)
+ {
+ t->f1 = t2;
+ t->f2 = t1;
+ // v = VOLUME (t);
+ // if (v < 0)
+ // throw;
+ }
+
+ t->g = pg;
+ tets.push_back(t);
+ nbTets++;
+ return t;
+ }
+
+ MDB_Tet *MDB_Mesh::add_tet(int p1, int p2, int p3, int p4, pGEntity pg)
+ {
+ MDB_Edge *e1 = add_edge(p1, p2);
+ MDB_Edge *e2 = add_edge(p2, p3);
+ MDB_Edge *e3 = add_edge(p3, p1);
+ MDB_Edge *e4 = add_edge(p1, p4);
+ MDB_Edge *e5 = add_edge(p2, p4);
+ MDB_Edge *e6 = add_edge(p3, p4);
+
+ MDB_Triangle *t1 = find_triangle(e1, e2, e3);
+ if(!t1)
+ t1 = add_triangle(e1, e2, e3);
+ MDB_Triangle *t2 = find_triangle(e1, e4, e5);
+ if(!t2)
+ t2 = add_triangle(e1, e4, e5);
+ MDB_Triangle *t3 = find_triangle(e2, e6, e5);
+ if(!t3)
+ t3 = add_triangle(e2, e6, e5);
+ MDB_Triangle *t4 = find_triangle(e3, e4, e6);
+ if(!t4)
+ t4 = add_triangle(e3, e4, e6);
+ return add_tet (t1, t2, t3, t4,pg);
+ }
+
+ MDB_Tet *MDB_Mesh::add_tet(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3, MDB_Point *p4, pGEntity pg)
+ {
+ MDB_Edge *e1 = find_edge(p1,p2);
+ if (!e1) e1 = add_edge(p1, p2, pg);
+ MDB_Edge *e2 = find_edge(p2,p3);
+ if (!e2) e2 = add_edge(p2, p3, pg);
+ MDB_Edge *e3 = find_edge(p3,p1);
+ if (!e3) e3 = add_edge(p3, p1, pg);
+ MDB_Edge *e4 = find_edge(p1,p4);
+ if (!e4) e4 = add_edge(p1, p4, pg);
+ MDB_Edge *e5 = find_edge(p2,p4);
+ if (!e5) e5 = add_edge(p2, p4, pg);
+ MDB_Edge *e6 = find_edge(p3,p4);
+ if (!e6) e6 = add_edge(p3, p4, pg);
+
+ MDB_Triangle *t1 = find_triangle(e1, e2, e3);
+ if(!t1)t1 = add_triangle(e1, e2, e3, pg);
+ MDB_Triangle *t2 = find_triangle(e1, e4, e5);
+ if(!t2)t2 = add_triangle(e1, e4, e5, pg);
+ MDB_Triangle *t3 = find_triangle(e2, e6, e5);
+ if(!t3)t3 = add_triangle(e2, e6, e5, pg);
+ MDB_Triangle *t4 = find_triangle(e3, e4, e6);
+ if(!t4)t4 = add_triangle(e3, e4, e6, pg);
+ return add_tet (t1, t2, t3, t4, pg);
+ }
+
+ void MDB_Mesh::del_tet(MDB_Tet * t)
+ {
+ t->f1->del(t);
+ t->f2->del(t);
+ t->f3->del(t);
+ t->f4->del(t);
+ nbTets--;
+ t->deleted = true;
+ }
+
+
+ void MDB_Mesh::del_face(MDB_Face *f)
+ {
+ int nbE = f->getNbEdges();
+ if ( nbE == 3 ) {
+ del_triangle ( dynamic_cast<MDB_Triangle *>(f) ); return;
+ }
+ else if ( nbE == 4 ) {
+ del_quad ( dynamic_cast<MDB_Quad *>(f) ); return;
+ }
+ throw;
+ }
+
+ MDB_Hex *MDB_Mesh::add_hex(MDB_Quad *q1, MDB_Quad *q2, MDB_Quad *q3, MDB_Quad *q4, MDB_Quad *q5, MDB_Quad *q6, pGEntity pg)
+ {
+ MDB_Hex *h= new MDB_Hex(q1, q2, q3, q4, q5, q6);
+
+ double v = VOLUME (h);
+ if (v < 0)
+ {
+ printf("Hexahedron has a negative volume.");
+ throw;
+ }
+
+ h->g = pg;
+ hexes.push_back(h);
+ nbHexes++;
+
+ return h;
+ }
+
+ MDB_Hex *MDB_Mesh::add_hex(int p1, int p2, int p3, int p4,
+ int p5, int p6, int p7, int p8, pGEntity pg)
+ {
+ MDB_Edge *e1 = add_edge(p1, p2);
+ MDB_Edge *e2 = add_edge(p2, p3);
+ MDB_Edge *e3 = add_edge(p3, p4);
+ MDB_Edge *e4 = add_edge(p4, p1);
+ MDB_Edge *e5 = add_edge(p1, p5);
+ MDB_Edge *e6 = add_edge(p2, p6);
+ MDB_Edge *e7= add_edge(p3, p7);
+ MDB_Edge *e8 = add_edge(p4, p8);
+ MDB_Edge *e9 = add_edge(p5, p6);
+ MDB_Edge *e10 = add_edge(p6, p7);
+ MDB_Edge *e11 = add_edge(p7, p8);
+ MDB_Edge *e12 = add_edge(p8, p5);
+
+ MDB_Quad *q1 = find_quad(e4, e3, e2, e1);
+ if(!q1) q1 = add_quad(e4, e3, e2, e1);
+ MDB_Quad *q2 = find_quad(e1, e6, e9, e5);
+ if(!q2) q2 = add_quad(e1, e6, e9, e5);
+ MDB_Quad *q3 = find_quad(e2, e7, e10, e6);
+ if(!q3) q3 = add_quad(e2, e7, e10, e6);
+ MDB_Quad *q4 = find_quad(e3, e8, e11, e7);
+ if(!q4) q4 = add_quad(e3, e8, e11, e7);
+ MDB_Quad *q5 = find_quad(e4, e5, e12, e8);
+ if(!q5) q5 = add_quad(e4, e5, e12, e8);
+ MDB_Quad *q6 = find_quad(e9, e10, e11, e12);
+ if(!q6) q6 = add_quad(e9, e10, e11, e12);
+ return add_hex (q1, q2, q3, q4, q5, q6, pg);
+ }
+
+ MDB_Hex *MDB_Mesh::add_hex(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3, MDB_Point *p4,
+ MDB_Point *p5, MDB_Point *p6,MDB_Point *p7, MDB_Point *p8, pGEntity pg)
+ {
+ MDB_Edge *e1 = find_edge(p1,p2);
+ if (!e1) e1 = add_edge(p1, p2);
+ MDB_Edge *e2 = find_edge(p2,p3);
+ if (!e2) e2 = add_edge(p2, p3);
+ MDB_Edge *e3 = find_edge(p3,p4);
+ if (!e3) e3 = add_edge(p3, p4);
+ MDB_Edge *e4 = find_edge(p4,p1);
+ if (!e4) e4 = add_edge(p4, p1);
+ MDB_Edge *e5 = find_edge(p1,p5);
+ if (!e5) e5 = add_edge(p1, p5);
+ MDB_Edge *e6 = find_edge(p2,p6);
+ if (!e6) e6 = add_edge(p2, p6);
+ MDB_Edge *e7 = find_edge(p3,p7);
+ if (!e7) e7 = add_edge(p3, p7);
+ MDB_Edge *e8 = find_edge(p4,p8);
+ if (!e8) e8 = add_edge(p4, p8);
+ MDB_Edge *e9 = find_edge(p5,p6);
+ if (!e9) e9 = add_edge(p5, p6);
+ MDB_Edge *e10 = find_edge(p6,p7);
+ if (!e10) e10 = add_edge(p6, p7);
+ MDB_Edge *e11 = find_edge(p7,p8);
+ if (!e11) e11 = add_edge(p7, p8);
+ MDB_Edge *e12 = find_edge(p8,p5);
+ if (!e12) e12 = add_edge(p8, p5);
+
+ MDB_Quad *q1 = find_quad(e4, e3, e2, e1);
+ if(!q1) q1 = add_quad(e4, e3, e2, e1);
+ MDB_Quad *q2 = find_quad(e1, e6, e9, e5);
+ if(!q2) q2 = add_quad(e1, e6, e9, e5);
+ MDB_Quad *q3 = find_quad(e2, e7, e10, e6);
+ if(!q3) q3 = add_quad(e2, e7, e10, e6);
+ MDB_Quad *q4 = find_quad(e3, e8, e11, e7);
+ if(!q4) q4 = add_quad(e3, e8, e11, e7);
+ MDB_Quad *q5 = find_quad(e4, e5, e12, e8);
+ if(!q5) q5 = add_quad(e4, e5, e12, e8);
+ MDB_Quad *q6 = find_quad(e9, e10, e11, e12);
+ if(!q6) q6 = add_quad(e9, e10, e11, e12);
+ return add_hex (q1, q2, q3, q4, q5, q6, pg);
+ }
+
+
+
+
+ MDB_Prism *MDB_Mesh::add_prism(MDB_Triangle *t1,MDB_Triangle *t2,
+ MDB_Quad *t3,MDB_Quad *t4,MDB_Quad *t5, pGEntity pg)
+ {
+ MDB_Prism *p = new MDB_Prism(t1, t2, t3, t4, t5);
+
+ //SL has not implemented the check on volume...
+ //double v = VOLUME (p);
+ //if (v < 0)
+ // {
+ // p->f1 = t2;
+ // p->f2 = t1;
+ // // v = VOLUME (p);
+ // // if (v < 0)
+ // // throw;
+ // }
+
+ p->g = pg;
+ prisms.push_back(p);
+ nbPrisms++;
+ return p;
+ }
+
+ MDB_Prism *MDB_Mesh::add_prism(int p1, int p2, int p3,
+ int p4, int p5, int p6, pGEntity pg)
+ {
+ MDB_Edge *e1 = add_edge(p1, p2);
+ MDB_Edge *e2 = add_edge(p1, p3);
+ MDB_Edge *e3 = add_edge(p2, p3);
+ MDB_Edge *e4 = add_edge(p4, p5);
+ MDB_Edge *e5 = add_edge(p4, p6);
+ MDB_Edge *e6 = add_edge(p5, p6);
+ MDB_Edge *e7= add_edge(p1, p4);
+ MDB_Edge *e8 = add_edge(p2, p5);
+ MDB_Edge *e9 = add_edge(p3, p6);
+
+ MDB_Triangle *q1 = find_triangle(e1, e2, e3);
+ if(!q1)
+ q1 = add_triangle(e1, e2, e3);
+ MDB_Triangle *q2 = find_triangle(e4, e6, e5);
+ if(!q2)
+ q2 = add_triangle(e4, e6, e5);
+ MDB_Quad *q3 = find_quad(e7, e4, e8, e1);
+ if(!q3)
+ q3 = add_quad(e7, e4, e8, e1);
+ MDB_Quad *q4 = find_quad(e8, e6, e9, e3);
+ if(!q4)
+ q4 = add_quad(e8, e6, e9, e3);
+ MDB_Quad *q5 = find_quad(e7, e2, e9, e5);
+ if(!q5)
+ q5 = add_quad(e7, e2, e9, e5);
+ return add_prism (q1, q2, q3, q4, q5, pg);
+ }
+
+ MDB_Prism *MDB_Mesh::add_prism(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3,
+ MDB_Point *p4, MDB_Point *p5, MDB_Point *p6, pGEntity pg)
+ {
+ MDB_Edge *e1 = find_edge(p1,p2);
+ if (!e1) e1 = add_edge(p1, p2);
+ MDB_Edge *e2 = find_edge(p1,p3);
+ if (!e2) e2 = add_edge(p1, p3);
+ MDB_Edge *e3 = find_edge(p2,p3);
+ if (!e3) e3 = add_edge(p2, p3);
+ MDB_Edge *e4 = find_edge(p4,p5);
+ if (!e4) e4 = add_edge(p4, p5);
+ MDB_Edge *e5 = find_edge(p4,p6);
+ if (!e5) e5 = add_edge(p4, p6);
+ MDB_Edge *e6 = find_edge(p5,p6);
+ if (!e6) e6 = add_edge(p5, p6);
+ MDB_Edge *e7 = find_edge(p1,p4);
+ if (!e7) e7 = add_edge(p1, p4);
+ MDB_Edge *e8 = find_edge(p2,p5);
+ if (!e8) e8 = add_edge(p2, p5);
+ MDB_Edge *e9 = find_edge(p3,p6);
+ if (!e9) e9 = add_edge(p3, p6);
+
+ MDB_Triangle *q1 = find_triangle(e1, e2, e3);
+ if(!q1) q1 = add_triangle(e1, e2, e3);
+ MDB_Triangle *q2 = find_triangle(e4, e6, e5);
+ if(!q2) q2 = add_triangle(e4, e6, e5);
+ MDB_Quad *q3 = find_quad(e7, e4, e8, e1);
+ if(!q3) q3 = add_quad(e7, e4, e8, e1);
+ MDB_Quad *q4 = find_quad(e8, e6, e9, e3);
+ if(!q4) q4 = add_quad(e8, e6, e9, e3);
+ MDB_Quad *q5 = find_quad(e7, e2, e9, e5);
+ if(!q5) q5 = add_quad(e7, e2, e9, e5);
+ return add_prism (q1, q2, q3, q4, q5, pg);
+ }
+
+ void MDB_Mesh::del_hex(MDB_Hex * h)
+ {
+ h->f1->del(h);
+ h->f2->del(h);
+ h->f3->del(h);
+ h->f4->del(h);
+ h->f5->del(h);
+ h->f6->del(h);
+ nbHexes--;
+ h->deleted = true;
+ }
+
+ void MDB_Mesh::del_prism(MDB_Prism * p)
+ {
+ p->f1->del(p);
+ p->f2->del(p);
+ p->f3->del(p);
+ p->f4->del(p);
+ p->f5->del(p);
+ nbPrisms--;
+ p->deleted = true;
+ }
+
+ void MDB_Mesh::del_triangle(MDB_Triangle * t)
+ {
+ t->e1->del(t);
+ t->e2->del(t);
+ t->e3->del(t);
+ nbTriangles--;
+ t->deleted = true;
+ if (t->getNbRegions())throw;
+ }
+
+ void MDB_Mesh::del_quad(MDB_Quad * q)
+ {
+ q->e1->del(q);
+ q->e2->del(q);
+ q->e3->del(q);
+ q->e4->del(q);
+ nbQuads--;
+ q->deleted = true;
+ if (q->getNbRegions())throw;
+ }
+
+ void MDB_Mesh::del_edge(MDB_Edge * e)
+ {
+ e->p1->del(e);
+ e->p2->del(e);
+ nbEdges--;
+ e->deleted = true;
+
+ if (e->numfaces())throw;
+ }
+
+ void MDB_Mesh::del_point(MDB_Point * p)
+ {
+ if (p->deleted) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "point already deleted");
+ }
+ p->deleted = true;
+ nbPoints--;
+ if (p->edges.size())throw;
+ }
+
+
+ void MDB_Edge::oppositeof(MDB_Point * oface[2]) const
+ {
+ oface[0] = oface[1] = 0;
+ if(faces(0)) {
+ MDB_Point *pts[3];
+ faces(0)->getNodes(pts);
+ if(pts[0] != p1 && pts[0] != p2)
+ oface[0] = pts[0];
+ else if(pts[1] != p1 && pts[1] != p2)
+ oface[0] = pts[1];
+ else
+ oface[0] = pts[2];
+ }
+ if(faces(1)) {
+ MDB_Point *pts[3];
+ faces(1)->getNodes(pts);
+ if(pts[0] != p1 && pts[0] != p2)
+ oface[1] = pts[0];
+ else if(pts[1] != p1 && pts[1] != p2)
+ oface[1] = pts[1];
+ else
+ oface[1] = pts[2];
+ }
+ }
+
+ template < class IT > void DESTROOOY(IT beg, IT end)
+ {
+ while(beg != end) {
+ delete *beg;
+ beg++;
+ }
+ }
+
+ MDB_Mesh ::~ MDB_Mesh ()
+ {
+ DESTROOOY ( points.begin(),points.end());
+ DESTROOOY ( edges.begin(),edges.end());
+ DESTROOOY ( triangles.begin(),triangles.end());
+ DESTROOOY ( quads.begin(),quads.end());
+ DESTROOOY ( tets.begin(),tets.end());
+ DESTROOOY ( hexes.begin(),hexes.end());
+ DESTROOOY ( prisms.begin(),prisms.end());
+ }
+
+ MDB_Edge::~MDB_Edge ()
+ {
+ }
+
+
+ MDB_Mesh::MDB_Mesh(const MDB_Mesh & other)
+ {
+ throw;
+ }
+
+ void MDB_Mesh :: load ( FILE *f )
+ {
+ _load (f);
+ shrinked = true;
+ }
+
+ void MDB_Mesh :: flush ( FILE *f ) const
+ {
+ _flush (f);
+ }
+
+ void MDB_Mesh :: shrink ()
+ {
+ VIter vit = M_vertexIter ( this );
+ pVertex pv;
+ GEntity2Physical gentity2phys(geomFeatures_Tags);
+ coords = new double[3*nbPoints];
+ ids = new int [ nbPoints];
+ int i=0;
+ nbInfos = 0;
+
+ int SIZE_INFO_PT = 4;
+ int SIZE_INFO_EDGE = 5;
+ int SIZE_INFO_TRIANGLE = 6;
+ int SIZE_INFO_TET = 7;
+
+ while ((pv = VIter_next (vit)))
+ {
+ int dim = EN_whatInType(pv);
+ if (dim == 0) nbInfos += SIZE_INFO_PT;
+ ids[i] = pv->iD;
+ pv->iD= i+1;
+ V_coord ( pv, &coords[3*i++]);
+ }
+ nbVertex = nbPoints;
+ EIter eit = M_edgeIter ( this );
+ pEdge pe;
+ while ((pe = EIter_next (eit)))
+ {
+ int dim = EN_whatInType(pe);
+ if (dim == 1) nbInfos += SIZE_INFO_EDGE;
+ }
+ FIter fit = M_faceIter ( this );
+ pFace pf;
+ while ((pf = FIter_next (fit)))
+ {
+ int dim = EN_whatInType(pf);
+ if (dim == 2) nbInfos += SIZE_INFO_TRIANGLE;
+ }
+ nbInfos += SIZE_INFO_TET * nbTets;
+
+ infos = new int [nbInfos];
+
+ VIter_reset(vit);
+ EIter_reset(eit);
+ FIter_reset(fit);
+
+ int K = 0;
+
+ while ((pv = VIter_next (vit)))
+ {
+ int dim = EN_whatInType(pv);
+ if (dim == 0)
+ {
+ pGEntity pg = EN_whatIn(pv);
+ int tag = GEN_tag ( pg );
+ int phys = gentity2phys.get_first_tag( pg );
+ infos[K++] = 15;
+ infos[K++] = phys;
+ infos[K++] = tag;
+ infos[K++] = EN_id(pv);
+ }
+ }
+
+ while ((pe = EIter_next (eit)))
+ {
+ int dim = EN_whatInType(pe);
+ if (dim == 1)
+ {
+ pGEntity pg = EN_whatIn(pe);
+ int tag = GEN_tag ( pg );
+ int phys = gentity2phys.get_first_tag( pg );
+ pVertex v1 = E_vertex ( pe, 0);
+ pVertex v2 = E_vertex ( pe, 1);
+ infos[K++] = 1;
+ infos[K++] = phys;
+ infos[K++] = tag;
+ infos[K++] = EN_id (v1);
+ infos[K++] = EN_id (v2);
+ }
+ }
+ while ((pf = FIter_next (fit)))
+ {
+ int dim = EN_whatInType(pf);
+ if (dim == 2)
+ {
+ pGEntity pg = EN_whatIn(pf);
+ int tag = GEN_tag ( pg );
+ int phys = gentity2phys.get_first_tag( pg );
+ pVertex v1 = F_vertex ( pf, 0);
+ pVertex v2 = F_vertex ( pf, 1);
+ pVertex v3 = F_vertex ( pf, 2);
+ infos[K++] = 2;
+ infos[K++] = phys;
+ infos[K++] = tag;
+ infos[K++] = EN_id (v1);
+ infos[K++] = EN_id (v2);
+ infos[K++] = EN_id (v3);
+ }
+ }
+
+ pRegion pr;
+ RIter rit = M_regionIter ( this );
+ while ((pr = RIter_next (rit)))
+ {
+ pGEntity pg = EN_whatIn(pr);
+ int tag = GEN_tag ( pg );
+ int phys = gentity2phys.get_first_tag( pg );
+ pVertex v1 = R_vertex ( pr, 0);
+ pVertex v2 = R_vertex ( pr, 1);
+ pVertex v3 = R_vertex ( pr, 2);
+ pVertex v4 = R_vertex ( pr, 3);
+ infos[K++] = 4;
+ infos[K++] = phys;
+ infos[K++] = tag;
+ infos[K++] = EN_id (v1);
+ infos[K++] = EN_id (v2);
+ infos[K++] = EN_id (v3);
+ infos[K++] = EN_id (v4);
+ }
+
+ // printf("%d %d\n",K,nbInfos);
+
+ VIter_delete(vit);
+ EIter_delete(eit);
+ FIter_delete(fit);
+ RIter_delete(rit);
+
+ DESTROOOY ( points.begin(),points.end());
+ DESTROOOY ( edges.begin(),edges.end());
+ DESTROOOY ( triangles.begin(),triangles.end());
+ DESTROOOY ( tets.begin(),tets.end());
+ DESTROOOY ( quads.begin(),quads.end());
+ DESTROOOY ( hexes.begin(),hexes.end());
+ DESTROOOY ( prisms.begin(),prisms.end());
+
+ points.clear();
+ edges.clear();
+ triangles.clear();
+ quads.clear();
+ tets.clear();
+ hexes.clear();
+ prisms.clear();
+
+ nbPoints = nbTriangles = nbEdges = nbTets = nbQuads = nbHexes = nbPrisms = 0;
+ maxId=0;
+
+ shrinked = true;
+ }
+ void MDB_Mesh :: classify_unclassified_entities ()
+ {
+ int nbV=0, nbE=0, nbF=0, nbR=0;
+
+ RIter rit = M_regionIter(this);
+ pRegion pr;
+ while ((pr = RIter_next(rit)))
+ {
+ if (pr->g)
+ {
+ pFace f1 = R_face (pr,0);
+ if (!f1->g) f1->g = pr->g;
+ pFace f2 = R_face (pr,1);
+ if (!f2->g) f2->g = pr->g;
+ pFace f3 = R_face (pr,2);
+ if (!f3->g) f3->g = pr->g;
+ pFace f4 = R_face (pr,3);
+ if (!f4->g) f4->g = pr->g;
+ pFace f5 = R_face (pr,4);
+ if (f5 && !f5->g) f5->g = pr->g;
+ pFace f6 = R_face (pr,5);
+ if (f6 && !f6->g) f6->g = pr->g;
+ }
+ else
+ {
+ nbR++;
+ }
+ }
+
+ RIter_delete(rit);
+
+ FIter fit = M_faceIter(this);
+ pFace pf;
+ while ((pf = FIter_next(fit)))
+ {
+ if (pf->g)
+ {
+ pEdge e1 = F_edge (pf,0);
+ if (!e1->g) e1->g = pf->g;
+ pEdge e2 = F_edge (pf,1);
+ if (!e2->g) e2->g = pf->g;
+ pEdge e3 = F_edge (pf,2);
+ if (!e3->g) e3->g = pf->g;
+ pEdge e4 = F_edge (pf,3);
+ if (e4 && !e4->g) e4->g = pf->g;
+ }
+ else
+ {
+ nbF++;
+ }
+ }
+ FIter_delete(fit);
+
+
+ EIter eit = M_edgeIter(this);
+ pEdge pe;
+ while ((pe = EIter_next(eit)))
+ {
+ if (pe->g)
+ {
+ pVertex v1 = E_vertex (pe,0);
+ if (!v1->g) v1->g = pe->g;
+ pVertex v2 = E_vertex (pe,1);
+ if (!v2->g) v2->g = pe->g;
+ }
+ else
+ {
+ nbE++;
+ }
+ }
+ EIter_delete(eit);
+
+ VIter vit = M_vertexIter(this);
+ pVertex pv;
+ while ((pv = VIter_next(vit)))
+ {
+ if (!pv->g)
+ {
+ nbV++;
+ }
+ }
+ VIter_delete(vit);
+
+ if ( !nbV || !nbE || !nbF || !nbR ) {
+ MAdMsgSgl::instance().info(__LINE__,__FILE__,
+ "There are unclassified entities: %d, regions, %d faces, %d edges, %d vertices\n",
+ nbR,nbF,nbE,nbV);
+ }
+ }
+
+ void MDB_Mesh :: destroyStandAloneEntities() {
+
+ // First build a list of entities < mesh dim and not to be deleted
+ // = those which are part of an entity of dimension = mesh dim
+ set<pVertex> usedV;
+ set<pEdge> usedE;
+ set<pFace> usedF;
+
+ // 3D case
+ if ( nbTets + nbHexes + nbPrisms != 0 ) {
+
+ RIter rit = M_regionIter(this);
+ pRegion pr;
+ while ((pr = RIter_next(rit)))
+ {
+ for (int i=0; i < pr->getNbFace(); i++) {
+ pFace f = R_face (pr,i);
+ usedF.insert(f);
+ }
+ for (int i=0; i < pr->getNbEdge(); i++) {
+ pEdge e = R_edge (pr,i);
+ usedE.insert(e);
+ }
+ for (int i=0; i < pr->getNbVertex(); i++) {
+ pVertex v = R_vertex (pr,i);
+ usedV.insert(v);
+ }
+ }
+ RIter_delete(rit);
+ }
+
+ // 2D case
+ else if ( nbTriangles + nbQuads != 0 ) {
+
+ FIter fit = M_faceIter(this);
+ pFace pf;
+ while ((pf = FIter_next(fit)))
+ {
+ usedF.insert(pf);
+ for (int i=0; i < pf->getNbEdges(); i++) {
+ pEdge e = F_edge (pf,i);
+ usedE.insert(e);
+ }
+ for (int i=0; i < pf->getNbNodes(); i++) {
+ pVertex v = F_vertex (pf,i);
+ usedV.insert(v);
+ }
+ }
+ FIter_delete(fit);
+ }
+
+ // 1D case
+ else if ( nbEdges != 0 ) {
+
+ EIter eit = M_edgeIter(this);
+ pEdge pe;
+ while ((pe = EIter_next(eit)))
+ {
+ usedE.insert(pe);
+ for (int i=0; i < 2; i++) {
+ pVertex v = E_vertex (pe,i);
+ usedV.insert(v);
+ }
+ }
+ EIter_delete(eit);
+ }
+
+ // 0D case
+ else {
+
+ VIter vit = M_vertexIter(this);
+ pVertex pv;
+ while ((pv = VIter_next(vit)))
+ {
+ usedV.insert(pv);
+ }
+ VIter_delete(vit);
+ }
+
+ // then delete the others
+ int delV = 0;
+ int delE = 0;
+ int delF = 0;
+
+ FIter fit = M_faceIter(this);
+ pFace pf;
+ while ((pf = FIter_next(fit)))
+ {
+ if (usedF.find(pf) == usedF.end() ) {
+ del_face(pf);
+ delF++;
+ }
+ }
+ FIter_delete(fit);
+
+ EIter eit = M_edgeIter(this);
+ pEdge pe;
+ while ((pe = EIter_next(eit)))
+ {
+ if (usedE.find(pe) == usedE.end() ) {
+// #warning "debug"
+// printf("Looking for a clone...");
+// pEdge peClone = find_clone_edge(pe);
+// if (peClone) printf("found one\n");
+// else printf("no clone\n");
+// if (peClone) {
+// printf("This edge will be deleted:\n");
+// E_info(pe);
+// printf("This edge is its clone:\n");
+// E_info(peClone);
+// }
+// if ( (peClone) && ( GEN_type(peClone->g) > GEN_type(pe->g) ) ) {
+// peClone->g = pe->g;
+// }
+
+ del_edge(pe);
+ delE++;
+ }
+ }
+ EIter_delete(eit);
+
+ VIter vit = M_vertexIter(this);
+ pVertex pv;
+ while ((pv = VIter_next(vit)))
+ {
+ if (usedV.find(pv) == usedV.end() ) {
+ del_point(pv);
+ delV++;
+ }
+ }
+ VIter_delete(vit);
+
+ if ( delV != 0 || delE != 0 || delF != 0 ) {
+ cout <<"WARNING: deleted stand alone entities: "
+ << delV <<" vertices, "
+ << delE <<" edges, "
+ << delF <<" faces\n";
+ }
+ }
+
+ // void MDB_Mesh :: checkGeomTagsCoherence () const
+ // {
+ // std::set<int> volumeTags;
+ // std::multimap<int, pGEntity >::const_iterator tagIt = geomFeatures_Tags.begin();
+ // for (; tagIt != geomFeatures_Tags.end(); tagIt++)
+ // if (GEN_type(tagIt->second) == 3)
+ // volumeTags.insert(tagIt->first);
+
+ // tagIt = geomFeatures_Tags.begin();
+ // for (; tagIt != geomFeatures_Tags.end(); tagIt++)
+ // if (GEN_type(tagIt->second) == 2)
+ // if ( volumeTags.find(tagIt->first) != volumeTags.end() ) {
+ // printf("Wrong input geometry: the geometric ID \'%d\' is used for both a volume and a surface\n",tagIt->first);
+ // exit(0);
+ // }
+ // }
+
+ void MDB_Mesh :: expand ()
+ {
+ initializeIdData();
+
+ pVertex *vs = new pVertex[nbVertex];
+
+ for (int i=0;i<nbVertex;i++)
+ {
+ // vs[i] = add_point (i+1,coords[3*i],coords[3*i+1],coords[3*i+2]);
+ vs[i] = add_point (ids[i],coords[3*i],coords[3*i+1],coords[3*i+2]);
+ }
+
+
+ nbVertex = 0;
+ delete [] coords;
+
+ int i=0;
+ while (i<nbInfos)
+ {
+ int type = infos[i++];
+ int physicalTag = infos[i++];
+ int elementaryTag = infos[i++];
+ pGEntity g=NULL;
+
+ if (type == 15)
+ {
+ pVertex p = vs[infos[i++]-1];
+ g = GM_entityByTag(model, 0, elementaryTag);
+ p->g = g;
+ }
+ else if (type == 1)
+ {
+ pVertex v1 = vs[infos[i++]-1];
+ pVertex v2 = vs[infos[i++]-1];
+ g = GM_entityByTag(model, 1, elementaryTag);
+ add_edge(v1,v2,g);
+ }
+ else if (type == 2)
+ {
+ int v1 = ids[infos[i++]-1];
+ int v2 = ids[infos[i++]-1];
+ int v3 = ids[infos[i++]-1];
+ g = GM_entityByTag(model, 2, elementaryTag);
+ add_triangle(v1,v2,v3,g);
+ }
+ else if (type == 4)
+ {
+ pVertex v1 = vs[infos[i++]-1];
+ pVertex v2 = vs[infos[i++]-1];
+ pVertex v3 = vs[infos[i++]-1];
+ pVertex v4 = vs[infos[i++]-1];
+ g = GM_entityByTag(model, 3, elementaryTag);
+ add_tet(v1,v2,v3,v4,g);
+ }
+ if (g)
+ {
+ bool find = false;
+ for (std::multimap<int, pGEntity>::iterator it = geomFeatures_Tags.lower_bound(physicalTag);
+ it != geomFeatures_Tags.upper_bound(physicalTag);++it)
+ if (it->second == g)find = true;
+ if (!find)
+ geomFeatures_Tags.insert(std::pair<int,pGEntity>(physicalTag, g));
+ }
+ }
+ delete [] infos; infos = NULL;
+ delete [] ids; ids = NULL;
+ delete [] vs; vs = NULL;
+ nbInfos = 0;
+ classify_unclassified_entities();
+ shrinked = false;
+ }
+
+ int MDB_Tet::face_vtx[4][3] = {{0,1,2},{0,1,3},{1,2,3},{0,2,3}};
+
+ // return 1 if the face direction points to outside of the tet
+ // return 0 inside
+ int MDB_Tet::getFaceDir (int n) const
+ {
+ int tetfacedir [] = {1,0,0,1};
+ int corr = tetfacedir[n];
+ pFace f = getFace(n);
+ pVertex v1f, v2f;
+ v1f = F_vertex (f,0);
+ v2f = F_vertex (f,1);
+
+ pVertex v[3];
+ switch (n)
+ {
+ case 0 : //inside
+ v[0] = getVertex(0);
+ v[1] = getVertex(1);
+ v[2] = getVertex(2);
+ break;
+ case 1 : // outside
+ v[0] = getVertex(0);
+ v[1] = getVertex(1);
+ v[2] = getVertex(3);
+ break;
+ case 2 : // outside
+ v[0] = getVertex(1);
+ v[1] = getVertex(2);
+ v[2] = getVertex(3);
+ break;
+ case 3 : //inside
+ v[0] = getVertex(0);
+ v[1] = getVertex(2);
+ v[2] = getVertex(3);
+ break;
+ default :
+ throw;
+ }
+
+
+ for(int j=0;j<3;j++)
+ {
+ if (v[j] == v1f)
+ {
+ pVertex vtest = v[(j+1)%3];
+ if (vtest == v2f) return 1-corr;
+ vtest = v[(j+2)%3];
+ if (vtest == v2f) return corr;
+ throw;
+ }
+ }
+ throw;
+ }
+
+ int MDB_Tet::getFaceOrientation (int n) const {
+
+ pFace f = getFace(n);
+ pVertex v0 = getVertex(face_vtx[n][0]);
+ pVertex v1 = getVertex(face_vtx[n][1]);
+
+ int orientation = 0;
+
+ for (int j=0;j<3;j++) if (F_vertex(f,j) == v0) orientation = j;
+
+ int direction = 1;
+ if (v1 == F_vertex(f,(orientation+2)%3)) direction = -1;
+
+ return direction * (orientation + 1);
+ }
+
+
+ int MDB_Hex::getFaceDir (int n) const { return 0;}
+
+ // -----------------------------------------------------------------------------
+ /*! \brief Compute orientation wrt face given by a list of principal nodes \ingroup internal */
+ /*! abs(rot) - 1 = the index of the node in the current element corresponding to node 0 in the remote element */
+ /*! sgn(rot) = 1 if the element is oriented in the same fashion, -1 if inverted */
+
+ int MDB_Face::orientation(MDB_Point* v0,
+ MDB_Point* v1,
+ MDB_Point* v2,
+ MDB_Point* v3) const {
+
+ if ((getNbNodes() == 4) && (v3 == NULL)) return 0;
+
+ int rot = 0;
+ for (int j=0;j<getNbNodes();j++) {
+ if (getNode(j) == v0) rot = j+1;
+ }
+
+ if (getNode(rot%getNbNodes()) != v1) {
+ if (getNode((rot-2+getNbNodes())%getNbNodes()) == v1) rot *= -1;
+ }
+ return rot;
+ }
+
+ // -----------------------------------------------------------------------------
+ /*! \brief Realign the edge with the direction given by a set of two nodes \ingroup internal */
+ /*! returns 1 if already aligned, -1 if inversely aligned, 0 if failed */
+
+ int MDB_Edge::align(MDB_Point* po1,MDB_Point* po2)
+ {
+ if ((p1 == po1) && (p2 == po2)) return 1;
+ if ((p2 == po1) && (p1 == po2)) {
+ std::swap(p1,p2);
+ swapHONodes();
+ return -1;
+ }
+ return 0;
+ }
+
+ // -----------------------------------------------------------------------------
+ /*! \brief Realign the triangle with the direction given by a set of three nodes \ingroup internal */
+ /*! Returns 0 if failed, otherwise
+ abs(rot) = index of node corresponding to v0
+ sng(rot) = 1 if same orientation, -1 if inverted orientation */
+
+ int MDB_Triangle::align(MDB_Point* v0,MDB_Point* v1,MDB_Point* v2,MDB_Point* v3) {
+
+ int rot = orientation(v0,v1,v2,v3);
+
+ if (rot != 1 && rot != 0) {
+
+ MDB_Edge* tmpEdge[3];
+ for (int i=0;i<3;i++) tmpEdge[i] = getEdge((i+abs(rot)-1)%3);
+
+ if (rot < 0) {
+ MDB_Edge* tmp = tmpEdge[0];
+ tmpEdge[0] = tmpEdge[2];
+ tmpEdge[2] = tmp;
+ }
+
+ e1 = tmpEdge[0];
+ e2 = tmpEdge[1];
+ e3 = tmpEdge[2];
+ }
+ return rot;
+ }
+
+ // -----------------------------------------------------------------------------
+ /*! \brief Realign the quadrilateral with the direction given by a set of four nodes \ingroup internal */
+ /*! Returns 0 if failed, otherwise
+ abs(rot) = index of node corresponding to v0
+ sng(rot) = 1 if same orientation, -1 if inverted orientation */
+
+ int MDB_Quad::align(MDB_Point* v0,MDB_Point* v1,MDB_Point* v2,MDB_Point* v3) {
+
+ int rot = orientation(v0,v1,v2,v3);
+ if (rot != 1 && rot != 0) {
+
+ MDB_Edge* tmpEdge[4];
+ for (int i=0;i<getNbEdges();i++) tmpEdge[i] = getEdge((i+abs(rot)-1)%getNbEdges());
+
+ if (rot < 0) {
+ MDB_Edge* tmp = tmpEdge[0];
+ tmpEdge[0] = tmpEdge[3];
+ tmpEdge[3] = tmp;
+ tmp = tmpEdge[1];
+ tmpEdge[1] = tmpEdge[2];
+ tmpEdge[2] = tmp;
+ }
+
+ e1 = tmpEdge[0];
+ e2 = tmpEdge[1];
+ e3 = tmpEdge[2];
+ e4 = tmpEdge[3];
+ }
+
+ return rot;
+
+ }
+
+} // End of namespace MAd
+
diff --git a/Mesh/MeshDataBase.h b/Mesh/MeshDataBase.h
new file mode 100644
index 0000000..575e4d3
--- /dev/null
+++ b/Mesh/MeshDataBase.h
@@ -0,0 +1,1191 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere, Koen Hillewaert
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASE
+#define H_MESHDATABASE
+#include <set>
+#include <vector>
+#include <algorithm>
+#include <list>
+#include <map>
+#include <cmath>
+#include <assert.h>
+#include <cstdarg>
+#include <string.h>
+#include <iostream>
+#include "ModelInterface.h"
+#include "MeshDataBaseIterators.h"
+#include "MeshDataBaseAttachable.h"
+#include "MeshDataBaseMiniMesh.h"
+#include "MeshDataBaseMessage.h"
+
+namespace MAd {
+
+ class MDB_Region;
+ class MDB_Tet;
+ class MDB_Hex;
+ class MDB_Prism;
+ class MDB_Quad;
+ class MDB_Face;
+ class MDB_Edge;
+ class MDB_EdgeP2;
+ class MDB_Triangle;
+ class MDB_Mesh;
+ class MDB_Point;
+
+ typedef std::list<MDB_Point *> MDB_ListP ;
+ typedef std::list<MDB_Edge *> MDB_ListE ;
+ typedef std::list<MDB_Triangle *> MDB_ListF ;
+ typedef std::list<MDB_Quad*> MDB_ListQ ;
+ typedef std::list<MDB_Face*> MDB_ListFace;
+ typedef std::list<MDB_Tet *> MDB_ListT ;
+ typedef std::list<MDB_Hex *> MDB_ListH ;
+ typedef std::list<MDB_Prism *> MDB_ListPr;
+ typedef std::list<MDB_Region *> MDB_ListR ;
+ typedef std::vector<MDB_Triangle *> MDB_VectorF ;
+ typedef std::vector<MDB_Quad *> MDB_VectorQ ;
+ typedef std::vector<MDB_Edge *> MDB_VectorE ;
+ typedef std::vector<MDB_Tet *> MDB_VectorT ;
+ typedef std::vector<MDB_Hex *> MDB_VectorH ;
+ typedef std::vector<MDB_Prism *> MDB_VectorPr;
+
+ class MDB_MeshEntity : public mAttachableDataContainer
+ {
+ public :
+ int iD;
+ bool deleted;
+ pGEntity g;
+ virtual int getDim() const = 0;
+ virtual int getOrder() const = 0;
+ MDB_MeshEntity ( int _ID = 0, pGEntity _g = 0) : iD(_ID), deleted (false), g(_g) {}
+ virtual ~MDB_MeshEntity() {}
+ };
+
+ /*! \brief Vertex */
+
+ class MDB_Point : public MDB_MeshEntity
+ {
+ public:
+ // SHOULD BE PRIVATE, 2B DONE
+ double X,Y,Z;
+ MDB_VectorE edges;
+
+ virtual int getDim() const {return 0;}
+ virtual int getOrder() const {return 0;}
+ virtual bool isParametric() const { return false; }
+ virtual bool getParams(double * u, double * v) const { return false; }
+
+ inline bool operator < (const MDB_Point & other) const
+ {
+ return iD < other.iD;
+ }
+ inline void del(MDB_Edge *e)
+ {
+ MDB_VectorE::iterator it = edges.begin();
+ MDB_VectorE::iterator ite = edges.end();
+ while(it!=ite){
+ if(*it == e){
+ edges.erase(it);
+ break;
+ }
+ ++it;
+ }
+ }
+ void getTriangles(MDB_ListF &) const;
+ void getTets(MDB_ListT &) const;
+ void getQuads(MDB_ListQ &) const;
+ void getHexes(MDB_ListH &) const;
+
+ //void getHexs (MDB_ListH &) const;
+
+ MDB_Point(int id, double x=0, double y=0, double z=0)
+ : MDB_MeshEntity(id),X(x),Y(y),Z(z)
+ {
+ // edges.reserve(12);
+ }
+ virtual ~MDB_Point() {}
+ };
+
+ /*! \brief Parametric vertex */
+
+ class MDB_PointParam : public MDB_Point
+ {
+ public:
+
+ MDB_PointParam(int id, double x=0, double y=0, double z=0, double u=0, double v=0)
+ : MDB_Point(id,x,y,z),U(u),V(v)
+ {}
+ ~MDB_PointParam() {}
+
+ bool isParametric() const { return true; }
+ bool getParams(double * u, double * v) const { *u=U; *v=V; return true; }
+
+ private:
+
+ double U,V;
+ };
+
+ /*! \brief Straight edge or base class for higher order edges */
+
+ class MDB_Edge: public MDB_MeshEntity
+ {
+ std::vector<MDB_Triangle *> _faces;
+// MDB_VectorF _faces;
+ MDB_VectorQ _quads;
+ public:
+
+ MDB_Point *p1,*p2;
+
+ virtual int getDim() const {return 1;}
+ virtual int getOrder() const {return 1;}
+
+ inline MDB_Triangle* faces(int i) const
+ {
+ if ( _faces.size() == 0 ) return NULL;
+ if ( _faces.size() == 1 && i == 1 ) return NULL;
+ return _faces [i];
+ }
+
+ inline MDB_Quad* quads(int i) const
+ {
+ if ( _quads.size() == 0 ) return NULL;
+ if ( _quads.size() == 1 && i == 1 ) return NULL;
+ return _quads [i];
+ }
+
+ inline double length() const
+ {
+ return sqrt((p1->X-p2->X)*(p1->X-p2->X)+(p1->Y-p2->Y)*(p1->Y-p2->Y)+(p1->Z-p2->Z)*(p1->Z-p2->Z));
+ }
+
+ inline int numfaces() const
+ {
+ return _faces.size();
+ }
+
+ inline int numquads() const
+ {
+ return _quads.size();
+ }
+
+ inline MDB_Point * commonvertex(const MDB_Edge *other) const
+ {
+ if(p1 == other->p1 || p1 == other->p2) return p1;
+ if(p2 == other->p1 || p2 == other->p2) return p2;
+ printf("two edges %d %d -- %d %d without common vertex\n",p1->iD,p2->iD, other->p1->iD, other->p2->iD);
+ throw;
+ }
+
+ inline MDB_Point * othervertex(const MDB_Point *p) const
+ {
+ if(p1 == p) return p2;
+ if(p2 == p) return p1;
+ return 0;
+ }
+
+ inline void addface(MDB_Triangle *f)
+ {
+ _faces.push_back(f);
+ }
+
+ inline void addface(MDB_Quad *q)
+ {
+ _quads.push_back(q);
+ }
+
+ inline MDB_Triangle * otherFace(const MDB_Triangle *f) const
+ {
+ if(numfaces()!=2) return NULL;
+ if(f == _faces[0]) return _faces[1];
+ if(f == _faces[1]) return _faces[0];
+ throw;
+ }
+
+ inline void del( MDB_Triangle *t )
+ {
+ _faces.erase(std::remove_if(_faces.begin(),_faces.end() , std::bind2nd(std::equal_to<MDB_Triangle*>(), t)) ,
+ _faces.end());
+ }
+
+ inline void del( MDB_Quad *t )
+ {
+ _quads.erase(std::remove_if(_quads.begin(),_quads.end() , std::bind2nd(std::equal_to<MDB_Quad*>(), t)) ,
+ _quads.end());
+ }
+
+ inline void oppositeof(MDB_Point * oface[2]) const;
+
+ virtual int getNbHighOrderPoints () const {return 0;}
+ virtual MDB_Point *getHighOrderPoint (int i) {throw;}
+
+ MDB_Edge(MDB_Point *A, MDB_Point *B)
+ : p1(A),p2(B)
+ {
+// _faces.reserve(2);
+// _quads.reserve(1);
+ p1->edges.push_back(this);
+ p2->edges.push_back(this);
+ }
+
+ virtual void swapHONodes() {}
+ virtual int align(MDB_Point* po1,MDB_Point* po2);
+ virtual ~MDB_Edge();
+ };
+
+ /*! \brief 2nd order equidistant Lagrange edge */
+
+ class MDB_EdgeP2: public MDB_Edge
+ {
+ MDB_Point *secondOrderPt;
+ public :
+ virtual int getOrder() const {return 2;}
+ virtual int getNbHighOrderPoints() const {return 1;}
+ virtual MDB_Point *getHighOrderPoint (int i) {assert (i==0);return secondOrderPt;}
+ MDB_EdgeP2(MDB_Point *A, MDB_Point *B, MDB_Point *C)
+ : MDB_Edge ( A, C ), secondOrderPt(B)
+ {
+ }
+ virtual ~MDB_EdgeP2() {delete secondOrderPt;}
+ };
+
+ /*! \brief 3rd order equidistant Lagrange edge */
+
+ class MDB_EdgeP3: public MDB_Edge
+ {
+ MDB_Point *Pt1,*Pt2;//third order points
+ public :
+ virtual int getOrder() const {return 3;}
+ virtual int getNbHighOrderPoints() const {return 2;}
+ virtual MDB_Point *getHighOrderPoint (int i) {
+ switch (i){
+ case 0:
+ return Pt1;
+ case 1:
+ return Pt2;
+ default:
+ std::cout << "Point " << i << "not defined for third order edges\n"; throw;
+ }
+ }
+ MDB_EdgeP3(MDB_Point *A, MDB_Point *B1, MDB_Point *B2, MDB_Point *C)
+ : MDB_Edge ( A, C ), Pt1(B1), Pt2(B2)
+ {
+ }
+ virtual ~MDB_EdgeP3() {delete Pt1;delete Pt2;}
+
+ virtual void swapHONodes() {
+
+ MDB_Point* tmp = Pt2;
+ Pt2 = Pt1;
+ Pt1 = tmp;
+ }
+ };
+
+ /*! \brief 4th order equidistant Lagrange edge */
+
+ class MDB_EdgeP4: public MDB_Edge
+ {
+ MDB_Point *Pt1,*Pt2,*Pt3;//fourth order points
+ public :
+ virtual int getOrder() const {return 4;}
+ virtual int getNbHighOrderPoints() const {return 3;}
+ virtual MDB_Point *getHighOrderPoint (int i) {
+ switch (i){
+ case 0:
+ return Pt1;
+ case 1:
+ return Pt2;
+ case 2:
+ return Pt3;
+ default:
+ std::cout << "Point " << i << "not defined for fourth order edges\n"; throw;
+ }
+ }
+ MDB_EdgeP4(MDB_Point *A, MDB_Point *B1, MDB_Point *B2, MDB_Point *B3, MDB_Point *C)
+ : MDB_Edge ( A, C ), Pt1(B1), Pt2(B2), Pt3(B3)
+ {
+ }
+ virtual ~MDB_EdgeP4() {delete Pt1;delete Pt2;delete Pt3;}
+
+ protected:
+
+ virtual void swapHONodes()
+ {
+ MDB_Point* tmp = Pt1;
+ Pt1 = Pt3;
+ Pt3 = tmp;
+ }
+ };
+
+ /*! \brief 5th order equidistant Lagrange edge */
+
+ class MDB_EdgeP5: public MDB_Edge
+ {
+ MDB_Point *Pt1,*Pt2,*Pt3, *Pt4;//fifth order points
+ public :
+ virtual int getOrder() const {return 5;}
+ virtual int getNbHighOrderPoints() const {return 4;}
+ virtual MDB_Point *getHighOrderPoint (int i) {
+ switch (i){
+ case 0:
+ return Pt1;
+ case 1:
+ return Pt2;
+ case 2:
+ return Pt3;
+ case 3:
+ return Pt4;
+ default:
+ std::cout << "Point " << i << "not defined for fifth order edges\n"; throw;
+ }
+ }
+ MDB_EdgeP5(MDB_Point *A, MDB_Point *B1, MDB_Point *B2, MDB_Point *B3, MDB_Point *B4, MDB_Point *C)
+ : MDB_Edge ( A, C ), Pt1(B1), Pt2(B2), Pt3(B3), Pt4(B4)
+ {
+ }
+ virtual ~MDB_EdgeP5() {delete Pt1;delete Pt2;delete Pt3;delete Pt4;}
+
+ protected:
+ virtual void swapHONodes()
+ {
+ MDB_Point* tmp = Pt1;
+ Pt1 = Pt4;
+ Pt4 = tmp;
+
+ tmp = Pt2;
+ Pt2 = Pt3;
+ Pt3 = tmp;
+ }
+ };
+
+ class MDB_Face: public MDB_MeshEntity
+ {
+ protected:
+ std::vector<MDB_Region *> _regions;
+ public :
+ virtual int getNbEdges () const = 0;
+ virtual int getNbNodes () const = 0;
+ virtual MDB_Edge * getEdge (int) const = 0;
+ virtual int getDim() const {return 2;}
+
+ inline MDB_Region* getRegion (int i) const
+ {
+ if (getNbRegions()==0)return 0;
+ if (getNbRegions()==1 && i == 1)return 0;
+ return _regions[i];
+ }
+
+ inline MDB_Region * opposite_region(MDB_Region *t)
+ {
+ if(t == getRegion(0))return getRegion(1);
+ if(t == getRegion(1))return getRegion(0);
+ throw;
+ }
+
+ inline int getNbRegions() const
+ {
+ return (_regions.size());
+ }
+
+ inline void addregion(MDB_Region *t)
+ {
+ _regions.push_back(t);
+ }
+
+ inline void del( MDB_Region *t )
+ {
+ _regions.erase(std::remove_if(_regions.begin(),_regions.end() , std::bind2nd(std::equal_to<MDB_Region*>(), t)) ,
+ _regions.end());
+ }
+
+ inline MDB_Edge * commonedge(const MDB_Face *other) const
+ {
+ for (int i=0;i<getNbEdges ();i++)
+ for (int j=0;j<other->getNbEdges ();j++)
+ {
+ MDB_Edge *e = getEdge(i);
+ if (e == other->getEdge(j)) return e;
+ }
+ throw;
+ }
+
+ inline MDB_Point *getNode(int i) const
+ {
+ if (!i)
+ {
+ int nbe = getNbEdges ();
+ return getEdge(0)->commonvertex(getEdge(nbe-1));
+ }
+ return getEdge(i)->commonvertex(getEdge(i-1));
+ }
+
+ inline void getNodes(MDB_Point **n) const
+ {
+ for (int i=0;i<getNbEdges ();i++)n[i] = getNode(i);
+ }
+
+ MDB_Face() /*: r1(0), r2(0) */{};
+ virtual MDB_Point *getHighOrderPoint (int i) {throw;}
+ virtual int getNbHighOrderPoints() const {return 0;}
+
+ virtual int align(MDB_Point* v0,MDB_Point* v1,MDB_Point* v2,MDB_Point* v3) = 0;
+
+ protected:
+
+ virtual int orientation(MDB_Point* v0,MDB_Point* v1,MDB_Point* v2,MDB_Point* v3) const;
+
+ };
+
+ /*! \brief Straight edged triangle and base class for higher order versions */
+
+ class MDB_Triangle: public MDB_Face
+ {
+ public:
+ MDB_Edge *e1,*e2,*e3;
+
+ virtual int getOrder() const {return 1;}
+ virtual int getNbEdges () const {return 3;}
+ virtual int getNbNodes () const {return 3;}
+ virtual int align(MDB_Point*,MDB_Point*,MDB_Point*,MDB_Point*);
+ virtual MDB_Edge * getEdge (int i) const
+ {
+ switch (i){
+ case 0 : return e1;
+ case 1 : return e2;
+ case 2 : return e3;
+ case 3 : return (MDB_Edge *) NULL;
+ }
+ throw;
+ }
+
+ MDB_Triangle(MDB_Edge *A, MDB_Edge *B, MDB_Edge *C)
+ : e1(A),e2(B),e3(C)
+ {
+ e1->addface(this);
+ e2->addface(this);
+ e3->addface(this);
+ }
+ virtual ~MDB_Triangle() {}
+
+ virtual int getNbHighOrderPoints() const { return 0;}
+
+ };
+
+
+ /*! \brief Generic order equidistant Lagrange triangle with complete interpolation */
+ template <int order>
+ class MDB_CompleteTriangle : public MDB_Triangle {
+
+ public:
+
+ MDB_CompleteTriangle(MDB_Edge *A, MDB_Edge *B, MDB_Edge *C,MDB_Point** P):
+ MDB_Triangle(A,B,C),nbPoints(std::max(0,(order-2)*(order-1)/2)),point(NULL) {
+ point = nbPoints > 0 ? new MDB_Point*[nbPoints] : NULL;
+ for (int i=0;i<nbPoints;i++) point[i] = P[i];
+ }
+
+ ~MDB_CompleteTriangle() {if (point) delete [] point;}
+
+ virtual int getOrder() const {return order;}
+ int getNbHighOrderPoints() const {return nbPoints;}
+ MDB_Point* getHighOrderPoint(int i) {return (i<nbPoints) ? point[i] : NULL;}
+
+ protected:
+
+ int nbPoints;
+ MDB_Point** point;
+
+
+ protected:
+
+
+ virtual int align(MDB_Point* v0,MDB_Point* v1,MDB_Point* v2,MDB_Point* v3) {
+
+
+ if (v3 != NULL) Msg(MDB_FATAL,"Aligning a triangle with a quadrilateral is not allowed\n");
+
+ int rot = MDB_Triangle::align(v0,v1,v2,NULL);
+
+
+ /* we only store the internal points (the higher order nodes on the edges are stored elsewhere)
+ this means that this corresponds to a triangle of order = order - 3 */
+ rotateHOPoints(rot,point,order-3);
+
+ return rot;
+ }
+
+
+ /*! rotate a triangular set of points such that the node on position abs(rot) - 1
+ is migrated to node 0; swap if rot < 0 */
+
+ void rotateHOPoints(int rot,MDB_Point** op,int recursiveOrder) {
+
+ if (recursiveOrder <= 0) return; // only one node needs no further reorientation
+ if (rot == 1) return; // already aligned
+
+ int nbRecursivePoints = (recursiveOrder+1)*(recursiveOrder+2)/2;
+ int nbEdgePoints = (recursiveOrder - 1);
+
+ MDB_Point** np = new MDB_Point*[nbRecursivePoints];
+
+ // first rearrange principal vertices
+
+ memcpy(np,op,nbRecursivePoints*sizeof(MDB_Point*));
+
+ for (int i=0;i<3;i++) np[i] = op[(i + abs(rot) - 1)%3];
+ if (rot < 0) std::swap(np[1],np[2]);
+
+
+ if (recursiveOrder > 1) {
+
+ // then edge nodes
+
+ if (rot > 0) {
+ for (int i=0;i<3;i++) {
+ MDB_Point** nb = np + 3 + i * nbEdgePoints;
+ MDB_Point** ob = op + 3 + (i + rot - 1) % 3 * nbEdgePoints;
+ for (int j=0;j<nbEdgePoints;j++) memcpy(nb,ob,nbEdgePoints * sizeof(MDB_Point*));
+ }
+ }
+
+ if (rot < 0) {
+ for (int i=0;i<3;i++) {
+ MDB_Point** nb = np + 2 + ((abs(rot) - i + 1) % 3 + 1) * nbEdgePoints;
+ MDB_Point** ob = op + 3 + i * nbEdgePoints;
+ for (int j=0;j<nbEdgePoints;j++) *nb-- = *ob++;
+ }
+ }
+
+ rotateHOPoints(rot,np + 3 * (nbEdgePoints+1) , recursiveOrder - 3);
+ }
+
+ memcpy(op,np,nbRecursivePoints * sizeof(MDB_Point*));
+ delete [] np;
+ }
+
+
+ };
+
+ class MDB_Quad : public MDB_Face
+ {
+ public:
+ MDB_Edge *e1,*e2,*e3,*e4;
+
+
+ virtual int getOrder() const {return 2;}
+ virtual int getNbEdges () const {return 4;}
+ virtual int getNbNodes () const {return 4;}
+ virtual int align(MDB_Point*,MDB_Point*,MDB_Point*,MDB_Point*);
+ virtual MDB_Edge * getEdge (int i) const
+ {
+ switch (i){
+ case 0 : return e1;
+ case 1 : return e2;
+ case 2 : return e3;
+ case 3 : return e4;
+ }
+ throw;
+ }
+
+ MDB_Quad(MDB_Edge *A, MDB_Edge *B, MDB_Edge *C, MDB_Edge *D)
+ : e1(A),e2(B),e3(C),e4(D)
+ {
+ e1->addface(this);
+ e2->addface(this);
+ e3->addface(this);
+ e4->addface(this);
+ }
+ virtual ~MDB_Quad() {}
+ };
+
+
+ class MDB_Region: public MDB_MeshEntity
+ {
+ public:
+ virtual MDB_Face *getFace (int i) const = 0;
+ virtual MDB_Edge *getEdge (int i) const = 0;
+ virtual MDB_Point *getVertex (int i) const = 0;
+ virtual MDB_Point *getHighOrderPoint (int i) {throw;}
+ virtual int getNbHighOrderPoints() const {return 0;}
+ virtual void getNodes(MDB_Point **n) const = 0;
+ virtual int getNbFace () const = 0;
+ virtual int getNbEdge () const = 0;
+ virtual int getNbVertex () const = 0;
+ virtual int getFaceDir (int) const = 0;
+ virtual int getFaceOrientation(int) const {throw;}
+
+ };
+
+ class MDB_Hex: public MDB_Region
+ {
+ public:
+ MDB_Quad *f1,*f2,*f3,*f4,*f5,*f6;
+
+ virtual int getOrder() const {return 3;}
+ virtual int getDim() const {return 3;}
+
+ virtual int getNbFace () const {return 6;}
+ virtual int getNbEdge () const {return 12;}
+ virtual int getNbVertex () const{return 8;}
+ virtual MDB_Face *getFace (int i) const
+ {
+ switch(i){
+ case 0:return f1;
+ case 1:return f2;
+ case 2:return f3;
+ case 3:return f4;
+ case 4:return f5;
+ case 5:return f6;
+ }
+ throw;
+ }
+ virtual MDB_Edge *getEdge (int n) const
+ {
+ switch (n){
+ case 0 : return f1->commonedge ( f2 );
+ case 1 : return f1->commonedge ( f3 );
+ case 2 : return f1->commonedge ( f4 );
+ case 3 : return f1->commonedge ( f5 );
+ case 4 : return f2->commonedge ( f5 );
+ case 5 : return f2->commonedge ( f3 );
+ case 6 : return f3->commonedge ( f4 );
+ case 7 : return f4->commonedge ( f5 );
+ case 8 : return f2->commonedge ( f6 );
+ case 9 : return f3->commonedge ( f6 );
+ case 10 : return f4->commonedge ( f6 );
+ case 11 : return f5->commonedge ( f6 );
+ }
+ throw;
+ }
+
+ virtual MDB_Point *getVertex (int n) const /*SL OK*/
+ {
+ MDB_Edge *e1=0,*e2=0;
+ switch (n){
+ case 0 : e1 = getEdge(0);e2 = getEdge(3);break;
+ case 1 : e1 = getEdge(0);e2 = getEdge(1);break;
+ case 2 : e1 = getEdge(1);e2 = getEdge(2);break;
+ case 3 : e1 = getEdge(2);e2 = getEdge(3);break;
+ case 4 : e1 = getEdge(4);e2 = getEdge(8);break;
+ case 5 : e1 = getEdge(5);e2 = getEdge(9);break;
+ case 6 : e1 = getEdge(6);e2 = getEdge(10);break;
+ case 7 : e1 = getEdge(7);e2 = getEdge(11);break;
+ default: throw;
+ }
+
+ return e1->commonvertex ( e2 );
+ }
+
+ virtual int getFaceDir (int n) const;
+
+
+ virtual void getNodes(MDB_Point **n) const
+ {
+ MDB_Point *o[4];
+ f1->getNodes(n);
+ f2->getNodes(o);
+ for(int i=0;i<4;i++) n[i+4]=o[i];
+ }
+
+ MDB_Hex(MDB_Quad *A, MDB_Quad *B, MDB_Quad *C, MDB_Quad *D, MDB_Quad *E, MDB_Quad *F)
+ : f1(A),f2(B),f3(C),f4(D),f5(E),f6(F)
+ {
+ f1->addregion(this);
+ f2->addregion(this);
+ f3->addregion(this);
+ f4->addregion(this);
+ f5->addregion(this);
+ f6->addregion(this);
+ }
+ virtual ~MDB_Hex() {}
+
+ };
+
+ class MDB_Tet: public MDB_Region
+ {
+ public:
+ MDB_Triangle *f1,*f2,*f3,*f4;
+
+ virtual int getOrder() const {return 1;}
+ virtual int getDim() const {return 3;}
+
+ virtual int getNbFace () const {return 4;}
+ virtual int getNbEdge () const {return 6;}
+ virtual int getNbVertex () const{return 4;}
+ virtual MDB_Face *getFace (int i) const
+ {
+ switch(i){
+ case 0:return f1;
+ case 1:return f2;
+ case 2:return f3;
+ case 3:return f4;
+ // NP default NULL added to avoid call to throw
+ // in classify_unclassified_entities
+ default: return (MDB_Face *) NULL;
+ }
+ throw;
+ }
+ virtual MDB_Edge *getEdge (int n) const
+ {
+ switch (n){
+ case 0 : return f1->commonedge ( f2 );
+ case 1 : return f1->commonedge ( f3 );
+ case 2 : return f1->commonedge ( f4 );
+ case 3 : return f2->commonedge ( f4 );
+ case 4 : return f2->commonedge ( f3 );
+ case 5 : return f3->commonedge ( f4 );
+ }
+ throw;
+ }
+
+ virtual MDB_Point *getVertex (int n) const
+ {
+ MDB_Edge *e1=0,*e2=0;
+ switch (n){
+ case 0 : e1 = getEdge(0);e2 = getEdge(2);break;
+ case 1 : e1 = getEdge(0);e2 = getEdge(1);break;
+ case 2 : e1 = getEdge(1);e2 = getEdge(2);break;
+ case 3 : e1 = getEdge(3);e2 = getEdge(5);break;
+ default: throw;
+ }
+ return e1->commonvertex ( e2 );
+ }
+
+ // return 1 if the face direction points to outside of the tet
+ // return 0 inside
+ virtual int getFaceDir (int n) const;
+ // return number of times we need to rotate the element to make
+ // the principal node coincide with that of the tetrahedron (before normal inversion)
+ virtual int getFaceOrientation (int n) const;
+
+ virtual void getNodes(MDB_Point **n) const
+ {
+ MDB_Point *o[3];
+ f1->getNodes(n);
+ f2->getNodes(o);
+ n[3] = 0; //for stupid gcc warning
+ if(o[0] != n[0] && o[0] != n[1] &&o[0] != n[2])n[3] = o[0];
+ if(o[1] != n[0] && o[1] != n[1] &&o[1] != n[2])n[3] = o[1];
+ if(o[2] != n[0] && o[2] != n[1] &&o[2] != n[2])n[3] = o[2];
+ }
+
+ MDB_Tet(MDB_Triangle *A, MDB_Triangle *B, MDB_Triangle *C, MDB_Triangle *D)
+ : f1(A),f2(B),f3(C),f4(D)
+ {
+ f1->addregion(this);
+ f2->addregion(this);
+ f3->addregion(this);
+ f4->addregion(this);
+ }
+ virtual ~MDB_Tet() {}
+
+ protected:
+
+ static int face_vtx[4][3];
+
+ };
+
+ // 2 be done
+ class MDB_Prism: public MDB_Region
+ {
+ public:
+ MDB_Triangle *f1,*f2;
+ MDB_Quad *f3,*f4,*f5;
+
+ virtual int getOrder() const {return 2;}
+ virtual int getDim() const {return 3;} /*SL OK*/
+
+ virtual int getNbFace () const {return 5;} /*SL OK*/
+ virtual int getNbEdge () const {return 9;} /*SL OK*/
+ virtual int getNbVertex () const{return 6;} /*SL OK*/
+ virtual MDB_Face *getFace (int i) const /*SL OK*/
+ {
+ switch(i){
+ case 0:return f1;
+ case 1:return f2;
+ case 2:return f3;
+ case 3:return f4;
+ case 4:return f5;
+ case 5:return (MDB_Face *) NULL;
+ }
+ throw;
+ }
+ virtual MDB_Edge *getEdge (int n) const /*SL OK*/
+ {
+ switch (n){
+ case 0 : return f1->commonedge ( f3 );
+ case 1 : return f1->commonedge ( f5 );
+ case 2 : return f1->commonedge ( f4 );
+ case 3 : return f2->commonedge ( f3 );
+ case 4 : return f2->commonedge ( f5 );
+ case 5 : return f2->commonedge ( f4 );
+ case 6 : return f3->commonedge ( f5 );
+ case 7 : return f3->commonedge ( f4 );
+ case 8 : return f4->commonedge ( f5 );
+ }
+ throw;
+ }
+
+ virtual MDB_Point *getVertex (int n) const /*SL OK*/
+ {
+ MDB_Edge *e1=0,*e2=0;
+ switch (n){
+ case 0 : e1 = getEdge(0);e2 = getEdge(1);break;
+ case 1 : e1 = getEdge(0);e2 = getEdge(2);break;
+ case 2 : e1 = getEdge(1);e2 = getEdge(2);break;
+ case 3 : e1 = getEdge(4);e2 = getEdge(3);break;
+ case 4 : e1 = getEdge(3);e2 = getEdge(5);break;
+ case 5 : e1 = getEdge(4);e2 = getEdge(5);break;
+ default: throw;
+ }
+ return e1->commonvertex ( e2 );
+ }
+
+ virtual int getFaceDir (int n) const
+ { std::cerr << "not yet implemented\n"; abort(); return 0;}
+
+
+ virtual void getNodes(MDB_Point **n) const
+ {
+ std::cerr << "not yet implemented\n"; abort();
+ /* MDB_Point *o[3];
+ f1->getNodes(n);
+ f2->getNodes(o);
+ n[3] = 0; //for stupid gcc warning
+ if(o[0] != n[0] && o[0] != n[1] &&o[0] != n[2])n[3] = o[0];
+ if(o[1] != n[0] && o[1] != n[1] &&o[1] != n[2])n[3] = o[1];
+ if(o[2] != n[0] && o[2] != n[1] &&o[2] != n[2])n[3] = o[2];*/
+ }
+
+ MDB_Prism(MDB_Triangle *A, MDB_Triangle *B, MDB_Quad *C,
+ MDB_Quad *D, MDB_Quad *E) /*SL OK*/
+ : f1(A),f2(B),f3(C),f4(D),f5(E)
+ {
+ f1->addregion(this);
+ f2->addregion(this);
+ f3->addregion(this);
+ f4->addregion(this);
+ f5->addregion(this);
+ }
+ virtual ~MDB_Prism() {} /*SL OK*/
+ };
+
+ /*! \brief Generic order equidistant Lagrange tetrahedron */
+
+ template <int order>
+ class MDB_CompleteTet : public MDB_Tet {
+
+ public:
+
+ MDB_CompleteTet(MDB_Triangle *A, MDB_Triangle *B,
+ MDB_Triangle *C, MDB_Triangle *D,MDB_Point** pp):
+
+ MDB_Tet(A,B,C,D),nbPoints(std::max(0,(order-3)*(order-2)*(order-1)/6))
+ {
+ point = nbPoints ? new MDB_Point*[nbPoints] : NULL;
+ for (size_t i=0;i<(unsigned int)nbPoints;i++) point[i] = pp[i];
+ }
+
+ int getNbHighOrderPoints() const {return nbPoints;}
+ MDB_Point* getHighOrderPoint(int i) {return (i<nbPoints) ? point[i] : NULL;}
+ int getOrder() {return order;}
+
+
+ protected:
+ int nbPoints;
+ MDB_Point** point;
+ };
+
+ class PointLessThan
+ {
+ public:
+ bool operator()(const MDB_Point* ent1, const MDB_Point* ent2) const
+ {
+ return *ent1 < *ent2;
+ }
+ };
+
+
+ class MDB_Mesh : public MDB_MiniMesh
+ {
+ // no copies allowed
+ MDB_Mesh(const MDB_Mesh &other);
+
+ private:
+ bool parametric;
+
+ public:
+
+ // this is an add on to the classical interface
+ // one can build lists of geometrical "features" that
+ // encompass more than one geometrical entities
+ std::multimap<int, pGEntity > geomFeatures_Tags;
+ // sometimes, features have names
+ std::map<std::string, int > geomFeatures_Names;
+
+ bool shrinked;
+
+ // constructor of an empty mesh
+ MDB_Mesh(int _MAXX = 1);
+ // the destructor
+ ~MDB_Mesh();
+ // initialize first vertex id and increments
+ void initializeIdData();
+ // load the mini mesh into the binary file f, mesh is still empty
+ bool isParametric() const { return parametric; }
+ void load ( FILE *f );
+ // expand the mini mesh in the bi directional data structure
+ // then, delete the mini mesh. Mesh adaptation can be performed
+ // only when the mesh is expanded
+ void expand ( );
+ // shrink the mini mesh from the bi-directional data structure
+ // then, delete the bi-directional data structure. The mesh
+ // is "idle", i.e. is shrinked in memory, allowing the solver
+ // to take the whole memory space
+ void shrink ( );
+ bool isShrinked() const { return shrinked; };
+ // flush the mini mesh
+ void flush ( FILE *f ) const;
+ // data about vertex ids (globally unique ids in parallel)
+ int maxId; // max vertex id
+ int idIncrement; // id increment size (=nbProcs)
+ // the geometric model on which the mesh entities are classified
+ pGModel model;
+ // bounding boxes
+ double Min[3],Max[3],LC;
+ // the datas
+ int nbPoints, nbEdgePoints, nbEdges, nbTriangles, nbQuads, nbTets, nbHexes, nbPrisms;
+ std::set<MDB_Point*,PointLessThan> points;
+ MDB_ListE edges;
+ MDB_ListF triangles;
+ MDB_ListQ quads;
+ MDB_ListT tets;
+ MDB_ListH hexes;
+ MDB_ListPr prisms;
+ // Points operations
+ MDB_Point * add_point(int num , double x, double y,double z, pGEntity=0);
+ MDB_PointParam * add_pointParam(int num , double x, double y, double z,
+ double u, double v, pGEntity=0);
+ void del_point(MDB_Point *p);
+ MDB_Point *find_point(int num);
+ void deleteTheHighOrderPoint(std::set < MDB_Point *, PointLessThan >::iterator it);
+ // Edges operations
+ /*! straight edge from point id's */
+ MDB_Edge * add_edge(int p1, int p2, pGEntity=0);
+ // MDB_Edge * add_edge(int p1, int p2, int p3, pGEntity=0);
+ /*! straight edge from points */
+ MDB_Edge * add_edge(MDB_Point *p1, MDB_Point *p2, pGEntity=0);
+ // MDB_Edge * add_edge(MDB_Point *p1, MDB_Point *p2, MDB_Point *p3, pGEntity=0);
+ /*! straight/curved edge from point id's */
+ MDB_Edge * add_edge(int numberOfPoints, pGEntity pg, int p1, ...);
+ /*! straight/curved edge from points */
+ MDB_Edge * add_edge(int numberOfPoints, pGEntity pg, MDB_Point *firstPoint, ...);
+ /*! straight/curved edge from points (gmsh order) */
+ MDB_Edge * add_edge(MDB_Point* p1,MDB_Point*p2,pGEntity,int o,MDB_Point** iP);
+ void del_edge(MDB_Edge *e);
+ MDB_Edge *find_edge(int p1, int p2);
+ MDB_Edge *find_edge(MDB_Point *p1, MDB_Point *p2)const;
+ MDB_Edge *find_edge(MDB_Point *p1, MDB_Point *p2, MDB_Triangle *t)const;
+ MDB_Edge *find_clone_edge(MDB_Edge *edge)const;
+ // Faces operations
+ void del_face(MDB_Face *f);
+ // Triangles operations
+ /*! straight triangle from vertex id's */
+ MDB_Triangle *add_triangle(int p1, int p2, int p3, pGEntity=0);
+ /* curvilinear triangle */
+ // MDB_Triangle *add_triangle(int p1, int p2, int p3, int p4, int p5, int p6, pGEntity=0);
+ /*! straight/serendipity triangle from edges */
+ MDB_Triangle *add_triangle(MDB_Edge *e1,MDB_Edge *e2,MDB_Edge *e3, pGEntity=0);
+ /*! straight/complete triangle triangle from edges and internal points */
+ MDB_Triangle *add_triangle(MDB_Edge *e1,MDB_Edge *e2,MDB_Edge *e3, pGEntity,int order,
+ bool serendip=true,MDB_Point** iP=NULL);
+ /*! straight/complete triangle triangle from point id's*/
+ //MDB_Triangle *add_triangle(pGEntity,int order,bool serendip=true,int* pp=NULL);
+ /*! straight/serendipity triangle from point id's */
+ MDB_Triangle *add_triangle(int order, bool complete, pGEntity pg, int p1, int p2, ...);
+ void del_triangle(MDB_Triangle *t);
+ MDB_Triangle *find_triangle(MDB_Edge *e1,MDB_Edge *e2,MDB_Edge *e3);
+ // Quad operations
+ MDB_Quad *add_quad(int p1, int p2, int p3, int p4, pGEntity=0);
+ MDB_Quad *add_quad(MDB_Edge *e1,MDB_Edge *e2,MDB_Edge *e3,MDB_Edge *e4, pGEntity=0);
+ void del_quad(MDB_Quad *q);
+ MDB_Quad *find_quad(MDB_Edge *e1,MDB_Edge *e2,MDB_Edge *e3,MDB_Edge *e4);
+ // Tets operations
+ /*! straight tet from point id's */
+ MDB_Tet *add_tet(int p1, int p2, int p3,int p4, pGEntity=0);
+ /*! straight/serendipity/complete triangle from point id's (in gmsh order) */
+ MDB_Tet *add_tet(pGEntity,int order,bool serendip,int* points);
+ /*! straight tet from points */
+ MDB_Tet *add_tet(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3, MDB_Point *p4, pGEntity=0);
+ /*! straight/serendipity tetrahedron from faces */
+ MDB_Tet *add_tet(MDB_Triangle *,MDB_Triangle *,MDB_Triangle *,MDB_Triangle *, pGEntity=0);
+ /*! straight/complete tetrahedron from faces and points */
+ MDB_Tet *add_tet(MDB_Triangle *,MDB_Triangle *,MDB_Triangle *,MDB_Triangle *, pGEntity,
+ int order,bool serendip=true,MDB_Point** iP=NULL);
+
+ /*! straight/complete tet from faces and internal point id's */
+ MDB_Tet *find_tet(MDB_Triangle * t1, MDB_Triangle * t2, MDB_Triangle * t3, MDB_Triangle * t4);
+ void del_tet(MDB_Tet *);
+ // Hexes operations
+ MDB_Hex *add_hex(int p1, int p2, int p3,int p4,int p5, int p6, int p7, int p8, pGEntity=0);
+ MDB_Hex *add_hex(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3, MDB_Point *p4,
+ MDB_Point *p5, MDB_Point *p6,MDB_Point *p7, MDB_Point *p8, pGEntity=0);
+ MDB_Hex *add_hex(MDB_Quad *,MDB_Quad *,MDB_Quad *,MDB_Quad *,MDB_Quad *,MDB_Quad *, pGEntity=0);
+ MDB_Hex *find_hex(MDB_Quad *,MDB_Quad *,MDB_Quad *,MDB_Quad *,MDB_Quad *,MDB_Quad *);
+ void del_hex(MDB_Hex *);
+ // Prisms operations
+ MDB_Prism *add_prism(int p1, int p2, int p3,int p4,int p5, int p6, pGEntity=0);
+ MDB_Prism *add_prism(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3,
+ MDB_Point *p4, MDB_Point *p5, MDB_Point *p6, pGEntity=0);
+ MDB_Prism *add_prism(MDB_Triangle *,MDB_Triangle *,MDB_Quad *,MDB_Quad *,MDB_Quad *, pGEntity=0);
+ MDB_Prism *find_prism(MDB_Triangle *,MDB_Triangle *,MDB_Quad *,MDB_Quad *,MDB_Quad *);
+ void del_prism(MDB_Prism *);
+ // classify entities that are not classified
+ void classify_unclassified_entities();
+ void destroyStandAloneEntities();
+
+// #ifdef PARALLEL
+// void bdryLinkRemotePoint();
+// #endif
+
+ // check if there is no identical geometrical tags between regions and faces
+ /* void checkGeomTagsCoherence () const; */
+ };
+
+ typedef std::set<MDB_Point*,PointLessThan> MDB_SetV;
+
+ class MDB_RIter : public MDB_Iter < MDB_ListR , MDB_Region , pGEntity>
+ {
+ public:
+ MDB_RIter (MDB_ListR*_l): MDB_Iter< MDB_ListR , MDB_Region , pGEntity > (_l){}
+ MDB_RIter (MDB_ListR*_l,pGEntity _g): MDB_Iter< MDB_ListR , MDB_Region , pGEntity > (_l,_g){}
+ };
+ class MDB_TIter : public MDB_Iter < MDB_ListT , MDB_Tet , pGEntity>
+ {
+ public:
+ MDB_TIter (MDB_ListT*_l): MDB_Iter< MDB_ListT , MDB_Tet , pGEntity > (_l){}
+ MDB_TIter (MDB_ListT*_l,pGEntity _g): MDB_Iter< MDB_ListT , MDB_Tet , pGEntity > (_l,_g){}
+ };
+ class MDB_HIter : public MDB_Iter < MDB_ListH , MDB_Hex , pGEntity>
+ {
+ public:
+ MDB_HIter (MDB_ListH*_l): MDB_Iter< MDB_ListH , MDB_Hex , pGEntity > (_l){}
+ MDB_HIter (MDB_ListH*_l,pGEntity _g): MDB_Iter< MDB_ListH , MDB_Hex , pGEntity > (_l,_g){}
+ };
+ class MDB_PIter : public MDB_Iter < MDB_ListPr , MDB_Prism , pGEntity>
+ {
+ public:
+ MDB_PIter (MDB_ListPr*_l): MDB_Iter< MDB_ListPr , MDB_Prism , pGEntity > (_l){}
+ MDB_PIter (MDB_ListPr*_l,pGEntity _g): MDB_Iter< MDB_ListPr , MDB_Prism , pGEntity > (_l,_g){}
+ };
+ class MDB_EIter : public MDB_Iter < MDB_ListE , MDB_Edge , pGEntity >
+ {
+ public:
+ MDB_EIter (MDB_ListE*_l): MDB_Iter< MDB_ListE , MDB_Edge, pGEntity > (_l){}
+ MDB_EIter (MDB_ListE*_l,pGEntity _g,int _c): MDB_Iter< MDB_ListE , MDB_Edge, pGEntity > (_l,_g,_c){}
+ };
+ class MDB_FIter : public MDB_Iter < MDB_ListF , MDB_Triangle , pGEntity >
+ {
+ public:
+ MDB_FIter (MDB_ListF*_l): MDB_Iter <MDB_ListF , MDB_Triangle ,pGEntity> (_l){}
+ MDB_FIter (MDB_ListF*_l,pGEntity _g,int _c): MDB_Iter <MDB_ListF , MDB_Triangle ,pGEntity> (_l,_g,_c){}
+ };
+ class MDB_QIter : public MDB_Iter < MDB_ListQ , MDB_Quad , pGEntity>
+ {
+ public:
+ MDB_QIter (MDB_ListQ*_l): MDB_Iter <MDB_ListQ , MDB_Quad , pGEntity> (_l){}
+ MDB_QIter (MDB_ListQ*_l,pGEntity _g,int _c): MDB_Iter <MDB_ListQ , MDB_Quad ,pGEntity> (_l,_g,_c){}
+ };
+ class MDB_VIter : public MDB_Iter < MDB_SetV , MDB_Point ,pGEntity >
+ {
+ public:
+ MDB_VIter (MDB_SetV *_l): MDB_Iter < MDB_SetV , MDB_Point , pGEntity > (_l){}
+ MDB_VIter (MDB_SetV *_l,pGEntity _g,int _c): MDB_Iter < MDB_SetV , MDB_Point , pGEntity > (_l,_g,_c){}
+ };
+
+ class MDB_FaceIter
+ {
+ public:
+ MDB_FIter itf;
+ MDB_QIter itq;
+
+ MDB_Triangle *t;
+ MDB_Quad *q;
+ public:
+ MDB_FaceIter ( MDB_ListF* _t , MDB_ListQ* _q):itf(_t),itq(_q),t(0),q(0){}
+ MDB_FaceIter ( MDB_ListF* _t , MDB_ListQ* _q, pGEntity _g,int _c):itf(_t,_g,_c),itq(_q,_g,_c),t(0),q(0){}
+ inline MDB_Face * next ()
+ {
+ t = itf.next();
+ if (t) return (MDB_Face*)t;
+ q = itq.next();
+ return (MDB_Face*)q;
+ }
+ inline void reset()
+ {
+ itf.reset();
+ itq.reset();
+ }
+ inline void cleanup()
+ {
+ itf.cleanup();
+ itq.cleanup();
+ }
+
+ };
+
+ class MDB_RegionIter
+ {
+ public:
+ MDB_TIter itt;
+ MDB_HIter ith;
+ MDB_PIter itp;
+
+ MDB_Tet *t;
+ MDB_Hex *h;
+ MDB_Prism *p;
+ public:
+ MDB_RegionIter ( MDB_ListT* _t , MDB_ListH* _h, MDB_ListPr* _p ):itt(_t),ith(_h),itp(_p),t(0),h(0),p(0){}
+ MDB_RegionIter ( MDB_ListT* _t , MDB_ListH* _h, MDB_ListPr* _p, pGEntity _g):itt(_t,_g),ith(_h,_g),itp(_p,_g),t(0),h(0),p(0){}
+ inline MDB_Region * next ()
+ {
+ t = itt.next();
+ if (t) return (MDB_Region*)t;
+ h = ith.next();
+ if (h) return (MDB_Region*)h;
+ p = itp.next();
+ return (MDB_Region*)p;
+ }
+ inline void reset()
+ {
+ itt.reset();
+ ith.reset();
+ itp.reset();
+ }
+ inline void cleanup()
+ {
+ itt.cleanup();
+ ith.cleanup();
+ itp.cleanup();
+ }
+
+ };
+
+} // End of namespace MAd
+
+#endif
+
+
+
+
+
+
diff --git a/Mesh/MeshDataBaseAttachable.h b/Mesh/MeshDataBaseAttachable.h
new file mode 100644
index 0000000..10271a8
--- /dev/null
+++ b/Mesh/MeshDataBaseAttachable.h
@@ -0,0 +1,176 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MATTACHABLEDATACONTAINER_H_
+#define _MATTACHABLEDATACONTAINER_H_
+
+#include <algorithm>
+#include <vector>
+
+namespace MAd {
+
+ /**
+ Base class for attachable data's
+ */
+ class mAttachableData
+ {
+ public :
+ virtual ~mAttachableData(){};
+ };
+
+ class mAttachableVoid : public mAttachableData
+ {
+ public :
+ ~mAttachableVoid(){}
+ void *veryNastyPointer;
+ };
+
+ /**
+ Int as attachable data
+ */
+ class mAttachableInt : public mAttachableData
+ {
+ public :
+ ~mAttachableInt(){}
+ int i;
+ };
+
+ /**
+ Double as attachable data
+ */
+ class mAttachableDouble : public mAttachableData
+ {
+ public :
+ ~mAttachableDouble(){}
+ double d;
+ };
+
+ /**
+ Container for attachable data's Internal, mEntity and mMesh provides interfaces.
+ */
+
+ class mAttachableDataContainer
+ {
+ public :
+ typedef std::pair <unsigned int, mAttachableData *> info;
+ typedef std::vector< info > container;
+ typedef container::iterator iter_attachdata;
+ typedef container::const_iterator citer_attachdata;
+ private :
+ container *tab;
+ public:
+ mAttachableDataContainer():tab(0){}
+ ~mAttachableDataContainer();
+ inline void attachData(unsigned int, mAttachableData *);
+ inline void deleteData(unsigned int);
+ inline mAttachableData * getData(unsigned int) ;
+ inline citer_attachdata begin_attachdata() const {return tab->begin();};
+ inline citer_attachdata end_attachdata() const {return tab->end();};
+ /// specific data types for int
+ inline void attachInt(unsigned int, int);
+ /// specific data types for int
+ inline int getAttachedInt(unsigned int);
+ /// specific data types for double
+ inline void attachDouble(unsigned int, double);
+ /// specific data types for double
+ inline double getAttachedDouble(unsigned int);
+ };
+
+ class equalInfoPred
+ {
+ const unsigned int c;
+ public:
+ equalInfoPred ( unsigned int i ) :c(i) {}
+ inline bool operator () (const mAttachableDataContainer::info &i) const
+ {
+ return (i.first == c);
+ }
+ };
+
+ inline mAttachableDataContainer::~mAttachableDataContainer()
+ {
+ if(!tab)return;
+ citer_attachdata it = begin_attachdata();
+ citer_attachdata itEnd = end_attachdata();
+ for(;it!=itEnd;++it)
+ {
+ mAttachableData *a = (*it).second;
+ delete a;
+ }
+ delete tab;
+ }
+
+ inline mAttachableData *mAttachableDataContainer::getData(unsigned int c)
+ {
+ if (!tab)return 0;
+ iter_attachdata it = std::find_if (tab->begin(),tab->end(),equalInfoPred(c));
+ if(it == tab->end())return 0;
+ return (*it).second;
+ }
+
+ inline void mAttachableDataContainer::attachData(unsigned int c, mAttachableData *v)
+ {
+ if (!tab) tab = new container;
+ tab->push_back(mAttachableDataContainer::info(c,v));
+ }
+
+ inline void mAttachableDataContainer::deleteData(unsigned int c)
+ {
+ mAttachableData *data = getData (c);
+ if (data)
+ {
+ delete data;
+ tab->erase ( std::remove_if (tab->begin(),tab->end(),equalInfoPred(c)) ,
+ tab->end () );
+ }
+ }
+
+ inline void mAttachableDataContainer::attachInt(unsigned int c, int i)
+ {
+ mAttachableInt *ai = (mAttachableInt *)getData(c);
+ if(!ai)
+ {
+ ai = new mAttachableInt;
+ attachData(c,ai);
+ }
+ ai->i = i;
+ }
+
+ inline int mAttachableDataContainer::getAttachedInt (unsigned int c)
+ {
+ mAttachableInt *ai = (mAttachableInt *)getData(c);
+ if(!ai)return 0;
+ return ai->i;
+ }
+
+ inline void mAttachableDataContainer::attachDouble(unsigned int c, double d)
+ {
+ mAttachableDouble *ai = (mAttachableDouble *)getData(c);
+ if(!ai)
+ {
+ ai = new mAttachableDouble;
+ attachData(c,ai);
+ }
+ ai->d = d;
+ }
+
+ inline double mAttachableDataContainer::getAttachedDouble (unsigned int c)
+ {
+ mAttachableDouble *ai = (mAttachableDouble *)getData(c);
+ if(!ai)return 0;
+ return ai->d;
+ }
+
+} // End of namespace MAd
+
+#endif
diff --git a/Mesh/MeshDataBaseComm.cc b/Mesh/MeshDataBaseComm.cc
new file mode 100644
index 0000000..5cce89c
--- /dev/null
+++ b/Mesh/MeshDataBaseComm.cc
@@ -0,0 +1,899 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MSops.h"
+#include "MeshDataBase.h"
+#ifdef PARALLEL
+#include "MeshDataBaseParallelInterface.h"
+#endif
+// #include "NullModel.h"
+#include "MeshDataBaseComm.h"
+
+
+#include "assert.h"
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+// for memcpy (gcc 4.3)
+#include <cstring>
+
+namespace MAd {
+
+ void exchangeDataOnVertices (pMesh m, MDB_DataExchanger &de )
+ {
+
+ int mysize = 1;
+ int myrank = 0;
+
+#ifdef PARALLEL
+ MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+#endif
+
+ int *sendcounts = new int[mysize];
+ for(int i=0;i<mysize;i++)sendcounts[i]=0;
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ VIter vit = M_vertexIter(m);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+
+ if(isInterface) {
+ const std::vector<std::pair<int , pVertex> > *recup =
+ (const std::vector<std::pair<int , pVertex> > *) temp_ptr;
+
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+
+
+
+ int sizebuf;
+ int iProc = (*recup)[j].first;
+ pVertex remote = (*recup)[j].second;
+
+ void *buf = de.sendData ((pEntity) pv, iProc, sizebuf );
+ if (buf)
+ {
+ if (iProc == myrank)
+ {
+ de.receiveData ((pEntity) remote, myrank,buf);
+ free(buf);
+ }
+ else
+ {
+#ifdef PARALLEL
+ char *msg = (char*)AP_alloc(iProc,de.tag(),sizeof(pEntity*)+sizebuf);
+ memcpy(msg,&remote,sizeof(pEntity*));
+ memcpy(&msg[sizeof(pEntity*)],buf,sizebuf);
+ free(buf);
+ AP_send(msg);
+ sendcounts[iProc] ++;
+#else
+ throw;
+#endif
+ }
+ }
+ }
+ }
+ }
+ VIter_delete(vit);
+#ifdef PARALLEL
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ int message=0;
+ int count;
+
+ while (!AP_recv_count(&count) || message<count)
+ {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int rc;
+ rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if (rc)
+ {
+ message++;
+ char * tmp = (char *) msg;
+ pEntity * pv = (pEntity *) &tmp[0];
+#ifdef DEBUG
+ assert(*pv);
+#endif
+ de.receiveData (*pv,from, &tmp[sizeof(pEntity*)]);
+ AP_free(msg);
+ }
+ }
+
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+ delete [] sendcounts;
+ }
+
+ // ----------------------------------------------------------------------------
+
+ void exchangeDataOnEdges (pMesh m, MDB_DataExchanger &de )
+ {
+ int mysize = 1;
+ int myrank = 0;
+
+#ifdef PARALLEL
+ MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+#endif
+
+ int *sendcounts = new int[mysize];
+ for(int i=0;i<mysize;i++)sendcounts[i]=0;
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ EIter eit = M_edgeIter(m);
+ pEdge pe;
+ while (pe = EIter_next(eit)) {
+
+ void* tmpptr = NULL;
+ if (EN_getDataPtr(pe,tagData,&tmpptr)) {
+
+ std::multimap<int,pEdge>* connections = (std::multimap<int,pEdge>*) tmpptr;
+ std::multimap<int,pEdge>::iterator cIter = connections->begin();
+
+
+ for (;cIter!=connections->end();++cIter) {
+
+ int iProc = cIter->first;
+ pEdge remote = cIter->second;
+ int sizebuf = 0;
+ void *buf = de.sendData ((pEntity) pe, iProc, sizebuf );
+ size_t sendSize = sizebuf + sizeof(pEntity*);
+
+ if (iProc == myrank) de.receiveData ((pEntity) cIter->second,myrank,buf);
+ else {
+#ifdef PARALLEL
+ char *msg = (char*)AP_alloc(iProc,de.tag(),sendSize);
+ memcpy(&msg[0],&remote,sizeof(pEntity));
+ memcpy(&msg[sizeof(pEntity)],buf,sizebuf);
+ AP_send(msg);
+ sendcounts[iProc] ++;
+#else
+ throw;
+#endif
+ }
+ free(buf);
+ }
+ }
+ }
+
+ EIter_delete(eit);
+
+
+#ifdef PARALLEL
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ int message=0;
+ int count;
+
+ while (!AP_recv_count(&count) || message<count)
+ {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int rc;
+ rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if (rc)
+ {
+ message++;
+ char * tmp = (char *) msg;
+ pEdge pe;
+ memcpy(&pe,&tmp[0],sizeof(pEntity));
+ de.receiveData ((pEntity) pe,from, &tmp[sizeof(pEntity*)]);
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+ delete [] sendcounts;
+ }
+
+ // ----------------------------------------------------------------------------
+
+ void exchangeDataOnFaces (pMesh m, MDB_DataExchanger &de )
+ {
+
+ int mysize = 1;
+ int myrank = 0;
+
+#ifdef PARALLEL
+ MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+#endif
+
+ int *sendcounts = new int[mysize];
+ for(int i=0;i<mysize;i++)sendcounts[i]=0;
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ FIter fit = M_faceIter(m);
+ pFace pf;
+ while (pf = FIter_next(fit)) {
+
+ void* tmpptr = NULL;
+ if (EN_getDataPtr((pEntity) pf,tagData,&tmpptr)) {
+
+ std::multimap<int,pFace>* connections = (std::multimap<int,pFace>*) tmpptr;
+ std::multimap<int,pFace>::iterator cIter = connections->begin();
+
+
+ for (;cIter!=connections->end();++cIter) {
+
+ int iProc = cIter->first;
+ pFace remote = cIter->second;
+ int sizebuf = 0;
+ void *buf = de.sendData ((pEntity) pf, iProc, sizebuf );
+ size_t sendSize = sizebuf + sizeof(pEntity*);
+
+ if (iProc == myrank) de.receiveData ((pEntity) cIter->second,myrank,buf);
+ else {
+
+#ifdef PARALLEL
+ char *msg = (char*)AP_alloc(iProc,de.tag(),sendSize);
+ memcpy(&msg[0],&remote,sizeof(pEntity));
+ memcpy(&msg[sizeof(pEntity)],buf,sizebuf);
+ AP_send(msg);
+ sendcounts[iProc] ++;
+#else
+ throw;
+#endif
+ }
+ free(buf);
+ }
+ }
+ }
+ FIter_delete(fit);
+
+#ifdef PARALLEL
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ int message=0;
+ int count;
+
+ while (!AP_recv_count(&count) || message<count)
+ {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int rc;
+ rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if (rc)
+ {
+ message++;
+ char * tmp = (char *) msg;
+ pEdge pe;
+ memcpy(&pe,&tmp[0],sizeof(pEntity));
+ de.receiveData ((pEntity) pe,from, &tmp[sizeof(pEntity*)]);
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+ delete [] sendcounts;
+ }
+
+
+// void exchangeDataOnEdges_old (pMesh m, MDB_DataExchanger &de )
+// {
+
+// int mysize = 1;
+// int myrank = 0;
+// #ifdef PARALLEL
+// MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+// MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+// #endif
+
+// int *sendcounts = new int[mysize];
+// for(int i=0;i<mysize;i++)sendcounts[i]=0;
+
+// pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+// EIter eit = M_edgeIter(m);
+// pEdge pe;
+// while ((pe = EIter_next(eit))) {
+// #ifdef PARALLEL
+// int distProc = -1;
+// std::vector<pVertex> distVt;
+
+// /// E_isInterface should be replaced by correct version or by direct use of the remotePoint
+// if ( E_isInterface(m,pe,&distProc,&distVt) ) {
+
+// // void * tmp_ptr;
+// // if( EN_getDataPtr((pEntity) pe, tagData, &tmp_ptr) ){
+// #endif
+// pVertex p1 = pe->p1;
+// pVertex p2 = pe->p2;
+// assert(p1); assert(p2);
+// void *temp_ptr1,*temp_ptr2;
+// EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+// EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+// const std::vector<std::pair<int , pVertex> > *recup1 =
+// (const std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+// const std::vector<std::pair<int , pVertex> > *recup2 =
+// (const std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+// int size = (*recup1).size();
+// assert(size);
+// int tab[1024];
+// for(int i=0 ; i< size ; i++) tab[i] = (*recup1)[i].first;
+
+// for(unsigned int j=0 ; j<(*recup2).size() ; j++) {
+// int iProc = (*recup2)[j].first;
+// int i;
+// for(i=0 ; i<size ; i++) {
+// if(iProc == tab[i]) break;
+// }
+// if(i < size) {
+// assert(iProc == tab[i]);
+
+// int sizebuf;
+// pVertex remote1 = (*recup1)[i].second;
+// pVertex remote2 = (*recup2)[j].second;
+// void *buf = de.sendData ((pEntity) pe, iProc, sizebuf );
+// if (buf)
+// {
+// if (iProc == myrank)
+// {
+// puts("*****************************pas parallele");
+// char *msg = (char*)malloc(2*sizeof(pEntity)+sizebuf);
+// memcpy(msg,&remote1,sizeof(pEntity));
+// memcpy(&msg[sizeof(pEntity)],&remote2,sizeof(pEntity));
+// memcpy(&msg[2*sizeof(pEntity)],buf,sizebuf);
+// free(buf);
+// MDB_VectorE ve = remote1->edges;
+// MDB_VectorE::iterator it = ve.begin();
+// MDB_VectorE::iterator ite = ve.end();
+// while(it!=ite){
+// if((*it)->p1 == remote1 && (*it)->p2 == remote2)break;
+// else if ((*it)->p2 == remote1 && (*it)->p1 == remote2) break;
+// ++it;
+// }
+// assert(it!=ite);
+// pEdge pe = *it;
+// de.receiveData ((pEntity) pe,
+// myrank,
+// msg);
+// free(msg);
+// }
+// else
+// {
+// #ifdef PARALLEL
+// char *msg = (char*)AP_alloc(iProc,
+// de.tag() ,
+// 2*sizeof(pEntity*)+sizebuf);
+// memcpy(&msg[0],&remote1,sizeof(pEntity));
+// memcpy(&msg[sizeof(pEntity)],&remote2,sizeof(pEntity));
+// memcpy(&msg[2*sizeof(pEntity)],buf,sizebuf);
+// free(buf);
+// AP_send(msg);
+// sendcounts[iProc] ++;
+// #else
+// throw;
+// #endif
+// }
+// }
+// }
+// }
+// #ifdef PARALLEL
+// }
+// #endif
+// }
+// EIter_delete(eit);
+
+// #ifdef PARALLEL
+// AP_check_sends(AP_NOFLAGS);
+// AP_reduce_nsends(sendcounts);
+
+// int message=0;
+// int count;
+
+// while (!AP_recv_count(&count) || message<count)
+// {
+// void *msg;
+// int from;
+// int tag;
+// int size;
+// int rc;
+// rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+// &msg, &size, &from, &tag);
+// if (rc)
+// {
+// message++;
+// char * tmp = (char *) msg;
+// pVertex v1;
+// pVertex v2;
+// memcpy(&v1,&tmp[0],sizeof(pEntity));
+// memcpy(&v2,&tmp[sizeof(pEntity)],sizeof(pEntity));
+
+// MDB_VectorE &ve = v1->edges;
+// MDB_VectorE::iterator it = ve.begin();
+// MDB_VectorE::iterator ite = ve.end();
+// while(it!=ite){
+// if((*it)->p2 == (v2) || (*it)->p1 == (v2))
+// {
+// assert((*it)->p2 == (v1) || (*it)->p1 == (v1));
+// break;
+// }
+// ++it;
+// }
+// // MISTAKE HERE, CECILE, YOU SHOULD VERIFY THAT !!
+// if(it==ite)
+// {
+// // printf("the edge does not exist here...\n");
+// // throw;
+// }
+// else
+// {
+// pEdge pe = *it;
+
+// /*
+// Little test : if edges are reversed on the
+// different sides of the interface then reverse
+// the ones on the smallest processor
+// */
+// if (v1 == pe->p2 && from < myrank)
+// {
+// pe->p1 = v1;
+// pe->p2 = v2;
+// }
+// // ------- END OF TEST ------------------------
+
+
+// de.receiveData ((pEntity) pe,from, &tmp[2*sizeof(pEntity*)]);
+// }
+// AP_free(msg);
+// }
+// }
+// AP_check_sends(AP_WAITALL);
+// MPI_Barrier(MPI_COMM_WORLD);
+// #endif
+// delete [] sendcounts;
+// }
+
+
+ // ---------------------------------------------------------------------
+ /*
+ The parallel faces are supposed to be classified on a geometric entity
+ of dimension 2 with the same tag as the unique volume entity which
+ supports the face on this partition. This is done when a mesh is
+ partitioned with japp.
+ */
+// void exchangeDataOnFaces_old (pMesh m, MDB_DataExchanger &de )
+// {
+// exchangeDataOnTriangles(m, de);
+// exchangeDataOnQuads(m, de);
+// }
+
+// void exchangeDataOnTriangles (pMesh m, MDB_DataExchanger &de )
+// {
+// int mysize = 1;
+// int myrank = 0;
+
+// #ifdef PARALLEL
+// MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+// MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+// #endif
+
+// // --------------------------------------------------------
+// // --- SEND -----------------------------------------------
+// // --------------------------------------------------------
+
+// int *sendcounts = new int[mysize];
+// for(int i=0;i<mysize;i++) sendcounts[i]=0;
+
+// pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+// // FIter fit = M_faceIter(m);
+// MDB_FIter fit(&m->triangles);
+// pFace pface;
+// // while ((pface = FIter_next(fit))) {
+// while (( pface = fit.next() )) {
+// pVertex nod[3];
+// pface->getNodes(nod);
+// pVertex p1 = nod[0];
+// pVertex p2 = nod[1];
+// pVertex p3 = nod[2];
+// void *temp_ptr1,*temp_ptr2,*temp_ptr3;
+// int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+// int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+// int isInterface3 = EN_getDataPtr((pEntity) p3 , tagData, &temp_ptr3);
+// if(isInterface1 && isInterface2 && isInterface3) {
+// const std::vector<std::pair<int , pVertex> > *recup1 =
+// (const std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+// const std::vector<std::pair<int , pVertex> > *recup2 =
+// (const std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+// const std::vector<std::pair<int , pVertex> > *recup3 =
+// (const std::vector<std::pair<int , pVertex> > *) temp_ptr3;
+// int size = (*recup1).size();
+// int *tab=new int[size];
+// for(int i=0 ; i< size ; i++) tab[i] = (*recup1)[i].first;
+
+// int size2 = (*recup2).size();
+// int *tab2=new int[size2];
+// for(int i=0 ; i< size2 ; i++) tab2[i] = (*recup2)[i].first;
+
+// for(unsigned int k=0 ; k<(*recup3).size() ; k++) {
+// // the 3 vertices could belong to 3 identical procs at the same time and the face
+// // belongs to only 2 of those. In this case 2 packets are sent. We have to
+// // ignore the 'wrong' packet at reception. (Done)
+// int iProc = (*recup3)[k].first;
+// int i;
+// for(i=0 ; i<size ; i++) {
+// if(iProc == tab[i]) break;
+// }
+// int j;
+// for(j=0 ; j<size2 ; j++) {
+// if(iProc == tab2[j]) break;
+// }
+// if(i < size && j < size2) {
+// assert(tab[i]==iProc);
+// assert(tab2[j]==iProc);
+
+// int sizebuf;
+
+// pVertex remote1 = (*recup1)[i].second;
+// pVertex remote2 = (*recup2)[j].second;
+// pVertex remote3 = (*recup3)[k].second;
+
+// void *buf = de.sendData ((pEntity) pface, iProc, sizebuf );
+// if (buf) {
+// if (iProc == myrank) {
+// puts("*****************************pas parallele");
+// char *msg = (char*)malloc(3*sizeof(pEntity*)+sizebuf);
+// memcpy(msg,&remote1,sizeof(pEntity*));
+// memcpy(&msg[sizeof(pEntity*)],&remote2,sizeof(pEntity*));
+// memcpy(&msg[2*sizeof(pEntity*)],&remote3,sizeof(pEntity*));
+// memcpy(&msg[3*sizeof(pEntity*)],buf,sizebuf);
+// free(buf);
+// MDB_ListF vf;
+// remote1->getTriangles(vf);
+// MDB_ListF::iterator it = vf.begin();
+// MDB_ListF::iterator ite = vf.end();
+// while(it!=ite){
+// pVertex nod[3];
+// (*it)->getNodes(nod);
+// if((nod[0] == remote1 || nod[1] == remote1 || nod[2] == remote1)&&
+// (nod[0] == remote2 || nod[1] == remote2 || nod[2] == remote2)&&
+// (nod[0] == remote3 || nod[1] == remote3 || nod[2] == remote3))break;
+// ++it;
+// }
+// assert(it!=ite);
+// pFace pface = *it;
+// de.receiveData ((pEntity) pface,
+// myrank,
+// msg);
+// free(msg);
+// }
+// else {
+// #ifdef PARALLEL
+// char *msg = (char*)AP_alloc(iProc,
+// de.tag() ,
+// 3*sizeof(pEntity*)+sizebuf);
+// memcpy(&msg[0],&remote1,sizeof(pEntity*));
+// memcpy(&msg[sizeof(pEntity*)],&remote2,sizeof(pEntity*));
+// memcpy(&msg[2*sizeof(pEntity*)],&remote3,sizeof(pEntity*));
+// memcpy(&msg[3*sizeof(pEntity*)],buf,sizebuf);
+// free(buf);
+// AP_send(msg);
+// sendcounts[iProc]++;
+// #else
+// throw;
+// #endif
+// }
+// }
+// }
+// }
+// delete []tab;
+// delete []tab2;
+// }
+// }
+// // FIter_delete(fit);
+// #ifdef PARALLEL
+// // #ifdef MDB_DEBUG
+// // MPI_Barrier( MPI_COMM_WORLD );
+// // AP_check_sends(AP_WAITDEFER);
+// // #else
+// AP_check_sends(AP_NOFLAGS);
+// // #endif
+// AP_reduce_nsends(sendcounts);
+
+// // --------------------------------------------------------
+// // --- RECEIVE --------------------------------------------
+// // --------------------------------------------------------
+
+// int message=0;
+// int count;
+
+// while (!AP_recv_count(&count) || message<count)
+// {
+// void *msg;
+// int from;
+// int tag;
+// int size;
+// int rc;
+// rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+// &msg, &size, &from, &tag);
+// if (rc)
+// {
+// message++;
+// char * tmp = (char *) msg;
+// pVertex * pv1 = (pVertex *) &tmp[0];
+// pVertex * pv2 = (pVertex *) &tmp[sizeof(pEntity*)];
+// pVertex * pv3 = (pVertex *) &tmp[2*sizeof(pEntity*)];
+// MDB_ListF vf;
+// (*pv1)->getTriangles(vf);
+// MDB_ListF::iterator it = vf.begin();
+// MDB_ListF::iterator ite = vf.end();
+// while(it!=ite){
+// pVertex nod[3];
+// (*it)->getNodes(nod);
+// if((nod[0] == (*pv2) || nod[1] == (*pv2) || nod[2] == (*pv2))&&
+// (nod[0] == (*pv3) || nod[1] == (*pv3) || nod[2] == (*pv3))) {
+// assert((nod[0] == (*pv1) || nod[1] == (*pv1) || nod[2] == (*pv1)));
+// break;
+// }
+// ++it;
+// }
+// // this can happen: see the comment above in the send part.
+// if ( it == ite ){
+// AP_free(msg);
+// }
+// else {
+// pFace pface = *it;
+// de.receiveData ((pEntity) pface,from, &tmp[3*sizeof(pEntity*)]);
+// AP_free(msg);
+// }
+// }
+// }
+// AP_check_sends(AP_WAITALL);
+// MPI_Barrier(MPI_COMM_WORLD);
+// #endif
+// delete [] sendcounts;
+// }
+
+// void exchangeDataOnQuads (pMesh m, MDB_DataExchanger &de )
+// {
+// int mysize = 1;
+// int myrank = 0;
+
+// #ifdef PARALLEL
+// MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+// MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+// #endif
+
+// // --------------------------------------------------------
+// // --- SEND -----------------------------------------------
+// // --------------------------------------------------------
+
+// int *sendcounts = new int[mysize];
+// for(int i=0;i<mysize;i++) sendcounts[i]=0;
+
+// pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+// // FIter fit = M_faceIter(m);
+// MDB_QIter fit(&m->quads);
+// pFace pface;
+// // while ((pface = FIter_next(fit))) {
+// while ((pface = fit.next())) {
+// pVertex nod[4];
+// pface->getNodes(nod);
+// pVertex p1 = nod[0];
+// pVertex p2 = nod[1];
+// pVertex p3 = nod[2];
+// pVertex p4 = nod[3];
+// void *temp_ptr1,*temp_ptr2,*temp_ptr3,*temp_ptr4;
+// int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+// int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+// int isInterface3 = EN_getDataPtr((pEntity) p3 , tagData, &temp_ptr3);
+// int isInterface4 = EN_getDataPtr((pEntity) p4 , tagData, &temp_ptr4);
+// if(isInterface1 && isInterface2 && isInterface3 && isInterface4) {
+// const std::vector<std::pair<int , pVertex> > *recup1 =
+// (const std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+// const std::vector<std::pair<int , pVertex> > *recup2 =
+// (const std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+// const std::vector<std::pair<int , pVertex> > *recup3 =
+// (const std::vector<std::pair<int , pVertex> > *) temp_ptr3;
+// const std::vector<std::pair<int , pVertex> > *recup4 =
+// (const std::vector<std::pair<int , pVertex> > *) temp_ptr4;
+// int size = (*recup1).size();
+// int *tab=new int[size];
+// for(int i=0 ; i< size ; i++) tab[i] = (*recup1)[i].first;
+
+// int size2 = (*recup2).size();
+// int *tab2=new int[size2];
+// for(int i=0 ; i< size2 ; i++) tab2[i] = (*recup2)[i].first;
+
+// int size3 = (*recup3).size();
+// int *tab3=new int[size3];
+// for(int i=0 ; i< size3 ; i++) tab3[i] = (*recup3)[i].first;
+
+// for(int l=0 ; l<(int)((*recup4).size()) ; l++) {
+// // this test is not robust: the 4 vertices could belong to 4 identical procs at the same
+// // time and the face belongs to only 2 of those. In this case 2 packets are sent. We have to
+// // ignore the 'wrong' packet at reception. (Done)
+// int iProc = (*recup4)[l].first;
+// int i;
+// for(i=0 ; i<size ; i++) {
+// if(iProc == tab[i]) break;
+// }
+// int j;
+// for(j=0 ; j<size2 ; j++) {
+// if(iProc == tab2[j]) break;
+// }
+// int k;
+// for(k=0 ; k<size3 ; k++) {
+// if(iProc == tab3[k]) break;
+// }
+// if(i < size && j < size2 && k < size3) {
+// assert(tab[i]==iProc);
+// assert(tab2[j]==iProc);
+// assert(tab3[k]==iProc);
+
+// int dimGeomFace = GEN_type(pface->g);
+// if (dimGeomFace == 2) {
+// int tagFace = GEN_tag(pface->g); //std::cout <<"tagFace: "<<tagFace<<std::endl;
+// if (F_numRegions(pface)!=1) continue; //SL assert(F_numRegions(pface)==1);
+// int tagVol = GEN_tag(F_region(pface,0)->g); //std::cout <<"tagVol: "<<tagVol<<std::endl;
+// if ( tagFace == tagVol ) {
+
+// int sizebuf;
+
+// pVertex remote1 = (*recup1)[i].second;
+// pVertex remote2 = (*recup2)[j].second;
+// pVertex remote3 = (*recup3)[k].second;
+// pVertex remote4 = (*recup4)[l].second;
+
+// void *buf = de.sendData ((pEntity) pface, iProc, sizebuf );
+// if (buf)
+// {
+// if (iProc == myrank)
+// {
+// puts("*****************************pas parallele");
+// char *msg = (char*)malloc(4*sizeof(pEntity*)+sizebuf);
+// memcpy(msg,&remote1,sizeof(pEntity*));
+// memcpy(&msg[sizeof(pEntity*)],&remote2,sizeof(pEntity*));
+// memcpy(&msg[2*sizeof(pEntity*)],&remote3,sizeof(pEntity*));
+// memcpy(&msg[3*sizeof(pEntity*)],&remote4,sizeof(pEntity*));
+// memcpy(&msg[4*sizeof(pEntity*)],buf,sizebuf);
+// free(buf);
+// MDB_ListF vf;
+// remote1->getTriangles(vf);
+// MDB_ListF::iterator it = vf.begin();
+// MDB_ListF::iterator ite = vf.end();
+// while(it!=ite){
+// pVertex nod[4];
+// (*it)->getNodes(nod);
+// if((nod[0] == remote1 || nod[1] == remote1 || nod[2] == remote1 || nod[3] == remote1)&&
+// (nod[0] == remote2 || nod[1] == remote2 || nod[2] == remote2 || nod[3] == remote2)&&
+// (nod[0] == remote3 || nod[1] == remote3 || nod[2] == remote3 || nod[3] == remote3)&&
+// (nod[0] == remote4 || nod[1] == remote4 || nod[2] == remote4 || nod[3] == remote4))break;
+// ++it;
+// }
+// assert(it!=ite);
+// pFace pface = *it;
+// de.receiveData ((pEntity) pface,
+// myrank,
+// msg);
+// free(msg);
+// }
+// else
+// {
+// #ifdef PARALLEL
+// char *msg = (char*)AP_alloc(iProc,
+// de.tag() ,
+// 4*sizeof(pEntity*)+sizebuf);
+// memcpy(&msg[0],&remote1,sizeof(pEntity*));
+// memcpy(&msg[sizeof(pEntity*)],&remote2,sizeof(pEntity*));
+// memcpy(&msg[2*sizeof(pEntity*)],&remote3,sizeof(pEntity*));
+// memcpy(&msg[3*sizeof(pEntity*)],&remote4,sizeof(pEntity*));
+// memcpy(&msg[4*sizeof(pEntity*)],buf,sizebuf);
+// free(buf);
+// AP_send(msg);
+// sendcounts[iProc]++;
+// #else
+// throw;
+// #endif
+// }
+// }
+// }
+// }
+// }
+// }
+// delete []tab;
+// delete []tab2;
+// delete []tab3;
+// }
+// }
+// // FIter_delete(fit);
+// #ifdef PARALLEL
+// // #ifdef MDB_DEBUG
+// // //MPI_Waitall();
+// // MPI_Barrier( MPI_COMM_WORLD );
+// // AP_check_sends(AP_WAITALL);
+// // #else
+// AP_check_sends(AP_NOFLAGS);
+// // #endif
+// AP_reduce_nsends(sendcounts);
+
+// // --------------------------------------------------------
+// // --- RECEIVE --------------------------------------------
+// // --------------------------------------------------------
+
+// int message=0;
+// int count;
+
+// while (!AP_recv_count(&count) || message<count)
+// {
+// void *msg;
+// int from;
+// int tag;
+// int size;
+// int rc;
+// rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+// &msg, &size, &from, &tag);
+// if (rc)
+// {
+// message++;
+// char * tmp = (char *) msg;
+// pVertex * pv1 = (pVertex *) &tmp[0];
+// pVertex * pv2 = (pVertex *) &tmp[sizeof(pEntity*)];
+// pVertex * pv3 = (pVertex *) &tmp[2*sizeof(pEntity*)];
+// pVertex * pv4 = (pVertex *) &tmp[3*sizeof(pEntity*)];
+// MDB_ListF vf;
+// (*pv1)->getTriangles(vf);
+// MDB_ListF::iterator it = vf.begin();
+// MDB_ListF::iterator ite = vf.end();
+// while(it!=ite){
+// pVertex nod[4];
+// (*it)->getNodes(nod);
+// if((nod[0] == (*pv2) || nod[1] == (*pv2) || nod[2] == (*pv2) || nod[3] == (*pv2))&&
+// (nod[0] == (*pv3) || nod[1] == (*pv3) || nod[2] == (*pv3) || nod[3] == (*pv3))&&
+// (nod[0] == (*pv4) || nod[1] == (*pv4) || nod[2] == (*pv4) || nod[3] == (*pv4))) {
+// assert((nod[0] == (*pv1) || nod[1] == (*pv1) || nod[2] == (*pv1) || nod[3] == (*pv1) ));
+// break;
+// }
+// ++it;
+// }
+// // this can happen: see the comment above in the send part.
+// if ( it == ite ){
+// AP_free(msg);
+// }
+// else {
+// pFace pface = *it;
+// de.receiveData ((pEntity) pface,from, &tmp[4*sizeof(pEntity*)]);
+// AP_free(msg);
+// }
+// }
+// }
+// AP_check_sends(AP_WAITALL);
+// MPI_Barrier(MPI_COMM_WORLD);
+// #endif
+// delete [] sendcounts;
+// }
+
+} // End of namespace MAd
diff --git a/Mesh/MeshDataBaseComm.h b/Mesh/MeshDataBaseComm.h
new file mode 100644
index 0000000..ccffdba
--- /dev/null
+++ b/Mesh/MeshDataBaseComm.h
@@ -0,0 +1,61 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MeshDataBaseCOMM_H
+#define _MeshDataBaseCOMM_H
+
+#include "MeshDataBase.h"
+
+/*
+ MDB_DataExchanger is a class that allow user to exchange
+ data's between partitions and/or periodic boundaries. User
+ has to provide a tag for non synchronous communications.
+ Basically, choose a tag that is higher that 200 for being
+ sure that it does not interact with internal messages.
+ User has to allocate buffers using malloc.
+
+ User will receive its datas.
+*/
+
+namespace MAd {
+
+ class MDB_DataExchanger
+ {
+ private:
+ int tagComm;
+ public :
+ // get a tag for the communication
+ int tag() const { return tagComm; }
+ // user allocates sends a message of _size size related to mesh entity pe to proc iProc
+ virtual void * sendData (MDB_MeshEntity * pe, // in
+ int iProcDest , // in
+ int &_size ) = 0; // out
+ // mesh entity pe recieves data *buf form proc iProc.
+ // The user shall NOT delete the message !!
+ virtual void receiveData (MDB_MeshEntity * pe, //in
+ int iProcSender ,//in
+ void *buf ) = 0; //in
+ // In case the user has to delete a data when 'pe' is deleted
+ virtual void deleteExternalData (MDB_MeshEntity * pe) const {}
+ MDB_DataExchanger(int _tag): tagComm(_tag) {}
+ virtual ~MDB_DataExchanger() {}
+ };
+ void exchangeDataOnVertices (MDB_Mesh * m, MDB_DataExchanger &de );
+ void exchangeDataOnEdges (MDB_Mesh * m, MDB_DataExchanger &de );
+ void exchangeDataOnFaces (MDB_Mesh * m, MDB_DataExchanger &de );
+ void exchangeDataOnTriangles(MDB_Mesh * m, MDB_DataExchanger &de );
+ void exchangeDataOnQuads (MDB_Mesh * m, MDB_DataExchanger &de );
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseCommCheck.cc b/Mesh/MeshDataBaseCommCheck.cc
new file mode 100644
index 0000000..2a0584a
--- /dev/null
+++ b/Mesh/MeshDataBaseCommCheck.cc
@@ -0,0 +1,235 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Koen Hillewaert
+// -------------------------------------------------------------------
+
+#include "MeshDataBaseCommCheck.h"
+#include "MeshDataBaseMessage.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseParallelInterface.h"
+
+#include <sstream>
+using std::ostringstream;
+using std::ostream;
+using std::cout;
+using std::endl;
+#include <iostream>
+
+#ifdef PARALLEL
+#include "mpi.h"
+#endif
+
+namespace MAd {
+
+ // -----------------------------------------------------------------------------
+
+ MDB_CommCheck::MDB_CommCheck():
+ MDB_DataExchanger(1354),numRecvs(0),numSends(0),numErrors(0) {}
+
+ // -----------------------------------------------------------------------------
+
+ void MDB_CommCheck::printStatus(ostream& out) const {
+
+ out << "Number of sends " << numSends
+ << ", number of receives " << numRecvs
+ << ", number of errors " << numErrors << std::endl;
+ }
+
+
+ // -----------------------------------------------------------------------------
+
+ void* MDB_CommCheck::sendData(pEntity pe,int iProc,int& size) {
+
+ int type = EN_type(pe);
+
+ void* buf = NULL;
+ size = sizeof(pEntity);
+
+ switch (type) {
+
+ case 0:
+ {
+ size += 2*sizeof(int);
+ buf = malloc(size);
+
+ int* ibuf = reinterpret_cast<int*>(buf);
+
+ *(ibuf++) = 1;
+ *(ibuf++) = EN_id(pe);
+
+ pEntity* ebuf = reinterpret_cast<pEntity*>(ibuf);
+ *ebuf = pe;
+
+ return buf;
+
+ break;
+ }
+ case 1:
+ {
+ pEdge pl = (pEdge) pe;
+ size += 3 * sizeof(int);
+ buf = malloc(size);
+
+ int *ibuf = reinterpret_cast<int*>(buf);
+
+ *(ibuf++) = 2;
+ *(ibuf++) = EN_id((pEntity) E_vertex(pl,0));
+ *(ibuf++) = EN_id((pEntity) E_vertex(pl,1));
+
+ pEntity* ebuf = reinterpret_cast<pEntity*>(ibuf);
+ *ebuf = pl;
+
+ break;
+ }
+ case 2:
+ {
+ pFace pf = (pFace) pe;
+ size += (1 + F_numVertices(pf)) * sizeof(int);
+ buf = malloc(size);
+
+ int *ibuf = reinterpret_cast<int*>(buf);
+
+ *(ibuf++) = F_numVertices(pf);
+ for (int i=0;i<F_numVertices(pf);i++) *(ibuf++) = EN_id((pEntity) F_vertex(pf,i));
+
+ pEntity* ebuf = reinterpret_cast<pEntity*>(ibuf);
+ *ebuf = pf;
+
+ break;
+ }
+ }
+ return buf;
+ }
+
+ // -----------------------------------------------------------------------------
+
+ void MDB_CommCheck::receiveData(pEntity pe,int from,void* buf) {
+
+ int myrank = 0;
+#ifdef PARALLEL
+ MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
+#endif
+
+ int type = EN_type(pe);
+
+ int* ibuf = reinterpret_cast<int*>(buf);
+ int np = *(ibuf++);
+
+
+ switch (type) {
+
+ case 0:
+ {
+ int id = *(ibuf++);
+
+ if (!V_corresponds((pVertex) pe,id)) {
+
+ Msg_char(MDB_FATAL,
+ "Non-corresponding communication vertex from proc %d : %d vs %d\n",
+ from,EN_id(pe),id);
+ }
+
+ pEntity* pbuf = reinterpret_cast<pEntity*>(ibuf);
+ pEntity corr = *pbuf;
+
+ std::pair<int,pEntity> comm = std::make_pair(from,corr);
+
+ if (communications[pe].find(comm) != communications[pe].end()) {
+ Msg_char(MDB_FATAL,
+ "Multiple identical communications for vertex %d on %d from %d",
+ EN_id(pe),myrank,from);
+
+ }
+ communications[pe].insert(comm);
+ break;
+ }
+ case 1:
+ {
+ pEdge pl = (pEdge) pe;
+ bool check = true;
+
+ int idSend[2];
+
+ for (int i=0;i<2;i++){
+ idSend[i] = *(ibuf++);
+ check = check && V_corresponds(E_vertex(pl,i),idSend[i]);
+ }
+
+ if (!check) {
+
+ Msg_char(MDB_FATAL,
+ "Non-corresponding edge from proc %d on proc %d : (%d,%d) vs (%d,%d)\n",
+ from,myrank,
+ idSend[0],
+ idSend[1],
+ EN_id(E_vertex(pl,0)),
+ EN_id(E_vertex(pl,1)));
+ }
+
+
+ pEntity* pbuf = reinterpret_cast<pEntity*>(ibuf);
+ pEntity corr = *pbuf;
+
+ std::pair<int,pEntity> comm = std::make_pair(from,corr);
+
+ if (communications[pe].find(comm) != communications[pe].end()) {
+ Msg_char(MDB_FATAL,
+ "Multiple identical communications for edge %d-%d on %d from %d",
+ EN_id((pEntity) E_vertex(pl,0)),
+ EN_id((pEntity) E_vertex(pl,1))
+ ,myrank,from);
+ }
+ communications[pe].insert(comm);
+ break;
+ }
+ case 2:
+ {
+ pFace pf = (pFace) pe;
+ bool check = (np == F_numVertices(pf));
+
+ int idSend[4];
+
+ for (int i=0;i<np ;i++){
+ idSend[i] = *(ibuf++);
+ check = check && V_corresponds(F_vertex(pf,i),idSend[i]);
+ }
+
+ if (!check) {
+
+ ostringstream recv;
+ for (int i=0;i<np;i++) recv << " " << idSend[i];
+ ostringstream send;
+ for (int i=0;i<F_numVertices(pf);i++) send << " " << EN_id((pEntity) F_vertex(pf,i));
+
+ Msg_char(MDB_FATAL,
+ "Non-corresponding face from proc %d - (%s) vs (%s)\n",
+ recv.str().c_str(),send.str().c_str());
+ }
+
+
+ pEntity* pbuf = reinterpret_cast<pEntity*>(ibuf);
+ pEntity corr = *pbuf;
+
+ std::pair<int,pEntity> comm = std::make_pair(from,corr);
+
+ if (communications[pe].find(comm) != communications[pe].end()) {
+ Msg_char(MDB_FATAL,
+ "Multiple identical communications for face %d-%d-%d on %d from %d",
+ EN_id((pEntity) F_vertex(pf,0)),
+ EN_id((pEntity) F_vertex(pf,1)),
+ EN_id((pEntity) F_vertex(pf,2)),
+ myrank,from);
+ }
+ communications[pe].insert(comm);
+ break;
+ }
+ }
+ }
+}
diff --git a/Mesh/MeshDataBaseCommCheck.h b/Mesh/MeshDataBaseCommCheck.h
new file mode 100644
index 0000000..43ee0ec
--- /dev/null
+++ b/Mesh/MeshDataBaseCommCheck.h
@@ -0,0 +1,53 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Koen Hillewaert
+// -------------------------------------------------------------------
+
+#ifndef MESHDATABASEPARALLELCHECK_H
+#define MESHDATABASEPARALLELCHECK_H
+
+#include "MeshDataBaseComm.h"
+#include "MeshDataBaseInterface.h"
+
+#include <iostream>
+#include <map>
+#include <set>
+
+
+namespace MAd {
+
+ /*! \brief Class for checking orientation of corresponding entities \ingroup parallel */
+
+ class MDB_CommCheck : public MDB_DataExchanger {
+
+ public:
+
+ MDB_CommCheck();
+
+ void printStatus(std::ostream&) const;
+
+ virtual void* sendData(MDB_MeshEntity *,int,int&);
+ virtual void receiveData(MDB_MeshEntity *,int,void*);
+
+ private:
+
+ int numRecvs;
+ int numSends;
+ int numErrors;
+
+ std::map<pEntity,std::set<std::pair<int,pEntity> > > communications;
+
+
+ };
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseCommPeriodic.h b/Mesh/MeshDataBaseCommPeriodic.h
new file mode 100644
index 0000000..1de3f97
--- /dev/null
+++ b/Mesh/MeshDataBaseCommPeriodic.h
@@ -0,0 +1,41 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MeshDataBaseCommPerio_H
+#define _MeshDataBaseCommPerio_H
+
+/*
+ MDB_DataExchangerPeriodic is a class that allow user to define function for
+ periodic boundaries.
+*/
+
+namespace MAd {
+
+ class MDB_DataExchangerPeriodic
+ {
+ public :
+ virtual int nbRefPeriodic() const = 0;
+ virtual void fperiodic (const int inv,
+ const double X,
+ const double Y,
+ const double Z,
+ int numref, // number of the transformation
+ double *Xnew,
+ double *Ynew,
+ double *Znew) = 0;
+ virtual ~MDB_DataExchangerPeriodic() {};
+ };
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseGEntity2Physical.cc b/Mesh/MeshDataBaseGEntity2Physical.cc
new file mode 100644
index 0000000..4b8cef5
--- /dev/null
+++ b/Mesh/MeshDataBaseGEntity2Physical.cc
@@ -0,0 +1,36 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBaseGEntity2Physical.h"
+
+namespace MAd {
+
+GEntity2Physical::GEntity2Physical(std::multimap<int,pGEntity> &inmap){
+ for(std::multimap<int,pGEntity>::iterator it=inmap.begin(); it!=inmap.end(); it++){
+ insert(std::pair<pGEntity,int>(it->second,it->first));
+ }
+}
+
+int GEntity2Physical::get_first_tag(const pGEntity g){
+ iterator first_it,end_it;
+ first_it=lower_bound(g);
+ end_it=upper_bound(g);
+ if(first_it==end_it){
+ // This entity doesn't have physical tag
+ // I don't think this could happen but who knows...
+ return 0;
+ }
+ return first_it->second;
+}
+
+}
+
diff --git a/Mesh/MeshDataBaseGEntity2Physical.h b/Mesh/MeshDataBaseGEntity2Physical.h
new file mode 100644
index 0000000..49efaa9
--- /dev/null
+++ b/Mesh/MeshDataBaseGEntity2Physical.h
@@ -0,0 +1,32 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASEGENTITY2PHYSICAL
+#define H_MESHDATABASEGENTITY2PHYSICAL
+#include <map>
+#include "ModelInterface.h"
+// build a reverse map of geomFeatures_Tags
+// (a map would be enough as we read only one physical tag for now,
+// but a multimap is used in prevision...)
+
+namespace MAd {
+
+ class GEntity2Physical:private std::multimap<pGEntity,int>{
+ public:
+ GEntity2Physical(std::multimap<int,pGEntity> &inmap);
+ int get_first_tag(pGEntity g);
+ };
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseIO.cc b/Mesh/MeshDataBaseIO.cc
new file mode 100644
index 0000000..53c4fc6
--- /dev/null
+++ b/Mesh/MeshDataBaseIO.cc
@@ -0,0 +1,1829 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere, Cecile Dobrzynski
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseIO.h"
+#include "MeshDataBaseMessage.h"
+#include "MeshDataBaseGEntity2Physical.h"
+#include <assert.h>
+#include "MeshDataBaseCommPeriodic.h"
+#include "MshTags.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <set>
+#include <map>
+#include <utility>
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+#include "MeshDataBaseParallelInterface.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ // ------------- Load a Gmsh mesh ------------------------------------
+ // -------------------------------------------------------------------
+
+ void LoadGmshMesh (pMesh m,const char *filename)
+ {
+ FILE *fp = fopen(filename, "r");
+ if(!fp) {
+ Msg(MDB_FATAL,"Unknown File %s\n",filename);
+ }
+
+#ifdef PARALLEL
+ int myRank = 0, nbProc = 0;
+ MPI_Comm_size(MPI_COMM_WORLD, &nbProc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
+#endif
+
+ char String[256];
+
+ if (!m->model) {
+ pGModel model = NULL;
+ GM_create(&model,"");
+ m->model = model;
+ }
+
+ // ----------------------------------------------
+ // ------ Reading format
+ // ----------------------------------------------
+
+ int version = -1;
+ do {
+ if(!fgets(String, sizeof(String),fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$' ||
+ strncmp(&String[1], "MeshFormat",10));
+
+ if(feof(fp)) {
+ version = 1;
+ }
+ else {
+ int a, b, c;
+ fscanf(fp, "%d %d %d", &a, &b, &c);
+ version = a;
+ }
+
+ rewind(fp);
+
+#ifdef PARALLEL
+ if ( version == 1 && nbProc > 1 ) {
+ Msg(MDB_FATAL,"Cannot load Gmsh mesh from file %s: parallel loading not implemented for file format msh1\n",filename);
+ }
+#endif
+
+ // -----------------------------------------------
+ // ------ Reading elements to find local nodes
+ // -----------------------------------------------
+
+ std::set<int> localNodeIds;
+
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$' ||
+ ( strncmp(&String[1], "ELM", 3) &&
+ strncmp(&String[1], "Elements", 8) ) );
+
+ if(!feof(fp)) {
+
+ int nbElems_world, NbTags, verts[256], Tag;
+ int Num, Type, Physical, Elementary, Nbr_Nodes, Partition;
+ fscanf(fp, "%d", &nbElems_world);
+
+ for(int i_Element = 0; i_Element < nbElems_world; i_Element++) {
+
+ if(version == 1){
+ fscanf(fp, "%d %d %d %d %d",
+ &Num, &Type, &Physical, &Elementary, &Nbr_Nodes);
+ Partition = -1;
+ }
+ else{
+ fscanf(fp, "%d %d %d", &Num, &Type, &NbTags);
+ Elementary = Physical = Partition = -1;
+ for(int j = 0; j < NbTags; j++){
+ fscanf(fp, "%d", &Tag);
+ if(j == 0)
+ Physical = Tag;
+ else if(j == 1)
+ Elementary = Tag;
+ else if(j == 2)
+ Partition = Tag - 1;
+ // ignore any other tags for now
+ }
+ Nbr_Nodes = getNumVerticesForElementTypeMSH(Type);
+ }
+
+ for(int j = 0; j < Nbr_Nodes; j++) {
+ fscanf(fp, "%d", &verts[j]);
+ }
+
+#ifdef PARALLEL
+ if ( nbProc == 1 || Partition == myRank ) {
+#endif
+ for(int j = 0; j < Nbr_Nodes; j++) {
+ localNodeIds.insert(verts[j]);
+ }
+#ifdef PARALLEL
+ }
+#endif
+ }
+ }
+
+ rewind(fp);
+
+
+ // ----------------------------------------------
+ // ------ Reading nodes
+ // ----------------------------------------------
+
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$' ||
+ (strncmp(&String[1], "NOD", 3) &&
+ strncmp(&String[1], "NOE", 3) &&
+ strncmp(&String[1], "Nodes", 5) ) );
+
+ if(!feof(fp)) {
+ int nbNodes_world;
+ fscanf(fp, "%d", &nbNodes_world);
+ for(int i_Node = 0; i_Node < nbNodes_world; i_Node++) {
+ int id;
+ double x,y,z;
+ fscanf(fp, "%d %lf %lf %lf", &id, &x, &y, &z);
+ if ( localNodeIds.find(id) != localNodeIds.end() ) {
+ m->add_point(id,x,y,z);
+ }
+ }
+ }
+
+ rewind(fp);
+
+ // ----------------------------------------------
+ // ------ Reading parametric nodes
+ // ----------------------------------------------
+
+ if ( version == 2 ) {
+ do {
+ if(!fgets(String, sizeof(String), fp)) break;
+ if(feof(fp)) break;
+ } while(String[0] != '$' ||
+ strncmp(&String[1], "ParametricNodes", 15) );
+
+ if(!feof(fp)) {
+ int nbNodes_world;
+ fscanf(fp, "%d", &nbNodes_world);
+ for(int i_Node = 0; i_Node < nbNodes_world; i_Node++) {
+ int id, gDim, gTag;
+ double x,y,z;
+ fscanf(fp, "%d %lf %lf %lf %d %d", &id, &x, &y, &z, &gDim, &gTag);
+ if ( gDim == 3 ) {
+ if ( localNodeIds.find(id) != localNodeIds.end() ) {
+ m->add_point(id,x,y,z);
+ }
+ }
+ else {
+ double u,v;
+ if ( gDim == 0 ) {
+ u = v = 0.;
+ }
+ if ( gDim == 1 ) {
+ fscanf(fp, "%lf", &u);
+ v = 0.;
+ }
+ if ( gDim == 2 ) {
+ fscanf(fp, "%lf %lf", &u, &v);
+ }
+ m->add_pointParam(id,x,y,z,u,v);
+ }
+ }
+ }
+
+ rewind(fp);
+ }
+
+ // ----------------------------------------------
+ // ------ Reading elements
+ // ----------------------------------------------
+
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$' ||
+ ( strncmp(&String[1], "ELM", 3) &&
+ strncmp(&String[1], "Elements", 8) ) );
+
+ if(!feof(fp)) {
+
+ int nbElems_world, NbTags, verts[256], Tag;
+ int Num, Type, Physical, Elementary, Nbr_Nodes, Partition;
+ fscanf(fp, "%d", &nbElems_world);
+
+ for(int i_Element = 0; i_Element < nbElems_world; i_Element++) {
+
+ if(version == 1){
+ fscanf(fp, "%d %d %d %d %d",
+ &Num, &Type, &Physical, &Elementary, &Nbr_Nodes);
+ Partition = -1;
+ }
+ else{
+ fscanf(fp, "%d %d %d", &Num, &Type, &NbTags);
+ Elementary = Physical = Partition = -1;
+ for(int j = 0; j < NbTags; j++){
+ fscanf(fp, "%d", &Tag);
+ if(j == 0)
+ Physical = Tag;
+ else if(j == 1)
+ Elementary = Tag;
+ else if(j == 2)
+ Partition = Tag - 1;
+ // ignore any other tags for now
+ }
+ Nbr_Nodes = getNumVerticesForElementTypeMSH(Type);
+ }
+
+ for(int j = 0; j < Nbr_Nodes; j++) {
+ fscanf(fp, "%d", &verts[j]);
+ }
+
+#ifdef PARALLEL
+ if ( nbProc == 1 || Partition == myRank ) {
+#endif
+
+ pGEntity geom = 0;
+
+ switch (Type) {
+ case MSH_LIN_2:
+ {
+ geom = (pGEntity) GM_edgeByTag(m->model,Elementary);
+ m->add_edge(verts[0],verts[1],geom);
+ }
+ break;
+ case MSH_LIN_3:
+ {
+ geom = (pGEntity) GM_edgeByTag(m->model,Elementary);
+ //m->add_edge(verts[0],verts[2],verts[1],geom);
+ m->add_edge(3,geom,verts[0],verts[2],verts[1]);
+ //m->add_edge(verts[0],verts[1],ge);
+ }
+ break;
+ case MSH_LIN_4:
+ {
+ geom = (pGEntity) GM_edgeByTag(m->model,Elementary);
+ m->add_edge(4,geom, verts[0],verts[2],verts[3],verts[1]);
+ }
+ break;
+ case MSH_LIN_5:
+ {
+ geom = (pGEntity) GM_edgeByTag(m->model,Elementary);
+ m->add_edge(5,geom, verts[0],verts[2],verts[3],verts[4],verts[1]);
+ }
+ break;
+ case MSH_LIN_6:
+ {
+ geom = (pGEntity) GM_edgeByTag(m->model,Elementary);
+ m->add_edge(6,geom, verts[0],verts[2],verts[3],verts[4],verts[5],verts[1]);
+ }
+ break;
+ case MSH_TRI_3:
+ {
+ geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+ m->add_triangle(verts[0],verts[1],verts[2],geom);
+ }
+ break;
+ // 6 nodes triangle
+ case MSH_TRI_6:
+ {
+ geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+ // printf ("adding a second order triangle %d %d %d %d %d %d\n",verts[0],verts[1],verts[2],verts[3],verts[4],verts[5]);
+ m->add_triangle(2,0,geom,verts[0],verts[3],verts[1],verts[4],verts[2],verts[5]);
+ //m->add_triangle(verts[0],verts[3],verts[1],verts[4],verts[2],verts[5],geom);
+ //m->add_triangle(verts[0],verts[1],verts[2],gf);
+ }
+ break;
+ // 9 nodes triangle (SERENDIP !)
+ case MSH_TRI_9:
+ {
+ geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+ m->add_triangle(3,0,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8]);
+ //m->add_triangle(verts[0],verts[3],verts[1],verts[4],verts[2],verts[5],geom);
+ }
+ break;
+ // 10 nodes triangle (LAGRANGE !)
+ case MSH_TRI_10:
+ {
+ geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+ m->add_triangle(3,1,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8],verts[9]);
+ }
+ break;
+ // 12 nodes triangle (SERENDIP !)
+ case MSH_TRI_12:
+ {
+ geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+ m->add_triangle(4,0,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11]);
+ }
+ break;
+ // 15 nodes triangle (LAGRANGE !)
+ case MSH_TRI_15:
+ {
+ geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+ m->add_triangle(4,1,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11],verts[12],verts[13],verts[14]);
+ }
+ break;
+ // 15 nodes triangle (SERENDIP !)
+ case MSH_TRI_15I:
+ {
+ geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+ m->add_triangle(5,0,geom,verts[0],verts[3],verts[4],verts[5],verts[6],verts[1],verts[7],verts[8],verts[9],verts[10],verts[2],verts[11],verts[12],verts[13],verts[14]);
+ }
+ break;
+ case MSH_QUA_4:
+ {
+ geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+ m->add_quad(verts[0],verts[1],verts[2],verts[3],geom);
+ }
+ break;
+ case MSH_TET_4:
+ {
+ geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+ if( !geom )
+ {
+ printf("READ MESH : no classification for Region\n");
+ }
+ m->add_tet(verts[0],verts[1],verts[2],verts[3],geom);
+ }
+ break;
+ case MSH_PRI_6:
+ {
+ geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+ m->add_prism(verts[0],verts[1],verts[2],
+ verts[3],verts[4],verts[5],geom);
+ }
+ break;
+ case MSH_PNT:
+ {
+ geom = (pGEntity) GM_vertexByTag(m->model,Elementary);
+ MDB_Point *p = m->find_point(verts[0]);
+ p->g = geom;
+ }
+ break;
+ // 8 nodes hexahedron
+ case MSH_HEX_8:
+ {
+ geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+ m->add_hex(verts[0],verts[1],verts[2],verts[3],verts[4],verts[5],verts[6],verts[7],geom);
+ }
+ break;
+ // 10 node tetrahedron, 2nd order
+ case MSH_TET_10:
+ {
+ geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+ m->add_tet(geom,2,false,verts);
+ break;
+ }
+ case MSH_TET_20:
+ {
+ geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+ m->add_tet(geom,3,false,verts);
+ break;
+ }
+ case MSH_TET_35:
+ {
+ geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+ m->add_tet(geom,4,false,verts);
+ break;
+ }
+ case MSH_TET_34:
+ {
+ geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+ m->add_tet(geom,4,true,verts);
+ break;
+ }
+ default:
+ throw;
+ break;
+ }
+ if (geom)
+ {
+ bool find = false;
+ for (std::multimap<int, pGEntity>::iterator it = m->geomFeatures_Tags.lower_bound(Elementary);
+ it != m->geomFeatures_Tags.upper_bound(Elementary);++it)
+ if (it->second == geom)find = true;
+ if (!find)
+ m->geomFeatures_Tags.insert(std::pair<int,pGEntity>(Elementary, geom));
+ }
+#ifdef PARALLEL
+ }
+#endif
+ }
+ }
+
+ m->classify_unclassified_entities();
+
+ m->destroyStandAloneEntities();
+
+ rewind(fp);
+
+
+ // ----------------------------------------------
+ // ------ Reading periodicity properties
+ // ----------------------------------------------
+
+ int isPeriodic = 0;
+ while(1) {
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$');
+
+ if(feof(fp))
+ break;
+
+ else if(!strncmp(&String[1], "PERIODICNOD", 11)) {
+ isPeriodic = 1;
+ }
+ else if(!strncmp(&String[1], "TRA", 3)) {
+ isPeriodic = 2;
+ }
+ else if (!strncmp(&String[1],"PeriodicNodes",13)) {
+ isPeriodic = 2;
+ }
+ else if (!strncmp(&String[1],"PER", 3)) {
+ isPeriodic = 2;
+ }
+
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ throw;
+ if(feof(fp))
+ throw;
+ } while(String[0] != '$');
+ }
+
+ rewind(fp);
+
+ // ----------------------------------------------
+ // ------ Reading periodic data
+ // ----------------------------------------------
+
+ if(isPeriodic) {
+ pMeshDataId tagPeriodic = MD_newMeshDataId("PeriodicPoint");
+ if(isPeriodic==1) {
+ fseek(fp,0,SEEK_SET);
+ while(1) {
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$');
+
+ if(feof(fp))
+ break;
+ if(!strncmp(&String[1], "PERIODICNOD", 11)) {
+ int nPeriod,nRefPeriod;
+ fscanf(fp, "%d %d", &nPeriod,&nRefPeriod);
+ printf("%d Ref Periodic\n",nRefPeriod);
+ int *t=new int[nRefPeriod];
+ for(int ip = 0; ip < nPeriod; ip++) {
+ int Num,v1,v2;
+ fscanf(fp, "%d ", &Num);
+ std::vector<int> transfo;
+ std::vector<int> invtransfo;
+ for(int k=0 ; k<nRefPeriod ; k++) {
+ fscanf(fp, "%d ", &t[k]);
+ transfo.push_back(t[k]);
+ invtransfo.push_back(-t[k]);
+ }
+ fscanf(fp, "%d %d",&v1, &v2);
+ pVertex vt1 = m->find_point(v1);
+ pVertex vt2 = m->find_point(v2);
+ //printf("point %d %d\n",EN_id((pEntity) vt1),EN_id((pEntity) vt2));
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) vt1 , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ unsigned int i=0;
+ for(i=0 ; i<(*recup).size() ; i++) {
+ unsigned int j=0;
+ for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+ if((*recup)[i].first[j] != transfo[j]) break;
+ }
+ if(j==(*recup)[i].first.size() ) break;
+ }
+ if(i==(*recup).size())
+ (*recup).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+ } else {
+ std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+ (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+ EN_attachDataPtr((pEntity) vt1 , tagPeriodic,
+ new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+
+ }
+
+ isPeriodic = EN_getDataPtr((pEntity) vt2 , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ unsigned int i;
+ for(i=0 ; i<(*recup).size() ; i++) {
+ unsigned int j;
+ for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+ if((*recup)[i].first[j] != invtransfo[j]) break;
+ }
+ if(j==(*recup)[i].first.size() ) break;
+ }
+ if(i==(*recup).size())
+ (*recup).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+ } else {
+ std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+ (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+ EN_attachDataPtr((pEntity) vt2 , tagPeriodic,
+ new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+ }
+ }
+ delete []t;
+ }
+ }
+ } else {
+
+ assert(isPeriodic==2);
+ puts("format periodic CENAERO");
+ fseek(fp,0,SEEK_SET);
+ while(1) {
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$');
+
+ if(feof(fp))
+ break;
+
+ if((!strncmp(&String[1],"PER", 3)) ||
+ (!strncmp(&String[1],"PeriodicNodes",13))) {
+
+ int nPeriod;
+ fscanf(fp, "%d ", &nPeriod);
+
+ pMeshDataId tagPeriodic = MD_newMeshDataId("PeriodicVertexID");
+
+ for(int ip = 0; ip < nPeriod; ip++) {
+ int Num,vtxId;
+ fscanf(fp, "%d ", &Num);
+
+ std::vector<int> vtcs;
+
+ for (size_t i=0;i<Num;i++) {
+ fscanf(fp, "%d ", &vtxId);
+ vtcs.push_back(vtxId);
+ }
+
+ int trafo;
+ fscanf(fp, "%d ",&trafo);
+
+ std::vector<int>::const_iterator vIter = vtcs.begin();
+ for (;vIter!=vtcs.end();vIter++) {
+
+ int vtxId = *vIter;
+ pVertex vt1 = m->find_point(vtxId);
+
+ if (vt1) {
+
+ void* tmp_periodic = NULL;
+ int havePeriodic = EN_getDataPtr((pEntity) vt1,tagPeriodic,&tmp_periodic);
+ std::map<int,std::vector<int> > * connections = NULL;
+
+ if (havePeriodic) connections = (std::map<int,std::vector<int> > * ) (tmp_periodic);
+ else {
+ connections = new std::map<int,std::vector<int> >;
+ EN_attachDataPtr((pEntity) vt1,tagPeriodic,connections);
+ }
+
+ // transformations will be written later, using topological classification
+
+ std::vector<int>::const_iterator vIter2 = vtcs.begin();
+ for (;vIter2!=vtcs.end();++vIter2) {
+ if (vtxId != *vIter2) connections->insert(std::make_pair(*vIter2,std::vector<int>()));
+ }
+ }
+ }
+ }
+ }
+
+// if(!strncmp(&String[1], "PER", 3)) {
+// int nPeriod,nRefPeriod;
+// nRefPeriod = 1;
+// fscanf(fp, "%d ", &nPeriod);
+// printf("%d Ref Periodic\n",nRefPeriod);
+// int *t=new int[nRefPeriod];
+// for(int ip = 0; ip < nPeriod; ip++) {
+// int Num,v1,v2;
+// fscanf(fp, "%d ", &Num);
+// std::vector<int> transfo;
+// std::vector<int> invtransfo;
+// fscanf(fp, "%d %d %d",&v1, &v2,&Num);
+// pVertex vt1 = m->find_point(v1);
+// pVertex vt2 = m->find_point(v2);
+
+
+// printf("point %d (%d) %d (%d)\n",EN_id((pEntity) vt1),GEN_tag(vt1->g),EN_id((pEntity) vt2),
+// GEN_tag(vt2->g));
+
+// for(int k=0 ; k<nRefPeriod ; k++) {
+// t[k]=-1;
+// transfo.push_back(t[k]);
+// invtransfo.push_back(-t[k]);
+// }
+// void *temp_ptr;
+// int isPeriodic = EN_getDataPtr((pEntity) vt1 , tagPeriodic, &temp_ptr);
+// if(isPeriodic) {
+// std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+// unsigned int i=0;
+// for(i=0 ; i<(*recup).size() ; i++) {
+// unsigned int j=0;
+// for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+// if((*recup)[i].first[j] != transfo[j]) break;
+// }
+// if(j==(*recup)[i].first.size() ) break;
+// }
+// if(i==(*recup).size())
+// (*recup).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+// } else {
+// std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+// (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+// EN_attachDataPtr((pEntity) vt1 , tagPeriodic,
+// new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+
+// }
+
+// isPeriodic = EN_getDataPtr((pEntity) vt2 , tagPeriodic, &temp_ptr);
+// if(isPeriodic) {
+// std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+// unsigned int i;
+// for(i=0 ; i<(*recup).size() ; i++) {
+// unsigned int j;
+// for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+// if((*recup)[i].first[j] != invtransfo[j]) break;
+// }
+// if(j==(*recup)[i].first.size() ) break;
+// }
+// if(i==(*recup).size())
+// (*recup).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+// } else {
+// std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+// (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+// EN_attachDataPtr((pEntity) vt2 , tagPeriodic,
+// new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+// }
+// }
+// delete []t;
+// }
+ }
+ }
+ }
+
+ fclose(fp);
+
+
+// #ifdef PARALLEL
+
+ // ----------------------------------------------
+ // ------ Tagging inter-partition nodes
+ // ----------------------------------------------
+
+ pMeshDataId tag = MD_lookupMeshDataId("RemotePoint");
+
+ V_createInfoInterface(m,tag);
+ E_createInfoInterface(m,tag);
+ F_createInfoInterface(m,tag);
+
+// #endif
+
+ m->initializeIdData();
+ }
+
+
+ // -------------------------------------------------------------------
+ // ------------- Save a Gmsh mesh ------------------------------------
+ // -------------------------------------------------------------------
+
+ void SaveGmshMesh (const pMesh m,const char *filename, int version,
+ const int * partitionTable)
+ {
+ if ( version == 1 && partitionTable ) {
+ Msg(MDB_FATAL,"Error while saving mesh on file %s: SaveGmshMesh not implemented for msh1 format with partitioning\n",filename);
+ }
+
+ int meshDim = M_dim(m);
+ int nbModelVertex = 0;
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+ // Create a reverse map of physical tags
+ GEntity2Physical gentity2phys(m->geomFeatures_Tags);
+ FILE *f = fopen(filename, "w");
+ if ( !f ) {
+ printf("Error: could not open file %s\n",filename);
+ throw;
+ }
+ if ( version != 1 ) {
+ fprintf(f, "$MeshFormat\n2 0 8\n$EndMeshFormat\n");
+ }
+ // ------ Writting the nodes ------
+ if ( version == 1 || !(m->isParametric()) )
+ {
+ if ( version == 1 ) { fprintf(f, "$NOD\n"); }
+ else { fprintf(f, "$Nodes\n"); }
+ fprintf(f, "%d\n", m->nbPoints);
+ VIter vit = M_vertexIter(m);
+ while (VIter_next(vit)){}
+ VIter_reset(vit);
+ pVertex pv;
+ int NN = 0;
+ while ((pv = VIter_next(vit)))
+ {
+ NN++;
+ if(pv->g)
+ {
+ int dim = GEN_type(pv->g);
+ if(dim == 0) nbModelVertex++;
+ fprintf(f, "%d %g %g %g\n", pv->iD, pv->X, pv->Y, pv->Z);
+ }
+ else
+ {
+ fprintf(f, "%d %g %g %g\n", pv->iD, pv->X, pv->Y, pv->Z);
+ }
+ }
+ if (NN != m->nbPoints) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Vertex iterator saw %d vertices while there are %d points in the mesh",
+ NN,m->nbPoints);
+ }
+ VIter_delete(vit);
+ if ( version == 1 ) { fprintf(f, "$ENDNOD\n"); }
+ else { fprintf(f, "$EndNodes\n"); }
+ }
+ // ------ Writting the parametric nodes ------
+ else
+ {
+ fprintf(f, "$ParametricNodes\n");
+ fprintf(f, "%d\n", m->nbPoints);
+ pVertex pv;
+ VIter vit = M_vertexIter(m);
+ while ((pv = VIter_next(vit)))
+ {
+ if(pv->g)
+ {
+ int gdim = GEN_type(pv->g);
+ int gtag = GEN_tag(pv->g);
+ fprintf(f, "%d %g %g %g %d %d", pv->iD, pv->X, pv->Y, pv->Z, gdim, gtag);
+ double u[2]; V_params(pv,&u[0],&u[1]);
+ switch (gdim) {
+ case 0: { nbModelVertex++; break; }
+ case 1: { fprintf(f, " %g", u[0]); break; }
+ case 2: { fprintf(f, " %g %g", u[0], u[1]); break; }
+ case 3: { break; }
+ }
+ fprintf(f, "\n");
+ }
+ else {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Parametric point without classification");
+ }
+ }
+ VIter_delete(vit);
+ fprintf(f, "$EndParametricNodes\n");
+ }
+ // ------ Writting the elements ------
+ {
+ if ( version == 1 ) { fprintf(f, "$ELM\n"); }
+ else { fprintf(f, "$Elements\n"); }
+
+ int nbClasEdges = 0;
+ int nbClasFaces = 0;
+ {
+ EIter eit = M_edgeIter(m);
+ pEdge pe;
+ while ((pe = EIter_next(eit)))
+ {
+ int dim = GEN_type(pe->g);
+ if(dim == 1) nbClasEdges++;
+ }
+ EIter_delete(eit);
+ }
+ {
+ FIter fit = M_faceIter(m);
+ pFace pf;
+ while ((pf = FIter_next(fit)))
+ {
+ int dim = GEN_type(pf->g);
+ if(dim == 2) nbClasFaces++;
+ else if(F_numRegions(pf)==1) nbClasFaces++;
+ }
+ FIter_delete(fit);
+ }
+
+ fprintf(f, "%ld\n", (long int)(nbClasEdges + nbModelVertex + nbClasFaces + m->nbTets) );
+
+ int k = 1;
+ // --- Nodes ---
+ {
+ VIter vit = M_vertexIter(m);
+ pVertex pv;
+ while ((pv = VIter_next(vit)))
+ {
+ if(pv->g)
+ {
+ int dim = GEN_type(pv->g);
+ int nbTags = 3;
+ int tag = GEN_tag (pv->g);
+ int phys = gentity2phys.get_first_tag(pv->g);
+ int partition = -1;
+ if ( partitionTable ) {
+ switch(meshDim) {
+ case 0:
+ partition = partitionTable[pv->iD];
+ break;
+ case 1:
+ for (int i=0; i < V_numEdges(pv); i++) {
+ int ePart = partitionTable[V_edge(pv,i)->iD];
+ partition = std::min(ePart,partition);
+ if (partition < 0) partition = ePart;
+ }
+ break;
+ case 2: {
+ pPList vFaces = V_faces(pv);
+ void *tmp_ptr = 0;
+ pFace pf;
+ while( (pf = (pFace) PList_next(vFaces,&tmp_ptr)) ) {
+ int fPart = partitionTable[pf->iD];
+ partition = std::min(fPart,partition);
+ if (partition < 0) partition = fPart;
+ }
+ PList_delete(vFaces);
+ break;
+ }
+ case 3: {
+ pPList vRegs = V_regions(pv);
+ void *tmp_ptr = 0;
+ pRegion pr;
+ while( (pr = (pRegion) PList_next(vRegs,&tmp_ptr)) ) {
+ int rPart = partitionTable[pr->iD];
+ partition = std::min(rPart,partition);
+ if (partition < 0) partition = rPart;
+ }
+ PList_delete(vRegs);
+ break;
+ }
+ }
+ }
+
+ if(dim == 0) {
+ if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d\n",
+ k++, 15, phys, tag, 1, pv->iD); }
+ else { fprintf(f, "%d %d %d %d %d %d %d\n",
+ k++, 15, nbTags, phys, tag, partition + 1, pv->iD); }
+ }
+ }
+ }
+ VIter_delete(vit);
+ }
+ // --- Edges ---
+ {
+ EIter eit = M_edgeIter(m);
+ pEdge pe;
+ while ((pe = EIter_next(eit)))
+ {
+ if(pe->g)
+ {
+ int dim = GEN_type(pe->g);
+ int nbTags = 3;
+ int tag = GEN_tag (pe->g);
+ int phys = gentity2phys.get_first_tag(pe->g);
+ int partition = -1;
+ if ( partitionTable ) {
+ switch(meshDim) {
+ case 1:
+ partition = partitionTable[pe->iD];
+ break;
+ case 2:
+ for (int i=0; i < E_numFaces(pe); i++) {
+ int fPart = partitionTable[E_face(pe,i)->iD];
+ partition = std::min(fPart,partition);
+ if (partition < 0) partition = fPart;
+ }
+ break;
+ case 3: {
+ pPList eRegs = E_regions(pe);
+ void *tmp_ptr = 0;
+ pRegion pr;
+ while( (pr = (pRegion) PList_next(eRegs,&tmp_ptr)) ) {
+ int rPart = partitionTable[pr->iD];
+ partition = std::min(rPart,partition);
+ if (partition < 0) partition = rPart;
+ }
+ PList_delete(eRegs);
+ break;
+ }
+ }
+ }
+
+ if(dim ==1) {
+ if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d\n",
+ k++, 1, phys, tag, 2,
+ pe->p1->iD, pe->p2->iD); }
+ else { fprintf(f, "%d %d %d %d %d %d %d %d\n",
+ k++, 1, nbTags, phys, tag, partition + 1,
+ pe->p1->iD, pe->p2->iD); }
+ }
+ }
+ }
+ EIter_delete(eit);
+ }
+ // --- Faces ---
+ {
+ FIter fit = M_faceIter(m);
+ pFace pf;
+ while ((pf = FIter_next(fit)))
+ {
+ if(pf->g)
+ {
+ MDB_Point *nod[4];
+ int dim = GEN_type(pf->g);
+ int nbTags = 3;
+ int tag = GEN_tag (pf->g);
+ int phys = gentity2phys.get_first_tag(pf->g);
+ int partition = -1;
+ if ( partitionTable ) {
+ switch(meshDim) {
+ case 2:
+ partition = partitionTable[pf->iD];
+ break;
+ case 3:
+ for (int i=0; i < F_numRegions(pf); i++) {
+ int rPart = partitionTable[F_region(pf,i)->iD];
+ partition = std::min(rPart,partition);
+ if (partition < 0) partition = rPart;
+ }
+ break;
+ }
+ }
+
+ pf->getNodes(nod);
+ if(dim == 2 || F_numRegions(pf)==1) {
+ if (pf->getNbEdges() == 4) { //quad
+ if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d %d %d\n",
+ k++, 3, phys, tag, 4,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD); }
+ else { fprintf(f, "%d %d %d %d %d %d %d %d %d %d\n",
+ k++, 3, nbTags, phys, tag, partition + 1,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD); }
+ }
+ else { //triangle
+ if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d %d\n",
+ k++, 2, phys, tag, 3,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD); }
+ else { fprintf(f, "%d %d %d %d %d %d %d %d %d\n",
+ k++, 2, nbTags, phys, tag, partition + 1,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD); }
+ }
+ }
+ }
+ }
+ FIter_delete(fit);
+ }
+ {
+ RIter rit = M_regionIter(m);
+ pRegion pr;
+ while ((pr = RIter_next(rit)))
+ {
+ if(pr->g)
+ {
+ MDB_Point *nod[8];
+ //int dim = GEN_type(pr->g);
+ int nbTags = 3;
+ int tag = GEN_tag (pr->g);
+ int phys = gentity2phys.get_first_tag(pr->g);
+ int partition = 0;
+ if ( partitionTable ) {
+ partition = partitionTable[pr->iD];
+ }
+
+ int numVer = pr->getNbVertex();
+ pPList ll = R_vertices(pr);
+ for(int i=0;i<numVer;i++) nod[i] = (pVertex)PList_item(ll, i);
+ PList_delete(ll);
+
+ if(numVer==4) {
+ if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d %d %d\n",
+ k++, 4, phys, tag, 4,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD); }
+ else { fprintf(f, "%d %d %d %d %d %d %d %d %d %d\n",
+ k++, 4, nbTags, phys, tag, partition + 1,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD); }
+ }
+ else if(numVer==8) {
+ if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ k++, 5, phys, tag, 5,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD,
+ nod[4]->iD, nod[5]->iD, nod[6]->iD, nod[7]->iD); }
+ else { fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ k++, 5, nbTags, phys, tag, partition + 1,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD,
+ nod[4]->iD, nod[5]->iD, nod[6]->iD, nod[7]->iD); }
+ }
+ else if(numVer==6) {
+ if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d\n",
+ k++, 6, phys, tag, 6,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD,
+ nod[4]->iD, nod[5]->iD); }
+ else { fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
+ k++, 6, nbTags, phys, tag, partition + 1,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD,
+ nod[4]->iD, nod[5]->iD); }
+ }
+ }
+ }
+ RIter_delete(rit);
+ }
+ if ( version == 1 ) { fprintf(f, "$ENDELM\n"); }
+ else { fprintf(f, "$EndElements\n"); }
+ {
+ int nperiodic = 0,nref = 0;;
+ VIter vit = M_vertexIter(m);
+ pVertex pv;
+ while ((pv = VIter_next(vit)))
+ {
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ if(!nperiodic) {
+ nref = (*recup)[0].first.size();
+ }
+ nperiodic+=(*recup).size();
+ }
+ }
+ VIter_delete(vit);
+ if(nperiodic) {
+ fprintf(f, "$PERIODICNOD\n");
+ fprintf(f, "%d %d\n", nperiodic,nref);
+ int num = 1;
+ vit = M_vertexIter(m);
+ while ((pv = VIter_next(vit)))
+ {
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ for(unsigned int k=0 ; k<(*recup).size() ; k++) {
+ fprintf(f, "%d", num++);
+ for(unsigned int j=0 ; j<(*recup)[k].first.size() ; j++) fprintf(f, " %d", (*recup)[k].first[j]);
+ fprintf(f, " %d %d \n", EN_id((pEntity) pv),EN_id((pEntity) (*recup)[k].second));
+ }
+ //delete recup;
+ //EN_deleteData((pEntity) pv , tagPeriodic);
+ }
+ }
+ VIter_delete(vit);
+ fprintf(f, "$ENDPERIODICNOD\n");
+ }
+ }
+ }
+ fclose(f);
+ //MD_deleteMeshDataId(tagPeriodic);
+
+ }
+
+
+
+ void SaveGmshMeshPer (const pMesh m,const char *filename,MDB_DataExchangerPeriodic &deperiodic, int version)
+ {
+ int nbModelVertex = 0;
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+ // Create a reverse map of physical tags
+ GEntity2Physical gentity2phys(m->geomFeatures_Tags);
+ FILE *f = fopen(filename, "w");
+ {
+ fprintf(f, "$NOD\n");
+ fprintf(f, "%d\n", m->nbPoints);
+ VIter vit = M_vertexIter(m);
+ while (VIter_next(vit)){}
+ VIter_reset(vit);
+ pVertex pv;
+ int NN = 0;
+ while ((pv = VIter_next(vit)))
+ {
+ if(pv->g)
+ {
+ NN++;
+ int dim = GEN_type(pv->g);
+ if (pv->deleted)printf("ouuch\n");
+ if(dim == 0)
+ nbModelVertex++;
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+ if(pv->X==2.25 && pv->Y==0.25) printf("%e %e %e : %d\n",pv->X,pv->Y,pv->Z,pv->iD);
+ if(pv->X==2.75 && pv->Y==0.25) printf("%e %e %e : %d\n",pv->X,pv->Y,pv->Z,pv->iD);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (
+ std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+
+ // the use of allocation is done due to ms visual c++ compiler
+ // that due not support c99 standard (it uses the c95 et c++98 standards)
+ int* ntrans = new int[deperiodic.nbRefPeriodic()];
+ for(int kk = 0 ; kk<deperiodic.nbRefPeriodic() ; kk++) {
+ ntrans[kk] = 0;
+ }
+ int nump = EN_id((pEntity) pv);
+ pVertex pnump = pv;
+ for(unsigned int k=0 ; k<(*recup).size() ; k++) {
+ if ( nump > EN_id((pEntity) (*recup)[k].second) ) {
+ nump = EN_id((pEntity) (*recup)[k].second);
+ pnump = (*recup)[k].second;
+ for(unsigned int j=0 ; j<(*recup)[k].first.size() ; j++) ntrans[j] = (-1) * (*recup)[k].first[j];
+ }
+ }
+ if (nump == EN_id((pEntity) pv)) {
+ fprintf(f, "%d %g %g %g\n", pv->iD, pv->X, pv->Y, pv->Z);
+ } else {
+ double X,Y,Z;
+ X = pnump->X;
+ Y = pnump->Y;
+ Z = pnump->Z;
+ for(int kk = 0 ; kk<deperiodic.nbRefPeriodic() ; kk++) {
+ if(ntrans[kk]){
+ int inv1 = (ntrans[kk] < 0) ? 1 : 0;
+ for(int nb = 0 ; nb<abs(ntrans[kk]) ; nb++) { //nb de fois qu'il faut appliquer la transfo
+ deperiodic.fperiodic(inv1,X,Y,Z,kk+1,&X,&Y,&Z);
+ }
+ }
+ }
+ fprintf(f, "%d %g %g %g\n", pv->iD, X, Y, Z);
+ if((fabs(X-pv->X) > 1e-12) || (fabs(Y-pv->Y) > 1e-12) || (fabs(Z-pv->Z) > 1e-12) ) {
+ printf("point %d : %e %e %e \n",EN_id((pEntity) pv),pv->X, pv->Y, pv->Z);
+ printf("-- corresp %d : %e %e %e\n",nump,pnump->X,pnump->Y,pnump->Z);
+ printf("*end* %e %e %e\n",X,Y,Z);
+ }
+ }
+ delete [] ntrans;
+ } else {
+ fprintf(f, "%d %g %g %g\n", pv->iD, pv->X, pv->Y, pv->Z);
+ }
+ }
+ else
+ {
+ NN++;
+ fprintf(f, "%d %g %g %g\n", pv->iD, pv->X, pv->Y, pv->Z);
+ }
+ // throw;
+ }
+ if (NN != m->nbPoints)
+ {
+ printf("%d != %d\n",NN,m->nbPoints);
+ throw;
+ }
+ VIter_delete(vit);
+ fprintf(f, "$ENDNOD\n");
+ }
+ {
+ fprintf(f, "$ELM\n");
+
+ int nbClasEdges = 0;
+ int nbClasFaces = 0;
+ {
+ EIter eit = M_edgeIter(m);
+ pEdge pe;
+ while ((pe = EIter_next(eit)))
+ {
+ int dim = GEN_type(pe->g);
+ if(dim == 1)nbClasEdges++;
+ }
+ EIter_delete(eit);
+ }
+ {
+ FIter fit = M_faceIter(m);
+ pFace pf;
+ while ((pf = FIter_next(fit)))
+ {
+ int dim = GEN_type(pf->g);
+ if(dim == 2)nbClasFaces++;
+ else if(F_numRegions(pf)==1) nbClasFaces++;
+ }
+ FIter_delete(fit);
+ }
+
+ fprintf(f, "%ld\n", (long int)(nbClasEdges + nbModelVertex + nbClasFaces + m->nbTets) );
+
+ int k = 1;
+ {
+ VIter vit = M_vertexIter(m);
+ pVertex pv;
+ while ((pv = VIter_next(vit)))
+ {
+ if(pv->g)
+ {
+ int dim = GEN_type(pv->g);
+ int tag = GEN_tag (pv->g);
+ int phys = gentity2phys.get_first_tag(pv->g);
+
+ if(dim == 0)
+ fprintf(f, "%d %d %d %d %d %d\n",
+ k++, 15, phys,tag, 1,pv->iD);
+ }
+ }
+ VIter_delete(vit);
+ }
+ {
+ EIter eit = M_edgeIter(m);
+ pEdge pe;
+ while ((pe = EIter_next(eit)))
+ {
+ if(pe->g)
+ {
+ int dim = GEN_type(pe->g);
+ int tag = GEN_tag (pe->g);
+ int phys = gentity2phys.get_first_tag(pe->g);
+
+ if(dim ==1)
+ fprintf(f, "%d %d %d %d %d %d %d\n", k++, 1, phys,tag, 2,pe->p1->iD, pe->p2->iD);
+ }
+ }
+ EIter_delete(eit);
+ }
+ {
+ FIter fit = M_faceIter(m);
+ pFace pf;
+ while ((pf = FIter_next(fit)))
+ {
+ if(pf->g)
+ {
+ MDB_Point *nod[4];
+ int dim = GEN_type(pf->g);
+ int tag = GEN_tag (pf->g);
+ int phys = gentity2phys.get_first_tag(pf->g);
+
+ pf->getNodes(nod);
+ if(dim == 2 || F_numRegions(pf)==1){
+ if (0 && nod[3]) //quad
+ fprintf(f, "%d %d %d %d %d %d %d %d %d\n",
+ k++, 3, phys,tag, 4,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD);
+ else //triangle
+ fprintf(f, "%d %d %d %d %d %d %d %d\n",
+ k++, 2, phys,tag, 3,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD);
+
+ }
+ }
+ }
+ FIter_delete(fit);
+ }
+ {
+ RIter rit = M_regionIter(m);
+ pRegion pr;
+ while ((pr = RIter_next(rit)))
+ {
+ if(pr->g)
+ {
+ MDB_Point *nod[8];
+ //int dim = GEN_type(pr->g);
+ int tag = GEN_tag (pr->g);
+ int phys = gentity2phys.get_first_tag(pr->g);
+
+ int numVer = pr->getNbVertex();
+ pPList ll = R_vertices(pr);
+ for(int i=0;i<numVer;i++) nod[i] = (pVertex)PList_item(ll, i);
+ PList_delete(ll);
+
+ if(numVer==4) fprintf(f, "%d %d %d %d %d %d %d %d %d\n", k++, 4, phys,tag, 4,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD);
+ else if(numVer==8) fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d %d\n", k++, 5, phys,tag, 5,
+ nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD, nod[4]->iD, nod[5]->iD, nod[6]->iD, nod[7]->iD);
+ }
+ }
+ RIter_delete(rit);
+ }
+ fprintf(f, "$ENDELM\n");
+ {
+ int nperiodic = 0,nref = 0;;
+ VIter vit = M_vertexIter(m);
+ pVertex pv;
+ while ((pv = VIter_next(vit)))
+ {
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ if(!nperiodic) {
+ nref = (*recup)[0].first.size();
+ }
+ nperiodic+=(*recup).size();
+ }
+ }
+ VIter_delete(vit);
+ if(nperiodic) {
+ fprintf(f, "$PERIODICNOD\n");
+ fprintf(f, "%d %d\n", nperiodic,nref);
+ int num = 1;
+ vit = M_vertexIter(m);
+ while ((pv = VIter_next(vit)))
+ {
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ for(unsigned int k=0 ; k<(*recup).size() ; k++) {
+ fprintf(f, "%d", num++);
+ for(unsigned int j=0 ; j<(*recup)[k].first.size() ; j++) fprintf(f, " %d", (*recup)[k].first[j]);
+ fprintf(f, " %d %d \n", EN_id((pEntity) pv),EN_id((pEntity) (*recup)[k].second));
+ }
+ //delete recup;
+ //EN_deleteData((pEntity) pv , tagPeriodic);
+ }
+ }
+ VIter_delete(vit);
+ fprintf(f, "$ENDPERIODICNOD\n");
+ }
+ }
+ }
+ fclose(f);
+ //MD_deleteMeshDataId(tagPeriodic);
+
+ }
+
+}
+
+
+
+ /*
+// -------------------------------------------------------------------
+// Old loader (no parallel)
+// -------------------------------------------------------------------
+
+void LoadGmshMesh (pMesh m,const char *filename, int version)
+{
+ FILE *fp = fopen(filename, "r");
+ int isperiodic=0;
+ pMeshDataId tagPeriodic = MD_newMeshDataId("PeriodicPoint");
+ if(!fp)
+ {
+ Msg(MDB_FATAL,"Unknown File %s\n",filename);
+ }
+ char String[256];
+ if (!m->model)
+ m->model = new NullModel;
+
+ while(1) {
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$');
+
+ if(feof(fp))
+ break;
+
+ if(!strncmp(&String[1], "MeshFormat", 10)) {
+ int a, b, c;
+ fscanf(fp, "%d %d %d", &a, &b, &c);
+ version = a;
+ }
+
+ if(!strncmp(&String[1], "NOD", 3) ||
+ !strncmp(&String[1], "NOE", 3) ||
+ !strncmp(&String[1], "Nodes", 5)) {
+
+ int Nbr_Nodes,Num;
+ double x,y,z;
+ fscanf(fp, "%d", &Nbr_Nodes);
+ for(int i_Node = 0; i_Node < Nbr_Nodes; i_Node++) {
+ fscanf(fp, "%d %lf %lf %lf", &Num, &x, &y, &z);
+ m->add_point (Num,x,y,z);
+ }
+ }
+
+ // ELEMENTS
+
+ else if(!strncmp(&String[1], "ELM", 3) ||
+ !strncmp(&String[1], "Elements", 8)) {
+ int Nbr_Elements, NbTags, verts[256],Tag;
+ int Num, Type, Physical, Elementary, Nbr_Nodes, Partition;
+ fscanf(fp, "%d", &Nbr_Elements);
+
+ for(int i_Element = 0; i_Element < Nbr_Elements; i_Element++) {
+
+ if(version == 1){
+ fscanf(fp, "%d %d %d %d %d",
+ &Num, &Type, &Physical, &Elementary, &Nbr_Nodes);
+ Partition = 1;
+ }
+ else{
+ fscanf(fp, "%d %d %d", &Num, &Type, &NbTags);
+ Elementary = Physical = Partition = 1;
+ for(int j = 0; j < NbTags; j++){
+ fscanf(fp, "%d", &Tag);
+ if(j == 0)
+ Physical = Tag;
+ else if(j == 1)
+ Elementary = Tag;
+ else if(j == 2)
+ Partition = Tag;
+ // ignore any other tags for now
+ }
+ Nbr_Nodes = getNumVerticesForElementTypeMSH(Type);
+ }
+
+ for(int j = 0; j < Nbr_Nodes; j++)
+ fscanf(fp, "%d", &verts[j]);
+
+ GEntity *geom = 0;
+
+ switch (Type) {
+ case 1:
+ {
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(verts[0],verts[1],geom);
+ }
+ break;
+ case 8:
+ {
+ geom = m->model->edgeByTag(Elementary);
+ //m->add_edge(verts[0],verts[2],verts[1],geom);
+ m->add_edge(3,geom,verts[0],verts[2],verts[1]);
+ //m->add_edge(verts[0],verts[1],ge);
+ }
+ break;
+ case 26:
+ {
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(4,geom, verts[0],verts[2],verts[3],verts[1]);
+ }
+ break;
+ case 27:
+ {
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(5,geom, verts[0],verts[2],verts[3],verts[4],verts[1]);
+ }
+ break;
+ case 28:
+ {
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(6,geom, verts[0],verts[2],verts[3],verts[4],verts[5],verts[1]);
+ }
+ break;
+ case 2:
+ {
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(verts[0],verts[1],verts[2],geom);
+ }
+ break;
+// 6 nodes triangle
+ case MSH_TRI_6:
+ {
+ geom = m->model->faceByTag(Elementary);
+ // printf ("adding a second order triangle %d %d %d %d %d %d\n",verts[0],verts[1],verts[2],verts[3],verts[4],verts[5]);
+ m->add_triangle(2,0,geom,verts[0],verts[3],verts[1],verts[4],verts[2],verts[5]);
+ //m->add_triangle(verts[0],verts[3],verts[1],verts[4],verts[2],verts[5],geom);
+ //m->add_triangle(verts[0],verts[1],verts[2],gf);
+ }
+ break;
+// 9 nodes triangle (SERENDIP !)
+ case MSH_TRI_9:
+ {
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(3,0,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8]);
+ //m->add_triangle(verts[0],verts[3],verts[1],verts[4],verts[2],verts[5],geom);
+ }
+ break;
+// 10 nodes triangle (LAGRANGE !)
+ case MSH_TRI_10:
+ {
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(3,1,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8],verts[9]);
+ }
+ break;
+// 12 nodes triangle (SERENDIP !)
+ case MSH_TRI_12:
+ {
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(4,0,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11]);
+ }
+ break;
+// 15 nodes triangle (LAGRANGE !)
+ case MSH_TRI_15:
+ {
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(4,1,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11],verts[12],verts[13],verts[14]);
+ }
+ break;
+// 15 nodes triangle (SERENDIP !)
+ case MSH_TRI_15I:
+ {
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(5,0,geom,verts[0],verts[3],verts[4],verts[5],verts[6],verts[1],verts[7],verts[8],verts[9],verts[10],verts[2],verts[11],verts[12],verts[13],verts[14]);
+ }
+ break;
+ case 3:
+ {
+ geom = m->model->faceByTag(Elementary);
+ m->add_quad(verts[0],verts[1],verts[2],verts[3],geom);
+ }
+ break;
+ case 4:
+ {
+ geom = m->model->regionByTag(Elementary);
+ m->add_tet(verts[0],verts[1],verts[2],verts[3],geom);
+ }
+ break;
+ case 6:
+ {
+ geom = m->model->regionByTag(Elementary);
+ m->add_prism(verts[0],verts[1],verts[2],
+ verts[3],verts[4],verts[5],geom);
+ }
+ break;
+ case 15:
+ {
+ geom = m->model->vertexByTag(Elementary);
+ MDB_Point *p = m->find_point(verts[0]);
+ p->g = geom;
+ }
+ break;
+// 8 nodes hexahedron
+ case 5:
+ {
+ geom = m->model->regionByTag(Elementary);
+ m->add_hex(verts[0],verts[1],verts[2],verts[3],verts[4],verts[5],verts[6],verts[7],geom);
+ }
+ break;
+ // 10 node tetrahedron, 2nd order
+ case MSH_TET_10:
+ {
+ geom = m->model->regionByTag(Elementary);
+ m->add_tet(geom,2,false,verts);
+ break;
+ }
+ default:
+ throw;
+ break;
+ }
+ if (geom)
+ {
+ bool find = false;
+ for (std::multimap<int, pGEntity>::iterator it = m->geomFeatures_Tags.lower_bound(Physical);
+ it != m->geomFeatures_Tags.upper_bound(Physical);++it)
+ if (it->second == geom)find = true;
+ if (!find)
+ m->geomFeatures_Tags.insert(std::pair<int,pGEntity>(Physical, geom));
+ }
+ }
+ }
+ else if(!strncmp(&String[1], "PERIODICNOD", 11)) {
+ isperiodic = 1;
+ }
+ else if(!strncmp(&String[1], "TRA", 3)) {
+ isperiodic = 2;
+ }
+
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ throw;
+ if(feof(fp))
+ throw;
+ } while(String[0] != '$');
+ }
+
+ m->classify_unclassified_entities();
+
+ m->destroyStandAloneEntities();
+
+ if(isperiodic) {
+ if(isperiodic==1) {
+ fseek(fp,0,SEEK_SET);
+ while(1) {
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$');
+
+ if(feof(fp))
+ break;
+ if(!strncmp(&String[1], "PERIODICNOD", 11)) {
+ int nPeriod,nRefPeriod;
+ fscanf(fp, "%d %d", &nPeriod,&nRefPeriod);
+ printf("%d Ref Periodic\n",nRefPeriod);
+ int *t=new int[nRefPeriod];
+ for(int ip = 0; ip < nPeriod; ip++) {
+ int Num,v1,v2;
+ fscanf(fp, "%d ", &Num);
+ std::vector<int> transfo;
+ std::vector<int> invtransfo;
+ for(int k=0 ; k<nRefPeriod ; k++) {
+ fscanf(fp, "%d ", &t[k]);
+ transfo.push_back(t[k]);
+ invtransfo.push_back(-t[k]);
+ }
+ fscanf(fp, "%d %d",&v1, &v2);
+ pVertex vt1 = m->find_point(v1);
+ pVertex vt2 = m->find_point(v2);
+//printf("point %d %d\n",EN_id((pEntity) vt1),EN_id((pEntity) vt2));
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) vt1 , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ unsigned int i=0;
+ for(i=0 ; i<(*recup).size() ; i++) {
+ unsigned int j=0;
+ for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+ if((*recup)[i].first[j] != transfo[j]) break;
+ }
+ if(j==(*recup)[i].first.size() ) break;
+ }
+ if(i==(*recup).size())
+ (*recup).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+ } else {
+ std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+ (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+ EN_attachDataPtr((pEntity) vt1 , tagPeriodic,
+ new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+
+ }
+
+ isPeriodic = EN_getDataPtr((pEntity) vt2 , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ unsigned int i;
+ for(i=0 ; i<(*recup).size() ; i++) {
+ unsigned int j;
+ for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+ if((*recup)[i].first[j] != invtransfo[j]) break;
+ }
+ if(j==(*recup)[i].first.size() ) break;
+ }
+ if(i==(*recup).size())
+ (*recup).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+ } else {
+ std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+ (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+ EN_attachDataPtr((pEntity) vt2 , tagPeriodic,
+ new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+ }
+ }
+ delete []t;
+ }
+ }
+ } else {
+ assert(isperiodic==2);
+ puts("format periodic CENAERO");
+ fseek(fp,0,SEEK_SET);
+ while(1) {
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$');
+
+ if(feof(fp))
+ break;
+ if(!strncmp(&String[1], "PER", 3)) {
+ int nPeriod,nRefPeriod;
+ nRefPeriod = 1;
+ fscanf(fp, "%d ", &nPeriod);
+ printf("%d Ref Periodic\n",nRefPeriod);
+ int *t=new int[nRefPeriod];
+ for(int ip = 0; ip < nPeriod; ip++) {
+ int Num,v1,v2;
+ fscanf(fp, "%d ", &Num);
+ std::vector<int> transfo;
+ std::vector<int> invtransfo;
+ fscanf(fp, "%d %d %d",&v1, &v2,&Num);
+ pVertex vt1 = m->find_point(v1);
+ pVertex vt2 = m->find_point(v2);
+
+
+ printf("point %d (%d) %d (%d)\n",EN_id((pEntity) vt1),GEN_tag(vt1->g),EN_id((pEntity) vt2),
+ GEN_tag(vt2->g));
+ if(GEN_tag(vt1->g)==132 || GEN_tag(vt1->g)==130 || GEN_tag(vt1->g)== 118 || GEN_tag(vt1->g)== 117) {
+ for(int k=0 ; k<nRefPeriod ; k++) {
+ t[k]=-1;
+ transfo.push_back(t[k]);
+ invtransfo.push_back(-t[k]);
+ }
+
+ } else {
+ assert(GEN_tag(vt1->g)==348 || GEN_tag(vt1->g)==31
+ || GEN_tag(vt1->g)== 93 || GEN_tag(vt1->g)== 345
+ || GEN_tag(vt1->g)== 29 || GEN_tag(vt1->g)== 94
+ || GEN_tag(vt1->g)== 16 || GEN_tag(vt1->g)== 66
+ || GEN_tag(vt1->g)== 13 || GEN_tag(vt1->g)== 74
+ || GEN_tag(vt1->g)== 115 || GEN_tag(vt1->g)== 351
+ || GEN_tag(vt1->g)== 116);
+ for(int k=0 ; k<nRefPeriod ; k++) {
+ t[k]=1;
+ transfo.push_back(t[k]);
+ invtransfo.push_back(-t[k]);
+ }
+
+ }
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) vt1 , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ unsigned int i=0;
+ for(i=0 ; i<(*recup).size() ; i++) {
+ unsigned int j=0;
+ for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+ if((*recup)[i].first[j] != transfo[j]) break;
+ }
+ if(j==(*recup)[i].first.size() ) break;
+ }
+ if(i==(*recup).size())
+ (*recup).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+ } else {
+ std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+ (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+ EN_attachDataPtr((pEntity) vt1 , tagPeriodic,
+ new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+
+ }
+
+ isPeriodic = EN_getDataPtr((pEntity) vt2 , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ unsigned int i;
+ for(i=0 ; i<(*recup).size() ; i++) {
+ unsigned int j;
+ for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+ if((*recup)[i].first[j] != invtransfo[j]) break;
+ }
+ if(j==(*recup)[i].first.size() ) break;
+ }
+ if(i==(*recup).size())
+ (*recup).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+ } else {
+ std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+ (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+ EN_attachDataPtr((pEntity) vt2 , tagPeriodic,
+ new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+ }
+ }
+ delete []t;
+ }
+
+ }
+ }
+ }
+
+ // compute parametric coordinates of vertices on
+// VIter vit = M_vertexIter(m);
+// pVertex pv;
+// while (pv = VIter_next(vit))
+// {
+// int vType=V_whatInType(pv);
+// if(vType==1)
+// {
+// double xyz[3];
+// V_coord(pv, xyz);
+// pGEdge pge = (pGEdge) EN_whatIn(pv);
+// double par = pge->parFromPoint(SPoint3(xyz[0],xyz[1],xyz[2]));
+// printf("parametric coord is %12.5E\n",par);
+// P_setParam1(pv, par);
+// }
+// }
+ fclose(fp);
+}
+
+
+
+*/
+
diff --git a/Mesh/MeshDataBaseIO.h b/Mesh/MeshDataBaseIO.h
new file mode 100644
index 0000000..3524e4d
--- /dev/null
+++ b/Mesh/MeshDataBaseIO.h
@@ -0,0 +1,44 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere, Cecile Dobrzynski
+// -------------------------------------------------------------------
+
+#ifndef _LOADGMSHMESH_H_
+#define _LOADGMSHMESH_H_
+
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseCommPeriodic.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+
+ // Load a Gmsh mesh
+ // - msh1 or msh2
+ // - serial or parallel (format msh2 for parallel)
+ // - periodic or non-periodic
+ void LoadGmshMesh (MAd::pMesh, const char *);
+
+ // Save a mesh
+ // - msh1 or msh2
+ // - serial only
+ // - If a partitioning table is submitted,
+ // write the right partition numbers in the file
+ void SaveGmshMesh (const MAd::pMesh, const char *, int version=2,
+ const int * partitionTable=NULL);
+
+ void SaveGmshMeshPer (const MAd::pMesh, const char *, MDB_DataExchangerPeriodic &deperiodic,int version=1);
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseInterface.cc b/Mesh/MeshDataBaseInterface.cc
new file mode 100644
index 0000000..b13422b
--- /dev/null
+++ b/Mesh/MeshDataBaseInterface.cc
@@ -0,0 +1,2905 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere, Koen Hillewaert
+// -------------------------------------------------------------------
+
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "MeshDataBase.h"
+#include "MeshDataBaseIO.h"
+#include "PList.h"
+#include "ParallelUtils.h"
+#include "MAdDefines.h"
+#include "MathUtils.h"
+#include <string>
+#include <map>
+#ifdef PARALLEL
+#include "MeshDataBaseParallelIO.h"
+#endif
+#include "MAdMessage.h"
+#include "MAdSingleton.h"
+
+#include <sstream>
+
+/*! \defgroup mesh Mesh operations */
+/*! \defgroup entity Entity operations */
+/*! \defgroup region Region operations */
+/*! \defgroup face Face operations */
+/*! \defgroup edge Edge operations */
+/*! \defgroup vertex Vertex operations */
+/*! \defgroup point Point operations */
+/*! \defgroup ios Mesh in- and output */
+/*! \defgroup parallel Communication */
+/*! \defgroup internal Internal routines */
+
+typedef MAdSingleton< std::map <std::string, unsigned int> > attachableDataIds;
+typedef MAdSingleton< std::map <unsigned int, std::string > > attachableDataIds_rev;
+
+namespace MAd {
+
+ pMeshDataId newMeshDataId(const std::string tag)
+ {
+ std::string tag2;
+ if ( !strcmp(tag.c_str(),"") ) {
+ tag2 = "X";
+ bool unique = false;
+ while ( !unique )
+ {
+ std::map<std::string, unsigned int>::iterator iter = (attachableDataIds::instance()).find(tag2);
+ if(iter != (attachableDataIds::instance()).end()) {
+ tag2 = tag2 + "X";
+ }
+ else unique = true;
+ }
+ }
+ else tag2 = tag;
+
+ std::map<std::string, unsigned int>::iterator iter = (attachableDataIds::instance()).find(tag2);
+ if(iter != (attachableDataIds::instance()).end()) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Mesh data id with tag \'%s\' already exists",tag2.c_str());
+ return (*iter).second;
+ }
+ if((attachableDataIds::instance()).empty())
+ {
+ (attachableDataIds_rev::instance())[1] = tag2;
+ (attachableDataIds::instance()) [tag2] = 1;
+ return 1;
+ }
+ else
+ {
+ unsigned int biggest = (*(--(attachableDataIds_rev::instance()).end())).first;
+ (attachableDataIds_rev::instance())[biggest+1] = tag2;
+ (attachableDataIds::instance()) [tag2] = biggest+1;
+ return biggest+1;
+ }
+ }
+
+ pMeshDataId MD_newMeshDataId(const std::string tag)
+ {
+ return newMeshDataId(tag);
+ }
+
+ pMeshDataId MD_lookupMeshDataId(const std::string tag) {
+ std::map <std::string, unsigned int>::const_iterator it =
+ (attachableDataIds::instance()).find(tag);
+ if(it == (attachableDataIds::instance()).end())return newMeshDataId(tag);
+ return (*it).second;
+ }
+
+ void MD_deleteMeshDataId(pMeshDataId id) {
+ (attachableDataIds::instance()).erase((attachableDataIds_rev::instance())[id]);
+ (attachableDataIds_rev::instance()).erase(id);
+ }
+
+ //! Returns type/dimension of element pe \ingroup entity
+ int EN_type(pEntity pe)
+ {
+ return pe->getDim();
+ }
+
+ //! Remove data with tag t from element pe \ingroup entity
+
+ void EN_removeData(pEntity pe, const char *t)
+ {
+ unsigned int itag = MD_lookupMeshDataId(t);
+ pe->deleteData (itag);
+ }
+
+ //! Add pointer data to element pe with tag \ingroup entity
+ void EN_attachDataP(pEntity pe, const char *tag, void *data)
+ {
+ unsigned int itag = MD_lookupMeshDataId(tag);
+ EN_attachDataPtr(pe, itag, data);
+ }
+
+ //! Remove data with tag id from element pe \ingroup entity
+ void EN_deleteData(pEntity pe, pMeshDataId id)
+ {
+ pe->deleteData (id);
+ }
+
+ //! Replace data with tag id with value \ingroup entity
+ void EN_modifyDataPtr(pEntity ent, pMeshDataId id, void * value)
+ {
+ EN_attachDataPtr(ent, id, value);
+ }
+
+ //! Add pointer data to element pe with tag \ingroup entity
+ void EN_attachDataPtr(pEntity pe, pMeshDataId id, void * value)
+ {
+ mAttachableVoid *av = (mAttachableVoid *)pe->getData(id);
+ if(!av)
+ {
+ av = new mAttachableVoid;
+ pe->attachData(id,av);
+ }
+ av->veryNastyPointer = value;
+ }
+
+ //! Get pointer data with tag from element \ingroup entity
+ void * EN_dataP(pEntity pe, const char *tag)
+ {
+ unsigned int itag = MD_lookupMeshDataId(tag);
+ mAttachableVoid *av = (mAttachableVoid *)pe->getData(itag);
+ if(!av)return 0;
+ return av->veryNastyPointer;
+ }
+
+ //! Replace data with tag id with value \ingroup entity
+ int EN_modifyDataP(pEntity pe, const char *tag, void * data)
+ {
+ EN_attachDataP(pe, tag, data);
+ return 1;
+ }
+
+
+ //! Add integer data with tag id to element pe \ingroup entity
+ void EN_attachDataI(pEntity pe, const char *tag, int data)
+ {
+ pe->attachInt(MD_lookupMeshDataId(tag),data);
+ }
+
+ //! Add integer data with tag id to element pe \ingroup entity
+ void EN_attachDataInt(pEntity pe, pMeshDataId id, int data)
+ {
+ pe->attachInt(id,data);
+ }
+
+ //! Get integer data with tag id from element pe \ingroup entity
+ int EN_dataI(pEntity pe, const char *tag)
+ {
+ return pe->getAttachedInt(MD_lookupMeshDataId(tag));
+ }
+
+
+ //! Get floating precision data pointer with tag id from element pe \ingroup entity
+ int EN_getDataDbl(pEntity ent, pMeshDataId id, double *value)
+ {
+ mAttachableDouble *ai = (mAttachableDouble *)ent->getData(id);
+ if(!ai)return 0;
+ *value = ai->d;
+ return 1;
+ //*value = ent->getAttachedDouble(id);
+ //return 1;
+ }
+
+ //! Add floating precision data pointer with tag id to element pe \ingroup entity
+ void EN_attachDataDbl(pEntity ent, pMeshDataId id, double value)
+ {
+ ent->attachDouble(id,value);
+ }
+
+
+ //! Modify floating precision data pointer with tag id in element pe \ingroup entity
+ void EN_modifyDataDbl(pEntity ent, pMeshDataId id, double value)
+ {
+ ent->attachDouble(id,value);
+ }
+
+ //! Modify integer data with tag id in element pe \ingroup entity
+ int EN_modifyDataI(pEntity pe, const char *tag, int data)
+ {
+ pe->attachInt(MD_lookupMeshDataId(tag),data);
+ return 1;
+ }
+
+ //! Modify integer data with tag id in element pe \ingroup entity
+ void EN_modifyDataInt(pEntity ent, pMeshDataId id, int value)
+ {
+ ent->attachInt(id,value);
+ }
+
+
+ //! Get address of data pointer with tag id in element pe \ingroup entity
+ int EN_getDataPtr(pEntity ent, pMeshDataId id, void **value)
+ {
+
+ mAttachableVoid *av = (mAttachableVoid *)ent->getData(id);
+ if(!av)return 0;
+ *value = av->veryNastyPointer;
+ return 1;
+ }
+
+ //! Get integer data with tag id from element pe \ingroup entity
+ int EN_getDataInt(pEntity ent, pMeshDataId id, int *value)
+ {
+ mAttachableInt *ai = (mAttachableInt *)ent->getData(id);
+ (*value) = 0;
+ if(!ai)return 0;
+ *value = ai->i;
+ return 1;
+
+ //*value = ent->getAttachedInt(id);
+ //if(*value)return 1;
+ //return 0;
+ }
+
+ pMesh M_new(pGModel pm)
+ {
+ pMesh m = new MDB_Mesh;
+ m->model = pm;
+ return m;
+ }
+
+ void M_delete(pMesh pm)
+ {
+ if (pm) { delete pm; pm=NULL; }
+ }
+
+ //! Load a mesh from a file \ingroup ios
+ //! - msh1 or msh2
+ //! - serial or parallel (format msh2 for parallel)
+ //! - periodic or non-periodic
+ void M_load(pMesh pm, const char *filename)
+ {
+ LoadGmshMesh (pm, filename);
+
+ pMeshDataId remoteTag = MD_lookupMeshDataId("RemotePoint");
+
+ V_createInfoInterface(pm,remoteTag);
+ E_createInfoInterface(pm,remoteTag);
+ F_createInfoInterface(pm,remoteTag);
+
+ }
+
+ //! Save a mesh \ingroup ios
+ //! - msh1 or msh2
+ //! - serial or parallel
+ //! - If a partitioning table is submitted,
+ //! write the right partition numbers in the file
+ void M_writeMsh(const pMesh mesh, const char *name,
+ int version, const int * partitionTable)
+ {
+#ifdef PARALLEL
+ SaveGmshMeshParallel (mesh, name, version);
+#else
+ SaveGmshMesh (mesh, name, version, partitionTable);
+#endif
+ }
+
+ //! Save a periodic mesh \ingroup ios
+ void M_writeMshPer(pMesh mesh, const char *name, MDB_DataExchangerPeriodic &deperiodic, int version)
+ {
+ SaveGmshMeshPer(mesh,name,deperiodic,version);
+ }
+
+ //! returns geometric model \ingroup mesh
+ pGModel M_model(pMesh mesh)
+ {
+ return mesh->model;
+ }
+
+ //! reduces the mesh to its minimal datastructure \ingroup mesh
+ void M_shrink(pMesh mesh)
+ {
+ mesh->shrink();
+ }
+
+ //! reverts the mesh to its usable form \ingroup mesh
+ void M_expand(pMesh mesh)
+ {
+ mesh->expand();
+ }
+
+ //! removes all deleted entities - clean up \ingroup mesh
+ void M_clean(pMesh mesh)
+ {
+ RIter rIter = M_regionIter(mesh);
+ while ( RIter_next(rIter) ) {}
+ RIter_delete(rIter);
+
+ FIter fIter = M_faceIter(mesh);
+ while ( FIter_next(fIter) ) {}
+ FIter_delete(fIter);
+
+ EIter eIter = M_edgeIter(mesh);
+ while ( EIter_next(eIter) ) {}
+ EIter_delete(eIter);
+
+ VIter vIter = M_vertexIter(mesh);
+ while ( VIter_next(vIter) ) {}
+ VIter_delete(vIter);
+ }
+
+ // -------------------------------------------------------------------
+ //! Dump informations on the mesh \ingroup mesh
+ void M_info(const pMesh mesh, std::ostream& out)
+ {
+ out << "\n";
+ out << "Mesh statistics:\n";
+ out << " Number of regions : " << M_numRegions(mesh) << "\n";
+ out << " Number of faces : " << M_numFaces(mesh) << "\n";
+ out << " Number of edges : " << M_numEdges(mesh) << "\n";
+ out << " Number of vertices: " << M_numVertices(mesh) << "\n";
+ out << "\n";
+ }
+
+ // -------------------------------------------------------------------
+#ifdef _HAVE_METIS_
+ //! Serial function to partition a mesh and write the partitioned mesh to a file in msh2 format \ingroup parallel
+ void M_Partition(pMesh mesh, int nbParts, const char *filename)
+ {
+ PartitionMesh(mesh, nbParts, filename);
+ }
+#endif
+
+ // -------------------------------------------------------------------
+ //! Returns the dimension of the mesh \ingroup mesh
+ int M_dim(pMesh pm)
+ {
+ if ( M_numRegions(pm) > 0 ) return 3;
+ else if ( M_numFaces(pm) > 0 ) return 2;
+ else if ( M_numEdges(pm) > 0 ) return 1;
+ else if ( M_numVertices(pm) > 0 ) return 0;
+ return -1;
+ }
+
+ // -------------------------------------------------------------------
+ //! returns the maximum mapping order for mesh edges \ingroup mesh
+ int M_edgeMaxOrder(pMesh mesh)
+ {
+ EIter eIter = M_edgeIter(mesh);
+ int o = 0;
+ while (pEdge pe = EIter_next(eIter)) o = std::max(o,pe->getOrder());
+ EIter_delete(eIter);
+ return o;
+ }
+
+ //! returns the maximum mapping order for mesh face \ingroup mesh
+ int M_faceMaxOrder(pMesh mesh)
+ {
+ FIter fIter = M_faceIter(mesh);
+ int o = 0;
+ while (pFace pf = FIter_next(fIter)) o = std::max(o,pf->getOrder());
+ FIter_delete(fIter);
+ return o;
+ }
+
+ //! returns the maximum mapping order for mesh regions \ingroup mesh
+ int M_regionMaxOrder(pMesh mesh)
+ {
+ RIter rIter = M_regionIter(mesh);
+ int o = 0;
+ while (pRegion pr = RIter_next(rIter)) o = std::max(o,pr->getOrder());
+ RIter_delete(rIter);
+ return o;
+ }
+
+ //! returns the maximum mapping order for all elements \ingroup mesh
+ int M_maxOrder(pMesh mesh) {
+ return std::max(M_edgeMaxOrder(mesh),
+ std::max(M_faceMaxOrder(mesh),
+ M_regionMaxOrder(mesh)));
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns true if boundary nodes have parametric coordinates \ingroup mesh
+ bool M_isParametric(pMesh mesh)
+ {
+ return mesh->isParametric();
+ }
+
+ // -------------------------------------------------------------------
+ //! returns number of regions in mesh \ingroup mesh \ingroup mesh
+ int M_numRegions(pMesh pm)
+ {
+ return pm->nbTets + pm->nbHexes + pm->nbPrisms;
+ }
+
+ //! returns number of tetrahedra in mesh \ingroup mesh
+ int M_numTets(pMesh pm)
+ {
+ return pm->nbTets;
+ }
+
+ //! returns number of hexahedra in mesh \ingroup mesh
+ int M_numHexes(pMesh pm)
+ {
+ return pm->nbHexes;
+ }
+
+ //! returns number of prism in mesh \ingroup mesh
+ int M_numPrisms(pMesh pm)
+ {
+ return pm->nbPrisms;
+ }
+
+ //! returns number of faces in mesh \ingroup mesh
+ int M_numFaces(pMesh pm)
+ {
+ return pm->nbTriangles + pm->nbQuads;
+ }
+
+ //! returns number of triangles in mesh \ingroup mesh
+ int M_numTriangles(pMesh pm)
+ {
+ return pm->nbTriangles;
+ }
+
+ //! returns number of quadrilaterals in mesh \ingroup mesh
+ int M_numQuads(pMesh pm)
+ {
+ return pm->nbQuads;
+ }
+
+ //! returns number of edges in mesh \ingroup mesh
+ int M_numEdges(pMesh pm)
+ {
+ return pm->nbEdges;
+ }
+
+ //! returns number of vertices in mesh \ingroup mesh
+ int M_numVertices(pMesh pm)
+ {
+ return pm->nbPoints;
+ }
+
+ //! returns number of regions classified on ge \ingroup mesh
+ int M_numClassifiedRegions(pMesh m,pGEntity ge) {
+
+ return countClassifiedElements< MDB_ListT , MDB_Tet , pGEntity> (&m->tets,ge);
+ }
+
+ //! returns number of faces classified on ge \ingroup mesh
+ int M_numClassifiedFaces(pMesh m,pGEntity ge) {
+
+ return countClassifiedElements< MDB_ListF , MDB_Triangle , pGEntity> (&m->triangles,ge);
+ }
+
+ //! returns number of edges classified on ge \ingroup mesh
+ int M_numClassifiedEdges(pMesh m,pGEntity ge) {
+
+ return countClassifiedElements< MDB_ListE , MDB_Edge , pGEntity> (&m->edges,ge);
+ }
+
+ //! returns number of vertices classified on ge \ingroup mesh
+ int M_numClassifiedVertices(pMesh m,pGEntity ge) {
+
+ return countClassifiedElements< MDB_SetV , MDB_Point , pGEntity> (&m->points,ge);
+ }
+
+ //! returns region iterator over mesh \ingroup mesh
+ /*! \warning not thread-safe */
+ RIter M_regionIter(pMesh mesh)
+ {
+ return new MDB_RegionIter (&mesh->tets,&mesh->hexes,&mesh->prisms);
+ }
+
+ //! returns face iterator over mesh \ingroup mesh
+ /*! \warning not thread-safe */
+ FIter M_faceIter(pMesh mesh)
+ {
+ return new MDB_FaceIter (&mesh->triangles,&mesh->quads);
+ }
+
+ //! returns edge iterator over mesh \ingroup mesh
+ /*! \warning not thread-safe */
+ EIter M_edgeIter(pMesh mesh)
+ {
+ return new MDB_EIter (&mesh->edges);
+ }
+
+ //! returns vertex iterator over mesh \ingroup mesh
+ /*! \warning not thread-safe */
+ VIter M_vertexIter(pMesh mesh)
+ {
+ return new MDB_VIter (&mesh->points);
+ }
+
+ //! returns iterator for regions in \e mesh classified on model entity \e pg \ingroup mesh
+ /*!
+ When done with it, should be deleted with function RIter_delete() to avoid
+ memory leaks.
+ */
+ RIter M_classifiedRegionIter(pMesh mesh,pGEntity pg)
+ {
+ return new MDB_RegionIter (&mesh->tets,&mesh->hexes,&mesh->prisms,pg);
+ }
+
+ //! returns iterator for faces in \e mesh classified on model entity \e pg \ingroup mesh
+ /*!
+ The argument \e c (closure) must currently be set to 0. Only the faces directly classified on \e pg will be considered. \n
+ Example: if \e pg is a model region, the mesh faces classified on the model
+ faces bordering \e pg will not be reachable with the present iterator. \n \n
+ When done with it, should be deleted with function FIter_delete() to avoid
+ memory leaks.
+ */
+ FIter M_classifiedFaceIter(pMesh mesh,pGEntity pg,int c)
+ {
+ return new MDB_FaceIter (&mesh->triangles,&mesh->quads,pg,c);
+ }
+
+ //! returns iterator for edges in \e mesh classified on model entity \e pg \ingroup mesh
+ /*!
+ The argument \e c (closure) must currently be set to 0. Only the edges directly classified on \e pg will be considered. \n
+ Example: if \e pg is a model region, the mesh edges classified on the model
+ edges and faces bordering \e pg will not be reachable with the present iterator. \n \n
+ When done with it, should be deleted with function EIter_delete() to avoid
+ memory leaks.
+ */
+ EIter M_classifiedEdgeIter(pMesh mesh,pGEntity pg,int c)
+ {
+ return new MDB_EIter (&mesh->edges,pg,c);
+ }
+
+ //! returns iterator for vertices in \e mesh classified on model entity \e pg \ingroup mesh
+ /*!
+ The argument \e c (closure) must currently be set to 0. Only the vertices directly classified on \e pg will be considered. \n
+ Example: if \e pg is a model region, the mesh vertices classified on the model
+ vertices, edges and faces bordering \e pg will not be reachable with the present iterator. \n \n
+ When done with it, should be deleted with function VIter_delete() to avoid
+ memory leaks.
+ */
+ VIter M_classifiedVertexIter(pMesh mesh,pGEntity pg,int c)
+ {
+ return new MDB_VIter (&mesh->points,pg,c);
+ }
+
+ //! returns vertex in \e mesh classified on model vertex \e pg \ingroup mesh
+ /*!
+ returns 0 if failed
+ */
+ pVertex M_classifiedVertex(pMesh mesh,pGVertex pg)
+ {
+ return (MDB_VIter(&mesh->points,(pGEntity) pg,0)).next();
+ }
+
+ // -------------------------------------------------------------------
+ // Iterators
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ pRegion RIter_next(RIter it)
+ {
+ return it->next();
+ }
+ pFace FIter_next(FIter it)
+ {
+ return it->next();
+ }
+ pEdge EIter_next(EIter it)
+ {
+ return it->next();
+ }
+ pVertex VIter_next(VIter it)
+ {
+ return it->next();
+ }
+
+ // -------------------------------------------------------------------
+ void RIter_reset(RIter it)
+ {
+ it->reset();
+ }
+ void FIter_reset(FIter it)
+ {
+ it->reset();
+ }
+ void EIter_reset(EIter it)
+ {
+ it->reset();
+ }
+ void VIter_reset(VIter it)
+ {
+ it->reset();
+ }
+
+ // -------------------------------------------------------------------
+ void RIter_delete(RIter it)
+ {
+ delete it;
+ }
+ void FIter_delete(FIter it)
+ {
+ delete it;
+ }
+ void EIter_delete(EIter it)
+ {
+ delete it;
+ }
+ void VIter_delete(VIter it)
+ {
+ delete it;
+ }
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // Region operators
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ //! Dumps all informations about the region. \ingroup region
+ void R_info(const pRegion region, std::string name, std::ostream& out)
+ {
+ out << "\nRegion \'" << name << "\' (" << region
+ << ", Id: "<<(int)EN_id((pEntity)region)
+ <<") informations:\n";
+
+ out << " Classification: ";
+ pGEntity pGE = (pGEntity)R_whatIn(region);
+ if (!pGE) {
+ out << "NULL";
+ }
+ else {
+ out << "GEntity: " << pGE
+ << ", dim: " << GEN_type(pGE)
+ << ", tag: " << GEN_tag(pGE);
+ }
+ out << "\n";
+
+ R_info_quality(region, out);
+ R_info_topology(region, out);
+
+ out << "\n";
+ }
+
+ // -------------------------------------------------------------------
+ //! Dumps quality informations about the region. \ingroup region
+ void R_info_quality(const pRegion region, std::ostream& out)
+ {
+ out << " Quality informations:\n";
+ double volume = R_volume(region);
+ out << " Volume : " << volume << "\n";
+ if (volume < 0.) out << " *** Negative volume ***\n";
+ else {
+ out << " r/R ratio : " << R_inscrRad(region)/R_circumRad(region)<< "\n";
+ double meanRatio3;
+ R_meanRatioCube(region,&meanRatio3);
+ out << " Cubic mean ratio : " << meanRatio3 << "\n";
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! Dumps topology informations about the region. \ingroup region
+ void R_info_topology(const pRegion region, std::ostream& out)
+ {
+ out << " Topology informations:\n";
+ out << "\n Faces (ids): type geom ent. tag orient\n";
+ for (int iF=0; iF<R_numFaces(region); iF++) {
+ pFace face = R_face(region,iF);
+ pGEntity pGE = F_whatIn(face);
+ int gTag = pGE ? GEN_tag(pGE) : -1;
+ int gDim = pGE ? GEN_type(pGE) : -1;
+ out << " " << face << " (" << EN_id((pEntity)face) << ") "
+ << gDim << " " << pGE << " " << gTag << " "
+ << R_faceDir(region,iF) << "\n";
+ }
+ out << "\n Edges (ids): type model ent. tag orient\n";
+ pPList rEdges = R_edges(region);
+ void * temp = NULL;
+ while( pEdge edge = (pEdge)PList_next(rEdges,&temp) ) {
+ pGEntity pGE = E_whatIn(edge);
+ int gTag = pGE ? GEN_tag(pGE) : -1;
+ int gDim = pGE ? GEN_type(pGE) : -1;
+ out << " " << edge << " (" << EN_id((pEntity)edge) << ") "
+ << gDim << " " << pGE << " " << gTag << "\n";
+ }
+ PList_delete(rEdges);
+
+ out << "\nVertices (ids): type model ent. tag coordinates\n";
+ pPList rVerts = R_vertices(region);
+ temp = NULL;
+ while( pVertex pV = (pVertex)PList_next(rVerts,&temp) ) {
+ double xyz[3];
+ V_coord(pV,xyz);
+ pGEntity pGE = V_whatIn(pV);
+ int gTag = pGE ? GEN_tag(pGE) : -1;
+ int gDim = pGE ? GEN_type(pGE) : -1;
+ out << " " << pV << " (" << EN_id((pEntity)pV) << ") "
+ << gDim << " " << pGE << " " << gTag << " "
+ << xyz[0] << " " << xyz[1] << " " << xyz[2] << "\n";
+ }
+ PList_delete(rVerts);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns number of faces for region "r" \ingroup region
+ int R_numFaces(pRegion pr)
+ {
+ return pr->getNbFace ();
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns n-th face for region "r" \ingroup region
+ pFace R_face(pRegion pr, int n)
+ {
+ return pr->getFace(n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns number of edges for region "r" \ingroup region
+ int R_numEdges(pRegion pr)
+ {
+ return pr->getNbEdge();
+ }
+
+ // -------------------------------------------------------------------
+ //! Classify region "r" on geometric entity "ge" \ingroup region
+ void R_setWhatIn(pRegion region, pGEntity what)
+ {
+ region->g = what;
+ for (int iF=0; iF<region->getNbFace(); iF++) {
+ pFace face = region->getFace(iF);
+ if ( GEN_type(face->g) > GEN_type(what) ) F_setWhatIn(face,what);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns n-th edge of region "r"
+ pEdge R_edge(pRegion pr, int n)
+ {
+ return pr->getEdge(n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns number of principal vertices in region "r" \ingroup region
+ int R_numVertices(pRegion pr)
+ {
+ return pr->getNbVertex();
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns nth vertex in region "r" \ingroup region
+ pVertex R_vertex(pRegion pr, int n)
+ {
+ return pr->getVertex (n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns 1 if the face normal points outwards of region pr, 0 otherwise \ingroup region
+ int R_faceDir (pRegion pr, int n)
+ {
+ return pr->getFaceDir(n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Determine face orientation with respect to the template of the region "r" \ingroup region
+ /*!
+ \warning Only implemented for tetrahedra
+ Returns s*(n+1), if the face is part of the closure of the region, 0 otherwise \n
+ Here
+ \li n is the number of times we need to rotate the face to correspond
+ with the principal vertex of the face in the element
+ \li s is the sign of the normal with respect to that of the template
+ */
+ int R_faceOri(pRegion pr,int n)
+ {
+ return pr->getFaceOrientation(n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Return a list of ordered edges \ingroup region
+ pPList R_edges(pRegion pr)
+ {
+ pPList pl = PList_new();
+ for (int i=0;i<pr->getNbEdge();i++)
+ PList_append(pl,R_edge(pr,i));
+ return pl;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns a list of ordered faces \ingroup region
+ pPList R_faces(pRegion pr)
+ {
+ pPList pl = PList_new();
+ for (int i=0;i<pr->getNbFace();i++)
+ PList_append(pl,R_face(pr,i));
+ return pl;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns a list of ordered principal vertices \ingroup region
+ pPList R_vertices(pRegion pr)
+ {
+ pPList pl = PList_new();
+ for (int i=0;i<pr->getNbVertex();i++)
+ PList_append(pl,R_vertex(pr,i));
+ return pl;
+ }
+
+ // -------------------------------------------------------------------
+ //! Verify whether or not entity ent is a principal vertex, edge or face of region "r" \ingroup region
+ int R_inClosure(pRegion pr, pEntity ent)
+ {
+ int dim = EN_type (ent);
+ if (dim == 2)
+ {
+ for (int i=0;i<pr->getNbFace();i++)
+ {
+ if (R_face(pr,i)== ent) return 1;
+ }
+ return 0;
+ }
+ else if (dim ==1)
+ {
+ for (int i=0;i<pr->getNbEdge();i++)
+ {
+ if (R_edge(pr,i)== ent) return 1;
+ }
+ return 0;
+ }
+ else if (dim ==0)
+ {
+ for (int i=0;i<pr->getNbVertex();i++)
+ {
+ if (R_vertex(pr,i) == ent) return 1;
+ }
+ return 0;
+ }
+ else throw;
+ }
+
+ // -------------------------------------------------------------------
+ // !return 1 if the face direction points to outside of the tet
+ // !return 0 inside
+ int R_dirUsingFace(pRegion pr, pFace face)
+ {
+ for (int i=0;i<pr->getNbFace();i++)
+ if (pr->getFace(i) == face)
+ return R_faceDir (pr,i);
+ throw;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the orientation of the face pf in region pr \ingroup region
+ /*! Returns -1 if the face is not in the closure of the region */
+ int R_oriUsingFace(pRegion pr, pFace face)
+ {
+ for (int i=0;i<pr->getNbFace();i++)
+ if (pr->getFace(i) == face)
+ return R_faceOri (pr,i);
+ return -1;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns n-th higher order point inside of the region, excluding those in its closure \ingroup region
+ pPoint R_point(pRegion pr, int n)
+ {
+ return pr->getHighOrderPoint (n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the number of higher order points of the region, excluding those in its closure \ingroup region
+ int R_numPoints(pRegion pr)
+ {
+ return pr->getNbHighOrderPoints();
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns 1 if the direction of the edge in pf follows the template, 0 otherwise \ingroup face
+ int F_dirUsingEdge(pFace pf, pEdge edge)
+ {
+ const int nbEdge = pf->getNbEdges ();
+ for (int i=0;i<nbEdge;i++)
+ if (pf->getEdge(i) == edge)
+ return F_edgeDir (pf,i);
+ throw;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the geometrical entity on which the region "r" is classified \ingroup region
+ pGRegion R_whatIn(pRegion pe)
+ {
+ return (pGRegion) pe->g;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the type of the geometrical entity on which region "r" is classified \ingroup region
+ int R_whatInType(pRegion e) { return EN_whatInType(e);}
+
+ // -------------------------------------------------------------------
+ //! Get coordinates of vertices of the region not including high-order points. \ingroup region
+ void R_coordP1(const pRegion region, double xyz[][3])
+ {
+ int iNode = 0;
+
+ // Summits of the region (first order nodes)
+ pPList rVerts = R_vertices(region);
+ void * temp = NULL;
+ while ( pVertex pV = (pVertex)PList_next(rVerts,&temp) ) {
+ V_coord(pV,xyz[iNode]);
+ iNode++;
+ }
+ PList_delete(rVerts);
+ }
+
+ // -------------------------------------------------------------------
+ //! Get coordinates of vertices and high-order points of the region. \ingroup region
+ void R_coord(const pRegion region, double xyz[][3])
+ {
+ // Summits of the region (first order nodes)
+ R_coordP1(region,xyz);
+ int iNode = region->getNbVertex();
+
+ // points on edges (higher order nodes)
+ pPList rEdges = R_edges(region);
+ void * temp = NULL;
+ while ( pEdge edge = (pEdge) PList_next(rEdges, &temp)) {
+ int nEPts = E_numPoints(edge);
+ for (int iEP=0; iEP<nEPts; iEP++) {
+ pPoint pP = E_point(edge,iEP);
+ xyz[iNode][0] = P_x(pP); xyz[iNode][1] = P_y(pP); xyz[iNode][2] = P_z(pP);
+ iNode++;
+ }
+ }
+ PList_delete(rEdges);
+
+ // points on face (higher order nodes)
+ pPList rFaces = R_faces(region);
+ temp = NULL;
+ while ( pFace face = (pFace) PList_next(rFaces, &temp)) {
+ int nFPts = F_numPoints(face);
+ for (int iFP=0; iFP<nFPts; iFP++) {
+ pPoint pP = F_point(face,iFP);
+ xyz[iNode][0] = P_x(pP); xyz[iNode][1] = P_y(pP); xyz[iNode][2] = P_z(pP);
+ iNode++;
+ }
+ }
+ PList_delete(rFaces);
+
+ // points on region (higher order nodes)
+ int nRPts = R_numPoints(region);
+ for (int iRP=0; iRP<nRPts; iRP++) {
+ pPoint pP = R_point(region,iRP);
+ xyz[iNode][0] = P_x(pP); xyz[iNode][1] = P_y(pP); xyz[iNode][2] = P_z(pP);
+ iNode++;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the physical volume of the region. \ingroup region
+ double R_volume(pRegion region)
+ {
+ double xyz[12][3];
+ R_coordP1(region,xyz);
+ return R_XYZ_volume(xyz);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the physical volume of the region with coordinates xyz. \ingroup region
+ double R_XYZ_volume (const double xyz[][3])
+ {
+ double e01[3], e02[3], e03[3];
+ diffVec(xyz[1],xyz[0],e01);
+ diffVec(xyz[2],xyz[0],e02);
+ diffVec(xyz[3],xyz[0],e03);
+ double nor012[3];
+ crossProd(e01,e02,nor012);
+ return ( dotProd(nor012,e03) * MAdSIXTH );
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the circumradius of the region \ingroup region
+ double R_circumRad(const pRegion region)
+ {
+ double xyz[4][3];
+ R_coordP1(region,xyz);
+
+ double edges0x[3][3];
+ for (int i=0; i<3; i++) diffVec(xyz[i+1],xyz[0],edges0x[i]);
+ double detEdgesInv = 1. / ( detMat(edges0x) );
+
+ double edgeMids[3][3];
+ for (int i=0; i<3; i++) {
+ for (int j=0; j<3; j++) {
+ edgeMids[i][j] = (xyz[0][j] + xyz[i+1][j]) * 0.5;
+ }
+ }
+
+ double tmpVec[3];
+ for (int i=0; i<3; i++) tmpVec[i] = dotProd(edges0x[i],edgeMids[i]);
+
+ double center[3];
+ double tmpMat[3][3];
+ for (int i=0; i<3; i++) {
+ tmpMat[i][0] = tmpVec[i];
+ tmpMat[i][1] = edges0x[i][1];
+ tmpMat[i][2] = edges0x[i][2];
+ }
+ center[0] = detMat(tmpMat);
+
+ for (int i=0; i<3; i++) {
+ tmpMat[i][0] = edges0x[i][0];
+ tmpMat[i][1] = tmpVec[i];
+ tmpMat[i][2] = edges0x[i][2];
+ }
+ center[1] = detMat(tmpMat);
+
+ for (int i=0; i<3; i++) {
+ tmpMat[i][0] = edges0x[i][0];
+ tmpMat[i][1] = edges0x[i][1];
+ tmpMat[i][2] = tmpVec[i];
+ }
+ center[2] = detMat(tmpMat);
+
+ for (int i=0; i<3; i++) { center[i] *= detEdgesInv; }
+
+ double tmpVec2[3];
+ diffVec(center,xyz[0],tmpVec2);
+
+ return sqrt( tmpVec2[0]*tmpVec2[0] + tmpVec2[1]*tmpVec2[1] + tmpVec2[2]*tmpVec2[2]);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the inscribed radius of the region \ingroup region
+ double R_inscrRad(const pRegion region)
+ {
+ double xyz[4][3];
+ R_coordP1(region,xyz);
+
+ double edges0x[5][3];
+ for (int i=0; i<3; i++) {
+ diffVec(xyz[i+1],xyz[0],edges0x[i]);
+ }
+ diffVec(xyz[1],xyz[2],edges0x[3]);
+ diffVec(xyz[2],xyz[3],edges0x[4]);
+
+ double tmpVec[3];
+ double A = 0.;
+
+ crossProd(edges0x[0],edges0x[1],tmpVec);
+ A += sqrt( dotProd(tmpVec,tmpVec) ) * 0.5;
+ double V = dotProd(tmpVec,edges0x[2]) * MAdSIXTH;
+ crossProd(edges0x[1],edges0x[2],tmpVec);
+ A += sqrt( dotProd(tmpVec,tmpVec) ) * 0.5;
+ crossProd(edges0x[2],edges0x[0],tmpVec);
+ A += sqrt( dotProd(tmpVec,tmpVec) ) * 0.5;
+ crossProd(edges0x[3],edges0x[4],tmpVec);
+ A += sqrt( dotProd(tmpVec,tmpVec) ) * 0.5;
+
+ return ( 3. * V ) / A;
+ }
+
+ // -------------------------------------------------------------------
+ //! Computes the cubic mean ratio of a region. Returns 0 if negative volume. \ingroup region
+ bool R_meanRatioCube(const pRegion region, double * mrc)
+ {
+ double xyz[4][3];
+ R_coordP1(region,xyz);
+ return R_XYZ_meanRatioCube(xyz,mrc) ;
+ }
+
+ // -------------------------------------------------------------------
+ //! Computes the cubic mean ratio of a region with coordinates xyz. Returns false if negative volume. \ingroup region
+ bool R_XYZ_meanRatioCube(const double xyz[][3], double * mrc)
+ {
+ double edges[6][3];
+ diffVec(xyz[0],xyz[1],edges[0]);
+ diffVec(xyz[0],xyz[2],edges[1]);
+ diffVec(xyz[0],xyz[3],edges[2]);
+ diffVec(xyz[1],xyz[2],edges[3]);
+ diffVec(xyz[1],xyz[3],edges[4]);
+ diffVec(xyz[2],xyz[3],edges[5]);
+
+ // compute the sum of edges length square
+ double lSq = 0.;
+ for (int iE=0; iE<6; iE++) {
+ lSq += dotProd(edges[iE],edges[iE]);
+ }
+
+ // compute volume
+ double vol = R_XYZ_volume(xyz);
+ if ( vol < 0. ) {
+ *mrc = 0.;
+ return false;
+ }
+
+ // compute cubic mean ratio
+ *mrc = 15552. * vol * vol / ( lSq * lSq * lSq );
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ //! Check if the region with coordinates xyz \ingroup region
+ //! is nearly flat or with a negative volume.
+ bool R_XYZ_isFlat(const double xyz[][3])
+ {
+ for(int i=0; i<4; i++) {
+ int ind[3];
+ switch (i) {
+ case 0:
+ ind[0] = 1;
+ ind[1] = 3;
+ ind[2] = 2;
+ break;
+ case 1:
+ ind[0] = 0;
+ ind[1] = 2;
+ ind[2] = 3;
+ break;
+ case 2:
+ ind[0] = 3;
+ ind[1] = 1;
+ ind[2] = 0;
+ break;
+ case 3:
+ ind[0] = 0;
+ ind[1] = 1;
+ ind[2] = 2;
+ break;
+ }
+
+ double v01[3], v02[3];
+ diffVec(xyz[ind[1]],xyz[ind[0]],v01);
+ diffVec(xyz[ind[2]],xyz[ind[0]],v02);
+
+ double normal[3];
+ crossProd(v01,v02,normal);
+ double ASq = dotProd(normal,normal);
+
+ double v0X[3];
+ diffVec(xyz[i],xyz[ind[0]],v0X);
+ double distA = dotProd(v0X,normal);
+
+ if( distA <= 0. || distA*distA < MAdTOL*MAdTOL*ASq) return true;
+ }
+
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the vertex of the region opposite to the face. \ingroup region
+ pVertex R_fcOpVt(const pRegion region, const pFace face)
+ {
+ pVertex opp = NULL;
+
+ pPList fVerts = F_vertices(face,1);
+ pPList rVerts = R_vertices(region);
+
+ void * tempR = NULL;
+ while( pVertex pRV = (pVertex)PList_next(rVerts,&tempR) ) {
+ bool foundVertInFace = false;
+ void * tempF = NULL;
+ while( pVertex pFV = (pVertex)PList_next(fVerts,&tempF) ) {
+ if ( pFV == pRV ) {
+ foundVertInFace = true;
+ break;
+ }
+ }
+ if ( !foundVertInFace ) {
+ opp = pRV;
+ break;
+ }
+ }
+ PList_delete(rVerts);
+ PList_delete(fVerts);
+
+ return opp;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the edge of the region opposite to given edge. \ingroup region
+ pEdge R_gtOppEdg(const pRegion region, const pEdge edge)
+ {
+ assert( region->getNbEdge() == 6 );
+
+ pVertex v0 = E_vertex(edge,0);
+ pVertex v1 = E_vertex(edge,1);
+
+ for (int iE=0; iE<6; iE++) {
+
+ pEdge rEdge = R_edge(region,iE);
+
+ if ( rEdge == edge ) continue;
+
+ pVertex rEV0 = E_vertex(rEdge,0);
+ if ( rEV0 == v0 || rEV0 == v1 ) continue;
+ pVertex rEV1 = E_vertex(rEdge,1);
+ if ( rEV1 == v0 || rEV1 == v1 ) continue;
+
+ return rEdge;
+ }
+
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "could not find opposite edge");
+ throw;
+ return NULL;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the face of the region opposite to the vertex. \ingroup region
+ pFace R_vtOpFc(const pRegion region, const pVertex vertex)
+ {
+ assert( region->getNbFace() == 4 );
+
+ for (int iF=0; iF<R_numFaces(region); iF++ ) {
+ pFace face = R_face(region,iF);
+ pPList fVerts = F_vertices(face,1);
+ if ( PList_inList(fVerts,vertex) ) {
+ PList_delete(fVerts);
+ continue;
+ }
+ PList_delete(fVerts);
+ return face;
+ }
+
+ return NULL;
+ }
+
+ // -------------------------------------------------------------------
+ //! Finds the coordinates in the parent element
+ void R_linearParams(const pRegion pR, const double xyz[3],
+ double res[3])
+ {
+ double rxyz[4][3];
+ R_coordP1(pR,rxyz);
+
+ double mat[3][3];
+ mat[0][0] = rxyz[1][0] - rxyz[0][0];
+ mat[0][1] = rxyz[1][1] - rxyz[0][1];
+ mat[0][2] = rxyz[1][2] - rxyz[0][2];
+ mat[1][0] = rxyz[2][0] - rxyz[0][0];
+ mat[1][1] = rxyz[2][1] - rxyz[0][1];
+ mat[1][2] = rxyz[2][2] - rxyz[0][2];
+ mat[2][0] = rxyz[3][0] - rxyz[0][0];
+ mat[2][1] = rxyz[3][1] - rxyz[0][1];
+ mat[2][2] = rxyz[3][2] - rxyz[0][2];
+
+ double invMat[3][3];
+ inverseMat(mat,invMat);
+
+ double vec[3];
+ diffVec(xyz,rxyz[0],vec);
+
+ vecMat(vec,invMat,res);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the center of a linear region. \ingroup region
+ void R_center(const pRegion region, double center[3])
+ {
+ double rxyz[4][3];
+ R_coordP1(region,rxyz);
+ center[0] = 0.25 * ( rxyz[0][0] + rxyz[1][0] + rxyz[2][0] + rxyz[3][0] );
+ center[1] = 0.25 * ( rxyz[0][1] + rxyz[1][1] + rxyz[2][1] + rxyz[3][1] );
+ center[2] = 0.25 * ( rxyz[0][2] + rxyz[1][2] + rxyz[2][2] + rxyz[3][2] );
+ }
+
+ // -------------------------------------------------------------------
+ // Get the Jacobian of a tetrahedron
+ void R_jacobian(const pRegion region, double jac[3][3])
+ {
+ double xyz[4][3];
+ R_coordP1(region,xyz);
+ for (int i=0; i<3; i++) {
+ jac[i][0] = xyz[1][i] - xyz[0][i];
+ jac[i][1] = xyz[2][i] - xyz[0][i];
+ jac[i][2] = xyz[3][i] - xyz[0][i];
+ }
+ }
+
+ // -------------------------------------------------------------------
+ // Get the inverse of the Jacobian of a tetrahedron
+ // returns the determinant of the Jacobian
+ double R_invJacobian(const pRegion region, double ijac[3][3])
+ {
+ double jac[3][3];
+ R_jacobian(region,jac);
+ return inverseMat(jac,ijac);
+ }
+
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // Face operators
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ //! Dumps informations about the face. \ingroup face
+ void F_info(const pFace face, std::string name, std::ostream& out)
+ {
+ out << "\n";
+ out << "Face \'" << name << "\' " << face
+ << ", id: " << EN_id((pEntity)face) << "\n";
+ out << " Classified on " << face->g
+ << " with dim " << GEN_type(face->g)
+ << " and tag " << GEN_tag(face->g) << "\n";
+
+ out << "\n--- Regions:\n";
+ for (int iR=0; iR<2; iR++) {
+ pRegion region = face->getRegion(iR);
+ if (!region) {
+ out << "Region "<<iR<<": "<<region<<"\n";
+ }
+ else {
+ out << "Region "<<iR<<" (" << region
+ << ", Id: "<<(int)EN_id((pEntity)region)
+ <<") informations:\n";
+ out << " Classification: ";
+ pGEntity pGE = (pGEntity)R_whatIn(region);
+ if (!pGE) {
+ out << "NULL";
+ }
+ else {
+ out << "GEntity: " << pGE
+ << ", dim: " << GEN_type(pGE)
+ << ", tag: " << GEN_tag(pGE);
+ }
+ out << " Vertex opposite to face: \n";
+ V_info(R_fcOpVt(region,face),"",out);
+ out << "\n";
+ }
+ }
+
+ out << "\n--- Edges:\n";
+ for (int iE=0; iE<face->getNbEdges(); iE++) {
+ pEdge edge = face->getEdge(iE);
+ out << "Edge " << iE << ":\n";
+ E_info(edge, "", out);
+ }
+
+// out << "Edge "<<iE<<" ("<< edge <<"), id "
+// << EN_id((pEntity)edge) <<":\n";
+// pGEntity pGE = EN_whatIn((pEntity)edge);
+// out << " - Classification: dim: " << GEN_type(pGE) << ", tag: " << GEN_tag(pGE) << "\n";
+// pVertex pv0 = E_vertex(edge,0);
+// pVertex pv1 = E_vertex(edge,1);
+// pGEntity pGE0 = EN_whatIn((pEntity)pv0);
+// pGEntity pGE1 = EN_whatIn((pEntity)pv1);
+// out << " - Vertices classifications:\n"
+// << " - V0: dim: " << GEN_type(pGE0) << ", tag: " << GEN_tag(pGE0) << "\n"
+// << " - V1: dim: " << GEN_type(pGE1) << ", tag: " << GEN_tag(pGE1) << "\n";
+// out << "\n";
+// }
+ out << "\n";
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns number of edges in pf \ingroup face
+ int F_numEdges(pFace pf)
+ {
+ return pf->getNbEdges();
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns n-th edge in pf \ingroup face
+ pEdge F_edge(pFace pf, int n)
+ {
+ return pf->getEdge(n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns number of vertices in pf \ingroup face
+ int F_numVertices(pFace pf)
+ {
+ return pf->getNbNodes();
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns n-th vertex in pf \ingroup face
+ pVertex F_vertex(pFace pf, int n)
+ {
+ return pf->getNode(n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns 1 if the direction of the n-th edge in pf follows the template, 0 otherwise \ingroup face
+ int F_edgeDir (pFace pf, int n)
+ {
+ pEdge e = F_edge (pf,n);
+ pVertex ve1 = E_vertex (e,0);
+ pVertex ve2 = E_vertex (e,1);
+ pVertex vf1 = F_vertex (pf,n);
+ pVertex vf2 = F_vertex (pf,(n+1)%3);
+ if (ve1 == vf1 && ve2 == vf2) return 1;
+ if (ve2 == vf1 && ve1 == vf2) return 0;
+ throw;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns number of regions referring to pf \ingroup face
+ int F_numRegions(pFace pf)
+ {
+ return pf->getNbRegions();
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the ordered list of vertices of pf \ingroup face
+ //! if dir \< 0 order is inverted, else the template is followed
+ pPList F_vertices(pFace pf, int dir)
+ {
+ pPList pl = PList_new();
+ if (dir<=0)
+ {
+ PList_append(pl,F_vertex(pf,2));
+ PList_append(pl,F_vertex(pf,1));
+ PList_append(pl,F_vertex(pf,0));
+ }
+ else
+ {
+ PList_append(pl,F_vertex(pf,0));
+ PList_append(pl,F_vertex(pf,1));
+ PList_append(pl,F_vertex(pf,2));
+ }
+ return pl;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the ordered list of edges composing the closure of pf \ingroup face
+ pPList F_edges(pFace pf)
+ {
+ pPList pl = PList_new();
+ PList_append(pl,F_edge(pf,0));
+ PList_append(pl,F_edge(pf,1));
+ PList_append(pl,F_edge(pf,2));
+ return pl;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the n-th region attached to pf \ingroup face
+ pRegion F_region(pFace pf, int n)
+ {
+ return pf->getRegion(n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the list of regions attached to pf \ingroup face
+ pPList F_regions(pFace pf)
+ {
+ pPList pl = PList_new();
+ for (int i=0;i<pf->getNbRegions();++i)
+ PList_append(pl,F_region(pf,i));
+ return pl;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the region around 'pf' which is not 'pr' or NULL if none \ingroup face
+ pRegion F_otherRegion(const pFace pf, const pRegion pr)
+ {
+ if ( pf->getRegion(0) == pr ) return pf->getRegion(1);
+ if ( pf->getRegion(1) == pr ) return pf->getRegion(0);
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Face not in the closure of region");
+ return NULL;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns 1 if ent is in the closure of pf, else 0 \ingroup face
+ int F_inClosure(pFace f, pEntity ent)
+ {
+ int dim = EN_type (ent);
+
+ if (dim ==1)
+ {
+ for (int i=0;i<f->getNbEdges();i++)
+ {
+ if (F_edge(f,i)== ent) return 1;
+ }
+ return 0;
+ }
+ else if (dim ==0)
+ {
+ for (int i=0;i<f->getNbEdges();i++)
+ {
+ if (F_vertex(f,i) == ent) return 1;
+ }
+ return 0;
+ }
+ else throw;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the geometric entity to which pf is attached \ingroup face
+ pGEntity F_whatIn(pFace pf)
+ {
+ return pf->g;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the type/dimension of the geometric entity to which pf is attached \ingroup face
+ int F_whatInType(pFace e) { return EN_whatInType(e);}
+
+ // -------------------------------------------------------------------
+ //! Classify pf on geometric entity 'what' \ingroup face
+ void F_setWhatIn(pFace face, pGEntity what)
+ {
+ face->g = what;
+ for (int iE=0; iE<face->getNbEdges(); iE++) {
+ pEdge edge = face->getEdge(iE);
+ if ( GEN_type(edge->g) > GEN_type(what) ) E_setWhatIn(edge,what);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! Inverts the direction of face pf by switching edge 1 and 2 \ingroup face
+ /*! \warning only implemented for triangles */
+ void F_chDir(pFace pf)
+ {
+ assert (pf->getNbEdges() == 3);
+ {
+ MDB_Triangle *t = (MDB_Triangle*)pf;
+ pEdge temp = t->e2;
+ t->e2 = t->e1;
+ t->e1 = temp;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the n-th higher-order point attached to pf, excluding the closure \ingroup face
+ pPoint F_point(pFace f, int n)
+ {
+ return f->getHighOrderPoint (n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the number of higher-order points attached to pf, excluding the closure \ingroup face
+ int F_numPoints(pFace f)
+ {
+ return f->getNbHighOrderPoints();
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the number of points attached to pf, including summits and points in closure \ingroup face
+ int F_numPointsTot(pFace f)
+ {
+ int numPt = f->getNbNodes() + f->getNbHighOrderPoints();
+
+ pPList list = F_edges(f);
+ void * temp = NULL;
+ while ( pEdge edge = (pEdge) PList_next(list, &temp)) {
+ numPt += edge->getNbHighOrderPoints();
+ }
+ PList_delete(list);
+
+ return numPt;
+ }
+
+ // -------------------------------------------------------------------
+ //! Aligns the face with a set of points
+ //! will return zero if not successful
+ //! otherwise the absolute value will contain the index of the element vertex coinciding with the first vertex
+ //! the sign indicates the orientation
+ int F_align(pFace pf,pVertex pv1,pVertex pv2,pVertex pv3,pVertex pv4)
+ {
+ return pf->align(pv1,pv2,pv3,pv4);
+ }
+
+ // -------------------------------------------------------------------
+ //! Gets coordinates of vertices of the face, not including high-order points. \ingroup face
+ void F_coordP1(const pFace face, double xyz[][3])
+ {
+ int iNode = 0;
+
+ // Summits of the face (first order nodes)
+ pPList fVerts = F_vertices(face,1);
+ void * temp = NULL;
+ while ( pVertex pV = (pVertex)PList_next(fVerts,&temp)) {
+ V_coord(pV,xyz[iNode]);
+ iNode++;
+ }
+ PList_delete(fVerts);
+ }
+
+ // -------------------------------------------------------------------
+ //! Gets coordinates of points of the face including high-order points. \ingroup face
+ void F_coord(const pFace face, double xyz[][3])
+ {
+ // Summits of the face (first order nodes)
+ F_coordP1(face,xyz);
+ int iNode = face->getNbNodes();
+
+ // points on edges (higher order nodes)
+ pPList fEdges = F_edges(face);
+ void * temp = NULL;
+ while ( pEdge edge = (pEdge) PList_next(fEdges, &temp)) {
+ int nEPts = E_numPoints(edge);
+ for (int iEP=0; iEP<nEPts; iEP++) {
+ pPoint pP = E_point(edge,iEP);
+ xyz[iNode][0] = P_x(pP); xyz[iNode][1] = P_y(pP); xyz[iNode][2] = P_z(pP);
+ iNode++;
+ }
+ }
+ PList_delete(fEdges);
+
+ // points on face (higher order nodes)
+ int nFPts = F_numPoints(face);
+ for (int iFP=0; iFP<nFPts; iFP++) {
+ pPoint pP = F_point(face,iFP);
+ xyz[iNode][0] = P_x(pP); xyz[iNode][1] = P_y(pP); xyz[iNode][2] = P_z(pP);
+ iNode++;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! Gets the parametric coordinates of the summits of the face \ingroup face
+ //! in the geometric entity on which it is classified.
+ //! Returns false if parametric coordinates are not available.
+ bool F_params(const pFace face, double u[][2])
+ {
+#ifdef _HAVE_GMSH_
+ pGEntity faceGE = F_whatIn(face);
+ int gDim = GEN_type(faceGE);
+ if ( gDim != 2 ) return false;
+
+ for (int iV=0; iV<F_numVertices(face); iV++)
+ {
+ pVertex pv = F_vertex(face,iV);
+ pGEntity vG = EN_whatIn(pv);
+ int vGDim = GEN_type(vG);
+
+ switch ( vGDim ) {
+ case 3: throw;
+ case 2: {
+ assert ( vG == faceGE );
+ if ( !V_params(pv,&u[iV][0],&u[iV][1]) ) return false;
+ break;
+ }
+ case 1: {
+ double tmp0,tmp1;
+ if ( !V_params(pv,&tmp0,&tmp1) ) return false;
+ GE_reparamOnFace( (pGEdge)vG, (pGFace)faceGE, tmp0, u[iV], NULL );
+ break;
+ }
+ case 0: {
+ GV_reparamOnFace( (pGVertex)vG, (pGFace)faceGE, u[iV], NULL );
+ break;
+ }
+ }
+ }
+ return true;
+#else
+ return false;
+#endif
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns area of a triangular face \ingroup face
+ //! if 'dir' is not NULL, the area is signed
+ double F_area(const pFace face, const double * dir)
+ {
+ double fxyz[4][3];
+ F_coordP1(face,fxyz);
+ return XYZ_F_area(fxyz,dir);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns area of a triangular face \ingroup face
+ //! if 'dir' is not NULL, the area is signed
+ double XYZ_F_area(const double xyz[][3], const double * dir)
+ {
+ double areaSq = XYZ_F_areaSq(xyz, dir);
+ if ( areaSq >= 0. ) return sqrt(areaSq);
+ return -1.0 * sqrt ( -1.0*areaSq );
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns square area of a triangular face. \ingroup face
+ //! if 'dir' is not NULL, the square area is signed
+ double F_areaSq(const pFace face, const double * dir)
+ {
+ double xyz[3][3];
+ F_coordP1(face,xyz);
+ return XYZ_F_areaSq(xyz,dir);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns square area of a triangular face with coordinates xyz. \ingroup face
+ //! if 'dir' is not NULL, the square area is signed
+ double XYZ_F_areaSq(const double xyz[][3], const double * dir)
+ {
+ double e01[3], e02[3], normal[3];
+ diffVec(xyz[1],xyz[0],e01);
+ diffVec(xyz[2],xyz[0],e02);
+ crossProd(e01,e02,normal);
+ if( dir && ( dotProd(dir,normal) < 0. ) ) {
+ return -0.25 * dotProd(normal,normal);
+ }
+ return 0.25 * dotProd(normal,normal);
+ }
+ // -------------------------------------------------------------------
+ //! Returns the center of a triangular linear face. \ingroup face
+ void F_center(const pFace face, double center[])
+ {
+ double fxyz[3][3];
+ F_coordP1(face,fxyz);
+ center[0] = MAdTHIRD * ( fxyz[0][0] + fxyz[1][0] + fxyz[2][0] );
+ center[1] = MAdTHIRD * ( fxyz[0][1] + fxyz[1][1] + fxyz[2][1] );
+ center[2] = MAdTHIRD * ( fxyz[0][2] + fxyz[1][2] + fxyz[2][2] );
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the coordinates (u,v) of the point in the parent element
+ void F_linearParams(const pFace pF, const double xyz[3],
+ double res[2])
+ {
+ // using barycentric coordinates
+ double fxyz[3][3];
+ F_coordP1(pF,fxyz);
+
+ Tri_linearParams(fxyz,xyz,res);
+ }
+
+ // -------------------------------------------------------------------
+ //! Computes the normal vector of the face \ingroup face
+ //! The normal is not normalized
+ void F_normal(const pFace face, double normal[3])
+ {
+ double xyz[4][3];
+ F_coordP1(face,xyz);
+ double v01[3],v02[3];
+ diffVec(xyz[1],xyz[0],v01);
+ diffVec(xyz[2],xyz[0],v02);
+ crossProd(v01,v02,normal);
+ }
+
+ // -------------------------------------------------------------------
+ //! Computes the normal vector of a triangle with given coordinates \ingroup face
+ //! The normal is not normalized
+ void XYZ_F_normal(const double xyz[3][3], double normal[3])
+ {
+ double v01[3],v02[3];
+ diffVec(xyz[1],xyz[0],v01);
+ diffVec(xyz[2],xyz[0],v02);
+ crossProd(v01,v02,normal);
+ }
+
+ // -------------------------------------------------------------------
+ //! Computes the ratio between the regions around the face \ingroup face
+ //! Returns false if there is less than 2 regions
+ bool F_volumeRatio(const pFace face, double * ratio)
+ {
+ const pRegion pr0 = F_region(face,0);
+ const pRegion pr1 = F_region(face,1);
+
+ if ( !( pr0 && pr1 ) ) return false;
+
+ double vol0 = R_volume(pr0);
+ double vol1 = R_volume(pr1);
+
+ if( vol0 <= 0. || vol1 <= 0. ) *ratio = -1.;
+ else *ratio = ( vol0 < vol1 ) ? vol1/vol0 : vol0/vol1;
+
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ //! Computes the maximal volume ratio among the faces \ingroup face
+ double F_worstVolumeRatio(const std::set<pFace> faces)
+ {
+ double maxRatio = 0.;
+
+ std::set<pFace>::const_iterator fIter = faces.begin();
+ for(; fIter != faces.end(); fIter++ ) {
+ double ratio;
+ if ( !F_volumeRatio(*fIter,&ratio) ) continue;
+ if( ratio < 0. ) return -1;
+ if( ratio > maxRatio ) maxRatio = ratio;
+ }
+
+ return maxRatio;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the vertex of face opposite to edge \ingroup face
+ pVertex F_edOpVt(const pFace face, const pEdge edge)
+ {
+ assert(face->getNbEdges() == 3);
+
+ pVertex v0 = E_vertex(edge,0);
+ pVertex v1 = E_vertex(edge,1);
+
+ for (int iE=0; iE<3; iE++) {
+ pEdge pE = face->getEdge(iE);
+ if (pE==edge) continue;
+ pVertex pEv0 = E_vertex(pE,0);
+ if ( pEv0 != v0 && pEv0 != v1 ) return pEv0;
+ else return E_vertex(pE,1);
+ }
+
+ return NULL;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the edge of face opposite to vertex \ingroup face
+ pEdge F_vtOpEd(const pFace face, const pVertex vertex)
+ {
+ assert(face->getNbEdges() == 3);
+
+ for (int iE=0; iE<3; iE++) {
+ pEdge pE = face->getEdge(iE);
+ if ( E_vertex(pE,0) != vertex &&
+ E_vertex(pE,1) != vertex ) {
+ return pE;
+ }
+ }
+ return NULL;
+ }
+
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // Edge operators
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ //! Dumps informations about the edge. \ingroup edge
+ void E_info(const pEdge edge, std::string name, std::ostream& out)
+ {
+ out << "\n";
+ out << "Edge \'" << name << "\' " << edge
+ << ", id: " << EN_id((pEntity)edge) << "\n";
+ pGEntity pGE = EN_whatIn((pEntity)edge);
+ out << " - Classification: dim: " << GEN_type(pGE) << ", tag: " << GEN_tag(pGE) << "\n";
+ pVertex pv0 = E_vertex(edge,0);
+ pVertex pv1 = E_vertex(edge,1);
+ out << " - Vertices:\n"
+ << " * Vertex 0:\n";
+ V_info(pv0, "", out);
+ out << " * Vertex 1:\n";
+ V_info(pv1, "", out);
+ out << "\n";
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the number of regions attached to the edge pe \ingroup edge
+ int E_numRegions(pEdge pe)
+ {
+ pPList rlist = E_regions(pe);
+ int num = PList_size(rlist);
+ PList_delete(rlist);
+ return num;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the number of vertices in edge pe \ingroup edge
+ //! Guess what, there are two !
+ int E_numVertices(pEdge pe)
+ {
+ return 2;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the n-th vertex of edge pe \ingroup edge
+ /*! \warning will throw an error for n>1 */
+ pVertex E_vertex(pEdge pe, int n)
+ {
+ switch(n){
+ case 0 : return pe->p1;
+ case 1 : return pe->p2;
+ }
+ throw;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns a list of the vertices of edge pe \ingroup edge
+ pPList E_vertices(const pEdge pe)
+ {
+ pPList vList;
+ PList_append(vList,pe->p1);
+ PList_append(vList,pe->p2);
+ return vList;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the number of faces attached to edge pe \ingroup edge
+ int E_numFaces(pEdge pe)
+ {
+ return pe->numfaces() ;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns a list of regions attached to edge pe \ingroup edge
+ pPList E_regions(pEdge e)
+ {
+ pPList pl = PList_new();
+ for (int i=0;i<e->numfaces();++i)
+ {
+ pFace pf = e->faces(i);
+ for(int k=0;k<pf->getNbRegions();k++)
+ PList_appUnique(pl,pf->getRegion(k));
+ }
+ return pl;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the number of higher-order points on edge pe, excluding vertices \ingroup edge
+ int E_numPoints(pEdge pE)
+ {
+ return pE->getNbHighOrderPoints ();
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the n-th face attached to edge pe \ingroup edge
+ pFace E_face(pEdge pe, int n)
+ {
+ return pe->faces(n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the list of faces connected to the edge \ingroup edge
+ pPList E_faces(const pEdge pe)
+ {
+ pPList eFaces = PList_new();
+ for (int iF=0; iF < pe->numfaces(); iF++) {
+ PList_append(eFaces,pe->faces(iF));
+ }
+ return eFaces;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns 1 of ent is one of the vertices of edge pe, else 0 \ingroup edge
+ int E_inClosure(pEdge pe, pEntity ent)
+ {
+ if (pe->p1 == ent) return 1;
+ if (pe->p2 == ent) return 1;
+ return 0;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the other face attached to edge pe belonging to the closure of region r \ingroup edge
+ pFace E_otherFace(pEdge edge, pFace face, pRegion r)
+ {
+ for (int i=0;i<r->getNbFace();i++)
+ {
+ pFace f1 = r->getFace(i);
+ if (f1 != face && F_inClosure (f1,edge) ) return f1;
+ }
+ throw;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the other vertex of edge pe \ingroup edge
+ pVertex E_otherVertex(pEdge e, pVertex v)
+ {
+ if(e->p1 == v)return e->p2;
+ if(e->p2 == v)return e->p1;
+ throw;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the n-th higher order point - excluding vertices - of edge pe \ingroup edge
+ pPoint E_point(pEdge e, int n)
+ {
+ return e->getHighOrderPoint (n);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the geometrical entity on which entity 'pe' is classified \ingroup entity
+ pGEntity EN_whatIn(pEntity pe)
+ {
+ return pe->g;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the type/dimension of the geometrical entity on which edge pe is classified \ingroup edge
+ pGEntity E_whatIn(pEdge pe)
+ {
+ return pe->g;
+ }
+
+ // -------------------------------------------------------------------
+ //! Classify entity e on the geometrical entity 'what' \ingroup entity
+ void EN_setWhatIn(pEntity e, pGEntity what){e->g = what;}
+
+ // -------------------------------------------------------------------
+ //! Classify edge e on the geometrical entity 'what' \ingroup entity
+ void E_setWhatIn(pEdge edge, pGEntity what)
+ {
+ edge->g = what;
+ pPoint p1 = edge->p1;
+ if ( GEN_type(p1->g) > GEN_type(what) ) V_setWhatIn(p1,what);
+ pPoint p2 = edge->p2;
+ if ( GEN_type(p2->g) > GEN_type(what) ) V_setWhatIn(p2,what);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the type/dimension of the geometrical entity on which edge pe is classified \ingroup edge
+ int E_whatInType(pEdge e) { return EN_whatInType(e);}
+
+ // -------------------------------------------------------------------
+ //! Aligns the current edge with the node order \ingroup edge
+ //! returns 1 if the edge is already aligned, -1 if the edge is inverted and 0 if the edge does not correspond
+ int E_align(pEdge pe,pVertex pv1,pVertex pv2) {return pe->align(pv1,pv2);}
+
+ // -------------------------------------------------------------------
+ //! Returns 1 of the edge is oriented from first vertex \ingroup edge
+ //! to second one, 0 otherwise
+ int E_dir(pEdge pe, pVertex pv1, pVertex pv2) {
+ if (pe->p1 == pv1 && pe->p2 == pv2) return 1;
+ if (pe->p1 == pv2 && pe->p2 == pv1) return 0;
+ throw;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns coordinates of vertices of the edge not including high-order points. \ingroup edge
+ void E_coordP1(const pEdge edge, double xyz[][3])
+ {
+ // points of extremities
+ MDB_Point * pP1 = edge->p1;
+ xyz[0][0] = P_x(pP1);
+ xyz[0][1] = P_y(pP1);
+ xyz[0][2] = P_z(pP1);
+ MDB_Point * pP2 = edge->p2;
+ xyz[1][0] = P_x(pP2);
+ xyz[1][1] = P_y(pP2);
+ xyz[1][2] = P_z(pP2);
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns coordinates of vertices of the edge including high-order points. \ingroup edge
+ void E_coord(const pEdge edge, double xyz[][3])
+ {
+ E_coordP1(edge,xyz);
+
+ // points on edges (higher order nodes)
+ int n = E_numPoints(edge);
+ for (int i=0; i<n; i++) {
+ pPoint pnt = E_point(edge,i);
+ xyz[2+i][0] = P_x(pnt); xyz[2+i][1] = P_y(pnt); xyz[2+i][2] = P_z(pnt);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! Gets the parametric coordinates of the summits of the edge \ingroup edge
+ //! in the geometric entity on which it is classified.
+ //! Returns false if parametric coordinates are not available.
+ bool E_params(const pEdge edge, double u[2][2])
+ {
+#ifdef _HAVE_GMSH_
+
+ pGEntity edgeGE = E_whatIn(edge);
+ int gDim = GEN_type(edgeGE);
+
+ if ( gDim != 1 && gDim != 2 ) return false;
+
+ for (int iV=0; iV<2; iV++) {
+
+ pVertex pv = E_vertex(edge,iV);
+ pGEntity vG = EN_whatIn(pv);
+ int vGDim = GEN_type(vG);
+
+ // --------------------------------------------------------------------
+ // edge classified on a surface: we want the parameters on the surface
+ // --------------------------------------------------------------------
+ if ( gDim == 2 ) {
+
+ switch ( vGDim ) {
+ case 3: throw;
+ case 2: {
+ if ( !V_params(pv,&u[iV][0],&u[iV][1]) ) return false;
+// printf("node on face %d: %lf %lf\n",GEN_tag(edgeGE),u[iV][0],u[iV][1]);
+ break;
+ }
+ case 1: {
+ double tmp0,tmp1;
+ if ( !V_params(pv,&tmp0,&tmp1) ) return false;
+
+ double * otherU = NULL;
+ if ( GE_isSeam( (pGEdge)vG, (pGFace)edgeGE ) )
+ {
+ pVertex otherV = E_vertex(edge,1-iV);
+ double tmp20,tmp21;
+ if ( V_whatInType(otherV)==2 && V_params(otherV,&tmp20,&tmp21) ) {
+ otherU = new double[2];
+ otherU[0] = tmp20;
+ otherU[1] = tmp21;
+ }
+ else if ( V_whatInType(otherV)==1 && V_params(otherV,&tmp20,&tmp21) ) {
+ if ( GE_isSeam( (pGEdge)V_whatIn(otherV), (pGFace)edgeGE ) ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Found a surface with 2 seams");
+ return false;
+ }
+ otherU = new double[2];
+ GE_reparamOnFace( (pGEdge)V_whatIn(otherV), (pGFace)edgeGE,
+ tmp20, &(otherU[0]) );
+ otherU[1] = -1.;
+ }
+ }
+ GE_reparamOnFace( (pGEdge)vG, (pGFace)edgeGE, tmp0, u[iV], otherU );
+// printf("node from edge %d on face %d: %lf %lf\n",GEN_tag(vG),GEN_tag(edgeGE),u[iV][0],u[iV][1]);
+ break;
+ }
+ case 0: {
+ double tmp0,tmp1;
+ if ( !V_params(pv,&tmp0,&tmp1) ) return false;
+
+ double * otherU = NULL;
+ if ( GV_isOnSeam( (pGVertex)vG, (pGFace)edgeGE ) )
+ {
+ pVertex otherV = E_vertex(edge,1-iV);
+ double tmp20,tmp21;
+ if ( V_whatInType(otherV)==2 && V_params(otherV,&tmp20,&tmp21) ) {
+ otherU = new double[2];
+ otherU[0] = tmp20;
+ otherU[1] = tmp21;
+ }
+ else if ( V_whatInType(otherV)==1 && V_params(otherV,&tmp20,&tmp21) ) {
+ if ( GE_isSeam( (pGEdge)V_whatIn(otherV), (pGFace)edgeGE ) ) {
+ MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+ "Found a surface with 2 seams");
+ return false;
+ }
+ otherU = new double[2];
+ GE_reparamOnFace( (pGEdge)V_whatIn(otherV), (pGFace)edgeGE,
+ tmp20, &(otherU[0]) );
+ otherU[1] = -1.;
+ }
+ }
+ GV_reparamOnFace( (pGVertex)vG, (pGFace)edgeGE, u[iV], otherU );
+// printf("vert %d on face %d: %lf %lf\n",GEN_tag(vG),GEN_tag(edgeGE),u[iV][0],u[iV][1]);
+ break;
+ }
+ }
+ }
+
+ // --------------------------------------------------------------
+ // edge classified on a line: we want the parameters on the line
+ // --------------------------------------------------------------
+ else if ( gDim == 1) {
+
+ switch ( vGDim ) {
+ case 3: throw;
+ case 2: throw;
+ case 1: {
+ double tmp;
+ if ( !V_params(pv,&u[iV][0],&tmp) ) return false;
+ break;
+ }
+ case 0: {
+ if ( !(pv->isParametric() ) ) return false;
+
+ double otherU = -1.;
+ pVertex otherV = E_vertex(edge,1-iV);
+ double tmp20,tmp21;
+ if ( V_whatInType(otherV)==1 && V_params(otherV,&tmp20,&tmp21) ) {
+ otherU = tmp20;
+ }
+ else if ( V_whatInType(otherV)==0 ) {
+ GV_reparamOnEdge( (pGVertex)V_whatIn(otherV), (pGEdge)edgeGE, &otherU );
+ }
+
+ GV_reparamOnEdge( (pGVertex)vG, (pGEdge)edgeGE, &u[iV][0], otherU );
+ break;
+ }
+ }
+
+ }
+
+ else throw;
+ }
+
+ return true;
+#else
+ return false;
+#endif
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the physical length of the edge \ingroup edge
+ double E_length(const pEdge edge)
+ {
+ double eCoords[2][3];
+ E_coordP1(edge,eCoords);
+ double e[3];
+ diffVec(eCoords[1],eCoords[0],e);
+ return sqrt ( e[0]*e[0] + e[1]*e[1] + e[2]*e[2] );
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the physical square length of the edge \ingroup edge
+ double E_lengthSq(const pEdge edge)
+ {
+ double eCoords[2][3];
+ E_coordP1(edge,eCoords);
+ double e[3];
+ diffVec(eCoords[1],eCoords[0],e);
+ return e[0]*e[0] + e[1]*e[1] + e[2]*e[2];
+ }
+
+ // -------------------------------------------------------------------
+ double E_linearParams(const pEdge pE,
+ const pVertex pv)
+ {
+ double xyz[3];
+ V_coord(pv,xyz);
+ return E_linearParams(pE,xyz);
+ }
+
+ // -------------------------------------------------------------------
+ double E_linearParams(const pEdge pE,
+ const double xyz[3])
+ {
+ double eCoords[2][3];
+ E_coordP1(pE,eCoords);
+
+ double v01[3];
+ diffVec(eCoords[1],eCoords[0],v01);
+
+ double vX1[3];
+ diffVec(eCoords[1],xyz,vX1);
+ double temp = dotProd(v01,vX1);
+ if ( temp < MAdTOL ) return 1.;
+
+ double v0X[3];
+ diffVec(xyz,eCoords[0],v0X);
+ double temp2 = dotProd(v01,v0X);
+ if ( temp2 < MAdTOL ) return 0.;
+
+ double ratio = temp2 / temp;
+ return ( ratio / (1. + ratio ) );
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the center of a linear edge. \ingroup edge
+ void E_center(const pEdge edge, double center[3])
+ {
+ double exyz[2][3];
+ E_coordP1(edge,exyz);
+ center[0] = 0.5 * ( exyz[0][0] + exyz[1][0] );
+ center[1] = 0.5 * ( exyz[0][1] + exyz[1][1] );
+ center[2] = 0.5 * ( exyz[0][2] + exyz[1][2] );
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the center of the cavity surrounding an edge. \ingroup edge
+ void E_cavityCenter(const pEdge edge, double center[3])
+ {
+ if( E_whatInType(edge)!=3 ) {
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "not implemented for edges classified on <3D");
+ }
+
+ center[0] = 0.; center[1] = 0.; center[2] = 0.;
+
+ int nbF = 0;
+ pPList vFaces = E_faces(edge);
+ void * temp = NULL;
+ while ( pFace face = (pFace)PList_next(vFaces,&temp) ) {
+ pVertex oppV = F_edOpVt(face,edge);
+ double xyz[3];
+ V_coord(oppV,xyz);
+ center[0] += xyz[0]; center[1] += xyz[1]; center[2] += xyz[2];
+ nbF++;
+ }
+ PList_delete(vFaces);
+
+ double invNbF = 1. / nbF;
+ center[0] *= invNbF; center[1] *= invNbF; center[2] *= invNbF;
+ }
+
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // Vertex operators
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ //! Dumps informations about the vertex. \ingroup vertex
+ void V_info(const pVertex vertex, std::string name, std::ostream& out)
+ {
+ out << "\n";
+ out << "Vertex \'" << name << "\' " << vertex
+ << ", id: " << EN_id((pEntity)vertex) << "\n";
+ pGEntity pGE = EN_whatIn((pEntity)vertex);
+ out << " - Classification: dim: " << GEN_type(pGE) << ", tag: " << GEN_tag(pGE) << "\n";
+ out << " - Num edges: " << vertex->edges.size() << "\n";
+ out << " - Parameters:\n";
+ double u,v;
+ if ( vertex->getParams(&u,&v) ) {
+ out << " Point is parametric: (u,v) = ("<<u<<", "<<v<<")\n";
+ }
+ else {
+ out <<" Point is not parametric\n";
+ }
+ out << " - Coordinates:\n";
+ double xyz[3];
+ V_coord(vertex,xyz);
+ out << " ( "<<xyz[0]<<", "<<xyz[1]<<", "<<xyz[2]<<" )\n";
+ out << "\n";
+
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the type/dimension of the geometrical entity on which vertex e is classified \ingroup vertex
+ int V_whatInType(pVertex e)
+ {
+ return EN_whatInType(e);
+ }
+
+ // -------------------------------------------------------------------
+ //! Classify vertex e on the geometrical entity 'what' \ingroup vertex
+ void V_setWhatIn(pVertex e, pGEntity what)
+ {
+ e->g = what;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the geometrical entity on which vertex pv is classified \ingroup vertex
+ pGEntity V_whatIn(pVertex pv)
+ {
+ return pv->g;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the list of regions attached to vertex v \ingroup vertex
+ pPList V_regions(pVertex v)
+ {
+ // 3D SPECIFIC printf("coucou\n");
+ pPList pl = PList_new();
+ for (unsigned int i=0;i<v->edges.size();++i)
+ {
+ pEdge pe = v->edges[i];
+ for (int j=0;j<pe->numfaces();j++)
+ {
+ pFace pf = pe->faces(j);
+ for(int k=0;k<pf->getNbRegions();k++)
+ PList_appUnique(pl,pf->getRegion(k));
+ }
+ }
+ return pl;
+ }
+
+ // -------------------------------------------------------------------
+ //! Copies the coordinates of vertex pv in point \ingroup vertex
+ pPoint V_point(pVertex pv)
+ {
+ return pv;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns number of edges attached to vertex pv \ingroup vertex
+ int V_numEdges(pVertex pv)
+ {
+ return pv->edges.size();
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns number of faces attached to vertex pv \ingroup vertex
+ int V_numFaces(pVertex pv)
+ {
+ pPList faces = V_faces(pv);
+ int num = PList_size(faces);
+ PList_delete(faces);
+ return num;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns number of regions attached to vertex pv \ingroup vertex
+ int V_numRegions(pVertex pv)
+ {
+ pPList regions = V_regions(pv);
+ int num = PList_size(regions);
+ PList_delete(regions);
+ return num;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns n-th edge attached to vertex pv \ingroup vertex
+ pEdge V_edge(pVertex pv, int n)
+ {
+ return pv->edges[n];
+ }
+
+
+ // -------------------------------------------------------------------
+ //! Returns the identity tag of the vertex pv \ingroup vertex
+ int V_id(const pVertex pv) {
+ return pv->iD;
+ }
+
+ // -------------------------------------------------------------------
+ //! Copy position of vertex p to xyz \ingroup vertex
+ void V_coord(const pVertex p, double xyz[3])
+ {
+ xyz[0] = p->X;
+ xyz[1] = p->Y;
+ xyz[2] = p->Z;
+ }
+
+ // -------------------------------------------------------------------
+ //! Gets the parametric coordinates of the vertex. \ingroup vertex
+ //! Returns false is the vertex is not parametric.
+ bool V_params(pVertex pv, double * u, double * v)
+ {
+ return pv->getParams(u,v);
+ }
+
+ // -------------------------------------------------------------------
+ //! Return the list of faces attached to vertex v \ingroup vertex
+ pPList V_faces(pVertex v)
+ {
+ pPList pl = PList_new();
+ for (unsigned int i=0;i<v->edges.size();++i)
+ {
+ pEdge pe = v->edges[i];
+ for (int j=0;j<pe->numfaces();j++)
+ {
+ pFace pf = pe->faces(j);
+ PList_appUnique(pl,pf);
+ }
+ }
+
+ return pl;
+ }
+
+ // -------------------------------------------------------------------
+ //! Return the list of edges attached to vertex v \ingroup vertex
+ pPList V_edges(pVertex v)
+ {
+ pPList pl = PList_new();
+ for (unsigned int i=0; i<v->edges.size(); ++i) {
+ pEdge pe = v->edges[i];
+ PList_append(pl,pe);
+ }
+
+ return pl;
+ }
+
+ // -------------------------------------------------------------------
+ //! Compute the mean length square of the edges adjacent to the vertex \ingroup vertex
+ double V_meanEdgeLenSq(const pVertex pv)
+ {
+ double lenSq = 0.;
+ for( int iE=0; iE<V_numEdges(pv); iE++ ) {
+ lenSq += E_lengthSq( V_edge(pv,iE) );
+ }
+ lenSq /= V_numEdges(pv);
+ return lenSq;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the center of the cavity surrounding a vertex. \ingroup vertex
+ void V_cavityCenter(const pVertex vertex, double center[3])
+ {
+ center[0] = 0.; center[1] = 0.; center[2] = 0.;
+
+ int nbE = 0;
+ pPList vEdges = V_edges(vertex);
+ void * temp = NULL;
+ while ( pEdge edge = (pEdge)PList_next(vEdges,&temp) ) {
+ pVertex otherV = E_otherVertex(edge,vertex);
+ double xyz[3];
+ V_coord(otherV,xyz);
+ center[0] += xyz[0]; center[1] += xyz[1]; center[2] += xyz[2];
+ nbE++;
+ }
+ PList_delete(vEdges);
+
+ double invNbE = 1. / nbE;
+ center[0] *= invNbE; center[1] *= invNbE; center[2] *= invNbE;
+ }
+
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // Point operators
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ //! Returns x coordinate of point p \ingroup point
+ double P_x(pPoint p){return p->X;}
+
+ // -------------------------------------------------------------------
+ //! Returns y coordinate of point p \ingroup point
+ double P_y(pPoint p){return p->Y;}
+
+ // -------------------------------------------------------------------
+ //! Returns z coordinate of point p \ingroup point
+ double P_z(pPoint p){return p->Z;}
+
+ // -------------------------------------------------------------------
+ //! Deletes point p \ingroup point
+ void P_delete(pPoint p)
+ {
+ delete p;
+ }
+
+ // -------------------------------------------------------------------
+ //! Sets the coordinates of point p \ingroup point
+ void P_setPos(pPoint p , double x, double y, double z)
+ {
+ p->X = x;
+ p->Y = y;
+ p->Z = z;
+ }
+
+ // -------------------------------------------------------------------
+ //! Sets the identity of point p \ingroup point
+ void P_setID(pPoint p, int id){p->iD = id;}
+
+ // -------------------------------------------------------------------
+ //! Returns the identity of point p \ingroup point
+ int P_id(pPoint p){return p->iD;}
+
+ // -------------------------------------------------------------------
+ double P_param1(pPoint p)
+ {
+ pMeshDataId id = MD_lookupMeshDataId("_param1");
+ double pp;
+ EN_getDataDbl(p, id,&pp);
+ return pp;
+ }
+
+ // -------------------------------------------------------------------
+ void P_setParam1(pPoint p, double param)
+ {
+ pMeshDataId id = MD_lookupMeshDataId("_param1");
+ EN_attachDataDbl(p, id, param);
+ }
+
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // Entity operators
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ //! Print informations about the entity
+ void EN_info(const pEntity e, std::string name, std::ostream& out)
+ {
+ switch ( EN_type(e) ) {
+ case 3: R_info((pRegion)e,name,out);
+ case 2: F_info((pFace)e, name,out);
+ case 1: E_info((pEdge)e, name,out);
+ case 0: V_info((pVertex)e,name,out);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the identity tag for entity e \ingroup entity
+ int EN_id(pEntity pe)
+ {
+ return pe->iD;
+ }
+
+ // -------------------------------------------------------------------
+ //! Sets the identity tag for entity e \ingroup entity
+ void EN_setID(pEntity pe, int id){
+ pe->iD=id;
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the type(dimension) of the geometrical entity on which entity e is classified \ingroup entity
+ int EN_whatInType(pEntity e){return GEN_type(e->g);}
+
+ // -------------------------------------------------------------------
+ //! Returns the number of vertices in the entity \ingroup entity
+ int EN_numVertices(const pEntity e)
+ {
+ switch ( EN_type(e) ) {
+ case 3: return R_numVertices((pRegion)e);
+ case 2: return F_numVertices((pFace)e);
+ case 1: return E_numVertices((pEdge)e);
+ case 0: return 1;
+ }
+ }
+
+ // -------------------------------------------------------------------
+ //! Returns the list of the vertices of the entity \ingroup entity
+ pPList EN_vertices(const pEntity e)
+ {
+ pPList vList;
+ switch ( EN_type(e) ) {
+ case 3: { vList = R_vertices((pRegion)e); break; }
+ case 2: { vList = F_vertices((pFace)e,1); break; }
+ case 1: { vList = E_vertices((pEdge)e); break; }
+ case 0: { vList = PList_new(); PList_append(vList,e); break; }
+ }
+ return vList;
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ /* mesh entity creation routines */
+
+ //! Creates a region, classified on gent, in mesh m using specified faces \ingroup mesh
+ pRegion M_createR(pMesh mesh, int nFace, pFace *faces, pGEntity gent)
+ {
+ pRegion pr(0);
+ switch(nFace)
+ {
+ case 4 : pr = mesh->add_tet((MDB_Triangle*)faces[0],(MDB_Triangle*)faces[1],(MDB_Triangle*)faces[2],(MDB_Triangle*)faces[3],gent);
+ break;
+ case 5 : pr = mesh->add_prism((MDB_Triangle*)faces[0],(MDB_Triangle*)faces[1],
+ (MDB_Quad*)faces[2],(MDB_Quad*)faces[3],(MDB_Quad*)faces[4],gent);
+ break;
+ case 6 : pr = mesh->add_hex((MDB_Quad*)faces[0],(MDB_Quad*)faces[1],(MDB_Quad*)faces[2],
+ (MDB_Quad*)faces[3],(MDB_Quad*)faces[4],(MDB_Quad*)faces[5],gent);
+ break;
+ }
+ return pr;
+ }
+
+ //! Creates a face, classified on gent, in mesh m using specified edges \ingroup mesh
+ /*! \warning currently only implemented for triangles */
+ pFace M_createF(pMesh mesh, int nEdge, pEdge *edges, pGEntity gent)
+ {
+ pFace pf = mesh->add_triangle (edges[0],edges[1],edges[2],gent);
+ return pf;
+ }
+
+ //! Create a edge, classified on ent, in mesh m using specified vertices \ingroup mesh
+ pEdge M_createE(pMesh mesh, pVertex v1, pVertex v2, pGEntity ent)
+ {
+ return mesh->add_edge (v1,v2,ent);
+ }
+ pVertex M_createV(pMesh mesh, double x, double y, double z,
+ int patch, pGEntity ent)
+ {
+ return mesh->add_point (patch,x,y,z,ent);
+ }
+ pVertex M_createV2(pMesh mesh, double xyz[3],int patch, pGEntity ent)
+ {
+ return M_createV(mesh,xyz[0],xyz[1],xyz[2],patch,ent);
+ }
+ pVertex M_createVP(pMesh mesh, double x, double y, double z,
+ double u, double v, int patch, pGEntity ent)
+ {
+ return mesh->add_pointParam (patch,x,y,z,u,v,ent);
+ }
+ /* mesh entity deletion routines */
+
+ //! Removes a region from the mesh, deletes it \ingroup mesh
+ void M_removeRegion(pMesh m, pRegion region)
+ {
+ if (dynamic_cast<MDB_Tet*>(region)) m->del_tet((MDB_Tet*)region);
+ else if (dynamic_cast<MDB_Hex*>(region)) m->del_hex((MDB_Hex*)region);
+ else if (dynamic_cast<MDB_Prism*>(region)) m->del_prism((MDB_Prism*)region);
+ }
+
+ //! Removes a face from the mesh, deletes it \ingroup mesh
+ /*! \warning currently only implemented for triangles */
+ void M_removeFace(pMesh m, pFace face)
+ {
+ m->del_triangle((MDB_Triangle*)face);
+ }
+
+ //! Removes an edge from the mesh, deletes it \ingroup mesh
+ void M_removeEdge(pMesh m, pEdge edge)
+ {
+ m->del_edge (edge);
+ }
+
+ //! Removes a vertex from the mesh, deletes it \ingroup mesh
+ void M_removeVertex(pMesh m, pVertex vertex)
+ {
+ m->del_point(vertex);
+ }
+
+ //! Return edge between two vertices, if not found returns 0 \ingroup mesh
+ pEdge E_exist(pVertex v1, pVertex v2)
+ {
+ MDB_VectorE edges = v1->edges;
+ MDB_VectorE::iterator it = edges.begin();
+ MDB_VectorE::iterator ite = edges.end();
+ while(it!=ite){
+ pVertex p = (*it)->othervertex(v1);
+ if(p==v2) return((*it));
+ ++it;
+ }
+ return 0;
+ }
+
+ //! Returns triangle defined by an edge and a vertex. Returns 0 if not found. \ingroup mesh
+ pFace F_exist(pEdge edge, pVertex vertex)
+ {
+ for (int iF=0; iF<edge->numfaces(); iF++) {
+ MDB_Triangle * tri = edge->faces(iF);
+ MDB_Edge * otherE = tri->e1;
+ if ( otherE == edge) otherE = tri->e2;
+ if ( otherE->p1 == vertex || otherE->p2 == vertex ) {
+ if ( edge->p1 == vertex || edge->p2 == vertex ) {
+ F_info(tri);
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,"Bad triangle or bad input (edge: %p, vertex: %p)",
+ edge,vertex);
+ }
+ return tri;
+ }
+ }
+ return NULL;
+ }
+
+ //! Returns face defined by at most 4 entities, return 0 on failure \ingroup mesh
+ /*! entities e1..4 may be either vertices or edges */
+ pFace F_exist(pEntity e1, pEntity e2, pEntity e3, pEntity e4){
+ int typeEnt = EN_type(e1);
+ switch(typeEnt) {
+ case 0:
+ { pVertex p1 = (pVertex) e1;
+ pVertex p2 = (pVertex) e2;
+ pVertex p3 = (pVertex) e3;
+ MDB_ListF listFaces;
+ p1->getTriangles(listFaces);
+ MDB_ListF::iterator it = listFaces.begin();
+ MDB_ListF::iterator ite = listFaces.end();
+ while(it!=ite){
+ pVertex p[3];
+ (*it)->getNodes(p);
+ if(p[0]==p1 && p[1]==p2 && p[2]==p3) return(*it);
+ if(p[0]==p1 && p[1]==p3 && p[2]==p2) return(*it);
+ if(p[0]==p2 && p[1]==p1 && p[2]==p3) return(*it);
+ if(p[0]==p2 && p[1]==p3 && p[2]==p1) return(*it);
+ if(p[0]==p3 && p[1]==p1 && p[2]==p2) return(*it);
+ if(p[0]==p3 && p[1]==p2 && p[2]==p1) return(*it);
+ ++it;
+ }
+ return 0;
+ }
+ break;
+ case 1:
+ {
+ pEdge ped1 = (pEdge) e1;
+ pEdge ped2 = (pEdge) e2;
+ pEdge ped3 = (pEdge) e3;
+ for(int k=0 ; k<ped1->numfaces() ; k++) {
+ pFace pface = ped1->faces(k);
+ if(pface->getEdge(0)==ped1 && pface->getEdge(1)==ped2 && pface->getEdge(2)==ped3) return(pface);
+ if(pface->getEdge(0)==ped1 && pface->getEdge(1)==ped3 && pface->getEdge(2)==ped2) return(pface);
+ if(pface->getEdge(0)==ped2 && pface->getEdge(1)==ped1 && pface->getEdge(2)==ped3) return(pface);
+ if(pface->getEdge(0)==ped2 && pface->getEdge(1)==ped3 && pface->getEdge(2)==ped1) return(pface);
+ if(pface->getEdge(0)==ped3 && pface->getEdge(1)==ped1 && pface->getEdge(2)==ped2) return(pface);
+ if(pface->getEdge(0)==ped3 && pface->getEdge(1)==ped2 && pface->getEdge(2)==ped1) return(pface);
+ }
+ return 0;
+ }
+ break;
+ default:
+ throw;
+ }
+ return 0;
+ }
+
+ //! Returns the number of geometric entities associated to the mesh \ingroup mesh
+
+ int M_numGeomFeatures (pMesh pm)
+ {
+ return pm->geomFeatures_Tags.size();
+ }
+
+ //! Returns the id tag of the n-th geometric entity associated to the mesh \ingroup mesh
+ int M_geomFeatureId (pMesh pm, int n)
+ {
+ int count = 0;
+ for (std::multimap<int, pGEntity>::iterator it = pm->geomFeatures_Tags.begin();
+ it != pm->geomFeatures_Tags.end();
+ ++it)
+ {
+ if (count++ == n) return it->first;
+ }
+ throw;
+ }
+
+ //! Returns the number of geometric entities associated to the mesh with tag id \ingroup mesh
+ /*! \warning id's are only guaranteed to be unique per type of geometric feature */
+ pPGList M_geomFeature (pMesh pm, int id)
+ {
+ pPGList pl = PGList_new();
+ for (std::multimap<int, pGEntity>::iterator it = pm->geomFeatures_Tags.lower_bound(id) ;
+ it != pm->geomFeatures_Tags.upper_bound(id) ; ++it)
+ PGList_append(pl,it->second);
+ return pl;
+ }
+
+ //! Print a list of geometric entities attached to the mesh to standard output \ingroup mesh
+ /*! \warning id's are only guaranteed to be unique per type of geometric feature */
+ void M_printGeomFeatures (pMesh pm)
+ {
+ std::cout << "\nPrinting geometric features: \n\n";
+ std::multimap<int, pGEntity>::iterator it = pm->geomFeatures_Tags.begin();
+ std::multimap<int, pGEntity>::iterator itEnd = pm->geomFeatures_Tags.end();
+ for (;it != itEnd; it++) {
+ std::cout << "geometric id: " << it->first << " geometric entity: " << it->second << "\n";
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ // PList operators
+ // -------------------------------------------------------------------
+
+ // -------------------------------------------------------------------
+ PList * PList_new()
+ {
+ return new PList();
+ }
+
+ // -------------------------------------------------------------------
+ void PList_delete(PList * lst)
+ {
+ if (lst) delete lst;
+ lst = NULL;
+ }
+
+ // -------------------------------------------------------------------
+ void PList_clear(PList * lst)
+ {
+ lst->clear();
+ }
+
+ // -------------------------------------------------------------------
+ PList * PList_appUnique(PList * lst, MDB_MeshEntity * ent)
+ {
+ for ( unsigned int i=0; i<lst->entities.size(); i++ ) {
+ if ( lst->entities[i] == ent ) return lst;
+ }
+ lst->entities.push_back(ent);
+ return lst;
+ }
+
+ // -------------------------------------------------------------------
+ PList * PList_appPListUnique(PList * lst, PList * source)
+ {
+ for ( unsigned int iSrc=0; iSrc<source->entities.size(); iSrc++ ) {
+ PList_appUnique(lst,source->entities[iSrc]);
+ }
+ return lst;
+ }
+
+ // -------------------------------------------------------------------
+ PList * PList_append(PList * lst, MDB_MeshEntity * ent)
+ {
+ lst->entities.push_back(ent);
+ return lst;
+ }
+
+ // -------------------------------------------------------------------
+ int PList_size(PList * lst)
+ {
+ return lst->entities.size();
+ }
+
+ // -------------------------------------------------------------------
+ MDB_MeshEntity * PList_item(PList * lst, int i)
+ {
+ return lst->entities[i];
+ }
+
+ // -------------------------------------------------------------------
+ MDB_MeshEntity * PList_next(PList * lst, void **restart)
+ {
+ if( *(int*)(restart) >= (int)lst->entities.size() ) return NULL;
+ return lst->entities[(*(int*)(restart))++];
+ }
+
+ // -------------------------------------------------------------------
+ int PList_inList(PList * lst, MDB_MeshEntity * ent)
+ {
+ for ( unsigned int i=0; i<lst->entities.size(); i++ ) {
+ if ( lst->entities[i] == ent ) return 1;
+ }
+ return 0;
+ }
+
+ // -------------------------------------------------------------------
+ void PList_remItem(PList * lst, MDB_MeshEntity * ent)
+ {
+ std::vector<MDB_MeshEntity *>::iterator eIter = lst->entities.begin();
+ for (; eIter != lst->entities.end() ; eIter++) {
+ if ( *eIter == ent ) lst->entities.erase(eIter);
+ }
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+
+}
diff --git a/Mesh/MeshDataBaseInterface.h b/Mesh/MeshDataBaseInterface.h
new file mode 100644
index 0000000..1f8acab
--- /dev/null
+++ b/Mesh/MeshDataBaseInterface.h
@@ -0,0 +1,381 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASEINTEFACE
+#define H_MESHDATABASEINTEFACE
+
+#include "MeshDataBase.h"
+#include "MeshDataBaseCommPeriodic.h"
+
+namespace MAd {
+
+ typedef unsigned int pMeshDataId;
+
+ typedef class MDB_Mesh * pMesh;
+
+ typedef class MDB_MeshEntity * pEntity;
+ typedef class MDB_Region * pRegion;
+ typedef class MDB_Face * pFace;
+ typedef class MDB_Edge * pEdge;
+ typedef class MDB_Point * pVertex;
+ typedef class MDB_Point * pPoint;
+
+ typedef class MDB_RegionIter * RIter;
+ typedef class MDB_FaceIter * FIter;
+ typedef class MDB_EIter * EIter;
+ typedef class MDB_VIter * VIter;
+
+ typedef class PList * pPList;
+
+ /********************/
+ /* Mesh Operators */
+ /********************/
+
+ pMesh M_new(pGModel);
+ void M_delete(pMesh);
+ void M_load(pMesh, const char * filename);
+ void M_clean(pMesh);
+
+ void M_shrink(pMesh);
+ void M_expand(pMesh);
+
+ void M_info(const pMesh, std::ostream& out=std::cout);
+ pGModel M_model(pMesh);
+ int M_dim(pMesh);
+
+ int M_edgesMaxOrder(pMesh);
+ int M_facesMaxOrder(pMesh);
+ int M_regionsMaxOrder(pMesh);
+ int M_maxOrder(pMesh);
+
+ bool M_isParametric(pMesh);
+
+ void M_writeMsh(const pMesh, const char *name,
+ int version=2, const int * partitionTable=NULL);
+ void M_writeMshPer(pMesh, const char *name,
+ MDB_DataExchangerPeriodic &, int version);
+
+#ifdef _HAVE_METIS_
+ void M_Partition(pMesh, int nbParts, const char * filename);
+#endif
+
+ int M_numRegions(pMesh);
+ int M_numTets(pMesh);
+ int M_numHexes(pMesh);
+ int M_numPrisms(pMesh);
+ int M_numFaces(pMesh);
+ int M_numQuads(pMesh);
+ int M_numTriangles(pMesh);
+ int M_numEdges(pMesh);
+ int M_numVertices(pMesh);
+
+ RIter M_regionIter(pMesh);
+ FIter M_faceIter(pMesh);
+ EIter M_edgeIter(pMesh);
+ VIter M_vertexIter(pMesh);
+
+ int M_numClassifiedRegions (pMesh, pGEntity);
+ int M_numClassifiedFaces (pMesh, pGEntity);
+ int M_numClassifiedEdges (pMesh, pGEntity);
+ int M_numClassifiedVertices(pMesh, pGEntity);
+
+ RIter M_classifiedRegionIter(pMesh, pGEntity);
+ FIter M_classifiedFaceIter (pMesh, pGEntity, int closure);
+ EIter M_classifiedEdgeIter (pMesh, pGEntity, int closure);
+ VIter M_classifiedVertexIter(pMesh, pGEntity, int closure);
+ pVertex M_classifiedVertex (pMesh, pGVertex);
+
+ /* mesh entity creation routines */
+ pRegion M_createR(pMesh, int nFace, pFace *faces, pGEntity);
+ pFace M_createF(pMesh, int nEdge, pEdge *edges, pGEntity);
+ pEdge M_createE(pMesh, pVertex v1, pVertex v2, pGEntity);
+ pVertex M_createV(pMesh, double x, double y, double z, int patch, pGEntity);
+ pVertex M_createV2(pMesh, double xyz[3], int patch, pGEntity);
+ pVertex M_createVP(pMesh, double x, double y, double z,
+ double u, double v, int patch, pGEntity);
+
+ /* mesh entity deletion routines */
+ void M_removeRegion(pMesh, pRegion);
+ void M_removeFace (pMesh, pFace);
+ void M_removeEdge (pMesh, pEdge);
+ void M_removeVertex(pMesh, pVertex);
+ void P_delete(pPoint);
+ pPoint P_new(void);
+
+ /***********************/
+ /* Geometric model ops */
+ /***********************/
+
+ int M_numGeomFeatures (pMesh);
+ int M_geomFeatureId (pMesh, int ith);
+ pPGList M_geomFeature (pMesh, int id);
+ void M_printGeomFeatures (pMesh);
+
+ /********************/
+ /* Entity Iter Ops */
+ /********************/
+
+ pRegion RIter_next (RIter);
+ void RIter_delete(RIter);
+ void RIter_reset (RIter);
+ pFace FIter_next (FIter);
+ void FIter_delete(FIter);
+ void FIter_reset (FIter);
+ pEdge EIter_next (EIter);
+ void EIter_delete(EIter);
+ void EIter_reset (EIter);
+ pVertex VIter_next (VIter);
+ void VIter_delete(VIter);
+ void VIter_reset (VIter);
+
+ /********************/
+ /* Entity Operators */
+ /********************/
+
+ void EN_info(const pEntity, std::string name="", std::ostream& out=std::cout);
+ void EN_setID(pEntity, int id);
+ int EN_id (pEntity);
+ void EN_print(pEntity);
+
+ int EN_type(pEntity);
+ int EN_whatInType(pEntity);
+ pGEntity EN_whatIn(pEntity);
+ void EN_setWhatIn(pEntity,pGEntity);
+
+ int EN_numVertices(const pEntity);
+ pPList EN_vertices(const pEntity);
+ int EN_inClosure(pEntity, pEntity);
+
+ /********************/
+ /* Region Operators */
+ /********************/
+
+ void R_info (const pRegion, std::string name="", std::ostream& out=std::cout);
+ void R_info_quality (const pRegion, std::ostream& out=std::cout);
+ void R_info_topology(const pRegion, std::ostream& out=std::cout);
+
+ pGRegion R_whatIn(pRegion);
+ int R_whatInType(pRegion);
+ void R_setWhatIn(pRegion, pGEntity);
+
+ int R_numPoints(pRegion);
+ pPoint R_point(pRegion,int);
+ int R_numVertices(pRegion);
+ pPList R_vertices(pRegion);
+ pVertex R_vertex(pRegion, int);
+ pVertex R_fcOpVt(const pRegion, const pFace);
+ pPList R_edges(pRegion);
+ pEdge R_edge(pRegion, int);
+ pEdge R_gtOppEdg(const pRegion, const pEdge);
+ int R_numFaces(pRegion);
+ pFace R_face(pRegion, int);
+ pPList R_faces(pRegion);
+ pFace R_vtOpFc(const pRegion, const pVertex);
+ int R_inClosure(pRegion, pEntity);
+ int R_faceDir(pRegion, int);
+ int R_faceOri(pRegion, int);
+ int R_dirUsingFace(pRegion,pFace);
+ int R_oriUsingFace(pRegion,pFace);
+
+ void R_coordP1(const pRegion, double [][3]);
+ void R_coord(const pRegion, double [][3]);
+ double R_volume(const pRegion);
+ double R_XYZ_volume (const double [][3]);
+ double R_circumRad(const pRegion);
+ double R_inscrRad(const pRegion);
+ bool R_meanRatioCube(const pRegion, double *);
+ bool R_XYZ_meanRatioCube(const double [][3], double *);
+ bool R_XYZ_isFlat(const double [][3]);
+ void R_linearParams(const pRegion, const double[3], double[3]);
+ void R_center(const pRegion, double [3]);
+ void R_jacobian(const pRegion, double [3][3]);
+ double R_invJacobian(const pRegion, double [3][3]);
+
+ /********************/
+ /* Face Operators */
+ /********************/
+
+ void F_info(const pFace, std::string name="", std::ostream& out=std::cout);
+
+ pFace F_exist(pEntity, pEntity, pEntity, pEntity);
+ pFace F_exist(pEdge,pVertex);
+
+ pGEntity F_whatIn(pFace);
+ int F_whatInType(pFace);
+ void F_setWhatIn(pFace, pGEntity);
+
+ pPoint F_point(pFace, int);
+ int F_numPoints(pFace);
+ int F_numPointsTot(pFace);
+ int F_numVertices(pFace);
+ pPList F_vertices(pFace, int dir);
+ pVertex F_vertex(pFace, int);
+ pEdge F_vtOpEd(const pFace, const pVertex);
+ int F_numEdges(pFace);
+ pPList F_edges(pFace);
+ pEdge F_edge(pFace, int);
+ int F_edgeDir(pFace, int);
+ pVertex F_edOpVt(const pFace, const pEdge);
+ int F_dirUsingEdge(pFace, pEdge);
+ int F_numRegions(pFace);
+ pPList F_regions(pFace);
+ pRegion F_region(pFace, int);
+ pRegion F_otherRegion(const pFace, const pRegion);
+ int F_inClosure(pFace, pEntity);
+ void F_chDir(pFace);
+ int F_align(pFace,pVertex,pVertex,pVertex,pVertex);
+
+ void F_coordP1(const pFace, double [][3]);
+ void F_coord(const pFace, double [][3]);
+ bool F_params(const pFace, double [][2]);
+ double F_area(const pFace, const double *dir=NULL);
+ double XYZ_F_area(const double [][3], const double *dir=NULL);
+ double F_areaSq(const pFace, const double *dir=NULL);
+ double XYZ_F_areaSq(const double [][3], const double *dir=NULL);
+ void F_linearParams(const pFace, const double[3], double[2]);
+ void F_center(const pFace, double [3]);
+ void F_normal(const pFace, double [3]);
+ void XYZ_F_normal(const double [3][3], double [3]);
+ bool F_volumeRatio(const pFace, double *);
+ double F_worstVolumeRatio(const std::set<pFace>);
+
+ /********************/
+ /* Edge Operators */
+ /********************/
+
+ void E_info(const pEdge, std::string name="", std::ostream& out=std::cout);
+
+ pEdge E_exist(pVertex, pVertex);
+
+ pGEntity E_whatIn(pEdge);
+ int E_whatInType(pEdge);
+ void E_setWhatIn(pEdge, pGEntity);
+
+ int E_numPoints(pEdge);
+ pPoint E_point(pEdge, int);
+ pVertex E_vertex(pEdge, int);
+ pPList E_vertices(const pEdge);
+ pVertex E_otherVertex(pEdge, pVertex);
+ int E_numFaces(pEdge);
+ pPList E_faces(const pEdge);
+ pFace E_face(pEdge, int);
+ pFace E_otherFace(pEdge, pFace, pRegion);
+ int E_numRegions(pEdge);
+ pPList E_regions(pEdge);
+ int E_inClosure(pEdge, pEntity);
+ int E_dir(pEdge, pVertex, pVertex);
+ int E_align(pEdge, pVertex,pVertex);
+
+ void E_coordP1(const pEdge, double [][3]);
+ void E_coord(const pEdge, double [][3]);
+ bool E_params(const pEdge, double [2][2]);
+ double E_length(const pEdge);
+ double E_lengthSq(const pEdge);
+ double E_linearParams(const pEdge, const pVertex);
+ double E_linearParams(const pEdge, const double[3]);
+ void E_center(const pEdge, double[3]);
+ void E_cavityCenter(const pEdge, double[3]);
+
+ /********************/
+ /* Point Operators */
+ /********************/
+
+ double P_x(pPoint);
+ double P_y(pPoint);
+ double P_z(pPoint);
+ void P_setPos(pPoint, double x, double y, double z);
+
+ void P_setID(pPoint, int);
+ int P_id(pPoint);
+
+ double P_param1(pPoint);
+ void P_setParam1(pPoint, double);
+
+ /********************/
+ /* Vertex Operators */
+ /********************/
+
+ void V_info(const pVertex, std::string name="", std::ostream& out=std::cout);
+
+ pGEntity V_whatIn(pVertex);
+ int V_whatInType(pVertex);
+ void V_setWhatIn(pVertex, pGEntity);
+
+ pPoint V_point(pVertex);
+ int V_numEdges(pVertex);
+ pPList V_edges(pVertex);
+ pEdge V_edge(pVertex, int);
+ int V_numFaces(pVertex);
+ pPList V_faces(pVertex);
+ int V_numRegions(pVertex);
+ pPList V_regions(pVertex);
+
+ int V_id(const pVertex);
+
+ void V_coord(const pVertex, double [3]);
+ bool V_params(pVertex, double *, double *);
+ double V_meanEdgeLenSq(const pVertex);
+ void V_cavityCenter(const pVertex, double[3]);
+
+ /***************************/
+ /* Entities list operators */
+ /***************************/
+
+ pPList PList_new();
+ pPList PList_allocate( );
+ void PList_delete (pPList);
+ void PList_deallocate (pPList);
+ void PList_clear (pPList);
+ pPList PList_appPListUnique (pPList, pPList source);
+ pPList PList_appUnique (pPList, pEntity);
+ pPList PList_append (pPList, pEntity);
+ int PList_size (pPList);
+ pEntity PList_item (pPList, int n);
+ pEntity PList_next (pPList, void ** restart);
+ int PList_inList (pPList, pEntity);
+ void PList_remItem (pPList, pEntity);
+
+ /***********************/
+ /* Attached data tools */
+ /***********************/
+
+ pMeshDataId MD_newMeshDataId(const std::string="");
+ pMeshDataId MD_lookupMeshDataId(const std::string);
+ void MD_deleteMeshDataId(pMeshDataId);
+
+ void EN_attachDataInt(pEntity, pMeshDataId, int);
+ void EN_attachDataDbl(pEntity, pMeshDataId, double);
+ void EN_attachDataPtr(pEntity, pMeshDataId, void *);
+ void EN_attachDataP (pEntity, const char *, void *);
+ void EN_attachDataI (pEntity, const char *, int);
+
+ void EN_modifyDataInt(pEntity, pMeshDataId, int);
+ void EN_modifyDataDbl(pEntity, pMeshDataId, double);
+ void EN_modifyDataPtr(pEntity, pMeshDataId, void *);
+ int EN_modifyDataP (pEntity, const char *, void *);
+ int EN_modifyDataI (pEntity, const char *, int);
+
+ void EN_deleteData(pEntity, pMeshDataId);
+ void EN_removeData(pEntity, const char *);
+
+ int EN_getDataInt(pEntity, pMeshDataId, int *);
+ int EN_getDataDbl(pEntity, pMeshDataId, double *);
+ int EN_getDataPtr(pEntity, pMeshDataId, void **);
+ void * EN_dataP(pEntity, const char *);
+ int EN_dataI(pEntity, const char *);
+
+}
+
+#endif
+
+
diff --git a/Mesh/MeshDataBaseIterators.h b/Mesh/MeshDataBaseIterators.h
new file mode 100644
index 0000000..33ea10e
--- /dev/null
+++ b/Mesh/MeshDataBaseIterators.h
@@ -0,0 +1,200 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASEITERATORS
+#define H_MESHDATABASEITERATORS
+
+namespace MAd {
+
+ template <class CONTAINER, class DATA, class CLASSIF>
+ class MDB_Iter
+ {
+ public:
+ CONTAINER *l;
+ CLASSIF g;
+ int closure;
+
+ typename CONTAINER::iterator current;
+ typename CONTAINER::iterator end;
+
+ MDB_Iter (CONTAINER *_l):l(_l),g(NULL),closure(0)
+ {
+ reset();
+ }
+ MDB_Iter (CONTAINER *_l,CLASSIF _g):l(_l),g((CLASSIF) _g),closure(0) {
+ reset();
+ }
+
+ MDB_Iter (CONTAINER *_l,CLASSIF _g,int _c):l(_l),g((CLASSIF) _g),closure(_c) {
+
+ /* if ((DATA::getDim() == 3) && (_c == 1)) { */
+ /* printf("Closure iterator not allowed for regions\n"); */
+ /* exit(1); */
+ /* } */
+
+ if (_c == 1) {
+ printf("Closure iterator not yet implemented \n");
+ exit(1);
+ }
+
+ reset();
+ }
+
+ virtual ~MDB_Iter() {}
+
+ inline void reset()
+ {
+ end = l->end();
+ current = l->begin();
+
+ if (!g) {
+ while(current != end && (*current)->deleted)
+ {
+ typename CONTAINER::iterator currentb = current;
+ current++;
+ delete *currentb;
+ l->erase(currentb);
+ }
+ }
+ else {
+ while(current != end && ((*current)->deleted || (*current)->g != g))
+ {
+ typename CONTAINER::iterator currentb = current;
+ current++;
+ if ((*currentb)->deleted) {
+ delete *currentb;
+ l->erase(currentb);
+ }
+ }
+ }
+ // if (!g && current!= end && (*current)->deleted)next();
+ // if (g && current!= end && ((*current)->deleted || (*current)->g != g)) next();
+
+ }
+ inline void cleanup()
+ {
+ current = l->begin();
+ while(next()){}
+ }
+
+ inline virtual DATA * next ()
+ {
+ if (current == end) return 0;
+
+ DATA *r = *current;
+ ++ current;
+
+ if (!g) {
+ while(current != end && (*current)->deleted)
+ {
+ typename CONTAINER::iterator currentb = current;
+ current++;
+ delete *currentb;
+ l->erase(currentb);
+ }
+ }
+ else {
+ while(current != end && ((*current)->deleted || (*current)->g != g))
+ {
+ typename CONTAINER::iterator currentb = current;
+ current++;
+ if ((*currentb)->deleted) {
+ delete *currentb;
+ l->erase(currentb);
+ }
+ }
+ }
+
+ // if the result data was marked for deletion
+ // after previous call to next() look for the next one
+ if (r->deleted) {
+
+ if (current == end) return 0;
+
+ r = *current;
+ ++ current;
+
+ if (!g) {
+ while(current != end && (*current)->deleted)
+ {
+ typename CONTAINER::iterator currentb = current;
+ current++;
+ delete *currentb;
+ l->erase(currentb);
+ }
+ }
+ else {
+ while(current != end && ((*current)->deleted || (*current)->g != g))
+ {
+ typename CONTAINER::iterator currentb = current;
+ current++;
+ if ((*currentb)->deleted) {
+ delete *currentb;
+ l->erase(currentb);
+ }
+ }
+ }
+
+ }
+
+ return r;
+ }
+
+ };
+
+ template <class CONTAINER, class DATA, class CLASSIF>
+ int countClassifiedElements (CONTAINER* c,CLASSIF g) {
+
+ MDB_Iter<CONTAINER,DATA,CLASSIF>* iter = new MDB_Iter<CONTAINER,DATA,CLASSIF>(c,g);
+
+ DATA* el = NULL;
+ int count = 0;
+ while ( (el = iter->next()) ) count++;
+ delete iter;
+
+ return count;
+
+ }
+
+}
+
+
+/* //report errors to koen.hillewaert at cenaero.be */
+/* template <class CONTAINER, class DATA> */
+/* class MDB_CIter: public MDB_Iter <CONTAINER,DATA> */
+/* { */
+/* public: */
+/* pGEntity ge; */
+/* MDB_CIter (CONTAINER *_l,pGEntity _g):MDB_Iter<CONTAINER,DATA>(_l),ge(_g) */
+/* { */
+/* reset(); */
+/* } */
+/* inline DATA * next () */
+/* { */
+/* if (current == end)return 0; */
+/* DATA *r = *current; */
+/* ++ current; */
+/* while(current != end && */
+/* (*current)->deleted && */
+/* EN_whatIn(current) != ge) */
+/* { */
+/* typename CONTAINER::iterator currentb = current; */
+/* current++; */
+/* delete *currentb; */
+/* l->erase(currentb); */
+/* } */
+/* return r; */
+/* } */
+/* }; */
+
+#endif
diff --git a/Mesh/MeshDataBaseLoadBalancing.cc b/Mesh/MeshDataBaseLoadBalancing.cc
new file mode 100644
index 0000000..9971300
--- /dev/null
+++ b/Mesh/MeshDataBaseLoadBalancing.cc
@@ -0,0 +1,3032 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+
+#include "MeshDataBase.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "MeshDataBaseLoadBalancing.h"
+#include "MeshDataBaseComm.h"
+
+#include "assert.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <fstream>
+#include <iostream>
+
+namespace MAd {
+
+ typedef std::pair<int, pVertex> CommonpVertex_type;
+ typedef std::vector< CommonpVertex_type > VectorOfCommonpVertex_type;
+ // -------------------------------------------------------------------
+ struct points_comm
+ {
+ pVertex p; //pointeur in dest
+ int nID; //myrank
+ int newproc;
+ };
+
+ // -------------------------------------------------------------------
+ struct oldinterfaces_comm
+ {
+ int oldnum;
+ pVertex oldpv;
+ };
+ // -------------------------------------------------------------------
+ struct coor_comm
+ {
+ double X,Y,Z;
+ int tag,dim;
+ int nproc;
+ pVertex psend;
+ };
+ // -------------------------------------------------------------------
+ struct newinterfaces_comm
+ {
+ int newproc;
+ };
+ // -------------------------------------------------------------------
+ struct points_comm_new
+ {
+ pVertex pdest; //pointeur in dest
+ int destID;
+ pVertex psend;
+ int sendID;
+ };
+
+ // -------------------------------------------------------------------
+ void ExchangeUpdatedInterfaceNodalInfo(pMesh mesh)
+ {
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv, tagData, &temp_ptr);
+
+ if(!isInterface) continue;
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) pv, tagChange, &tmp);
+ assert(isChanged);
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) pv, tagRemote, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 =
+ (VectorOfCommonpVertex_type *) temp_ptr2;
+
+ for(int j=0; j<(int)((*recup).size()); j++) {
+ for( int i=0; i<(int)((*recup2).size()); i++) {
+ int remoteID = (*recup)[j].first;
+ assert(remoteID != myrank);
+ void *buf = AP_alloc(remoteID,444,sizeof(points_comm));
+ points_comm *castbuf = (points_comm *) buf;
+ castbuf->p = (*recup)[j].second;
+ castbuf->nID = myrank;
+ assert((*recup2)[i].first < nproc);
+ castbuf->newproc = (*recup2)[i].first;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ }
+ }
+ VIter_delete(vit);
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ points_comm * castbuf = (points_comm*) msg;
+ pVertex precv (NULL);
+ precv = castbuf -> p;
+ assert(precv);
+ int nprocrecv = castbuf->newproc;
+ assert(nprocrecv<nproc);
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) precv, tagChange, &tmp);
+ assert(isChanged);
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) precv, tagRemote, &temp_ptr);
+ assert(is);
+ VectorOfCommonpVertex_type *recup =
+ (VectorOfCommonpVertex_type *) temp_ptr;
+ int * tabproc = new int[nproc];
+ for(int i=0 ; i<nproc ; i++){
+ tabproc[i] = 0;
+ }
+ for(unsigned int i=0 ; i<(*recup).size() ; i++){
+ tabproc[(*recup)[i].first] = 1;
+ }
+ if(!tabproc[nprocrecv]){
+ (*recup).push_back( CommonpVertex_type (nprocrecv,NULL));
+ }
+
+ AP_free(msg);
+ delete []tabproc;
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+ }
+
+ // -------------------------------------------------------------------
+ void MarkEltVertex(pMesh mesh, pMeshDataId tagElt)
+ {
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ // Integer set to one if the vertex will change
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+
+ // Data attached to each parallel vertex: distant proc
+ // together with distant pointer for the same vertex
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+
+ // Like tagData but after the interface move
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+
+
+ // --- Mark vertices ---
+ int Dim = (mesh->tets.empty()) ? 2 : 3;
+ if(Dim==2) {
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ int dest;
+ int migre = EN_getDataInt((pEntity) pface, tagElt, &dest);
+ if(!migre) continue;
+
+ pVertex nod[3];
+ nod[0] = F_vertex(pface,0);
+ nod[1] = F_vertex(pface,1);
+ nod[2] = F_vertex(pface,2);
+ for(int i=0 ; i<3 ; i++) {
+ EN_attachDataInt((pEntity) nod[i], tagChange, 1);
+ }
+ }
+ FIter_delete(fit);
+ } else {
+ if(Dim!=3) throw;
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ int dest;
+ int migre = EN_getDataInt((pEntity) pr, tagElt, &dest);
+ if(!migre) continue;
+
+ pVertex nod[4];
+ nod[0] = R_vertex(pr,0);
+ nod[1] = R_vertex(pr,1);
+ nod[2] = R_vertex(pr,2);
+ nod[3] = R_vertex(pr,3);
+ for(int i=0 ; i<4 ; i++) {
+ EN_attachDataInt((pEntity) nod[i], tagChange, 1);
+ }
+ }
+ RIter_delete(rit);
+ }
+
+ // --- Attach info about every future distant node to the marked nodes ---
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ vit = M_vertexIter(mesh);
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv, tagData, &temp_ptr);
+ if(!(isInterface || isChanged)) continue;
+ if(!isChanged) EN_attachDataInt((pEntity) pv, tagChange, 1);
+ /*vertex ball*/
+ int ncompt = 0;
+ int *tabproc=new int[nproc];
+ for(int i=0 ; i<nproc ; i++){
+ tabproc[i] = 0;
+ }
+ if(Dim==2) {
+ void *iter = 0;
+ pPList ball = V_faces (pv);
+ pFace pface;
+ while( (pface =(pFace) PList_next(ball,&iter)) ) {
+ int dest;
+ int migre = EN_getDataInt((pEntity) pface, tagElt, &dest);
+ if(migre) {
+ tabproc[dest-1] = 1;
+ } else {
+ tabproc[myrank] = 1;
+ }
+ }
+ } else {
+ void *iter = 0;
+ pPList ball = V_regions (pv);
+ pRegion pr;
+ while( (pr =(pRegion) PList_next(ball,&iter)) ) {
+ int dest;
+ int migre = EN_getDataInt((pEntity) pr , tagElt,&dest);
+ if(migre) {
+ tabproc[dest-1] = 1;
+ } else {
+ tabproc[myrank] = 1;
+ }
+ }
+
+ }
+ for(int i=0 ; i<nproc ; i++){
+ ncompt += tabproc[i];
+ }
+ if(ncompt > 1) {
+ VectorOfCommonpVertex_type remoteUpdate;
+ for(int i=0 ; i<nproc ; i++) {
+ if(tabproc[i]) {
+ (remoteUpdate).push_back(CommonpVertex_type(i,NULL));
+ }
+ EN_attachDataPtr((pEntity) pv , tagRemote,
+ new VectorOfCommonpVertex_type (remoteUpdate));
+ }
+ } else {
+ int i=0;
+ for(i=0 ; i<nproc ; i++) {
+ if(tabproc[i] && (i != myrank)) break;
+ }
+ if(i==nproc) {
+ assert(tabproc[myrank]);
+ assert(isInterface);
+ i = myrank;
+ }
+ VectorOfCommonpVertex_type remoteUpdate;
+ (remoteUpdate).push_back(CommonpVertex_type(i,NULL));
+ EN_attachDataPtr((pEntity) pv , tagRemote,
+ new VectorOfCommonpVertex_type (remoteUpdate));
+ }
+ delete []tabproc;
+ }
+ VIter_delete(vit);
+
+ // --- Send and receive info at nodes for updated interface ---
+ ExchangeUpdatedInterfaceNodalInfo(mesh);
+
+ }
+
+#ifdef DEBUG
+ // -------------------------------------------------------------------
+ void checkRemotePointer(pMesh mesh, pMeshDataId tagData ) {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ if(!isInterface) continue;
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ int sizeinterface = (*recup).size();
+
+ for(int i=0 ; i<sizeinterface ; i++) {
+ int remoteID = (*recup)[i].first;
+ assert(remoteID!=myrank);
+ void *buf = AP_alloc(remoteID,444,sizeof(oldinterfaces_comm));
+ oldinterfaces_comm *castbuf = (oldinterfaces_comm *) buf;
+ castbuf->oldnum = myrank;
+ assert((*recup)[i].second);
+ castbuf->oldpv = (*recup)[i].second;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ }
+ VIter_delete(vit);
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ oldinterfaces_comm * castbuf = (oldinterfaces_comm *) msg;
+ pVertex pv = castbuf->oldpv;
+ int recvID = castbuf->oldnum;
+ void *temp_ptr;
+ int isInte = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ assert(isInte);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j=0;
+ for( j=0 ; j<(*recup).size() ; j++) {
+ int remoteID = (*recup)[j].first;
+ assert((*recup)[j].second);
+ if(remoteID == recvID) break;
+ }
+ assert(j!= (*recup).size());
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+
+
+ }
+
+ // -------------------------------------------------------------------
+ void checkRemotePointer2(pMesh mesh, pMeshDataId tagData ) {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ if(!isInterface) continue;
+ int tmp;
+ int isChange=EN_getDataInt((pEntity) pv , tagChange, &tmp);
+ if(!(isChange && tmp==1)) continue;
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ int sizeinterface = (*recup).size();
+
+ for(int i=0 ; i<sizeinterface ; i++) {
+ int remoteID = (*recup)[i].first;
+ assert(remoteID!=myrank);
+ void *buf = AP_alloc(remoteID,444,sizeof(oldinterfaces_comm));
+ oldinterfaces_comm *castbuf = (oldinterfaces_comm *) buf;
+ castbuf->oldnum = myrank;
+ castbuf->oldpv = (*recup)[i].second;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ }
+ VIter_delete(vit);
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ oldinterfaces_comm * castbuf = (oldinterfaces_comm *) msg;
+ pVertex pv = castbuf->oldpv;
+ int recvID = castbuf->oldnum;
+ void *temp_ptr;
+ int isInte = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ assert(isInte);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j=0;
+ for( j=0 ; j<(*recup).size() ; j++) {
+ int remoteID = (*recup)[j].first;
+ if(remoteID == recvID) break;
+ }
+ assert(j!= (*recup).size());
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+
+
+ }
+
+ // -------------------------------------------------------------------
+ void checkRemotePointerChange(pMesh mesh, pMeshDataId tagData,
+ pMeshDataId tagNew, pMeshDataId tagChange ) {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isChange = EN_getDataInt((pEntity) pv , tagChange, &tmp);
+ if(isChange) {
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagNew, &temp_ptr);
+ assert(isInterface);
+ if(!isInterface) continue;
+ VectorOfCommonpVertex_type *recup =
+ (VectorOfCommonpVertex_type *) temp_ptr;
+ int sizeinterface = (*recup).size();
+ for(int i=0 ; i<sizeinterface ; i++) {
+ int remoteID = (*recup)[i].first;
+ if(remoteID==myrank){
+ assert(sizeinterface==1);
+ continue;
+ }
+ void *buf = AP_alloc(remoteID,444,sizeof(oldinterfaces_comm));
+ oldinterfaces_comm *castbuf = (oldinterfaces_comm *) buf;
+ castbuf->oldnum = myrank;
+ castbuf->oldpv = (*recup)[i].second;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+
+ } else {
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ if(!isInterface) continue;
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ int sizeinterface = (*recup).size();
+
+ for(int i=0 ; i<sizeinterface ; i++) {
+ int remoteID = (*recup)[i].first;
+ assert(remoteID!=myrank);
+ void *buf = AP_alloc(remoteID,444,sizeof(oldinterfaces_comm));
+ oldinterfaces_comm *castbuf = (oldinterfaces_comm *) buf;
+ castbuf->oldnum = myrank;
+ castbuf->oldpv = (*recup)[i].second;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ }
+ }
+ VIter_delete(vit);
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ oldinterfaces_comm * castbuf = (oldinterfaces_comm *) msg;
+ pVertex pv = castbuf->oldpv;
+ int recvID = castbuf->oldnum;
+ int tmp;
+ int isChange = EN_getDataInt((pEntity) pv , tagChange, &tmp);
+ if(isChange) {
+ void *temp_ptr;
+ int isInte = EN_getDataPtr((pEntity) pv , tagNew, &temp_ptr);
+ assert(isInte);
+ VectorOfCommonpVertex_type *recup =
+ (VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j=0;
+ for( j=0 ; j<(*recup).size() ; j++) {
+ int remoteID = (*recup)[j].first;
+ if(remoteID == recvID) break;
+ }
+ assert(j!= (*recup).size());
+
+ } else {
+ void *temp_ptr;
+ int isInte = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ if(isInte) {
+ unsigned int j=0;
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ for( j=0 ; j<(*recup).size() ; j++) {
+ int remoteID = (*recup)[j].first;
+ if(remoteID == recvID) break;
+ }
+ if(j==(*recup).size()) {
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) pv , tagNew, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 =
+ (VectorOfCommonpVertex_type *) temp_ptr2;
+ if((*recup2).size()==1) break;
+ for( j=0 ; j<(*recup2).size() ; j++) {
+ int remoteID = (*recup2)[j].first;
+ if(remoteID == recvID) break;
+ }
+ if(j==(*recup2).size()) {
+ for( j=0 ; j<(*recup2).size() ; j++) {
+ printf("recup2 %d\n",(*recup2)[j].first);
+ }
+ printf("je suis %d et tu es %d\n",myrank,recvID);
+ }
+ assert(j<(*recup2).size());
+ int minproc = nproc + 10;
+ for( j=0 ; j<(*recup2).size() ; j++) {
+ int remoteID = (*recup2)[j].first;
+ minproc = std::min(minproc,remoteID);
+ }
+ assert(minproc==recvID);
+ }
+ }
+ }
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+ }
+
+ // -------------------------------------------------------------------
+ void checkNew(pMesh mesh, pMeshDataId tagData,pMeshDataId tagChange ) {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+ pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isMaster = EN_getDataInt((pEntity) pv , tagMaster, &tmp);
+ if(!isMaster) continue;
+ int isChange = EN_getDataInt((pEntity) pv , tagChange, &tmp);
+ if(!(isChange && (tmp==1))) continue;
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ assert(isInterface);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ int sizeinterface = (*recup).size();
+ if(sizeinterface<=1) {
+ printf("--------------- my %d\n",myrank);
+ unsigned int kk;
+ for(kk=0 ; kk<(*recup).size() ; kk++) {
+ printf("recup %d \n",(*recup)[kk].first);
+ }
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 =
+ (VectorOfCommonpVertex_type *) temp_ptr2;
+ assert((*recup2).size());
+ for(kk=0 ; kk<(*recup2).size() ; kk++){
+ printf("recup2 %d \n",(*recup2)[kk].first);
+ }
+ }
+ assert(sizeinterface>1);
+ int i;
+ for(i=0 ; i<sizeinterface ; i++){
+ if(myrank==(*recup)[i].first) break;
+ }
+ assert(i<sizeinterface);
+ }
+ VIter_delete(vit);
+
+ vit = M_vertexIter(mesh);
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isChange = EN_getDataInt((pEntity) pv , tagChange, &tmp);
+ if(!(isChange && (tmp==1))) continue;
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ assert(isInterface);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ int sizeinterface = (*recup).size();
+ if(sizeinterface<=1) {
+ printf("--------------- my %d\n",myrank);
+ unsigned int kk;
+ for(kk=0 ; kk<(*recup).size() ; kk++){
+ printf("recup %d \n",(*recup)[kk].first);
+ }
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 =
+ (VectorOfCommonpVertex_type *) temp_ptr2;
+ assert((*recup2).size());
+ for(kk=0 ; kk<(*recup2).size() ; kk++) {
+ printf("recup2 %d %p\n",(*recup2)[kk].first,(*recup2)[kk].second);
+ }
+ }
+ assert(sizeinterface>1);
+ int i;
+ for(i=0 ; i<sizeinterface ; i++){
+ if(myrank==(*recup)[i].first) break;
+ }
+ assert(i<sizeinterface);
+ }
+ VIter_delete(vit);
+ }
+
+#endif
+
+ // -------------------------------------------------------------------
+ void UpdateInterfaces4(pMesh mesh) {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isMaster = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+ if(!isMaster) continue;
+
+ int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+ assert(tmp==1 && isChanged);
+
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ assert(isInterface);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ assert((*recup).size()>1);
+
+ for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+ int remoteID = (*recup)[i].first;
+ if(remoteID==myrank) continue;
+ pVertex remoteP = (*recup)[i].second;
+ assert(remoteP);
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+ int intID = (*recup)[j].first;
+ if(intID==remoteID || intID==myrank) continue;
+ pVertex intP = (*recup)[j].second;
+ assert(intP);
+ void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+ points_comm_new *castbuf = (points_comm_new *) buf;
+ castbuf->pdest = remoteP;
+ castbuf->psend = intP;
+ castbuf->sendID = intID;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ }
+ }
+ VIter_delete(vit);
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ points_comm_new * castbuf = (points_comm_new *) msg;
+ pVertex pmine = castbuf->pdest;
+ pVertex precv = castbuf->psend;
+ int recvID = castbuf->sendID;
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pmine , tagData, &temp_ptr);
+ int tmp;
+ int isMaster = EN_getDataInt((pEntity) pmine , tagMaster,&tmp);
+ assert(isInterface);
+ assert(!isMaster);
+ VectorOfCommonpVertex_type *recup =
+ (VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j=0;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ int remoteID = (*recup)[j].first;
+ if(remoteID == recvID) {
+ (*recup)[j].second = precv;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+ vit = M_vertexIter(mesh);
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ EN_getDataInt((pEntity) pv , tagChange,&tmp);
+ if(tmp!=1) continue;
+
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ assert(isInterface);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ assert((*recup).size()>1);
+
+ VectorOfCommonpVertex_type newInterface;
+ for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+ int remoteID = (*recup)[i].first;
+ if(remoteID==myrank) continue;
+ pVertex remoteP = (*recup)[i].second;
+ assert(remoteP);
+ newInterface.push_back(CommonpVertex_type(remoteID,remoteP));
+ }
+ EN_attachDataPtr((pEntity) pv ,tagData,
+ new VectorOfCommonpVertex_type(newInterface));
+
+ }
+ VIter_delete(vit);
+
+
+ }
+
+ // -------------------------------------------------------------------
+ void UpdateInterfaces3(pMesh mesh) {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+ if(!isChanged) continue;
+ if(tmp==2) continue;
+ if(tmp==3) continue;
+ assert(tmp==1);
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ int isMaster = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+ if(isMaster) assert(isInterface);
+ assert(isInterface);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ if(isMaster) assert((*recup).size()>1);
+ if(!isMaster) {
+ assert((*recup).size()>1);
+ int remoteID = nproc + 10;
+ pVertex psend;
+ for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+ if(remoteID > (*recup)[i].first) {
+ remoteID = (*recup)[i].first;
+ psend = (*recup)[i].second;
+ }
+ }
+ assert(remoteID < nproc);
+ assert(remoteID!=myrank);
+ assert(remoteID<myrank);
+ for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+ assert(remoteID <=(*recup)[i].first);
+ }
+ void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+ points_comm_new *castbuf = (points_comm_new *) buf;
+ castbuf->pdest = psend;
+ castbuf->psend = pv;
+ castbuf->sendID = myrank;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ }
+ VIter_delete(vit);
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ points_comm_new * castbuf = (points_comm_new *) msg;
+ pVertex pmine = castbuf->pdest;
+ pVertex precv = castbuf->psend;
+ int recvID = castbuf->sendID;
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pmine , tagData, &temp_ptr);
+ int tmp;
+ int isMaster = EN_getDataInt((pEntity) pmine , tagMaster,&tmp);
+ assert(isInterface);
+ assert(isInterface && isMaster);
+ VectorOfCommonpVertex_type *recup =
+ (VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j=0;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ int remoteID = (*recup)[j].first;
+ if(remoteID == recvID) {
+ (*recup)[j].second = precv;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+ }
+
+ // -------------------------------------------------------------------
+ void UpdateInterfaces2(pMesh mesh, MDB_DataExchanger &de) {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+ pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isMaster = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+ if(!isMaster) continue;
+#ifdef DEBUG
+ int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+ assert(isChanged);
+ assert(tmp==1);
+#endif
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr2);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup2 =
+ (const VectorOfCommonpVertex_type *) temp_ptr2;
+ int sizeinterface = (*recup2).size();
+ assert(sizeinterface>1);
+ int *listID=new int[sizeinterface];
+ for(int i=0 ; i<sizeinterface ; i++){
+ listID[i] = (*recup2)[i].first;
+ }
+#ifdef DEBUG
+ int k;
+ for(k=0 ; k<sizeinterface ; k++){
+ if(myrank==(*recup2)[k].first) break;
+ }
+ assert(k!=sizeinterface);
+#endif
+ void *temp_ptr;
+ int oldPoint = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr);
+ VectorOfCommonpVertex_type *recup =
+ (VectorOfCommonpVertex_type *) temp_ptr;
+ assert(oldPoint);
+ assert((*recup).size());
+#ifdef DEBUG
+ unsigned int kk;
+ for(kk=0 ; kk<(*recup).size() ; kk++){
+ if(myrank==(*recup)[kk].first) break;
+ }
+ if(kk!=(*recup).size()) {
+ if((*recup).size()!=1) {
+ printf("----------------- myrank %d %d\n",myrank,kk);
+ for(k=0 ; k<sizeinterface ; k++){
+ printf("recup2 %d \n",(*recup2)[k].first);
+ }
+ for(kk=0 ; kk<(*recup).size() ; kk++){
+ printf("recup %d \n",(*recup)[kk].first);
+ }
+ }
+ assert((*recup).size()==1);
+ }
+#endif
+
+ int *tabp=new int[nproc];
+ int *tabproc=new int[nproc];
+ for(int i=0 ; i<nproc ; i++) tabproc[i] = 0;
+ for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+ tabproc[(*recup)[i].first] += 1;
+ tabp[(*recup)[i].first] = i;
+ }
+ for(int i=0 ; i<sizeinterface ; i++) {
+ int remoteID = (*recup2)[i].first;
+ if(remoteID==myrank) continue;
+ if(tabproc[remoteID]) { /*already exists -- send my pointer, my ID and its pointer*/
+ assert(tabproc[remoteID]==1);
+ assert(remoteID!=myrank);
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+
+ void *buf = AP_alloc(remoteID,de.tag(),sizeof(int) +
+ sizeof(points_comm_new) + sizebuf);
+ char *castbuf = (char *) buf;
+ int cas = -1;
+ memcpy(&castbuf[0],&cas,sizeof(int));
+ points_comm_new pcn;
+ pcn.pdest = ((*recup)[tabp[remoteID]]).second;
+ assert(((*recup)[tabp[remoteID]]).first==remoteID);
+ pcn.psend = pv;
+ pcn.sendID = myrank;
+ pcn.destID = remoteID;
+ memcpy(&castbuf[sizeof(int)],&pcn,sizeof(points_comm_new));
+ memcpy(&castbuf[sizeof(int)+sizeof(points_comm_new)],msg,sizebuf);
+ free(msg);
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ } else { /*new for proc remoteID -- send coor point + Remote info + my pointer*/
+ assert(remoteID!=myrank);
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+ void *buf = AP_alloc(remoteID,de.tag(),2*sizeof(int)+
+ sizeof(coor_comm)+ (sizeinterface) * sizeof(int) + sizebuf );
+ char *castbuf = (char *) buf;
+ int cas = 1;
+ memcpy(&castbuf[0],&cas,sizeof(int));
+ coor_comm coorcom;
+ coorcom.X = P_x(pv);
+ coorcom.Y = P_y(pv);
+ coorcom.Z = P_z(pv);
+ pGEntity pg = EN_whatIn(pv);
+ coorcom.tag = GEN_tag(pg);
+ coorcom.dim = GEN_type(pg);
+ coorcom.nproc = myrank;
+ coorcom.psend = pv;
+ memcpy(&castbuf[sizeof(int)],&coorcom,sizeof(coor_comm));
+ memcpy(&castbuf[sizeof(int) + sizeof(coor_comm)],&sizeinterface,sizeof(int));
+ memcpy(&castbuf[sizeof(int) + sizeof(coor_comm) + sizeof(int)],&listID[0],sizeinterface * sizeof(int));
+ memcpy(&castbuf[2*sizeof(int) + sizeof(coor_comm)+ (sizeinterface) * sizeof(int)],msg,sizebuf);
+ free(msg);
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ }
+ delete []tabp;
+ delete []tabproc;
+ delete []listID;
+ }
+ VIter_delete(vit);
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ char * castbuf = (char *) msg;
+ int cas = *((int *) &castbuf[0]);
+ if(cas == 1) {/*point doesn't exist*/
+ coor_comm * coorcom = (coor_comm * ) &castbuf[sizeof(int)];
+ pGEntity pent;
+ int dim = coorcom->dim;
+ int tag = coorcom->tag;
+ if(dim == 0) {
+ pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+ } else if(dim==1) {
+ pent = (pGEntity) GM_edgeByTag(mesh->model,tag);
+ } else if(dim==2) {
+ pent = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pent = (pGEntity) GM_regionByTag(mesh->model,tag);
+ } else {
+ printf("pbs**** %d\n",dim);
+ }
+ // double X = coorcom->X;
+ // double Y = coorcom->Y;
+ // double Z = coorcom->Z;
+ // pVertex pnew = M_createVP(mesh,X,Y,Z,-1,pent);
+
+ double XYZ[3] = {coorcom->X,coorcom->Y,coorcom->Z};
+ pVertex pnew = M_createV2(mesh,XYZ,-1,pent);
+
+ assert(pnew);
+ int procdep = coorcom->nproc;
+ pVertex pdep = coorcom->psend;
+ unsigned int sizeinterfaces = *((int *) &castbuf[sizeof(int) +
+ sizeof(coor_comm)]);
+ assert(sizeinterfaces > 1);
+ VectorOfCommonpVertex_type RemoteData;
+ int isOK=0;
+ for(unsigned int i=0 ; i<sizeinterfaces ; i++) {
+ int num = *((int *) &castbuf[2*sizeof(int) + sizeof(coor_comm)
+ + i*sizeof(int)]);
+ if(num==procdep) {
+ isOK = 1;
+ RemoteData.push_back(CommonpVertex_type(procdep,pdep));
+ } else {
+ RemoteData.push_back(CommonpVertex_type(num,NULL));
+ }
+ }
+ assert(isOK);
+ EN_attachDataInt((pEntity) pnew ,tagChange, 1);
+ assert(RemoteData.size()==sizeinterfaces);
+ assert(RemoteData.size()>1);
+
+ EN_attachDataPtr((pEntity) pnew ,tagData,
+ new VectorOfCommonpVertex_type(RemoteData));
+ de.receiveData (pnew,from, &castbuf[2*sizeof(int)
+ + sizeof(coor_comm)+ (sizeinterfaces) * sizeof(int)]);
+
+ } else { /*point already exists*/
+ assert(cas==-1);
+ points_comm_new * pcn = (points_comm_new * ) &castbuf[sizeof(int)];
+ pVertex pv = pcn->pdest;
+ pVertex precv = pcn->psend;
+ int recvID = pcn->sendID;
+ int destID = pcn->destID;
+ assert(pv);
+ assert(destID==myrank);
+ assert(recvID!=myrank);
+ void *temp_ptr;
+ int isInte = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr);
+ assert(isInte);
+#ifdef DEBUG
+ int tmp;
+ int isMaster = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+ assert(isInte && !isMaster);
+ int isC = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+ assert(isC && (tmp==1));
+#endif
+ VectorOfCommonpVertex_type *recup =
+ (VectorOfCommonpVertex_type *) temp_ptr;
+ assert((*recup).size()>1);
+ VectorOfCommonpVertex_type newRemote;
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+ int remoteID = (*recup)[j].first;
+ if(remoteID == recvID) {
+ newRemote.push_back(CommonpVertex_type(remoteID,precv));
+ } else {
+ newRemote.push_back(CommonpVertex_type(remoteID,NULL));
+ }
+ }
+ assert(newRemote.size()>1);
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr2);
+ if(is) EN_deleteData((pEntity) pv , tagData);
+
+ EN_attachDataPtr((pEntity) pv ,tagData,
+ new VectorOfCommonpVertex_type(newRemote));
+ de.receiveData (pv,from, &castbuf[sizeof(int)+sizeof(points_comm_new)]);
+
+ }
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+ }
+
+
+ // -------------------------------------------------------------------
+ void UpdateInterfaces1(pMesh mesh, MDB_DataExchanger &de)
+ {
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+ pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+ if(!isChanged) continue;
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 =
+ (VectorOfCommonpVertex_type *) temp_ptr2;
+ if((*recup2).size()==1) {
+
+ EN_attachDataInt((pEntity) pv , tagChange,2);
+ continue;
+ }
+ assert((*recup2).size()>1);
+ /*est ce que je suis a la fin?*/
+ unsigned int i=0;
+ for(i=0 ; i< (*recup2).size(); i++){
+ if(myrank==(*recup2)[i].first) break;
+ }
+ if(i==(*recup2).size()) EN_attachDataInt((pEntity) pv , tagChange,3);
+
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+
+ int remoteID;
+
+ if(isInterface) {
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ int minproc = nproc + 10;
+ assert((*recup).size());
+ for(unsigned int i=0 ; i<(*recup).size() ; i++){
+ minproc = std::min(minproc,(*recup)[i].first);
+ }
+ minproc = std::min(minproc,myrank);
+
+ remoteID = nproc + 10 ;
+ for(unsigned int i=0 ; i<(*recup2).size() ; i++) {
+ remoteID = std::min(remoteID,(*recup2)[i].first);
+ }
+ assert(remoteID<nproc && remoteID > -1);
+
+ if(remoteID == myrank) {
+ EN_attachDataInt((pEntity) pv , tagMaster,1);
+ /*swap RemoteData and Data*/
+ VectorOfCommonpVertex_type temp ;
+ for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+ int num = (*recup)[i].first;
+ pVertex p = (*recup)[i].second;
+ temp.push_back(CommonpVertex_type(num,p));
+ }
+ assert((*recup2).size()>1);
+ VectorOfCommonpVertex_type temp2 ;
+ for(unsigned int i=0 ; i<(*recup2).size() ; i++) {
+ int num = (*recup2)[i].first;
+ pVertex p = (*recup2)[i].second;
+ temp2.push_back(CommonpVertex_type(num,p));
+ }
+ delete recup2;
+ delete recup;
+ EN_attachDataPtr((pEntity) pv , tagData,
+ new VectorOfCommonpVertex_type(temp2));
+ EN_attachDataPtr((pEntity) pv , tagRemote,
+ new VectorOfCommonpVertex_type(temp));
+ continue;
+ }
+
+ if(minproc != myrank) continue;
+ assert(minproc==myrank);
+ int recupsize = (*recup).size();
+ assert(recupsize);
+ int recupsize2 = (*recup2).size();
+ int i=0;
+ for(i=0 ; i< recupsize; i++){
+ if(remoteID==(*recup)[i].first) break;
+ }
+ if(i!=recupsize) continue; /*proc remoteID already knows info*/
+ assert(i==recupsize);
+ /*send info to remoteID*/
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+ void *buf = AP_alloc(remoteID,de.tag(),2*sizeof(int)+ recupsize
+ * sizeof(oldinterfaces_comm)
+ + recupsize2 * sizeof(newinterfaces_comm)
+ + sizeof(coor_comm) + sizebuf);
+ char *castbuf = (char *) buf;
+ memcpy(&castbuf[0],&(recupsize),sizeof(int));
+ for(i=0 ; i<recupsize ; i++) {
+ oldinterfaces_comm oldint;
+ oldint.oldnum = (*recup)[i].first;
+ oldint.oldpv = (*recup)[i].second;
+ memcpy(&castbuf[i*sizeof(oldinterfaces_comm)
+ + sizeof(int)],&oldint,sizeof(oldinterfaces_comm));
+ }
+ memcpy(&castbuf[recupsize*sizeof(oldinterfaces_comm)
+ + sizeof(int)],&(recupsize2),sizeof(int));
+ for(i=0 ; i<recupsize2 ; i++) {
+ newinterfaces_comm newint;
+ newint.newproc = (*recup2)[i].first;
+ memcpy(&castbuf[i * sizeof(newinterfaces_comm)
+ + recupsize*sizeof(oldinterfaces_comm) + 2*sizeof(int)],
+ &newint,sizeof(newinterfaces_comm));
+ }
+ coor_comm coorcom;
+ coorcom.X = P_x(pv);
+ coorcom.Y = P_y(pv);
+ coorcom.Z = P_z(pv);
+ pGEntity pg = EN_whatIn(pv);
+ coorcom.tag = GEN_tag(pg);
+ coorcom.dim = GEN_type(pg);
+ coorcom.nproc = myrank;
+ coorcom.psend = pv;
+ memcpy(&castbuf[recupsize * sizeof(oldinterfaces_comm)
+ + recupsize2 * sizeof(newinterfaces_comm)
+ + 2*sizeof(int)],&coorcom,sizeof(coor_comm));
+ memcpy(&castbuf[recupsize * sizeof(oldinterfaces_comm)
+ + recupsize2 * sizeof(newinterfaces_comm) + 2*sizeof(int)
+ + sizeof(coor_comm)],msg,sizebuf);
+ free(msg);
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ } else {
+ remoteID = nproc + 10;
+ assert((*recup2).size() != 1);
+ for(unsigned int i=0 ; i<(*recup2).size() ; i++){
+ remoteID = std::min(remoteID,(*recup2)[i].first);
+ }
+ assert(remoteID<nproc);
+ if(remoteID == myrank) {
+ int tmp;
+ int is = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+ assert(!is);
+ EN_attachDataInt((pEntity) pv , tagMaster, 1);
+ /*swap RemoteData and Data*/
+ assert((*recup2).size()>1);
+ VectorOfCommonpVertex_type temp2 ;
+ for(unsigned int i=0 ; i<(*recup2).size() ; i++) {
+ int num = (*recup2)[i].first;
+ pVertex p = (*recup2)[i].second;
+ temp2.push_back(CommonpVertex_type(num,p));
+ }
+ EN_attachDataPtr((pEntity) pv , tagData,
+ new VectorOfCommonpVertex_type(temp2));
+ VectorOfCommonpVertex_type temp;
+ temp.push_back(CommonpVertex_type(myrank,pv));
+ EN_attachDataPtr((pEntity) pv , tagRemote,
+ new VectorOfCommonpVertex_type(temp));
+
+
+ continue;
+ }
+ /*send info to remoteID*/
+ int recupsize = 0;
+ int recupsize2 = (*recup2).size();
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+ void *buf = AP_alloc(remoteID,de.tag(),2*sizeof(int)
+ + recupsize2 * sizeof(newinterfaces_comm)
+ + sizeof(coor_comm) +sizebuf);
+ char *castbuf = (char *) buf;
+ memcpy(&castbuf[0],&(recupsize),sizeof(int));
+ memcpy(&castbuf[sizeof(int)],&(recupsize2),sizeof(int));
+ for(int i=0 ; i<recupsize2 ; i++)
+ memcpy(&castbuf[i * sizeof(newinterfaces_comm) + 2*sizeof(int) ],
+ &(*recup2)[i].first,sizeof(newinterfaces_comm));
+ coor_comm coorcom;
+ coorcom.X = P_x(pv);
+ coorcom.Y = P_y(pv);
+ coorcom.Z = P_z(pv);
+ pGEntity pg = EN_whatIn(pv);
+ coorcom.tag = GEN_tag(pg);
+ coorcom.dim = GEN_type(pg);
+ coorcom.nproc = myrank;
+ coorcom.psend = pv;
+ memcpy(&castbuf[recupsize * sizeof(oldinterfaces_comm)
+ + recupsize2 * sizeof(newinterfaces_comm)
+ + 2*sizeof(int) ],&coorcom,sizeof(coor_comm));
+ memcpy(&castbuf[2*sizeof(int)+ recupsize2 * sizeof(newinterfaces_comm)
+ + sizeof(coor_comm)],msg,sizebuf);
+ free(msg);
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ }
+
+ VIter_delete(vit);
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ char * castbuf = (char *) msg;
+ VectorOfCommonpVertex_type oldRemoteData;
+ int sizeold = *((int *) &castbuf[0]);
+ for(int i=0 ; i<sizeold ; i++) {
+ oldinterfaces_comm * oldint =
+ (oldinterfaces_comm *) &castbuf[sizeof(int)+ i*sizeof(oldinterfaces_comm)];
+ int num = oldint->oldnum;
+ pVertex pv = oldint->oldpv;
+ oldRemoteData.push_back(CommonpVertex_type(num,pv));
+ }
+ VectorOfCommonpVertex_type newRemoteData;
+ int sizenew = *((int *) &castbuf[sizeof(int) + sizeold
+ * sizeof(oldinterfaces_comm)]);
+ assert(sizenew>1);
+ for(int i=0 ; i<sizenew ; i++) {
+ newinterfaces_comm * newint =
+ (newinterfaces_comm *) &castbuf[2*sizeof(int)+ sizeold
+ * sizeof(oldinterfaces_comm) + i * sizeof(newinterfaces_comm)];
+ int nn = newint->newproc;
+ newRemoteData.push_back(CommonpVertex_type(nn,NULL));
+
+ }
+ coor_comm * coorcom = (coor_comm * ) &castbuf[2*sizeof(int)
+ +sizeold*sizeof(oldinterfaces_comm) +
+ sizenew*sizeof(newinterfaces_comm)];
+ pGEntity pent;
+ int dim = coorcom->dim;
+ int tag = coorcom->tag;
+ if(dim == 0) {
+ pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+ } else if(dim==1) {
+ pent = (pGEntity) GM_edgeByTag(mesh->model,tag);
+ } else if(dim==2) {
+ pent = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pent = (pGEntity) GM_regionByTag(mesh->model,tag);
+ } else {
+ printf("pbs**** %d\n",dim);
+ pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+ }
+
+ // double X = coorcom->X;
+ // double Y = coorcom->Y;
+ // double Z = coorcom->Z;
+ // pVertex pnew = M_createVP(mesh,X,Y,Z,-1,pent);
+
+ double XYZ[3] = {coorcom->X,coorcom->Y,coorcom->Z};
+ pVertex pnew = M_createV2(mesh,XYZ,-1,pent);
+ assert(pnew);
+ int procdep = coorcom->nproc;
+ // if(sizeold!=0) assert(procdep==-1);
+ // if(sizeold == 0) {
+ // assert(!oldRemoteData.size());
+ pVertex pinit = coorcom->psend;
+ oldRemoteData.push_back(CommonpVertex_type(procdep,pinit));
+ // }
+
+ EN_attachDataInt((pEntity) pnew , tagChange,1);
+ EN_attachDataInt((pEntity) pnew , tagMaster,1);
+ assert(newRemoteData.size()>1);
+
+ EN_attachDataPtr((pEntity) pnew , tagData,
+ new VectorOfCommonpVertex_type(newRemoteData));
+ assert(oldRemoteData.size());
+ EN_attachDataPtr((pEntity) pnew , tagRemote,
+ new VectorOfCommonpVertex_type(oldRemoteData));
+
+ de.receiveData (pnew,from, &castbuf[2*sizeof(int)+ sizeold *
+ sizeof(oldinterfaces_comm)
+ + sizenew * sizeof(newinterfaces_comm)
+ + sizeof(coor_comm)]);
+
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+ }
+
+ // -------------------------------------------------------------------
+ void UpdateInterfaces(pMesh mesh, MDB_DataExchanger &de) {
+
+#ifdef DEBUG
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+ pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+#endif
+
+ /*Phase 1 : send info to the smallest rank*/
+ UpdateInterfaces1(mesh,de);
+#ifdef DEBUG
+ checkRemotePointerChange(mesh,tagData,tagRemote,tagMaster);
+ puts("check third ok");
+#endif
+
+ /*Phase 2 : send info to all proc*/
+ UpdateInterfaces2(mesh,de);
+#ifdef DEBUG
+ checkNew(mesh,tagData,tagChange);
+ puts("check forth ok");
+#endif
+
+ /*Phase 3 : update info of smallest rank*/
+ UpdateInterfaces3(mesh);
+
+ /*Phase 4 : update info of all proc*/
+ UpdateInterfaces4(mesh);
+ }
+
+
+ // -------------------------------------------------------------------
+ void UpdatePointerInterface(pMesh mesh) {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+ pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+ if(!isChanged) continue;
+ if((tmp==2) || (tmp==10) || (tmp==11)) continue; //if 1 : interface new -- if 3 : must be deleted
+ assert(tmp==1 || tmp==3);
+ int isMaster = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+ if(!isMaster) continue;
+
+ void *temp_ptr2;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr2);
+ assert(isInterface);
+ const VectorOfCommonpVertex_type *recup2 =
+ (const VectorOfCommonpVertex_type *) temp_ptr2;
+ assert((*recup2).size());
+
+ void *temp_ptr;
+ int isInternal = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr);
+ assert(isInternal);
+ VectorOfCommonpVertex_type *recup = (VectorOfCommonpVertex_type *) temp_ptr;
+ int sizeold = (*recup).size();
+ if(sizeold==1){//old internal point
+ int remoteID = (*recup)[0].first;
+ if(remoteID==myrank) continue;
+ pVertex remoteP = (*recup)[0].second;
+ assert(remoteP);
+ for(unsigned int i=0 ; i <(*recup2).size() ; i++) {
+ int newID = (*recup2)[i].first;
+ pVertex newP = (*recup2)[i].second;
+ assert(newP);
+ void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+ points_comm_new *castbuf = (points_comm_new *) buf;
+ castbuf->pdest = remoteP;
+ castbuf->destID = remoteID;
+ castbuf->psend = newP;
+ castbuf->sendID = newID;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+ points_comm_new *castbuf = (points_comm_new *) buf;
+ castbuf->pdest = remoteP;
+ castbuf->destID = remoteID;
+ castbuf->psend = pv;
+ castbuf->sendID = myrank;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+
+ } else { //old interface point
+ int *tabproc=new int[nproc];
+ for(int i=0 ; i<nproc ; i++) tabproc[i] = 0;
+ for(unsigned int i=0 ; i <(*recup2).size() ; i++) {
+ tabproc[(*recup2)[i].first] = 1;
+ }
+ for(unsigned int i=0 ; i <(*recup).size() ; i++) {
+ int remoteID = (*recup)[i].first;
+ if(tabproc[remoteID]) continue;
+ pVertex remoteP = (*recup)[i].second;
+ assert(remoteP);
+ for(unsigned int j=0 ; j <(*recup2).size() ; j++) {
+ int newID = (*recup2)[j].first;
+ pVertex newP = (*recup2)[j].second;
+ assert(newID!=remoteID); assert(newID!=myrank);
+ assert(newP);
+ void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+ points_comm_new *castbuf = (points_comm_new *) buf;
+ castbuf->pdest = remoteP;
+ castbuf->destID = remoteID;
+ castbuf->psend = newP;
+ castbuf->sendID = newID;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+ points_comm_new *castbuf = (points_comm_new *) buf;
+ castbuf->pdest = remoteP;
+ castbuf->destID = remoteID;
+ castbuf->psend = pv;
+ castbuf->sendID = myrank;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ delete []tabproc;
+ }
+
+ }
+ VIter_delete(vit);
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ points_comm_new * pcn = (points_comm_new * ) msg;
+ pVertex precv = pcn->pdest;
+ assert(myrank == pcn->destID);
+ int procdep = pcn->sendID;
+ pVertex pv = pcn->psend;
+ void *temp_ptr;
+ int isInternal = EN_getDataPtr((pEntity) precv , tagRemote, &temp_ptr);
+ assert(isInternal);
+ VectorOfCommonpVertex_type *recup = (VectorOfCommonpVertex_type *) temp_ptr;
+#ifdef DEBUG
+ int tmp;
+ int isMaster = EN_getDataInt((pEntity) precv , tagMaster, &tmp);
+ assert(!isMaster);
+#endif
+ unsigned int i;
+ for(i=0 ; i<(*recup).size() ; i++) {
+ int remoteID = (*recup)[i].first;
+ if(remoteID == procdep) {
+ (*recup)[i].second = pv;
+ break;
+ }
+ }
+ assert(i<(*recup).size());
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+ }
+ // -------------------------------------------------------------------
+ void UpdateoldInterface(pMesh mesh) {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+ // pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+
+ int * sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+ if(!isChanged) continue;
+ if(!(tmp==2 || tmp==10 || tmp==11)) continue; //if 1 : interface new -- if 3 : must be deleted
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 = (VectorOfCommonpVertex_type *) temp_ptr2;
+ assert((*recup2).size()==1);
+
+ void *temp_ptr;
+ int isoldInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ if(!isoldInterface) continue;
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ assert((*recup).size());
+
+ int minproc = nproc + 10;
+ for(unsigned int i=0 ; i<(*recup).size() ; i++){
+ minproc = std::min(minproc,(*recup)[i].first);
+ }
+ minproc = std::min(minproc,myrank);
+ if(minproc!=myrank) continue;
+ int newID = (*recup2)[0].first;
+ pVertex newP = (*recup2)[0].second;
+ if(!newP) {
+ assert(newID==myrank);
+ newP = pv;
+ }
+
+ for(unsigned i=0 ; i<(*recup).size() ; i++) {
+ int remoteID = (*recup)[i].first;
+ assert(remoteID!=myrank);
+ pVertex remoteP = (*recup)[i].second;
+ void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+ points_comm_new *castbuf = (points_comm_new *) buf;
+ castbuf->pdest = remoteP;
+ castbuf->destID = remoteID;
+ castbuf->psend = newP;
+ castbuf->sendID = newID;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ }
+ VIter_delete(vit);
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ points_comm_new * pcn = (points_comm_new * ) msg;
+ pVertex precv = pcn->pdest;
+ assert(myrank == pcn->destID);
+ int procdep = pcn->sendID;
+ pVertex pv = pcn->psend;
+ void *temp_ptr;
+ int isInternal = EN_getDataPtr((pEntity) precv , tagRemote, &temp_ptr);
+ assert(isInternal);
+ VectorOfCommonpVertex_type *recup = (VectorOfCommonpVertex_type *) temp_ptr;
+#ifdef DEBUG
+ int tmp;
+ int isChange = EN_getDataInt((pEntity) precv , tagChange, &tmp);
+ assert(isChange);
+ //assert(tmp==2);
+ assert((*recup).size()==1);
+#endif
+ int remoteID = (*recup)[0].first;
+ assert(remoteID == procdep);
+ (*recup)[0].second = pv;
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+
+ }
+
+ // -------------------------------------------------------------------
+ void UpdatePointerInternal(pMesh mesh) {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+ // pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+ if(!isChanged) continue;
+ if(!(tmp==10 || tmp==11)) continue; //if 1 : interface new -- if 3 : must be deleted
+
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 = (VectorOfCommonpVertex_type *) temp_ptr2;
+ assert((*recup2).size()==1);
+
+ if(tmp==10) {
+ int remoteID = (*recup2)[0].first;
+ if(remoteID==myrank) continue;
+ pVertex remoteP = (*recup2)[0].second;
+ assert(remoteP);
+ void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+ points_comm_new *castbuf = (points_comm_new *) buf;
+ castbuf->pdest = remoteP;
+ castbuf->destID = remoteID;
+ castbuf->psend = pv;
+ castbuf->sendID = myrank;
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ } else {
+ void *temp_ptr;
+ is = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ assert((*recup).size());
+ int minproc = nproc + 10;
+ int ip ;
+ for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+ if(minproc > (*recup)[i].first) {
+ minproc = (*recup)[i].first;
+ ip = i;
+ }
+ }
+ minproc = std::min(minproc,myrank);
+ if(minproc==myrank) continue;
+ void *buf = AP_alloc(minproc,444,sizeof(points_comm_new));
+ points_comm_new *castbuf = (points_comm_new *) buf;
+ castbuf->pdest = (*recup)[ip].second;
+ castbuf->destID = minproc;
+ castbuf->psend = pv;
+ castbuf->sendID = myrank;
+ AP_send(buf);
+ sendcounts[minproc]++;
+ }
+ }
+ VIter_delete(vit);
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ points_comm_new * pcn = (points_comm_new * ) msg;
+ pVertex precv = pcn->pdest;
+ assert(myrank == pcn->destID);
+ int procdep = pcn->sendID;
+ pVertex pv = pcn->psend;
+ void *temp_ptr;
+ int isInternal = EN_getDataPtr((pEntity) precv , tagRemote, &temp_ptr);
+ assert(isInternal);
+ VectorOfCommonpVertex_type *recup = (VectorOfCommonpVertex_type *) temp_ptr;
+#ifdef DEBUG
+ int tmp;
+ int isChange = EN_getDataInt((pEntity) precv , tagChange, &tmp);
+ assert(isChange);
+ assert(tmp==2);
+ assert((*recup).size()==1);
+#endif
+ int remoteID = (*recup)[0].first;
+ assert(remoteID == procdep);
+ (*recup)[0].second = pv;
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+ UpdateoldInterface(mesh);
+ }
+
+ // -------------------------------------------------------------------
+ void SendVertex(pMesh mesh, MDB_DataExchanger &de)
+ {
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+ if(!isChanged) continue;
+ if(tmp!=2) continue; //if 1 : interface new -- if 3 : must be deleted
+
+ void *temp_ptr2;
+ int isInternal = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+ assert(isInternal);
+ VectorOfCommonpVertex_type *recup2 =
+ (VectorOfCommonpVertex_type *) temp_ptr2;
+ assert((*recup2).size()==1);
+
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ if(isInterface){
+ /*send only if I'm minproc*/
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ int minproc = nproc + 10;
+ int *tabproc=new int[nproc];
+ for(int i=0 ; i<nproc ; i++) tabproc[i] = 0;
+ for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+ minproc = std::min(minproc,(*recup)[i].first);
+ tabproc[(*recup)[i].first] = 1;
+ }
+ minproc = std::min(minproc,myrank);
+
+ int remoteID = (*recup2)[0].first;
+ if(remoteID==myrank) {
+ EN_attachDataInt((pEntity) pv , tagChange,11);
+ continue;
+ }
+
+ if(minproc!=myrank) continue;
+
+
+ if(tabproc[remoteID]) continue; //remoteID already knows info
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+ void *buf = AP_alloc(remoteID,de.tag(),sizeof(coor_comm)+sizebuf);
+
+ char *cast = (char *) buf;
+ coor_comm castbuf;
+ castbuf.X = P_x(pv);
+ castbuf.Y = P_y(pv);
+ castbuf.Z = P_z(pv);
+ pGEntity pg = EN_whatIn(pv);
+ castbuf.tag = GEN_tag(pg);
+ castbuf.dim = GEN_type(pg);
+ castbuf.nproc = myrank;
+ castbuf.psend = pv;
+ memcpy(&cast[0],&castbuf,sizeof(coor_comm));
+ memcpy(&cast[sizeof(coor_comm)],msg,sizebuf);
+ free(msg);
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ delete []tabproc;
+ } else {
+ int remoteID = (*recup2)[0].first;
+ assert(remoteID!=myrank);
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+ void *buf = AP_alloc(remoteID,de.tag(),sizeof(coor_comm)+sizebuf);
+ char *cast = (char *) buf;
+ coor_comm castbuf ;
+ castbuf.X = P_x(pv);
+ castbuf.Y = P_y(pv);
+ castbuf.Z = P_z(pv);
+ pGEntity pg = EN_whatIn(pv);
+ castbuf.tag = GEN_tag(pg);
+ castbuf.dim = GEN_type(pg);
+ castbuf.nproc = myrank;
+ castbuf.psend = pv;
+ memcpy(&cast[0],&castbuf,sizeof(coor_comm));
+ memcpy(&cast[sizeof(coor_comm)],msg,sizebuf);
+ free(msg);
+ AP_send(buf);
+ sendcounts[remoteID]++;
+ }
+ }
+ VIter_delete(vit);
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ char * castbuf = (char *) msg;
+ coor_comm * coorcom = (coor_comm * ) &castbuf[0];
+ pGEntity pent;
+ int dim = coorcom->dim;
+ int tag = coorcom->tag;
+ if(dim == 0) {
+ pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+ } else if(dim==1) {
+ pent = (pGEntity) GM_edgeByTag(mesh->model,tag);
+ } else if(dim==2) {
+ pent = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pent = (pGEntity) GM_regionByTag(mesh->model,tag);
+ } else {
+ printf("pbs**** %d\n",dim);
+ }
+ // double X = coorcom->X;
+ // double Y = coorcom->Y;
+ // double Z = coorcom->Z;
+ // pVertex pnew = M_createVP(mesh,X,Y,Z,-1,pent);
+ double XYZ[3] = {coorcom->X,coorcom->Y,coorcom->Z};
+ pVertex pnew = M_createV2(mesh,XYZ,-1,pent);
+ assert(pnew);
+ int procdep = coorcom->nproc;
+ pVertex pv = coorcom->psend;
+ EN_attachDataInt((pEntity) pnew , tagChange,10);
+ VectorOfCommonpVertex_type oldRemoteData;
+ oldRemoteData.push_back(CommonpVertex_type(procdep,pv));
+ EN_attachDataPtr((pEntity) pnew , tagRemote,
+ new VectorOfCommonpVertex_type(oldRemoteData));
+
+ de.receiveData (pnew,from, &castbuf[sizeof(coor_comm)]);
+
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+ UpdatePointerInterface(mesh);
+ UpdatePointerInternal(mesh);
+ }
+
+ // -------------------------------------------------------------------
+ struct tetra_comm {
+ pVertex pdest[4];
+ int tag,dim;
+ };
+
+ // -------------------------------------------------------------------
+ void SendTetra(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de) {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ int dest;
+ int migre = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+ if(!migre) continue;
+ dest--;
+ assert(dest!=myrank);
+ pVertex nod[4];
+ nod[0] = R_vertex(pr,0);
+ nod[1] = R_vertex(pr,1);
+ nod[2] = R_vertex(pr,2);
+ nod[3] = R_vertex(pr,3);
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pr, dest, sizebuf );
+ void *buf = AP_alloc(dest,de.tag(),sizeof(tetra_comm)+sizebuf);
+ char *cast = (char *) buf;
+ tetra_comm castbuf ;
+ pGEntity pg = EN_whatIn(pr);
+ castbuf.tag = GEN_tag(pg);
+ castbuf.dim = GEN_type(pg);
+ for(int i = 0 ; i<4 ; i++) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) nod[i] ,tagChange, &tmp);
+ assert(isChanged);
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) nod[i] , tagRemote, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 = (VectorOfCommonpVertex_type *) temp_ptr2;
+ if((*recup2).size()==1){
+ if((tmp==2) || (tmp==10)){
+ assert((*recup2)[0].first==dest);
+ castbuf.pdest[i] = (*recup2)[0].second;
+ } else {
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup = (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ if((*recup)[j].first == dest) {
+ castbuf.pdest[i] = (*recup)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ }
+ } else {
+ assert((tmp==1) || (tmp==3));
+ if(tmp==3) {
+ unsigned int j;
+ for(j=0 ; j<(*recup2).size() ; j++) {
+ if((*recup2)[j].first == dest) {
+ castbuf.pdest[i] = (*recup2)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup2).size());
+ } else {
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup = (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ if((*recup)[j].first == dest) {
+ castbuf.pdest[i] = (*recup)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ }
+ }
+ }
+ memcpy(&cast[0],&castbuf,sizeof(tetra_comm));
+ memcpy(&cast[sizeof(tetra_comm)],msg,sizebuf);
+ free(msg);
+ AP_send(buf);
+ sendcounts[dest]++;
+ }
+ RIter_delete(rit);
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ char * castbuf = (char *) msg;
+ tetra_comm * regioncom = (tetra_comm * ) &castbuf[0];
+ pVertex p1 = regioncom->pdest[0];
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) p1 ,tagChange, &tmp);
+ assert(isChanged);
+ pVertex p2 = regioncom->pdest[1];
+ isChanged = EN_getDataInt((pEntity) p2 ,tagChange, &tmp);
+ assert(isChanged);
+ pVertex p3 = regioncom->pdest[2];
+ isChanged = EN_getDataInt((pEntity) p3 ,tagChange, &tmp);
+ assert(isChanged);
+ pVertex p4 = regioncom->pdest[3];
+ isChanged = EN_getDataInt((pEntity) p4 ,tagChange, &tmp);
+ assert(isChanged);
+ pFace pface[4];
+ pGEntity pg;
+ int dim = regioncom->dim;
+ int tag = regioncom->tag;
+ if(dim==2) {
+ pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+ } else {
+ printf("----pbs faces**** %d\n",dim);
+ }
+ // pface[0] = F_exist(2,p1,p2,p3,0);
+ // assert(pface[0]);
+ // pface[1] = F_exist(2,p1,p2,p4,0);
+ // assert(pface[1]);
+ // pface[2] = F_exist(2,p2,p3,p4,0);
+ // assert(pface[2]);
+ // pface[3] = F_exist(2,p1,p3,p4,0);
+ // assert(pface[3]);
+
+ pface[0] = F_exist(p1,p2,p3,0);
+ assert(pface[0]);
+ pface[1] = F_exist(p1,p2,p4,0);
+ assert(pface[1]);
+ pface[2] = F_exist(p2,p3,p4,0);
+ assert(pface[2]);
+ pface[3] = F_exist(p1,p3,p4,0);
+ assert(pface[3]);
+
+ pRegion pr = M_createR(mesh,4,pface,pg);
+ assert(pr);
+ de.receiveData (pr,from, &castbuf[sizeof(tetra_comm)]);
+
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+ }
+ // -------------------------------------------------------------------
+ struct face_comm2 {
+ pVertex pdest[3];
+ int tag,dim;
+ };
+
+ // -------------------------------------------------------------------
+ void SendFaces(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de) {
+ int Dim = (mesh->tets.empty()) ? 2 : 3;
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+
+ if(Dim==2) {
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ int dest;
+ int migre = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+ if(!migre) continue;
+ dest--;
+ assert(dest!=myrank);
+ pVertex nod[3];
+ pface->getNodes(nod);
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pface, dest, sizebuf );
+ void *buf = AP_alloc(dest,de.tag(),sizeof(face_comm2) +sizebuf);
+ char *cast = (char *) buf;
+
+ face_comm2 castbuf;
+ pGEntity pg = EN_whatIn(pface);
+ castbuf.tag = GEN_tag(pg);
+ castbuf.dim = GEN_type(pg);
+ for(int i = 0 ; i<3 ; i++) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) nod[i] ,tagChange, &tmp);
+ assert(isChanged);
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) nod[i] , tagRemote, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 =
+ (VectorOfCommonpVertex_type *) temp_ptr2;
+ if((*recup2).size()==1){
+ if((tmp==2) || (tmp==10)){
+ assert((*recup2)[0].first==dest);
+ castbuf.pdest[i] = (*recup2)[0].second;
+ } else {
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ if((*recup)[j].first == dest) {
+ castbuf.pdest[i] = (*recup)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ }
+ } else {
+ assert((tmp==1) || (tmp==3));
+ if(tmp==3) {
+ unsigned int j;
+ for(j=0 ; j<(*recup2).size() ; j++) {
+ if((*recup2)[j].first == dest) {
+ castbuf.pdest[i] = (*recup2)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup2).size());
+ } else {
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ if((*recup)[j].first == dest) {
+ castbuf.pdest[i] = (*recup)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ }
+ }
+ }
+ memcpy(&cast[0],&castbuf,sizeof(face_comm2));
+ memcpy(&cast[sizeof(face_comm2)],msg,sizebuf);
+ free(msg);
+ AP_send(buf);
+ sendcounts[dest]++;
+ }
+ FIter_delete(fit);
+ } else {//Dim==3
+ if(Dim!=3) throw;
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ pPList prlist = F_regions(pface);
+ pRegion pr;
+ void* iter=0;
+ while( (pr =(pRegion) PList_next(prlist,&iter))){
+ int dest;
+ int migre = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+ if(!migre) continue;
+ dest--;
+ assert(dest!=myrank);
+ ((MDB_Triangle*)pface)->del((MDB_Tet*)pr);
+
+ pVertex nod[3];
+ pface->getNodes(nod);
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pface, dest, sizebuf );
+ void *buf = AP_alloc(dest,de.tag(),sizeof(face_comm2)+sizebuf);
+ char *cast = (char*) buf;
+ face_comm2 castbuf;
+ pGEntity pg = EN_whatIn(pface);
+ castbuf.tag = GEN_tag(pg);
+ castbuf.dim = GEN_type(pg);
+ for(int i = 0 ; i<3 ; i++) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) nod[i] ,tagChange, &tmp);
+ assert(isChanged);
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) nod[i] , tagRemote, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 =
+ (VectorOfCommonpVertex_type *) temp_ptr2;
+ if((*recup2).size()==1){
+ if((tmp==2) || (tmp==10)){
+ assert((*recup2)[0].first==dest);
+ castbuf.pdest[i] = (*recup2)[0].second;
+ } else {
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ if((*recup)[j].first == dest) {
+ castbuf.pdest[i] = (*recup)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ }
+ } else {
+ assert((tmp==1) || (tmp==3));
+ if(tmp==3) {
+ unsigned int j;
+ for(j=0 ; j<(*recup2).size() ; j++) {
+ if((*recup2)[j].first == dest) {
+ castbuf.pdest[i] = (*recup2)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup2).size());
+ } else {
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ if((*recup)[j].first == dest) {
+ castbuf.pdest[i] = (*recup)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ }
+ }
+ }
+ memcpy(&cast[0],&castbuf,sizeof(face_comm2));
+ memcpy(&cast[sizeof(face_comm2)],msg,sizebuf);
+ free(msg);
+ AP_send(buf);
+ sendcounts[dest]++;
+ }
+ }
+ FIter_delete(fit);
+ }
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ char * castbuf = (char *) msg;
+
+ face_comm2 * facecom = (face_comm2 * ) &castbuf[0];
+ pVertex p1 = facecom->pdest[0];
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) p1 ,tagChange, &tmp);
+ assert(isChanged);
+ pVertex p2 = facecom->pdest[1];
+ isChanged = EN_getDataInt((pEntity) p2 ,tagChange, &tmp);
+ assert(isChanged);
+ pVertex p3 = facecom->pdest[2];
+ isChanged = EN_getDataInt((pEntity) p3 ,tagChange, &tmp);
+ assert(isChanged);
+ pEdge pe[3];
+ pGEntity pg;
+ int dim = facecom->dim;
+ int tag = facecom->tag;
+ if(dim==2) {
+ pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+ } else {
+ printf("----pbs faces**** %d\n",dim);
+ }
+ pe[0] = E_exist(p1,p2);
+ assert(pe[0]);
+ pe[1] = E_exist(p2,p3);
+ assert(pe[1]);
+ pe[2] = E_exist(p1,p3);
+ assert(pe[2]);
+
+ // pFace pface =F_exist(2,pe[0],pe[1],pe[2],0);
+ // if(!pface) {
+ pFace pface = M_createF(mesh,3,pe,pg);
+ assert(pface);
+ de.receiveData (pface,from, &castbuf[sizeof(face_comm2)]);
+
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+ }
+
+ // -------------------------------------------------------------------
+ struct edge_comm {
+ pVertex pdest[2];
+ int tag,dim;
+ };
+
+ // -------------------------------------------------------------------
+ void SendEdges(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de) {
+ int Dim = (mesh->tets.empty()) ? 2 : 3;
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+
+ if(Dim==2) {
+ EIter eit = M_edgeIter(mesh);
+ pEdge pedge;
+ while ((pedge = EIter_next(eit))) {
+ pVertex p[2];
+ p[0] = pedge->p1;
+ p[1] = pedge->p2;
+ int tmp1;
+ int isChanged1 = EN_getDataInt((pEntity) p[0] ,tagChange, &tmp1);
+ int tmp2;
+ int isChanged2 = EN_getDataInt((pEntity) p[1] ,tagChange, &tmp2);
+ if(!isChanged1 || !isChanged2) continue;
+ int nbfaces = pedge->numfaces();
+ for(int k = 0 ; k < nbfaces ; k++) {
+ pFace pface = pedge->faces(k);
+ int dest;
+ int migre = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+ if(!migre) continue;
+ dest--;
+ assert(dest!=myrank);
+ pedge->del((MDB_Triangle*)pface);
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pedge, dest, sizebuf );
+
+ void *buf = AP_alloc(dest,de.tag(),sizeof(edge_comm) + sizebuf);
+ char *cast = (char *) buf;
+ edge_comm castbuf;
+ pGEntity pg = EN_whatIn(pedge);
+ castbuf.tag = GEN_tag(pg);
+ castbuf.dim = GEN_type(pg);
+ for(int i = 0 ; i< 2 ; i++) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) p[i] ,tagChange, &tmp);
+ assert(isChanged);
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) p[i] , tagRemote, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 =
+ (VectorOfCommonpVertex_type *) temp_ptr2;
+ if((*recup2).size()==1){
+ if((tmp==2) || (tmp==10)){
+ assert((*recup2)[0].first==dest);
+ castbuf.pdest[i] = (*recup2)[0].second;
+ } else {
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) p[i] , tagData, &temp_ptr);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ if((*recup)[j].first == dest) {
+ castbuf.pdest[i] = (*recup)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ }
+ } else {
+ assert((tmp==1) || (tmp==3));
+ if(tmp==3) {
+ unsigned int j;
+ for(j=0 ; j<(*recup2).size() ; j++) {
+ if((*recup2)[j].first == dest) {
+ castbuf.pdest[i] = (*recup2)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup2).size());
+ } else {
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) p[i] , tagData, &temp_ptr);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ if((*recup)[j].first == dest) {
+ castbuf.pdest[i] = (*recup)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ }
+ }
+ }
+ memcpy(&cast[0],&castbuf,sizeof(edge_comm));
+ memcpy(&cast[sizeof(edge_comm)],msg,sizebuf);
+ free(msg);
+ AP_send(buf);
+ sendcounts[dest]++;
+ }
+ }
+ EIter_delete(eit);
+ } else {//Dim==3
+ if(Dim!=3) throw;
+ EIter eit = M_edgeIter(mesh);
+ pEdge pedge;
+ while ((pedge = EIter_next(eit))) {
+ pVertex p[2];
+ p[0] = pedge->p1;
+ p[1] = pedge->p2;
+ int tmp1;
+ int isChanged1 = EN_getDataInt((pEntity) p[0] ,tagChange, &tmp1);
+ int tmp2;
+ int isChanged2 = EN_getDataInt((pEntity) p[1] ,tagChange, &tmp2);
+ if(!isChanged1 || !isChanged2) continue;
+ pPList prlist = E_regions(pedge);
+ pRegion pr;
+ void* iter=0;
+ while( (pr =(pRegion) PList_next(prlist,&iter))){
+ int dest;
+ int migre = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+ if(!migre) continue;
+ dest--;
+ assert(dest!=myrank);
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pedge, dest, sizebuf );
+
+ void *buf = AP_alloc(dest,de.tag(),sizeof(edge_comm) +sizebuf);
+ char *cast = (char *) buf;
+
+ edge_comm castbuf;
+ pGEntity pg = EN_whatIn(pedge);
+ castbuf.tag = GEN_tag(pg);
+ castbuf.dim = GEN_type(pg);
+
+ for(int i = 0 ; i< 2 ; i++) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) p[i] ,tagChange, &tmp);
+ assert(isChanged);
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) p[i] , tagRemote, &temp_ptr2);
+ assert(is);
+ VectorOfCommonpVertex_type *recup2 =
+ (VectorOfCommonpVertex_type *) temp_ptr2;
+ if((*recup2).size()==1){
+ if((tmp==2) || (tmp==10)){
+ assert((*recup2)[0].first==dest);
+ castbuf.pdest[i] = (*recup2)[0].second;
+ } else {
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) p[i] , tagData, &temp_ptr);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ if((*recup)[j].first == dest) {
+ castbuf.pdest[i] = (*recup)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ }
+ } else {
+ assert((tmp==1) || (tmp==3));
+ if(tmp==3) {
+ unsigned int j;
+ for(j=0 ; j<(*recup2).size() ; j++) {
+ if((*recup2)[j].first == dest) {
+ castbuf.pdest[i] = (*recup2)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup2).size());
+ } else {
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) p[i] , tagData, &temp_ptr);
+ assert(is);
+ const VectorOfCommonpVertex_type *recup =
+ (const VectorOfCommonpVertex_type *) temp_ptr;
+ unsigned int j;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ if((*recup)[j].first == dest) {
+ castbuf.pdest[i] = (*recup)[j].second;
+ break;
+ }
+ }
+ assert(j<(*recup).size());
+ }
+ }
+ }
+ memcpy(&cast[0],&castbuf,sizeof(edge_comm));
+ memcpy(&cast[sizeof(edge_comm)],msg,sizebuf);
+ free(msg);
+ AP_send(buf);
+ sendcounts[dest]++;
+ }
+ }
+ EIter_delete(eit);
+ }
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive pointers*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ char * castbuf = (char *) msg;
+ edge_comm * edgecom = (edge_comm * ) &castbuf[0];
+ pVertex p1 = edgecom->pdest[0];
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) p1 ,tagChange, &tmp);
+ assert(isChanged);
+ pVertex p2 = edgecom->pdest[1];
+ isChanged = EN_getDataInt((pEntity) p2 ,tagChange, &tmp);
+ assert(isChanged);
+ pGEntity pg;
+ int dim = edgecom->dim;
+ int tag = edgecom->tag;
+ if(dim==1) {
+ pg = (pGEntity) GM_edgeByTag(mesh->model,tag);
+ } else if(dim==2) {
+ pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+ } else {
+ printf("----pbs**** %d\n",dim);
+ }
+ pEdge e = E_exist(p1,p2);
+ if (!e) e = M_createE(mesh,p1,p2,pg);
+ de.receiveData (e,from, &castbuf[sizeof(edge_comm)]);
+
+ AP_free(msg);
+ }
+
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+
+ }
+
+ // -------------------------------------------------------------------
+ void SendElt(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de) {
+
+ SendEdges(mesh,tagElt,de);
+
+ SendFaces(mesh,tagElt,de);
+
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+ if(dim==3) SendTetra(mesh,tagElt,de);
+ }
+
+ // -------------------------------------------------------------------
+ void DeleteEntities(pMesh mesh,pMeshDataId tagElt) {
+ int nproc,myrank;
+ int Dim = (mesh->tets.empty()) ? 2 : 3;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+ pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+
+ if(Dim==2) {
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ int dest;
+ int migre = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+ if(!migre) continue;
+ dest--;
+ assert(dest!=myrank);
+ EN_deleteData((pEntity)pface, tagElt);
+ M_removeFace(mesh,pface);
+ }
+ FIter_delete(fit);
+ MD_deleteMeshDataId(tagElt);
+ } else {
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ int dest;
+ int migre = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+ if(!migre) continue;
+ dest--;
+ assert(dest!=myrank);
+ EN_deleteData((pEntity)pr, tagElt);
+ M_removeRegion(mesh,pr);
+ }
+ RIter_delete(rit);
+ MD_deleteMeshDataId(tagElt);
+
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ int num = F_numRegions(pface);
+ if(!num) M_removeFace(mesh,pface);
+ }
+ FIter_delete(fit);
+ }
+
+ EIter eit = M_edgeIter(mesh);
+ pEdge ped;
+ while ((ped = EIter_next(eit))) {
+ int num = E_numFaces(ped);
+ if(!num) M_removeEdge(mesh,ped);
+ }
+ EIter_delete(eit);
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int tmp;
+ int isChanged = EN_getDataInt((pEntity) pv ,tagChange, &tmp);
+ if(!isChanged) continue;
+ void *temp_ptr2;
+ int is2 = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr2);
+#ifdef DEBUG
+ if(tmp==10)assert(!is2);
+ if(tmp==1) assert(is2);
+#endif
+ void *temp_ptr;
+ int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr);
+
+
+ int num = V_numEdges(pv);
+ if(tmp==3 ) assert(!num);
+ if(tmp==11) {
+ assert(num);
+ assert(is2);
+ EN_deleteData((pEntity)pv, tagData);
+ }
+ if(tmp==2) assert(!num);
+ if(tmp==1) assert(num);
+ if(!num) assert(!V_numFaces(pv));
+
+ if(is) EN_deleteData((pEntity)pv,tagRemote);
+ int isMaster = EN_getDataInt((pEntity) pv ,tagMaster, &tmp);
+
+ if(isMaster) EN_deleteData((pEntity)pv, tagMaster);
+ EN_deleteData((pEntity)pv, tagChange);
+
+ if(!num) M_removeVertex(mesh,pv);
+ }
+ VIter_delete(vit);
+ MD_deleteMeshDataId(tagChange);
+ MD_deleteMeshDataId(tagRemote);
+ MD_deleteMeshDataId(tagMaster);
+ }
+ // -------------------------------------------------------------------
+ void DeleteEntitiesAndData(pMesh mesh, pMeshDataId tagElt,
+ MDB_DataExchanger &de )
+ {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+ pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+ pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+ int Dim = (mesh->tets.empty()) ? 2 : 3;
+ if(Dim==2) {
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ EN_deleteData((pEntity)pface, tagRemote);
+ EN_deleteData((pEntity)pface, tagMaster);
+ EN_deleteData((pEntity)pface, tagChange);
+ int dest;
+ int migre = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+ if(!migre) continue;
+ dest--;
+ assert(dest!=myrank);
+ EN_deleteData((pEntity)pface, tagElt);
+ de.deleteExternalData( (pEntity) pface );
+ M_removeFace(mesh,pface);
+ }
+ FIter_delete(fit);
+ MD_deleteMeshDataId(tagElt);
+ }
+ else {
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ EN_deleteData((pEntity)pr, tagRemote);
+ EN_deleteData((pEntity)pr, tagMaster);
+ EN_deleteData((pEntity)pr, tagChange);
+ int dest;
+ int migre = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+ if(!migre) continue;
+ dest--;
+ assert(dest!=myrank);
+ EN_deleteData((pEntity)pr, tagElt);
+ de.deleteExternalData( (pEntity) pr );
+ M_removeRegion(mesh,pr);
+ }
+ RIter_delete(rit);
+ MD_deleteMeshDataId(tagElt);
+
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+
+ EN_deleteData((pEntity)pface, tagRemote);
+ EN_deleteData((pEntity)pface, tagMaster);
+ EN_deleteData((pEntity)pface, tagChange);
+ int num = F_numRegions(pface);
+ if(!num){
+ de.deleteExternalData( (pEntity) pface );
+ M_removeFace(mesh,pface);
+ }
+ }
+ FIter_delete(fit);
+ }
+
+ EIter eit = M_edgeIter(mesh);
+ pEdge ped;
+ while ((ped = EIter_next(eit))) {
+ EN_deleteData((pEntity)ped, tagRemote);
+ EN_deleteData((pEntity)ped, tagMaster);
+ EN_deleteData((pEntity)ped, tagChange);
+ int num = E_numFaces(ped);
+ if(!num){
+ de.deleteExternalData( (pEntity) ped );
+ M_removeEdge(mesh,ped);
+ }
+ }
+ EIter_delete(eit);
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ EN_deleteData((pEntity)pv, tagRemote);
+ EN_deleteData((pEntity)pv, tagMaster);
+ EN_deleteData((pEntity)pv, tagChange);
+ int num = V_numEdges(pv);
+ if(!num){
+ de.deleteExternalData( (pEntity) pv );
+ M_removeVertex(mesh,pv);
+ }
+ }
+ VIter_delete(vit);
+ MD_deleteMeshDataId(tagChange);
+ MD_deleteMeshDataId(tagRemote);
+ MD_deleteMeshDataId(tagMaster);
+
+ }
+ // -------------------------------------------------------------------
+ void loadBalancing2(pMesh mesh, pMeshDataId tagElt, MDB_DataExchanger &de)
+ {
+ // 0 the destination of local subentitiees
+ MarkEltSubEntities(mesh, tagElt);
+ // 1 entities Migration
+ pMeshDataId tagDest = MD_lookupMeshDataId("tagDestinations");
+ MigrateEntitiesAndData(mesh, tagDest, de);
+ // 2 delete entities
+ DeleteEntitiesAndData( mesh,tagElt, de );
+
+
+ pMeshDataId tagVertex = MD_lookupMeshDataId("RemotePoint");
+ MD_deleteMeshDataId(tagVertex);
+ MD_deleteMeshDataId(tagDest);
+ mesh->initializeIdData();
+ }
+ // -------------------------------------------------------------------
+ void loadBalancing(pMesh mesh, pMeshDataId tagElt, MDB_DataExchanger &de)
+ {
+#ifdef DEBUG
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ checkRemotePointer(mesh,tagData);
+ puts("check first ok");
+#endif
+ // 1) Mark local and distant vertices with their new proc(s)
+ MarkEltVertex(mesh,tagElt);
+
+#ifdef DEBUG
+ checkRemotePointer(mesh,tagData);
+ puts("check second ok");
+#endif
+
+ // 2) update and send new interfaces points
+ UpdateInterfaces(mesh,de);
+
+#ifdef DEBUG
+ checkRemotePointer2(mesh,tagData);
+ puts("check fifth ok");
+#endif
+
+ // 3) send other points and update RemotePointer
+ SendVertex(mesh,de);
+
+ // 4) send elt
+ SendElt(mesh,tagElt,de);
+
+ // // 5) delete entities
+ // DeleteEntities(mesh,tagElt);
+ DeleteEntitiesAndData( mesh,tagElt, de );
+
+ // // 6) classification
+ mesh->classify_unclassified_entities();
+
+
+ pMeshDataId tagVertex = MD_lookupMeshDataId("RemotePoint");
+ MD_deleteMeshDataId(tagVertex);
+#ifdef PARALLEL
+
+ // ----------------------------------------------
+ // ------ Tagging inter-partition nodes
+ // ----------------------------------------------
+
+ pMeshDataId tag = MD_lookupMeshDataId("RemotePoint");
+
+ V_createInfoInterface(mesh,tag);
+ E_createInfoInterface(mesh,tag);
+ F_createInfoInterface(mesh,tag);
+ mesh->initializeIdData();
+
+#endif
+
+#ifdef DEBUG
+ checkRemotePointer(mesh,tagData);
+ puts("last check ok");
+#endif
+
+ }
+ // -------------------------------------------------------------------
+
+} // End of namespace MAd
+
+#endif
diff --git a/Mesh/MeshDataBaseLoadBalancing.h b/Mesh/MeshDataBaseLoadBalancing.h
new file mode 100644
index 0000000..1c62230
--- /dev/null
+++ b/Mesh/MeshDataBaseLoadBalancing.h
@@ -0,0 +1,40 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASELOADBALANCE
+#define H_MESHDATABASELOADBALANCE
+
+#ifdef PARALLEL
+
+namespace MAd {
+
+#ifdef DEBUG
+ void checkRemotePointer(pMesh mesh, pMeshDataId tagData );
+ void checkRemotePointer2(pMesh mesh, pMeshDataId tagData );
+ void checkRemotePointerChange(pMesh mesh, pMeshDataId tagData,pMeshDataId tagNew, pMeshDataId tagChange );
+ void checkNew(pMesh mesh, pMeshDataId tagData,pMeshDataId tagChange);
+#endif
+ void MarkedEltVertex(pMesh mesh,pMeshDataId tagElt);
+ void CommOldInterfaces(pMesh mesh);
+
+ void UpdateInterfaces(pMesh mesh, MDB_DataExchanger &de);
+ void SendVertex(pMesh mesh, MDB_DataExchanger &de);
+ void SendElt(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de);
+ void DeleteEntitiesAndData(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de );
+ void MarkEltSubEntities(pMesh mesh, pMeshDataId tagElt);
+ void MigrateEntitiesAndData(pMesh mesh, pMeshDataId tagDest, MDB_DataExchanger &de);
+
+}
+
+#endif
+#endif
diff --git a/Mesh/MeshDataBaseMessage.cc b/Mesh/MeshDataBaseMessage.cc
new file mode 100644
index 0000000..2fce545
--- /dev/null
+++ b/Mesh/MeshDataBaseMessage.cc
@@ -0,0 +1,150 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include <signal.h>
+#ifndef _WIN_
+#include <sys/time.h>
+#include <sys/resource.h>
+#else
+#include <windows.h>
+#include <psapi.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+#include "MeshDataBaseMessage.h"
+using std::string;
+
+namespace MAd {
+
+ // Handle signals. We should not use Msg functions in these...
+
+ void Signal(int sig_num)
+ {
+ switch (sig_num) {
+ case SIGSEGV:
+ Msg(MDB_FATAL, "Segmentation violation (invalid memory reference)");
+ break;
+ case SIGFPE:
+ Msg(MDB_FATAL, "Floating point exception (division by zero?)");
+ break;
+ case SIGINT:
+ Msg(MDB_FATAL, "Interrupt (generated from terminal special char)");
+ break;
+ default:
+ Msg(MDB_FATAL, "Unknown signal");
+ break;
+ }
+ }
+
+ // General purpose message routine
+
+ void Msg(int level, string fmt, ...)
+ {
+ va_list args;
+ va_start(args, fmt);
+
+ Msg_char(level, fmt.c_str(), args);
+
+ va_end(args);
+ }
+
+ void Msg_char(int level, const char *fmt, ...)
+ {
+ va_list args;
+ int abort = 0;
+
+ va_start(args, fmt);
+
+ switch (level) {
+
+ case MDB_PROGRESS:
+ case MDB_STATUS1N:
+ case MDB_STATUS2N:
+ case MDB_STATUS3N:
+ break;
+
+ case MDB_DIRECT:
+ vfprintf(stdout, fmt, args);
+ fprintf(stdout, "\n");
+ break;
+
+ case MDB_FATAL:
+ case MDB_FATAL3: abort = 1;
+ case MDB_FATAL1:
+ case MDB_FATAL2:
+ fprintf(stderr, MDB_FATAL_STR);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ break;
+
+ case MDB_GERROR:
+ case MDB_GERROR1:
+ case MDB_GERROR2:
+ case MDB_GERROR3:
+ fprintf(stderr, MDB_ERROR_STR);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ break;
+
+ case MDB_WARNING:
+ case MDB_WARNING1:
+ case MDB_WARNING2:
+ case MDB_WARNING3:
+ fprintf(stderr, MDB_WARNING_STR);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ break;
+
+ // case DEBUG:
+ // case DEBUG1:
+ // case DEBUG2:
+ // case DEBUG3:
+ // fprintf(stderr, DEBUG_STR);
+ // vfprintf(stderr, fmt, args);
+ // fprintf(stderr, "\n");
+ // break;
+
+ default:
+ fprintf(stderr, MDB_INFO_STR);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ break;
+ }
+
+ va_end(args);
+
+ if(abort)
+ throw;
+ }
+
+ // CPU time computation
+
+ void GetResources(long *s, long *us, long *mem)
+ {
+#ifndef _WIN_
+ static struct rusage r;
+
+ getrusage(RUSAGE_SELF, &r);
+ *s = (long)r.ru_utime.tv_sec;
+ *us = (long)r.ru_utime.tv_usec;
+ *mem = (long)r.ru_maxrss;
+#else
+ PROCESS_MEMORY_COUNTERS counters;
+ if (GetProcessMemoryInfo (GetCurrentProcess(), &counters, sizeof (counters)))
+ *mem=counters.PagefileUsage;
+ SYSTEMTIME systime;
+ GetSystemTime(&systime);
+ *s=systime.wSecond;
+ *us=systime.wMilliseconds;
+#endif
+ }
+}
diff --git a/Mesh/MeshDataBaseMessage.h b/Mesh/MeshDataBaseMessage.h
new file mode 100644
index 0000000..d27ce1f
--- /dev/null
+++ b/Mesh/MeshDataBaseMessage.h
@@ -0,0 +1,74 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MESSAGE_H_
+#define _MESSAGE_H_
+
+#include <stdarg.h>
+#include <string>
+
+#define MDB_FATAL 1 // Fatal error (causes Gmsh to exit)
+#define MDB_FATAL1 2 // First part of a multiline FATAL message
+#define MDB_FATAL2 3 // Middle part of a multiline FATAL message
+#define MDB_FATAL3 4 // Last part of a multiline FATAL message
+
+#define MDB_GERROR 5 // Error (but Gmsh can live with it)
+#define MDB_GERROR1 6 // First part of a multiline ERROR message
+#define MDB_GERROR2 7 // Middle part of a multiline ERROR message
+#define MDB_GERROR3 8 // Last part of a multiline ERROR message
+
+#define MDB_WARNING 9 // Warning
+#define MDB_WARNING1 10 // First part of a multiline WARNING message
+#define MDB_WARNING2 11 // Middle part of a multiline WARNING message
+#define MDB_WARNING3 12 // Last part of a multiline WARNING message
+
+#define MDB_INFO 13 // Long informations
+#define MDB_INFO1 14 // First part of a multiline INFO message
+#define MDB_INFO2 15 // Middle part of a multiline INFO message
+#define MDB_INFO3 16 // Last part of a multiline INFO message
+
+#define MDB_STATUS1 21 // Small information in status bar (left)
+#define MDB_STATUS2 22 // Small interaction in status bar (middle)
+#define MDB_STATUS3 23 // Small interaction in status bar (right)
+
+#define MDB_STATUS1N 24 // Same as STATUS1, but not going into the log file
+#define MDB_STATUS2N 25 // Same as STATUS2, but not going into the log file
+#define MDB_STATUS3N 26 // Same as STATUS3, but not going into the log file
+
+#define MDB_ONSCREEN 27 // Persistent on-screen message
+
+#define MDB_DIRECT 30 // Direct message (no special formatting)
+#define MDB_SOLVER 31 // Solver message
+#define MDB_SOLVERR 32 // Solver errors and warnings
+
+#define MDB_PROGRESS 40 // Progress indicator
+
+#define MDB_WHITE_STR " : "
+#define MDB_FATAL_STR "Fatal : "
+#define MDB_ERROR_STR "Error : "
+#define MDB_WARNING_STR "Warning : "
+#define MDB_INFO_STR "Info : "
+/* #define MDB_DEBUG_STR "Debug : " */
+#define MDB_STATUS_STR "Info : "
+
+namespace MAd {
+
+ void Signal(int signum);
+ void Msg(int level, std::string fmt, ...);
+ void Msg_char(int level, const char * fmt, ...);
+ double Cpu(void);
+ double GetValue(char *text, double defaultval);
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseMigration.cc b/Mesh/MeshDataBaseMigration.cc
new file mode 100644
index 0000000..62b9254
--- /dev/null
+++ b/Mesh/MeshDataBaseMigration.cc
@@ -0,0 +1,626 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Josue Barboza
+// -------------------------------------------------------------------
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "MeshDataBaseLoadBalancing.h"
+#include "assert.h"
+#include <iostream>
+
+namespace MAd {
+
+ typedef std::set< int > SetOfDestination_type;
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ struct coor_comm2
+ {
+ double X,Y,Z;
+ int tag,dim;
+ int id;
+ };
+
+ // -------------------------------------------------------------------
+ void MarkVertex( pVertex pv, pMeshDataId tagD ,int d_proc )
+ {
+ void *temp_ptr;
+ SetOfDestination_type *recup = NULL;
+ int is = EN_getDataPtr((pEntity) pv, tagD, &temp_ptr);
+ if( !is ){
+ recup = new SetOfDestination_type;
+ EN_attachDataPtr((pEntity) pv , tagD, recup);
+ }else
+ {
+ recup = reinterpret_cast< SetOfDestination_type *> (temp_ptr);
+ }
+ recup->insert( d_proc );
+ }
+ // -------------------------------------------------------------------
+ void MarkEdge( pEdge pe, pMeshDataId tagD ,int d_proc )
+ {
+ void *temp_ptr;
+ SetOfDestination_type *recup = NULL;
+ int is = EN_getDataPtr((pEntity) pe, tagD, &temp_ptr);
+ if( !is ){
+ recup = new SetOfDestination_type;
+ EN_attachDataPtr((pEntity) pe, tagD, recup);
+ }else {
+ recup = reinterpret_cast<SetOfDestination_type *> (temp_ptr);
+ }
+ recup->insert(d_proc);
+ pVertex nod[2];
+ nod[0] = E_vertex(pe,0);
+ nod[1] = E_vertex(pe,1);
+ MarkVertex( nod[0], tagD, d_proc);
+ MarkVertex( nod[1], tagD, d_proc);
+ }
+ // -------------------------------------------------------------------
+ void MarkFace( pFace pf, pMeshDataId tagD ,int d_proc )
+ {
+ void *temp_ptr;
+ SetOfDestination_type *recup = NULL;
+ int is = EN_getDataPtr((pEntity) pf, tagD, &temp_ptr);
+ if( !is ){
+ recup = new SetOfDestination_type;
+ EN_attachDataPtr((pEntity) pf, tagD, recup);
+ }else {
+ recup = reinterpret_cast<SetOfDestination_type *> (temp_ptr);
+ }
+ recup->insert(d_proc);
+ for( int i = 0; i<(pf->getNbEdges()); i++) {
+ MarkEdge( F_edge( pf,i ), tagD, d_proc );
+ }
+ }
+ // -------------------------------------------------------------------
+ void MarkRegion( pRegion pr, pMeshDataId tagD ,int d_proc )
+ {
+ void *temp_ptr;
+ SetOfDestination_type *recup = NULL;
+ int is = EN_getDataPtr((pEntity) pr, tagD, &temp_ptr);
+ if( !is ){
+ recup = new SetOfDestination_type;
+ EN_attachDataPtr((pEntity) pr, tagD, recup);
+ }else {
+ recup = reinterpret_cast<SetOfDestination_type *> (temp_ptr);
+ }
+ recup->insert(d_proc);
+ for( int i = 0; i<(pr->getNbFace()); i++) {
+ MarkFace( R_face( pr,i ), tagD, d_proc );
+ }
+ }
+
+ // -------------------------------------------------------------------
+ void MarkEltSubEntities( pMesh mesh, pMeshDataId tagElt )
+ {
+ pMeshDataId tagDest = MD_lookupMeshDataId("tagDestinations");
+ MD_deleteMeshDataId(tagDest);
+
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+ if( dim == 2 ){
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ int dest;
+ int migre = EN_getDataInt((pEntity) pface, tagElt, &dest);
+ if(!migre) continue;
+ MarkFace( pface, tagDest ,dest-1 );
+ }
+ FIter_delete(fit);
+ }
+ else {
+ if(dim!=3) throw;
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ int dest;
+ int migre = EN_getDataInt((pEntity) pr, tagElt, &dest);
+ if(!migre) continue;
+ MarkRegion( pr, tagDest ,dest-1 );
+ }
+ RIter_delete(rit);
+ }
+ }
+ // -------------------------------------------------------------------
+ void * VertexAndDataPackaging( pVertex pv, int d, MDB_DataExchanger &de)
+ {
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pv, d, sizebuf );
+ void *buf = AP_alloc(d,de.tag(),sizeof(coor_comm2)+sizebuf);
+
+ char *cast = reinterpret_cast< char *> (buf);
+ coor_comm2 castbuf;
+ castbuf.X = P_x(pv);
+ castbuf.Y = P_y(pv);
+ castbuf.Z = P_z(pv);
+ pGEntity pg = EN_whatIn(pv);
+ castbuf.tag = GEN_tag(pg);
+ castbuf.dim = GEN_type(pg);
+ castbuf.id = EN_id( pv );
+ memcpy(&cast[0],&castbuf,sizeof(coor_comm2));
+ memcpy(&cast[sizeof(coor_comm2)],msg,sizebuf);
+ free(msg);
+ return buf;
+ }
+ // -------------------------------------------------------------------
+ void VertexAndDataUnpackaging( pMesh mesh, void *msg, int from,
+ MDB_DataExchanger &de)
+ {
+ char * castbuf = reinterpret_cast< char *> ( msg );
+ coor_comm2 * coorcom = reinterpret_cast< coor_comm2 *> (castbuf);
+ pGEntity pg = NULL;
+ int dim = coorcom->dim;
+ int tag = coorcom->tag;
+ if(dim == 0) {
+ pg = (pGEntity) GM_vertexByTag(mesh->model,tag);
+ } else if(dim==1) {
+ pg = (pGEntity) GM_edgeByTag(mesh->model,tag);
+ } else if(dim==2) {
+ pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+ }
+ pVertex pnew = mesh->find_point(coorcom->id);
+ if( !pnew ){
+
+ // double X = coorcom->X;
+ // double Y = coorcom->Y;
+ // double Z = coorcom->Z;
+ // pnew = M_createVP(mesh,X,Y,Z,coorcom->id,pg);
+
+ double XYZ[3] = {coorcom->X,coorcom->Y,coorcom->Z};
+ pnew = M_createV2(mesh,XYZ,coorcom->id,pg);
+ }
+ de.receiveData (pnew,from, &castbuf[sizeof(coor_comm2)]);
+
+ }
+ // -------------------------------------------------------------------
+ void MigrateVerticesAndData( pMesh mesh, pMeshDataId tagDest,
+ MDB_DataExchanger &de)
+ {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ int *sendcounts = new int[nproc];
+ for( int i=0; i<nproc; i++){
+ sendcounts[i]= 0;
+ }
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ void *temp_ptr;
+ int migre = EN_getDataPtr((pEntity) pv, tagDest, &temp_ptr);
+ if(!migre) continue;
+ const SetOfDestination_type *recup =
+ reinterpret_cast< const SetOfDestination_type* > (temp_ptr);
+ assert( (recup->size())>0 );
+ SetOfDestination_type::const_iterator itd = recup->begin();
+ for(; itd!=recup->end(); itd ++) {
+ int dest = *itd;
+ assert(dest!=myrank);
+ void *buf = VertexAndDataPackaging( pv, dest, de );
+ AP_send(buf);
+ sendcounts[dest]++;
+ }
+ }
+ VIter_delete(vit);
+
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive Vertices and data*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ VertexAndDataUnpackaging( mesh, msg, from, de);
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+ }
+ // -------------------------------------------------------------------
+ void * EdgeAndDataPackaging( pEdge pe, int d, MDB_DataExchanger &de)
+ {
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pe, d, sizebuf );
+ int castbuf[4];
+ int sizeOfcastbuf = sizeof(int) *4;
+ void *buf = AP_alloc(d,de.tag(), sizeOfcastbuf +sizebuf );
+ char *cast = reinterpret_cast< char *> (buf);
+ pGEntity pg = EN_whatIn( pe );
+ castbuf[0] = GEN_tag( pg );
+ castbuf[1] = GEN_type( pg );
+ castbuf[2] = EN_id( E_vertex( pe, 0 ) );
+ castbuf[3] = EN_id( E_vertex( pe, 1 ) );
+ memcpy( &cast[0], castbuf, sizeOfcastbuf );
+ memcpy( &cast[sizeOfcastbuf],msg,sizebuf);
+ free(msg);
+ return buf;
+ }
+ // -------------------------------------------------------------------
+ void EdgeAndDataUnpackaging( pMesh mesh, void *msg, int from,
+ MDB_DataExchanger &de)
+ {
+ char* castbuf = reinterpret_cast<char*> (msg);
+ int * Edge_comm = reinterpret_cast<int*> (castbuf);
+ int tag = *(Edge_comm++);
+ int dim = *(Edge_comm++);
+ pGEntity pg = NULL;
+ if(dim==2) {
+ pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+ }
+
+ pVertex pv[2];
+ pv[0]= mesh->find_point( *(Edge_comm++) );
+ pv[1]= mesh->find_point( *(Edge_comm++) );
+
+
+ pEdge pe = E_exist(pv[0],pv[1]);
+ if( !pe ) {
+ pe = M_createE(mesh,pv[0],pv[1],pg);
+ }
+ assert(pe);
+ de.receiveData (pe,from, &castbuf[sizeof(int)*4]);
+ }
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ void MigrateEdgesAndData(pMesh mesh, pMeshDataId tagDest,
+ MDB_DataExchanger &de)
+ {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ int *sendcounts = new int[nproc];
+ for( int i=0; i<nproc; i++){
+ sendcounts[i]= 0;
+ }
+ EIter eit = M_edgeIter(mesh);
+ pEdge pe;
+ while ((pe = EIter_next(eit))) {
+ void *temp_ptr;
+ int migre = EN_getDataPtr((pEntity) pe, tagDest, &temp_ptr);
+ if(!migre) continue;
+ const SetOfDestination_type *recup =
+ reinterpret_cast< const SetOfDestination_type* > (temp_ptr);
+ assert( (recup->size())>0 );
+ SetOfDestination_type::const_iterator itd = recup->begin();
+ for(; itd!=recup->end(); itd ++) {
+ int dest = *itd;
+ assert(dest!=myrank);
+ void *buf = EdgeAndDataPackaging( pe, dest, de );
+ AP_send(buf);
+ sendcounts[dest]++;
+ }
+ }
+ EIter_delete(eit);
+
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive Edges and data*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ EdgeAndDataUnpackaging( mesh, msg, from, de);
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+ }
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ void * FaceAndDataPackaging( pFace pf, int d, MDB_DataExchanger &de )
+ {
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pf, d, sizebuf );
+ int nV = F_numVertices( pf );
+ int nComm = nV+3;
+ int *castbuf = new int[nComm];
+ int sizeOfcastbuf = sizeof(int) * nComm;
+ void *buf = AP_alloc(d,de.tag(), sizeOfcastbuf +sizebuf );
+ char *cast = reinterpret_cast< char *> (buf);
+ pGEntity pg = EN_whatIn( pf );
+ castbuf[0] = GEN_tag( pg );
+ castbuf[1] = GEN_type( pg );
+ castbuf[2] = nV;
+ for( int i = 0; i< nV; i++) {
+ int vId = EN_id( F_vertex( pf, i ) );
+ castbuf[3+i]= vId ;
+ }
+ memcpy( &cast[0], castbuf, sizeOfcastbuf );
+ memcpy( &cast[sizeOfcastbuf],msg,sizebuf );
+ delete [] castbuf;
+ free(msg);
+ return buf;
+ }
+ // -------------------------------------------------------------------
+ void FaceAndDataUnpackaging( pMesh mesh, void *msg, int from,
+ MDB_DataExchanger &de )
+ {
+ /*! \TODO: only triangle is taken into account. Should be extended to other*/
+ char* castbuf = reinterpret_cast< char* >( msg );
+ int* pf_com = reinterpret_cast< int* > (castbuf);
+ int tag = pf_com[0];
+ int dim = pf_com[1];
+ int nbV = pf_com[2];
+ if( nbV != 3 ) {
+ std::cout<<"Unpackaging Face that is diff. form triangle is not implemented: "
+ <<nbV<<std::endl;
+ assert(0);
+ }
+ pGEntity pg = NULL;
+ if(dim==2) {
+ pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+ }
+
+ pVertex *ListOfpVertex = new pVertex[nbV];
+ for( int i = 0; i< nbV; i++ ) {
+ ListOfpVertex[i] = mesh->find_point( pf_com[3+i] );
+ }
+ pEdge pe[3];
+ pe[0] = E_exist(ListOfpVertex[0],ListOfpVertex[1]);
+ assert(pe[0]);
+ pe[1] = E_exist(ListOfpVertex[1],ListOfpVertex[2]);
+ assert(pe[1]);
+ pe[2] = E_exist(ListOfpVertex[0],ListOfpVertex[2]);
+ assert(pe[2]);
+
+ // pFace pface = F_exist(2,pe[0],pe[1],pe[2],0);
+ pFace pface = F_exist(pe[0],pe[1],pe[2],0);
+ if( !pface ) {
+ pface = M_createF(mesh,3,pe,pg);
+ }
+ assert(pface);
+ de.receiveData (pface,from, &castbuf[sizeof(int)*(nbV+3)]);
+
+ delete [] ListOfpVertex ;
+ }
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ void MigrateFacesAndData( pMesh mesh, pMeshDataId tagDest,
+ MDB_DataExchanger &de)
+ {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ int *sendcounts = new int[nproc];
+ for( int i=0; i<nproc; i++){
+ sendcounts[i]= 0;
+ }
+ FIter fit = M_faceIter(mesh);
+ pFace pf;
+ while ((pf = FIter_next(fit))) {
+ void *temp_ptr;
+ int migre = EN_getDataPtr((pEntity) pf, tagDest, &temp_ptr);
+ if(!migre) continue;
+ const SetOfDestination_type *recup =
+ reinterpret_cast< const SetOfDestination_type* > (temp_ptr);
+ assert( (recup->size())>0 );
+ SetOfDestination_type::const_iterator itd = recup->begin();
+ for(; itd!=recup->end(); itd ++) {
+ int dest = *itd;
+ assert(dest!=myrank);
+ void *buf = FaceAndDataPackaging( pf, dest, de );
+ AP_send(buf);
+ sendcounts[dest]++;
+ }
+ }
+ FIter_delete(fit);
+
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive Faces and data*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ FaceAndDataUnpackaging( mesh, msg, from, de);
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+ }
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ void * RegionAndDataPackaging( pRegion pr, int d, MDB_DataExchanger &de)
+ {
+ int sizebuf;
+ void *msg = de.sendData ((pEntity) pr, d, sizebuf );
+ int nV = R_numVertices( pr );
+ int nComm = nV+3;
+ int *castbuf = new int[nComm];
+ int sizeOfcastbuf = sizeof(int) * nComm;
+ void *buf = AP_alloc(d,de.tag(), sizeOfcastbuf +sizebuf );
+ char *cast = reinterpret_cast<char *> (buf);
+ pGEntity pg = EN_whatIn( pr );
+ castbuf[0] = GEN_tag( pg );
+ castbuf[1] = GEN_type( pg );
+ castbuf[2] = nV;
+ for( int i = 0; i< nV; i++) {
+ int vId = EN_id( R_vertex( pr, i ) );
+ castbuf[3+i]= vId ;
+ }
+ memcpy( &cast[0], castbuf, sizeOfcastbuf );
+ memcpy( &cast[sizeOfcastbuf],msg,sizebuf);
+ delete [] castbuf;
+ free(msg);
+ return buf;
+ }
+ // -------------------------------------------------------------------
+ void RegionAndDataUnpackaging( pMesh mesh, void *msg, int from,
+ MDB_DataExchanger &de)
+ {
+ /*! \TODO: only tethra is taken into account. Should be extended to other*/
+ char* castbuf = reinterpret_cast<char*> (msg);
+ int * Region_comm = reinterpret_cast<int*> (castbuf);
+ int tag = *(Region_comm++);
+ int dim = *(Region_comm++);
+ int nbVertices = *(Region_comm++);
+ if( nbVertices != 4 ) {
+ std::cout<<"Unpackaging Region that is diff. form tethra is not implemented"
+ <<nbVertices<<std::endl;
+ assert(0);
+ }
+ pGEntity pg = NULL;
+ if(dim==2) {
+ pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+ }
+
+ pVertex *ListOfpVertex = new pVertex[nbVertices];
+ for( int i = 0; i< nbVertices; i++ ) {
+ ListOfpVertex[i] = mesh->find_point( *(Region_comm++) );
+ }
+
+
+ pFace pface[4];
+
+ // pface[0] = F_exist(2,ListOfpVertex[0],ListOfpVertex[1],ListOfpVertex[2],0);
+ // assert(pface[0]);
+ // pface[1] = F_exist(2,ListOfpVertex[0],ListOfpVertex[1],ListOfpVertex[3],0);
+ // assert(pface[1]);
+ // pface[2] = F_exist(2,ListOfpVertex[1],ListOfpVertex[2],ListOfpVertex[3],0);
+ // assert(pface[2]);
+ // pface[3] = F_exist(2,ListOfpVertex[0],ListOfpVertex[2],ListOfpVertex[3],0);
+ // assert(pface[3]);
+
+ pface[0] = F_exist(ListOfpVertex[0],ListOfpVertex[1],ListOfpVertex[2],0);
+ assert(pface[0]);
+ pface[1] = F_exist(ListOfpVertex[0],ListOfpVertex[1],ListOfpVertex[3],0);
+ assert(pface[1]);
+ pface[2] = F_exist(ListOfpVertex[1],ListOfpVertex[2],ListOfpVertex[3],0);
+ assert(pface[2]);
+ pface[3] = F_exist(ListOfpVertex[0],ListOfpVertex[2],ListOfpVertex[3],0);
+ assert(pface[3]);
+
+
+ pRegion pr = M_createR(mesh,4,pface,pg);
+ assert(pr);
+ de.receiveData (pr,from, &castbuf[sizeof(int)*(nbVertices+3)]);
+
+ delete [] ListOfpVertex ;
+ }
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ void MigrateRegionsAndData( pMesh mesh, pMeshDataId tagDest,
+ MDB_DataExchanger &de)
+ {
+ int nproc,myrank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ int *sendcounts = new int[nproc];
+ for( int i=0; i<nproc; i++){
+ sendcounts[i]= 0;
+ }
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ void *temp_ptr;
+ int migre = EN_getDataPtr((pEntity) pr, tagDest, &temp_ptr);
+ if(!migre) continue;
+ const SetOfDestination_type *recup =
+ reinterpret_cast< const SetOfDestination_type*> (temp_ptr);
+ assert( (recup->size())>0 );
+ int dest = *(recup->begin());
+ assert(dest!=myrank);
+ void *buf = RegionAndDataPackaging( pr, dest, de );
+ AP_send(buf);
+ sendcounts[dest]++;
+ }
+ RIter_delete(rit);
+
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ /*receive Regions and data*/
+ int message=0;
+ int count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+ recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+ message++;
+ RegionAndDataUnpackaging( mesh, msg, from, de);
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+ }
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ void MigrateEntitiesAndData(pMesh mesh, pMeshDataId tagDest,
+ MDB_DataExchanger &de)
+ {
+ MigrateVerticesAndData( mesh, tagDest, de);
+ MigrateEdgesAndData( mesh, tagDest, de);
+ MigrateFacesAndData( mesh, tagDest, de);
+ MigrateRegionsAndData( mesh, tagDest, de);
+ }
+
+}
+
+#endif
+
diff --git a/Mesh/MeshDataBaseMiniMesh.cc b/Mesh/MeshDataBaseMiniMesh.cc
new file mode 100644
index 0000000..8c503e9
--- /dev/null
+++ b/Mesh/MeshDataBaseMiniMesh.cc
@@ -0,0 +1,60 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBaseMiniMesh.h"
+
+namespace MAd {
+
+ size_t MDB_MiniMesh::size_buf () const
+ {
+ return sizeof(int) * ( 2 + nbInfos ) + sizeof(double) * 3 * nbVertex + sizeof(int) * nbVertex;
+ }
+
+ MDB_MiniMesh::~MDB_MiniMesh()
+ {
+ if (nbVertex)
+ {
+ if (coords) delete [] coords;
+ delete [] infos;
+ delete [] ids;
+ }
+ }
+
+ void MDB_MiniMesh::_load ( FILE *f )
+ {
+ if (nbVertex != 0)
+ {
+ if (coords) { delete [] coords; coords=NULL; }
+ delete [] infos;
+ delete [] ids;
+ }
+ fread ( &nbVertex , sizeof(int) , 1, f );
+ fread ( &nbInfos , sizeof(int) , 1, f );
+ coords = new double [3 * nbVertex];
+ infos = new int [nbInfos ];
+ ids = new int [nbVertex ];
+ fread ( coords , sizeof(double), nbVertex * 3, f );
+ fread ( infos , sizeof(int) , nbInfos, f );
+ fread ( ids , sizeof(int) , nbVertex, f );
+ }
+
+ void MDB_MiniMesh::_flush ( FILE *f ) const
+ {
+ if (nbVertex == 0) throw;
+ fwrite ( &nbVertex , sizeof(int) , 1, f );
+ fwrite ( &nbInfos , sizeof(int) , 1, f );
+ fwrite ( coords , sizeof(double), nbVertex * 3, f );
+ fwrite ( infos , sizeof(int) , nbInfos, f );
+ fwrite ( ids , sizeof(int) , nbVertex, f );
+ }
+
+}
diff --git a/Mesh/MeshDataBaseMiniMesh.h b/Mesh/MeshDataBaseMiniMesh.h
new file mode 100644
index 0000000..4012c88
--- /dev/null
+++ b/Mesh/MeshDataBaseMiniMesh.h
@@ -0,0 +1,39 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MESHDATABASE_MINIMESH_
+#define _MESHDATABASE_MINIMESH_
+
+#include <stdio.h>
+
+namespace MAd {
+
+ class MDB_MiniMesh
+ {
+ protected:
+ int nbVertex;
+ double * coords;
+ int nbInfos;
+ int *infos;
+ int *ids;
+ void _flush ( FILE *F ) const;
+ void _load ( FILE *F );
+ size_t size_buf () const;
+ public:
+ virtual ~MDB_MiniMesh ();
+ MDB_MiniMesh () : nbVertex (0) , coords(0), nbInfos (0), infos(0), ids(0) {}
+ };
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseParallelIO.cc b/Mesh/MeshDataBaseParallelIO.cc
new file mode 100644
index 0000000..77d7c42
--- /dev/null
+++ b/Mesh/MeshDataBaseParallelIO.cc
@@ -0,0 +1,1415 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Cecile Dobrzynski, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseIO.h"
+#include "MeshDataBaseMessage.h"
+#include "MeshDataBaseGEntity2Physical.h"
+#ifndef _WIN_
+#include <unistd.h>
+#endif
+#include "MshTags.h"
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#include "fcntl.h"
+#include "MeshDataBaseParallelInterface.h"
+#endif
+
+#include <cstdlib>
+#include <cstring>
+// #include <set>
+// #include <utility>
+
+extern int getNumVerticesForElementTypeMSH(int type);
+
+namespace MAd {
+
+#ifdef PARALLEL
+ // -------------------------------------------------------------------
+ // -------------------- SaveGmshMeshParallel -------------------------
+ // -------------------------------------------------------------------
+
+ // Save a mesh (for parallel only) with format msh1 or msh2 \ingroup parallel
+ // GCRMK: now vertex ids are unique: we can use the ids directly and simplify this function
+ void SaveGmshMeshParallel (const pMesh mesh, const char *filename, int version)
+ {
+ // ***************** update ID interface ***************
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ V_createInfoInterface(mesh, tagData);
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ int nbModelVertex = 0;
+ int myrank,nproc;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ if(myrank==0) {
+ FILE * nop = fopen(filename,"w");
+ fclose(nop);
+ }
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ int npt = 0;
+
+ VIter vit = M_vertexIter(mesh);
+ while (VIter_next(vit)){}
+ VIter_reset(vit);
+ pVertex pv;
+ int NN = 0,nssint = 0;;
+ while ((pv = VIter_next(vit)))
+ {
+ if(pv->g)
+ {
+ NN++;
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ int j =0,size= 0;
+ if(isInterface) {
+ const std::vector<std::pair<int , MDB_Point*> > *recup =
+ (const std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+ size = (*recup).size() ;
+ for(j=0 ; j<size; j++) {
+ int remoteID = (*recup)[j].first;
+ assert(remoteID!=myrank);
+ if(remoteID < myrank) break;
+ }
+ }
+ if(j == size) {
+ nssint++;
+ }
+ } else {
+ throw;
+ }
+ }
+ if (NN != mesh->nbPoints)
+ {
+ printf("%d != %d\n",NN,mesh->nbPoints);
+ throw;
+ }
+ VIter_delete(vit);
+ int *tab=new int[nproc];
+ int sendnum = nssint;
+ if(myrank) {
+ MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);
+ } else {
+ MPI_Status status;
+ tab[0] = sendnum;
+ for(int i=1 ; i<nproc ; i++) {
+ MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+ }
+ }
+
+ MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+
+ int *tabmax=new int[nproc];
+ sendnum = mesh->maxId;
+ if(myrank) {
+ MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);
+ } else {
+ MPI_Status status;
+ tabmax[0] = sendnum;
+ for(int i=1 ; i<nproc ; i++) {
+ MPI_Recv(&tabmax[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+ }
+ }
+
+ MPI_Bcast(&tabmax[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+
+ // --------------------------------------------------
+ // Defines a control point for a sequential writting:
+ // Proc n+1 does not continue while proc n is
+ // not at the next control point
+ int send = 0,recv = 0;
+ if(!myrank) recv = 1;
+ MPI_Status status;
+ while(!recv) {
+ if(myrank!=(nproc-1)) MPI_Send(&send,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+ MPI_Recv(&recv,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+ }
+ int nseek = recv;
+ int nplace = nseek;
+ if (!myrank) nplace = 0;
+ // --------------------------------------------------
+
+ int nop = open(filename,O_WRONLY);
+
+
+ // ----------------------------------------------------
+ // Write format (for msh2 only)
+ // ----------------------------------------------------
+
+ if ( !myrank && version != 1 ) {
+ char format[256];
+ sprintf(format, "$MeshFormat\n2 0 8\n$EndMeshFormat\n");
+ int size = strlen(format);
+ write(nop,format,size);
+ nplace += size;
+ }
+
+ // ----------------------------------------------------
+ // Write partitionning of nodes (for msh1 only)
+ // ----------------------------------------------------
+
+ if ( version == 1 ) {
+
+ if(!myrank) {
+ write(nop,"$PARALLELNOD\n",sizeof("$PARALLELNOD"));
+ nplace += sizeof("$PARALLELNOD");
+ char nb[256];
+ int nbtot = 0;
+ for(int i=0 ; i<nproc ; i++) nbtot +=tab[i];
+ sprintf(nb,"%d\n",nbtot);
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ // int IdGlobal = 0;
+ if(myrank) {
+ lseek(nop,nseek,0);
+ // for(int j=0 ; j<myrank; j++) IdGlobal += tabmax[j];
+ }
+ vit = M_vertexIter(mesh);
+ while (VIter_next(vit)){}
+ VIter_reset(vit);
+ NN = 0;
+ while ((pv = VIter_next(vit)))
+ {
+ if(pv->g)
+ {
+ NN++;
+ if (pv->deleted)printf("ouuch\n");
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ int j =0,size= 0/*,nId = IdGlobal*/;
+ if(isInterface) {
+ const std::vector<std::pair<int , MDB_Point*> > *recup = (const std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+ size = (*recup).size() ;
+ for(j=0 ; j<size; j++) {
+ int remoteID = (*recup)[j].first;
+ if(remoteID < myrank) break;
+ }
+ }
+ if(j == size) {
+ nssint++;
+
+ char nb[256];
+ if(size) sprintf(nb,"%d %d %d ",pv->iD /*+ nId*/, size + 1,myrank);
+ else sprintf(nb,"%d %d %d \n",pv->iD /*+ nId*/, size + 1,myrank);
+ for(j=0 ; j<size; j++) {
+ const std::vector<std::pair<int , MDB_Point*> > *recup = (const std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+ char nbtmp[256];
+ if(j == (size-1) ) sprintf(nbtmp,"%d \n",(*recup)[j].first);
+ else sprintf(nbtmp,"%d ",(*recup)[j].first);
+ int sizetmp = strlen(nbtmp);
+ strncat(nb,nbtmp,sizetmp);
+ }
+
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ } else {
+ throw;
+ }
+ }
+ if (NN != mesh->nbPoints)
+ {
+ printf("%d != %d\n",NN,mesh->nbPoints);
+ throw;
+ }
+ VIter_delete(vit);
+
+ MPI_Send(&nplace,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+
+ if(!myrank) MPI_Recv(&npt,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ send = 0,recv = 0;
+ if(!myrank) recv = 1;
+
+ while(!recv) {
+ if(myrank!=(nproc-1)) MPI_Send(&send,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+ MPI_Recv(&recv,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+ }
+
+ nseek = recv;
+ nplace = nseek;
+
+ if(!myrank) {
+ nplace = npt;
+ lseek(nop,nplace,0);
+ write(nop,"$ENDPARALLELNOD\n",sizeof("$ENDPARALLELNOD"));
+ nplace += sizeof("$ENDPARALLELNOD");
+ }
+
+ }
+
+ // ----------------------------------------------------
+ // Write nodes
+ // ----------------------------------------------------
+
+ if(!myrank) {
+ char nb[256];
+ if ( version == 1 ) sprintf(nb,"$NOD\n");
+ else sprintf(nb,"$Nodes\n");
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ if(!myrank) {
+ char nb[256];
+ int nbtot = 0;
+ for(int i=0 ; i<nproc ; i++) nbtot +=tab[i];
+ sprintf(nb,"%d\n",nbtot);
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ // int IdGlobal = 0;
+ if(myrank) {
+ lseek(nop,nseek,0);
+ // for(int j=0 ; j<myrank; j++) IdGlobal += tabmax[j];
+ }
+ vit = M_vertexIter(mesh);
+ while (VIter_next(vit)){}
+ VIter_reset(vit);
+ NN = 0;
+ while ((pv = VIter_next(vit)))
+ {
+ if(pv->g)
+ {
+ NN++;
+ int dim = GEN_type(pv->g);
+
+ if (pv->deleted)printf("ouuch\n");
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ int j =0,size= 0/*,nId = IdGlobal*/;
+ if(isInterface) {
+ const std::vector<std::pair<int , MDB_Point*> > *recup =
+ (const std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+ size = (*recup).size() ;
+ for(j=0 ; j<size; j++) {
+ int remoteID = (*recup)[j].first;
+ if(remoteID < myrank) break;
+ }
+ }
+ if(j == size) {
+ nssint++;
+ if(dim == 0)
+ nbModelVertex++;
+
+ char nb[256];
+ sprintf(nb,"%d %g %g %g\n",pv->iD /*+ nId*/, pv->X, pv->Y, pv->Z);
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ } else {
+ throw;
+ }
+ }
+ if (NN != mesh->nbPoints)
+ {
+ printf("%d != %d\n",NN,mesh->nbPoints);
+ throw;
+ }
+ VIter_delete(vit);
+
+ // --------------------------------------------------
+ // End of the control point
+ MPI_Send(&nplace,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+
+ if(!myrank) MPI_Recv(&npt,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+
+ MPI_Barrier(MPI_COMM_WORLD);
+ // --------------------------------------------------
+
+ // pMeshDataId tagGlob = MD_lookupMeshDataId("IdGlobal");
+ // UpdateIDGlobal(mesh,IdGlobal);
+ // MPI_Barrier(MPI_COMM_WORLD);
+
+ pMeshDataId tagEdge = MD_lookupMeshDataId("WriteEdge");
+ E_createInfoInterface(mesh,tagEdge);
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ pMeshDataId tagFaceInterface = MD_lookupMeshDataId("FaceInterface");
+ F_createInfoInterface(mesh,tagFaceInterface);
+
+ // *****************ecriture des elt*******************
+ int nbClasEdges = 0;
+ int nbClasFaces = 0;
+
+ pMeshDataId tagFace = MD_newMeshDataId("WriteFace");
+
+ {
+ EIter eit = M_edgeIter(mesh);
+ pEdge pe;
+ while ((pe = EIter_next(eit)))
+ {
+ int dim = GEN_type(pe->g);
+ if(dim == 1) {
+ void * tmpptr;
+ int is = EN_getDataPtr((pEntity) pe , tagEdge,&tmpptr);
+ if(!is){
+ nbClasEdges++;
+ } else {
+ std::map<int,pEdge> *recup = (std::map<int,pEdge> *) tmpptr;
+ int minproc = myrank;
+ for( std::map<int,pEdge>::const_iterator iter=(*recup).begin() ;
+ iter!=(*recup).end() ; iter++){
+ minproc = std::min(minproc,(*iter).first);
+ }
+ if(minproc==myrank) {
+ nbClasEdges++;
+ }
+ }
+ }
+ }
+ EIter_delete(eit);
+ }
+ {
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit)))
+ {
+ int dim = GEN_type(pface->g);
+ if(dim == 2){
+ void * list;
+ int is = EN_getDataPtr((pEntity) pface , tagFaceInterface,&list);
+ if(!is){
+ nbClasFaces++;
+ EN_attachDataInt((pEntity) pface,tagFace,1);
+ } else {
+ std::vector<int> *recup = (std::vector<int> *) list;
+ int minproc = myrank;
+ for(unsigned int i=0 ; i<(*recup).size() ; i++){
+ minproc = std::min(minproc,(*recup)[i]);
+ }
+ if(minproc==myrank) {
+ nbClasFaces++;
+ EN_attachDataInt((pEntity) pface,tagFace,1);
+ }
+ }
+ }
+ }
+ FIter_delete(fit);
+ }
+
+ sendnum = nbClasEdges + nbModelVertex + nbClasFaces + mesh->nbTets;
+
+ // the first proc collects the number of elements from the others...
+ if(myrank) {
+ MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);
+ } else {
+ MPI_Status status;
+ tab[0] = sendnum;
+ for(int i=1 ; i<nproc ; i++) {
+ MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+ }
+ }
+
+ // printf("Before: Proc %d: tab:\t%d\t%d\n",myrank,tab[0],tab[1]);
+
+ // ... and sends its results to everyone
+ MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+
+ // printf("After: Proc %d: tab:\t%d\t%d\n",myrank,tab[0],tab[1]);
+
+
+ // --------------------------------------------------
+ // Defines a control point for a sequential writting:
+ // Proc n+1 does not continue while proc n is
+ // not at the next control point
+ send = 0,recv = 0;
+ if(!myrank) recv = 1;
+
+ while(!recv) {
+ if(myrank!=(nproc-1)) MPI_Send(&send,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+ MPI_Recv(&recv,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+ }
+
+ nseek = recv;
+ nplace = nseek;
+ // --------------------------------------------------
+
+ if(!myrank) {
+ nplace = npt;
+ lseek(nop,nplace,0);
+ char nb[256];
+ if ( version == 1 ) sprintf(nb,"$ENDNOD\n");
+ else sprintf(nb,"$EndNodes\n");
+ int size = strlen(nb);
+ write(nop,nb,size);
+ nplace += size;
+ }
+
+ // ----------------------------------------------------
+ // Write partitionning of elements (for msh1 only)
+ // ----------------------------------------------------
+
+ if ( version == 1 ) {
+
+ if(!myrank) {
+ write(nop,"$PARALLELELM\n",sizeof("$PARALLELELM"));
+ nplace += sizeof("$PARALLELELM");
+ char nb[256];
+ int nbtot = 0;
+ for(int i=0 ; i<nproc ; i++) nbtot +=tab[i];
+ sprintf(nb,"%d\n",nbtot);
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ if(myrank) {
+ lseek(nop,nseek,0);
+ }
+
+ int k = 1;
+ if(myrank) {
+ for(int i=0 ; i<myrank ; i++) k+= tab[i];
+ }
+ {
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit)))
+ {
+ int dim = GEN_type(pv->g);
+ if(dim == 0) {
+ char nb[256];
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+ if(isInterface) {
+ const std::vector<std::pair<int, MDB_Point*> > *recup = (const std::vector<std::pair<int, MDB_Point*> > *) temp_ptr;
+ int minproc = nproc + 10;
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) minproc = std::min(minproc,(*recup)[j].first);
+ minproc = std::min(myrank,minproc);
+ if(minproc!=myrank) continue;
+ int size = (*recup).size();
+ for(int j=0 ; j<size ; j++) {
+ sprintf(nb,"%d %d %d ",k++, size + 1,myrank);
+ char nbtmp[256];
+ if(j == (size-1) ) sprintf(nbtmp,"%d \n",(*recup)[j].first);
+ else sprintf(nbtmp,"%d ",(*recup)[j].first);
+ int sizetmp = strlen(nbtmp);
+ strncat(nb,nbtmp,sizetmp);
+ }
+ } else {
+ sprintf(nb,"%d %d %d \n",k++, 1,myrank);
+ }
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ }
+ VIter_delete(vit);
+ }
+ {
+ EIter eit = M_edgeIter(mesh);
+ pEdge pe;
+ while ((pe = EIter_next(eit)))
+ {
+ int dim = GEN_type(pe->g);
+ if(dim == 1) {
+ void* tmpptr;
+ int isMarked = EN_getDataPtr((pEntity) pe,tagEdge,&tmpptr);
+ char nb[256];
+ if(!isMarked) {
+ sprintf(nb,"%d %d %d \n", k++, 1,myrank);
+ } else {
+ std::map<int,pEdge> *recup = (std::map<int,pEdge> *) tmpptr;
+ int minproc = myrank;
+ for(std::map<int,pEdge>::const_iterator iter=(*recup).begin() ;
+ iter!=(*recup).end() ; iter++){
+ minproc = std::min(minproc,(*iter).first);
+ }
+ if(minproc!=myrank) continue;
+ sprintf(nb,"%d %d %d ", k++, (*recup).size() + 1,myrank);
+ for(std::map<int,pEdge>::const_iterator iter=(*recup).begin() ;
+ iter!=(*recup).end() ; iter++) {
+ char nbtmp[256];
+ if((*iter).first == ((*recup).size()-1) ){
+ sprintf(nbtmp,"%d \n",(*iter).first);
+ } else{
+ sprintf(nbtmp,"%d ",(*iter).first);
+ }
+ int sizetmp = strlen(nbtmp);
+ strncat(nb,nbtmp,sizetmp);
+ }
+ }
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ }
+ EIter_delete(eit);
+ }
+ {
+ FIter fit = M_faceIter(mesh);
+ pFace pf;
+ while ((pf = FIter_next(fit)))
+ {
+ int ntmp;
+ int isMarked = EN_getDataInt((pEntity) pf,tagFace,&ntmp);
+ if(!isMarked) continue;
+ int dim = GEN_type(pf->g);
+ if(dim == 2) {
+ void* tmpptr;
+ int isInt = EN_getDataPtr((pEntity) pf,tagFaceInterface,&tmpptr);
+ char nb[256];
+ if(!isInt) {
+ sprintf(nb, "%d %d %d \n", k++, 1,myrank);
+ } else {
+ std::vector<int> *recup = (std::vector<int> *) tmpptr;
+ int size = (*recup).size();
+ sprintf(nb,"%d %d %d ", k++, size + 1,myrank);
+ for(int j=0 ; j<size ; j++) {
+ char nbtmp[256];
+ if(j == (size-1) ) sprintf(nbtmp,"%d \n",(*recup)[j]);
+ else sprintf(nbtmp,"%d ",(*recup)[j]);
+ int sizetmp = strlen(nbtmp);
+ strncat(nb,nbtmp,sizetmp);
+ }
+ }
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ }
+ FIter_delete(fit);
+ }
+ {
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ char nb[256];
+ sprintf(nb,"%d %d %d \n", k++,1,myrank );
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ RIter_delete(rit);
+ }
+
+ // --------------------------------------------------
+ // End of the control point
+ MPI_Send(&nplace,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+
+ if(!myrank) MPI_Recv(&npt,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+
+ MPI_Barrier(MPI_COMM_WORLD);
+ // --------------------------------------------------
+
+ // --------------------------------------------------
+ // Defines a control point for a sequential writting:
+ // Proc n+1 does not continue while proc n is
+ // not at the next control point
+ send = 0,recv = 0;
+ if(!myrank) recv = 1;
+
+ while(!recv) {
+ if(myrank!=(nproc-1)) MPI_Send(&send,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+ MPI_Recv(&recv,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+ }
+
+ nseek = recv;
+ nplace = nseek;
+ // --------------------------------------------------
+
+ if(!myrank) {
+ nplace = npt;
+ lseek(nop,nplace,0);
+ write(nop,"$ENDPARALLELELM\n",sizeof("$ENDPARALLELELM"));
+ nplace += sizeof("$ENDPARALLELELM");
+ }
+
+ }
+
+ // ----------------------------------------------------
+ // Write elements
+ // ----------------------------------------------------
+
+ if(!myrank) {
+ char nb[256];
+ if ( version == 1 ) { sprintf(nb,"$ELM\n"); }
+ else { sprintf(nb,"$Elements\n"); }
+ int size = strlen(nb);
+ write(nop,nb,size);
+ nplace += size;
+ }
+ if(!myrank) {
+ char nb[256];
+ int nbtot = 0;
+ for(int i=0 ; i<nproc ; i++) nbtot += tab[i];
+ sprintf(nb,"%d\n",nbtot);
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ if(myrank) {
+ lseek(nop,nseek,0);
+ }
+
+ int k = 1;
+ // Create a reverse map of physical tags
+ GEntity2Physical gentity2phys(mesh->geomFeatures_Tags);
+ if(myrank) {
+ for(int i=0 ; i<myrank ; i++) k+= tab[i];
+ }
+ // --- Nodes ---
+ {
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit)))
+ {
+ int dim = GEN_type(pv->g);
+ int tag = GEN_tag (pv->g);
+ int phys = gentity2phys.get_first_tag(pv->g);
+ if(dim == 0) {
+ char nb[256];
+ //int nId = IdGlobal;
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv, tagData, &temp_ptr);
+ if(isInterface) {
+ const std::vector<std::pair<int , MDB_Point*> > *recup = (const std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+ int minproc = nproc + 10;
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) minproc = std::min(minproc,(*recup)[j].first);
+ minproc = std::min(myrank,minproc);
+ if(minproc!=myrank) continue;
+ }
+ if ( version == 1 ) {
+ sprintf(nb,"%d %d %d %d %d %d\n",
+ k++, 15, phys, tag, 1, pv->iD /*+ nId*/);
+ } else {
+ int nbTags = 3;
+ sprintf(nb,"%d %d %d %d %d %d %d\n",
+ k++, 15, nbTags, phys, tag, myrank+1, pv->iD /*+ nId*/);
+ }
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ }
+ VIter_delete(vit);
+ }
+ // --- Edges ---
+ {
+ EIter eit = M_edgeIter(mesh);
+ pEdge pe;
+ while ((pe = EIter_next(eit)))
+ {
+ int dim = GEN_type(pe->g);
+ int tag = GEN_tag (pe->g);
+ int phys = gentity2phys.get_first_tag(pe->g);
+ if(dim == 1) {
+ char nb[256];
+ pVertex p1 = pe->p1;
+ pVertex p2 = pe->p2;
+ //int nId1 = pe->p1->iD /*+ IdGlobal*/,nId2 = pe->p2->iD /*+ IdGlobal*/;
+ //void *temp_ptr1,*temp_ptr2;
+ //int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+ //int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+ //if(isInterface1) {
+ // int isGlob;
+ // int is = EN_getDataInt((pEntity) p1, tagGlob, &isGlob);
+ // assert(is);
+ // nId1 = --isGlob;
+ //}
+ //if(isInterface2) {
+ // int isGlob;
+ // int is = EN_getDataInt((pEntity) p2, tagGlob, &isGlob);
+ // assert(is);
+ // nId2 = --isGlob;
+ //}
+ void * tmpptr;
+ int isMarked = EN_getDataPtr((pEntity) pe, tagEdge, &tmpptr);
+ if(!isMarked) {
+ if ( version == 1 ) {
+ sprintf(nb,"%d %d %d %d %d %d %d\n",
+ k++, 1, phys, tag, 2,p1->iD, p2->iD /* nId1, nId2*/);
+ } else {
+ int nbTags = 3;
+ sprintf(nb,"%d %d %d %d %d %d %d %d\n",
+ k++, 1, nbTags, phys, tag, myrank+1,p1->iD, p2->iD /* nId1, nId2*/);
+ }
+ } else {
+ const std::map<int,pEdge> *recup = (const std::map<int,pEdge> *) tmpptr;
+ int minproc = myrank;
+ for(std::map<int,pEdge>::const_iterator iter=(*recup).begin() ;
+ iter!=(*recup).end() ; iter++){
+ minproc = std::min(minproc,(*iter).first);
+ }
+ if(minproc!=myrank) continue;
+ if ( version == 1 ) {
+ sprintf(nb,"%d %d %d %d %d %d %d\n",
+ k++, 1, phys, tag, 2, p1->iD, p2->iD /* nId1, nId2*/);
+ } else {
+ int nbTags = 3;
+ sprintf(nb,"%d %d %d %d %d %d %d %d\n",
+ k++, 1, nbTags, phys, tag, myrank+1,p1->iD, p2->iD /* nId1, nId2*/);
+ }
+ }
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ }
+ EIter_delete(eit);
+ }
+ // --- Faces ---
+ {
+ FIter fit = M_faceIter(mesh);
+ pFace pf;
+ while ((pf = FIter_next(fit)))
+ {
+ int ntmp;
+ int isMarked = EN_getDataInt((pEntity) pf,tagFace,&ntmp);
+ if(!isMarked) continue;
+ MDB_Point *nod[3];
+ int dim = GEN_type(pf->g);
+ int tag = GEN_tag (pf->g);
+ int phys = gentity2phys.get_first_tag(pf->g);
+ pf->getNodes(nod);
+ if(dim == 2) {
+ char nb[256];
+ //int nId[3];
+ pf->getNodes(nod);
+ //void *temp_ptr1;
+ //for(int j=0 ; j<3 ; j++){
+ // int isInterface = EN_getDataPtr((pEntity) nod[j], tagData, &temp_ptr1);
+ // if(isInterface) {
+ // int isGlob;
+ // int is = EN_getDataInt((pEntity) nod[j], tagGlob, &isGlob);
+ // assert(is);
+ // nId[j] = --isGlob;
+ // }
+ // else nId[j] = nod[j]->iD + IdGlobal;
+ //}
+ if ( version == 1 ) {
+ sprintf(nb, "%d %d %d %d %d %d %d %d\n",
+ k++, 2, phys,tag, 3, nod[0]->iD, nod[1]->iD,nod[2]->iD/*nId[0], nId[1], nId[2]*/);
+ } else {
+ int nbTags = 3;
+ sprintf(nb, "%d %d %d %d %d %d %d %d %d\n",
+ k++, 2, nbTags, phys, tag, myrank+1, nod[0]->iD, nod[1]->iD,nod[2]->iD/* nId[0], nId[1], nId[2]*/);
+ }
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ }
+ FIter_delete(fit);
+ }
+ // --- Regions ---
+ {
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit)))
+ {
+ MDB_Point *nod[4];
+ int tag = GEN_tag (pr->g);
+ int phys = gentity2phys.get_first_tag(pr->g);
+ pPList ll = R_vertices(pr);
+ nod[0] = (pVertex)PList_item(ll, 0);
+ nod[1] = (pVertex)PList_item(ll, 1);
+ nod[2] = (pVertex)PList_item(ll, 2);
+ nod[3] = (pVertex)PList_item(ll, 3);
+ PList_delete(ll);
+ char nb[256];
+ // int nId[4];
+ // void *temp_ptr1;
+ // for(int j=0 ; j<4 ; j++){
+ // int isInterface = EN_getDataPtr((pEntity) nod[j] , tagData, &temp_ptr1);
+ // if(isInterface){
+ // int isGlob;
+ // int is = EN_getDataInt((pEntity) nod[j] , tagGlob , &isGlob);
+ // assert(is);
+ // nId[j] = --isGlob;
+ // }
+ // else nId[j] = nod[j]->iD + IdGlobal;
+ // }
+ if ( version == 1 ) {
+ sprintf(nb, "%d %d %d %d %d %d %d %d %d\n",
+ k++, 4, phys, tag, 4, nod[0]->iD, nod[1]->iD,nod[2]->iD,nod[3]->iD/* nId[0], nId[1], nId[2], nId[3]*/);
+ } else {
+ int nbTags = 3;
+ sprintf(nb, "%d %d %d %d %d %d %d %d %d %d\n",
+ k++, 4, nbTags, phys, tag, myrank+1, nod[0]->iD, nod[1]->iD,nod[2]->iD,nod[3]->iD/*nId[0], nId[1], nId[2], nId[3]*/);
+ }
+ int size = strlen(nb);
+ nplace += size;
+ write(nop,nb,size);
+ }
+ RIter_delete(rit);
+ }
+
+ // --------------------------------------------------
+ // End of the control point
+ MPI_Send(&nplace,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+
+ if(!myrank) MPI_Recv(&npt,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+
+ MPI_Barrier(MPI_COMM_WORLD);
+ // --------------------------------------------------
+
+ if(!myrank) {
+ nplace = npt;
+ lseek(nop,nplace,0);
+ char nb[256];
+ if ( version == 1 ) { sprintf(nb,"$ENDELM\n"); }
+ else { sprintf(nb,"$EndElements\n"); }
+ int size = strlen(nb);
+ write(nop,nb,size);
+ nplace += size;
+ }
+
+ close(nop);
+
+ //vit = M_vertexIter(mesh);
+ //while ((pv=VIter_next(vit))){
+ // int isGlob;
+ // int is = EN_getDataInt((pEntity) pv , tagGlob , &isGlob);
+ // if(is) EN_deleteData((pEntity) pv,tagGlob);
+ //}
+ //VIter_reset(vit);
+ // MD_deleteMeshDataId(tagGlob);
+
+ EIter eit = M_edgeIter(mesh);
+ pEdge pe;
+ while ((pe=EIter_next(eit))){
+ void* is;
+ int isMarked = EN_getDataPtr((pEntity) pe , tagEdge , &is);
+ if(isMarked) EN_deleteData((pEntity) pe,tagEdge);
+ }
+ EIter_reset(eit);
+ MD_deleteMeshDataId(tagEdge);
+
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface=FIter_next(fit))){
+ int is;
+ int isMarked = EN_getDataInt((pEntity) pface , tagFace , &is);
+ if(isMarked) EN_deleteData((pEntity) pface,tagFace);
+ void* isp;
+ isMarked = EN_getDataPtr((pEntity) pface , tagFaceInterface , &isp);
+ if(isMarked) EN_deleteData((pEntity) pface,tagFaceInterface);
+ }
+ FIter_reset(fit);
+ MD_deleteMeshDataId(tagFace);
+ MD_deleteMeshDataId(tagFaceInterface);
+ delete []tab;
+ delete []tabmax;
+ }
+
+#endif
+
+}
+
+// -------------------------------------------------------------------
+// ---------------- LoadGmshParallelOld ------------------------------
+// -------------------------------------------------------------------
+/*
+void LoadGmshParallelOld (pMesh m,const char *filename,const int numproc,int version)
+{
+ FILE *fp = fopen(filename, "r");
+ if(!fp)
+ {
+ Msg(MDB_FATAL,"Unknown File %s\n",filename);
+ }
+ char String[256];
+ // if (!m->model)
+ m->model = new NullModel;
+ int Nbr_local = 0;
+ int *tabelt = NULL;
+#ifdef PARALLEL
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+#endif
+ int nread = 0;
+ // Interfaces NODES
+ while(1) {
+ do {
+ if(!fgets(String, sizeof(String),fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$' ||
+ strncmp(&String[1], "PARALLELNOD",3));
+
+ if(feof(fp) || (nread==2)){
+ break;
+ }
+ else {
+ if(!strncmp(&String[1], "PARALLELNOD", 11)) {
+ nread ++;
+ int Nbr_NodesInterfaces,Num,Nb;
+ fscanf(fp, "%d", &Nbr_NodesInterfaces);
+ for(int i_Node = 0; i_Node < Nbr_NodesInterfaces; i_Node++) {
+ fscanf(fp, "%d %d", &Num, &Nb);
+ if(Nb == 1) {
+ int nproc;
+ fscanf(fp,"%d",&nproc);
+ if(nproc == numproc) {
+ Nbr_local++;
+ m->add_point(Num,0.,0.,0.);
+ }
+ } else {
+ int *listproc=new int[Nb];
+ int ismine = 0;
+ for(int j=0 ; j < Nb ; j++) {
+ int nproc;
+ fscanf(fp,"%d",&nproc);
+ listproc[j] = nproc;
+ if(nproc == numproc) {
+ Nbr_local++;
+ ismine++;
+ m->add_point(Num,0.,0.,0.);
+ }
+ }
+#ifdef PARALLEL
+ if(ismine) {
+ std::vector<std::pair<int , MDB_Point*> > remotePoints;
+ for(int j=0 ; j < Nb ; j++) {
+ if(listproc[j]!=numproc) {
+ (remotePoints).push_back(std::pair <int , MDB_Point*>(listproc[j],NULL));
+ }
+ }
+ // attach remotePoints
+ assert(remotePoints.size()==(unsigned int)(Nb-1));
+ MDB_Point * vt = m->find_point(Num);
+ EN_attachDataPtr((pEntity) vt , tagData,
+ new std::vector<std::pair<int , MDB_Point*> >(remotePoints));
+ }
+#endif
+ delete []listproc;
+ }
+ }
+ printf("%d Nodes in this partition\n",Nbr_local);
+ if(!Nbr_local) Nbr_local++;
+ } else if(!strncmp(&String[1], "PARALLELELM", 11)) {
+ nread++;
+ int Nbr_Elt_local = 0,Num,Nb,Nbr_Elt;
+ fscanf(fp, "%d", &Nbr_Elt);
+ tabelt = (int *) calloc(Nbr_Elt,sizeof(int));
+ for(int i = 0; i < Nbr_Elt; i++) {
+ fscanf(fp, "%d %d", &Num, &Nb);
+ tabelt[i] = -1;
+ if(Nb == 1) {
+ int nproc;
+ fscanf(fp,"%d",&nproc);
+ if(nproc == numproc) {
+ Nbr_Elt_local++;
+ tabelt[i] = Num;
+ }
+ } else {
+ int *listproc=new int[Nb];
+ for(int j=0 ; j < Nb ; j++) {
+ int nproc;
+ fscanf(fp,"%d",&nproc);
+ listproc[j] = nproc;
+ if(nproc == numproc) {
+ Nbr_Elt_local++;
+ tabelt[i] = Num;
+ }
+ }
+ delete []listproc;
+ }
+ }
+ printf("%d Elt in this partition\n",Nbr_Elt_local);
+ }
+ }
+ }
+
+ fseek(fp,0,SEEK_SET);
+ while(1) {
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ break;
+ if(feof(fp))
+ break;
+ } while(String[0] != '$');
+
+ if(feof(fp))
+ break;
+
+
+ // NODES
+ if(!strncmp(&String[1], "NOD", 3) ||
+ !strncmp(&String[1], "NOE", 3) ||
+ !strncmp(&String[1], "Nodes", 5)) {
+
+ int Nbr_Nodes,Num,ncurc = 0;
+ double x,y,z;
+ fscanf(fp, "%d", &Nbr_Nodes);
+ for(int i_Node = 0; i_Node < Nbr_Nodes; i_Node++) {
+ fscanf(fp, "%d %lf %lf %lf", &Num, &x, &y, &z);
+ if(Nbr_local) {
+ MDB_Point * p = m->find_point(Num);
+ if(p) {
+ ncurc++;
+ p->X = x;
+ p->Y = y;
+ p->Z = z;
+ }
+ } else {
+ m->add_point(Num,x,y,z);
+ }
+ }
+ }
+
+ // ELEMENTS
+ else if(!strncmp(&String[1], "ELM", 3) ||
+ !strncmp(&String[1], "Elements", 8)) {
+ int Nbr_Elements, NbTags, verts[256],Tag;
+ int Num, Type, Physical, Elementary, Nbr_Nodes, Partition;
+ fscanf(fp, "%d", &Nbr_Elements);
+ for(int i_Element = 0; i_Element < Nbr_Elements; i_Element++) {
+
+ if(version == 1){
+ fscanf(fp, "%d %d %d %d %d",
+ &Num, &Type, &Physical, &Elementary, &Nbr_Nodes);
+ Partition = 1;
+ }
+ else{
+ fscanf(fp, "%d %d %d", &Num, &Type, &NbTags);
+ Elementary = Physical = Partition = 1;
+ for(int j = 0; j < NbTags; j++){
+ fscanf(fp, "%d", &Tag);
+ if(j == 0)
+ Physical = Tag;
+ else if(j == 1)
+ Elementary = Tag;
+ else if(j == 2)
+ Partition = Tag;
+ // ignore any other tags for now
+ }
+ Nbr_Nodes = getNumVerticesForElementTypeMSH(Type);
+ }
+ // int myrank;
+ // MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ for(int j = 0; j < Nbr_Nodes; j++)
+ fscanf(fp, "%d", &verts[j]);
+
+ GEntity *geom = 0;
+ switch (Type) {
+
+ // -------------------------------------------------------------------
+ // linear elements
+ // -------------------------------------------------------------------
+
+ case MSH_LIN_2:
+ {
+ if(Nbr_local) {
+ if(tabelt[i_Element]>=0) {
+ if(tabelt[i_Element]!=Num) printf(" %d tab %d num %d\n",i_Element,tabelt[i_Element],Num);
+ assert(tabelt[i_Element]==Num);
+ for (int k=0;k<2;k++) assert(m->find_point(verts[k]));
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(verts[0],verts[1],geom);
+ }
+ } else {
+ GEdge* geom = m->model->edgeByTag(Elementary);
+ m->add_edge(verts[0],verts[1],geom);
+ }
+ }
+ break;
+ case MSH_LIN_3:
+ {
+ if(Nbr_local) {
+ if(tabelt[i_Element]>=0) {
+ if(tabelt[i_Element]!=Num) printf(" %d tab %d num %d\n",i_Element,tabelt[i_Element],Num);
+ assert(tabelt[i_Element]==Num);
+ assert(m->find_point(verts[0]) && m->find_point(verts[1]) && m->find_point(verts[2]));
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(3,geom,verts[0],verts[2],verts[1]);
+ }
+ } else {
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(3,geom,verts[0],verts[2],verts[1]);
+ }
+ }
+ break;
+
+ case MSH_LIN_4:
+ {
+ if(Nbr_local) {
+ if(tabelt[i_Element]>=0) {
+ if(tabelt[i_Element]!=Num) printf(" %d tab %d num %d\n",i_Element,tabelt[i_Element],Num);
+ assert(tabelt[i_Element]==Num);
+ assert(m->find_point(verts[0]) && m->find_point(verts[1]));
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(4,geom, verts[0],verts[2],verts[3],verts[1]);
+ }
+ } else {
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(4,geom, verts[0],verts[2],verts[3],verts[1]);
+ }
+ }
+ break;
+ case MSH_LIN_5:
+ {
+ if(Nbr_local) {
+ if(tabelt[i_Element]>=0) {
+ if(tabelt[i_Element]!=Num) printf(" %d tab %d num %d\n",i_Element,tabelt[i_Element],Num);
+ assert(tabelt[i_Element]==Num);
+ assert(m->find_point(verts[0]) && m->find_point(verts[1]));
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(5,geom, verts[0],verts[2],verts[3],verts[4],verts[1]);
+ }
+ } else {
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(5,geom, verts[0],verts[2],verts[3],verts[4],verts[1]);
+ }
+ }
+ break;
+ case MSH_LIN_6:
+ {
+ if(Nbr_local) {
+ if(tabelt[i_Element]>=0) {
+ if(tabelt[i_Element]!=Num) printf(" %d tab %d num %d\n",i_Element,tabelt[i_Element],Num);
+ assert(tabelt[i_Element]==Num);
+ assert(m->find_point(verts[0]) && m->find_point(verts[1]));
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(6,geom, verts[0],verts[2],verts[3],verts[4],verts[5],verts[1]);
+ }
+ } else {
+ geom = m->model->edgeByTag(Elementary);
+ m->add_edge(6,geom, verts[0],verts[2],verts[3],verts[4],verts[5],verts[1]);
+ }
+ }
+ break;
+
+ // -------------------------------------------------------------------
+ // TRIANGLES
+ // -------------------------------------------------------------------
+
+ case MSH_TRI_3:
+ {
+ if(Nbr_local) {
+ if(tabelt[i_Element]>=0) {
+ assert(tabelt[i_Element]==Num);
+ assert(m->find_point(verts[0]) && m->find_point(verts[1]) && m->find_point(verts[2]));
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(verts[0],verts[1],verts[2],geom);
+ }
+ } else {
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(verts[0],verts[1],verts[2],geom);
+ }
+ }
+ break;
+
+ // order 2
+
+ case MSH_TRI_6:
+ {
+ if(Nbr_local) {
+ if(tabelt[i_Element]>=0) {
+ assert(tabelt[i_Element]==Num);
+ assert(m->find_point(verts[0]) && m->find_point(verts[1]) && m->find_point(verts[2]));
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(2,0,geom,verts[0],verts[3],verts[1],verts[4],verts[2],verts[5]);
+ }
+ } else {
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(2,0,geom,verts[0],verts[3],verts[1],verts[4],verts[2],verts[5]);
+ }
+ }
+ break;
+
+ // order 3
+
+ case MSH_TRI_9:
+ {
+ if (Nbr_local) {
+
+ if(tabelt[i_Element]>=0) {
+ assert(tabelt[i_Element]==Num);
+ for (int i=0;i<9;i++) assert(m->find_point(verts[i]));
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(3,false,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8]);
+ }
+ }
+ else {
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(3,false,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8]);
+ }
+ break;
+ }
+
+ // Serendipity order 4
+
+ case MSH_TRI_12:
+ {
+ if (Nbr_local) {
+
+ if(tabelt[i_Element]>=0) {
+ assert(tabelt[i_Element]==Num);
+ for (int i=0;i<12;i++) assert(m->find_point(verts[i]));
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(4,false,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11]);
+ }
+ }
+ else {
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(4,false,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11]);
+ }
+ break;
+ }
+
+ // Complete
+
+ case MSH_TRI_15:
+ {
+ if (Nbr_local) {
+
+ if(tabelt[i_Element]>=0) {
+ assert(tabelt[i_Element]==Num);
+ for (int i=0;i<24;i++) assert(m->find_point(verts[i]));
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(4,true,geom,verts[0],verts[3],verts[4],verts[5],verts[6],verts[1],verts[7],verts[8],verts[9],verts[10],verts[2],verts[11],verts[12],verts[13],verts[14]);
+ }
+ }
+ else {
+ geom = m->model->faceByTag(Elementary);
+ m->add_triangle(4,true,geom,verts[0],verts[3],verts[4],verts[5],verts[6],verts[1],verts[7],verts[8],verts[9],verts[10],verts[2],verts[11],verts[12],verts[13],verts[14]);
+ }
+ break;
+ }
+
+ // -------------------------------------------------------------------
+ // Tetrahedra
+ // -------------------------------------------------------------------
+
+ // linear
+
+ case MSH_TET_4:
+ {
+
+ if(Nbr_local) {
+ if(tabelt[i_Element]>=0) {
+ assert(tabelt[i_Element]==Num);
+ assert(m->find_point(verts[0]) && m->find_point(verts[1]) && m->find_point(verts[2]) &&m->find_point(verts[3]));
+ geom = m->model->regionByTag(Elementary);
+ m->add_tet(verts[0],verts[1],verts[2],verts[3],geom);
+ }
+ } else {
+ geom = m->model->regionByTag(Elementary);
+ m->add_tet(verts[0],verts[1],verts[2],verts[3],geom);
+ }
+ }
+ break;
+
+ // quadratic
+
+ case MSH_TET_10:
+ {
+ if (Nbr_local) {
+
+ if(tabelt[i_Element]>=0) {
+ assert(tabelt[i_Element]==Num);
+ for (int i=0;i<10;i++) assert(m->find_point(verts[i]));
+ geom = m->model->regionByTag(Elementary);
+ m->add_tet(geom,2,false,verts);
+ }
+ }
+ else {
+ geom = m->model->regionByTag(Elementary);
+ m->add_tet(geom,2,false,verts);
+ }
+ break;
+ }
+ // -------------------------------------------------------------------
+ // Hexahedra
+ // -------------------------------------------------------------------
+
+ case MSH_HEX_8:
+ {
+
+ if(Nbr_local) { cout << "not yet implemented!!!" << endl; throw; }
+ geom = m->model->regionByTag(Elementary);
+ m->add_hex(verts[0],verts[1],verts[2],verts[3],
+ verts[4],verts[5],verts[6],verts[7],geom);
+ }
+ break;
+
+ // -------------------------------------------------------------------
+ // Prisms
+ // -------------------------------------------------------------------
+
+ case MSH_PRI_6:
+ {
+
+ if(Nbr_local) { cout << "not yet implemented!!!" << endl; throw; }
+ geom = m->model->regionByTag(Elementary);
+ m->add_prism(verts[0],verts[1],verts[2],
+ verts[3],verts[4],verts[5],geom);
+ }
+ break;
+
+ // -------------------------------------------------------------------
+ // node
+ // -------------------------------------------------------------------
+
+ case 15:
+ {
+ if(Nbr_local) {
+ MDB_Point *p = m->find_point(verts[0]);
+ if(p) {
+ assert(tabelt[i_Element]==Num);
+ GVertex *gv = m->model->vertexByTag(Elementary);
+ p->g = gv;
+ }
+ } else {
+ geom = m->model->vertexByTag(Elementary);
+ MDB_Point *p = m->find_point(verts[0]);
+ p->g = geom;
+ }
+ }
+ break;
+ default:
+ throw;
+ }
+ if (geom)
+ {
+ bool find = false;
+ for (std::multimap<int, pGEntity>::iterator it = m->geomFeatures_Tags.lower_bound(Physical);
+ it != m->geomFeatures_Tags.upper_bound(Physical);++it)
+ if (it->second == geom)find = true;
+ if (!find)
+ m->geomFeatures_Tags.insert(std::pair<int,pGEntity>(Physical, geom));
+ }
+ }
+ }
+
+ do {
+ if(!fgets(String, sizeof(String), fp))
+ throw;
+ if(feof(fp))
+ throw;
+ } while(String[0] != '$');
+ }
+
+ m->classify_unclassified_entities();
+
+#ifdef PARALLEL
+// linkRemotePoints(m);
+ pMeshDataId tagVertex = MD_lookupMeshDataId("RemotePoint");
+ V_createInfoInterface(m, tagVertex);
+#endif
+}
+*/
+
diff --git a/Mesh/MeshDataBaseParallelIO.h b/Mesh/MeshDataBaseParallelIO.h
new file mode 100644
index 0000000..13b1660
--- /dev/null
+++ b/Mesh/MeshDataBaseParallelIO.h
@@ -0,0 +1,37 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _LOADPARALLELGMSHMESH_H_
+#define _LOADPARALLELGMSHMESH_H_
+
+#include "MeshDataBaseInterface.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+
+#ifdef PARALLEL
+ // Save a mesh (for parallel only) \ingroup parallel
+ // - msh1 or msh2
+ // GCTODO: merge serial and parallel versions
+ void SaveGmshMeshParallel (const pMesh, const char *filename, int version=2);
+#endif
+
+ // Load a Gmsh mesh written in msh1 (deprecated)
+ // void LoadGmshParallelOld (pMesh, const char *, const int numproc, int version=1);
+
+ // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseParallelInterface.cc b/Mesh/MeshDataBaseParallelInterface.cc
new file mode 100644
index 0000000..5c1ea38
--- /dev/null
+++ b/Mesh/MeshDataBaseParallelInterface.cc
@@ -0,0 +1,1737 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: J.-F. Remacle, C. Dobrzynski, K. Hillewaert, G. Compere
+// -------------------------------------------------------------------
+
+#include "assert.h"
+#include "MeshDataBase.h"
+#include "MeshDataBaseIO.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "MeshDataBaseParallelIO.h"
+#include "MeshDataBaseMessage.h"
+#include "MeshDataBaseCommCheck.h"
+#include "MeshDataBaseComm.h"
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+// #include <sstream>
+// using std::ostringstream;
+// #include <fstream>
+// using std::ofstream;
+#include <set>
+#include <iterator>
+#include <algorithm>
+
+namespace MAd {
+
+ struct point_comm
+ {
+ pVertex p; // local pointer
+ int nID; // myrank
+ int numGlobal; // Id global for the vertex
+ };
+
+ struct edge_comm {
+ int distProc; // remote processor
+ pEdge pe; // edge
+ pVertex p1,p2; // vertices on remote processor
+ int id1,id2; // local identity tags
+ };
+
+ struct face_comm
+ {
+ int distProc; // remote processor
+ pFace pf; // face
+ pVertex p1,p2,p3,p4; // vertices on remote processor
+ int id1,id2,id3,id4; // local identity tags
+ };
+
+ // -------------------------------------------------------------------
+ /*! \brief write mesh in parallel format \ingroup internal */
+#ifdef PARALLEL
+ void M_writeParallel(pMesh m, const char * filename, int version)
+ {
+ SaveGmshMeshParallel(m, filename, version);
+ }
+#endif
+
+ // -------------------------------------------------------------------
+ /*! \brief flags true if entity pe is on a partition boundary \ingroup internal
+ \warning only valid after creation of interface exchange information (based
+ on data with tag "RemotePoint") */
+
+ bool EN_isInterface(pEntity pe)
+ {
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr(pe, tagData, &temp_ptr);
+ if (isInterface) return true;
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ /*! \brief flags true if vertex pv is on a partition boundary \ingroup parallel
+ \warning only valid after V_createInfoInterface (based on EN_isInterface) */
+
+ bool V_isInterface(pVertex pv) { return EN_isInterface((pEntity) pv);}
+
+ // -------------------------------------------------------------------
+ /*! \brief flags true if edge pe is on a partition boundary \ingroup parallel
+ \warning only valid after E_createInfoInterface (based on EN_isInterface) */
+
+ bool E_isInterface(pEdge pe) { return EN_isInterface((pEntity) pe);}
+
+ // -------------------------------------------------------------------
+ /*! \brief flags true if face pf is on a partition boundary \ingroup parallel
+ \warning only valid after F_createInfoInterface (based on EN_isInterface) */
+
+ bool F_isInterface(pFace pf) { return EN_isInterface((pEntity) pf);}
+
+ // -------------------------------------------------------------------
+ /*! \brief Lists all processors on which the vertex pv has a copy \ingroup internal
+ The data with tag "RemotePoint" is created during
+ V_createInfoInterface and stores a list of pairs consisting of processor
+ id and vertex pointer
+ */
+
+ int V_listInterface(pVertex pv, std::vector<int>* distProcs)
+ {
+ pMeshDataId tagVertex = MD_lookupMeshDataId("RemotePoint");
+
+ void *temp_ptr;
+ int isInterface = EN_getDataPtr((pEntity) pv, tagVertex, &temp_ptr);
+ if(isInterface) {
+ const std::vector<std::pair<int,pVertex> > *recup =
+ (const std::vector<std::pair<int,pVertex> > *) temp_ptr;
+
+ std::set<int> parts;
+ std::vector<std::pair<int,pVertex> >::const_iterator pIter = recup->begin();
+ for (;pIter!=recup->end();++pIter) parts.insert(pIter->first);
+
+ distProcs->insert(distProcs->begin(),parts.begin(),parts.end());
+
+ }
+ return distProcs->size();
+ }
+
+ // -------------------------------------------------------------------
+ /*! \brief Returns true if the node is a (periodic) copy of the node with global id rId \ingroup internal */
+ /*! This information is based on data read with the mesh and hence will always be correct */
+
+ bool V_corresponds(pVertex pv,int rId)
+ {
+ if (EN_id((pEntity) pv) == rId) return true;
+
+ pMeshDataId tagVertex = MD_lookupMeshDataId("PeriodicVertexID");
+ void* tmpptr = NULL;
+ if (!EN_getDataPtr((pEntity) pv,tagVertex,&tmpptr)) return false;
+ std::map<int,std::vector<int> >* conn = (std::map<int,std::vector<int> >*) tmpptr;
+ return (conn->find(rId) != conn->end());
+ }
+
+ // -------------------------------------------------------------------
+
+ /*! \brief return true if the edge corresponds (possibly) \ingroup internal */
+ /*! \warning error for edges transformed onto oneself */
+
+ bool E_corresponds(pEdge pe,int rv1,int rv2) {
+
+ pVertex pv1 = E_vertex(pe,0);
+ pVertex pv2 = E_vertex(pe,1);
+
+
+ int lv1 = EN_id((pEntity) pv1);
+ int lv2 = EN_id((pEntity) pv2);
+
+ int lmin = std::min(lv1,lv2);
+ int lmax = std::max(lv1,lv2);
+
+ int rmin = std::min(rv1,rv2);
+ int rmax = std::max(rv1,rv2);
+
+ // identical edge - most of the cases
+
+ if (lmin == rmin && lmax == rmax) return true;
+
+ // only one shared node -> problems
+
+ if (lmin == rmax && lmax != rmax) return false;
+ if (lmin != rmin && lmax == rmax) return false;
+
+ // all other cases should be ok ? (Koen)
+
+ if (V_corresponds(pv1,rv1) && V_corresponds(pv2,rv2)) return true;
+ if (V_corresponds(pv1,rv2) && V_corresponds(pv2,rv1)) return true;
+
+ }
+
+ // -------------------------------------------------------------------
+ /*! \brief return true if the face corresponds \ingroup internal */
+ /*! \warning not yet fully functional outside of F_createInfoInterface */
+ /*! <ul>
+ <li> we do not really verify periodic nodes
+ <li> error for edges transformed onto oneself
+ </ul>
+ */
+
+ bool F_corresponds(pFace pf,int rv1,int rv2,int rv3,int rv4) {
+
+ std::set<int> lverts;
+
+ for (int i=0;i<F_numVertices(pf);i++) {
+ lverts.insert(EN_id((pEntity) F_vertex(pf,i)));
+ }
+
+ std::set<int> rverts;
+ rverts.insert(rv1);
+ rverts.insert(rv2);
+ rverts.insert(rv3);
+ if (rv4 != -1) rverts.insert(rv4);
+
+ // obvious checks ...
+ if (rverts.size() != lverts.size()) return false;
+
+ // same face ...
+ if (rverts == lverts) return true;
+
+ // only some shared nodes is not ok ?
+ std::set<int> nonShared;
+ std::set_difference(lverts.begin(),lverts.end(),
+ rverts.begin(),rverts.end(),
+ std::insert_iterator< std::set<int> > (nonShared,
+ nonShared.begin()));
+
+ if (nonShared.size() != lverts.size()) return false;
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ /*! \brief Returns true if the node is a (periodic) copy of the node with global id rId \ingroup parallel
+
+ This information is based on data read with the mesh and hence will always
+ be correct; only valid for check on local partition */
+
+ bool V_corresponds(pVertex p1,pVertex p2)
+ {
+ return (V_corresponds(p1,EN_id((pEntity) p2)) &&
+ V_corresponds(p2,EN_id((pEntity) p1)));
+ }
+
+ // --------------------------------------------------------------------
+
+ /*! \brief returns true if the node is flagged as periodic \ingroup parallel
+
+ This information is based on data read with the mesh and hence will always
+ be correct */
+
+ bool V_isPeriodic(pVertex pv) {
+
+ pMeshDataId tagVertex = MD_lookupMeshDataId("PeriodicVertexID");
+ void* tmpptr = NULL;
+ if (!EN_getDataPtr((pEntity) pv,tagVertex,&tmpptr)) return false;
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+ /*!\brief An edge flagged as potentially on a parallel interface \ingroup internal
+
+ \warning the check is not correct for 2D meshes with internal edges */
+
+ bool E_isPotentialInterface(pMesh mesh, pEdge pe)
+ {
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+
+ switch (dim) {
+ case 2:
+ {
+
+ // --- check that the edge has less than two neighbouring faces ---
+
+ int numf = pe->numfaces();
+ if( numf == 2 ) return false;
+
+ // --- check that the edge is not alone or
+ // with multiple neighbouring faces (debug) ---
+
+ assert(numf == 1);
+ return true;
+
+ // KH: for the moment an edge is always classified on an edge ... (nullmodel)
+ // hence the following check is not usable ...
+ ///
+ // if edge is classified on an edge, still two possibilities
+ //
+ // 1. periodic edge: check whether or not nodes are periodic - ok
+ // 2. internal edge: not yet treated correctly
+
+
+ if ( E_whatInType(pe) == 1 ) {
+ for (int i=0;i<2;i++) if (!V_isPeriodic(E_vertex(pe,i))) return false;
+ return true;
+ }
+
+
+ break;
+ }
+ case 3:
+ {
+ // --- check that the edge has at least one neighbouring face that is potentially shared ---
+
+ int numf = pe->numfaces();
+ for (int iF=0; iF < numf; iF++) {
+ if ( F_isPotentialInterface(mesh,E_face(pe,iF))) return true;
+ }
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+
+// bool E_isInterface(pMesh mesh, pEdge pe, int * distProc,
+// std::vector<pVertex>* distVt)
+// {
+// if (distProc) *distProc = -1;
+// if (distVt) (*distVt).clear();
+
+// if ( !E_isPotentialInterface(mesh,pe) ) return false;
+
+// // GCREMARK: the rest of the function gives informations about the
+// // distant partition(s) but is just a cross-check.
+
+// // --- check that the two nodes are on a parallel boundary ---
+// // KHREMARK :
+// // - this is not conclusive, we should verify that the edge exists on the other partitions
+// // - on the other hand, if the edge is possibly on more than two partitions,
+// // we will not flag all remote partitions
+
+// pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+// pVertex pv1 = pe->p1;
+// pVertex pv2 = pe->p2;
+// void * temp_ptr1, *temp_ptr2;
+// int isInterface1 = EN_getDataPtr((pEntity) pv1 , tagData, &temp_ptr1);
+// int isInterface2 = EN_getDataPtr((pEntity) pv2 , tagData, &temp_ptr2);
+// if( !(isInterface1 && isInterface2) ) {
+// Msg(MDB_FATAL,"Error: found an edge which nodes are not both on a parallel boundary although it fits the conditions to be a parallel boundary edge\n");
+// }
+
+// // --- check that the two nodes are on the same parallel boundary ---
+// const std::vector<std::pair<int,pVertex> > *recup1 =
+// (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+// const std::vector<std::pair<int,pVertex> > *recup2 =
+// (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+
+// std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+// std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+
+// for (; rIter1 != recup1->end(); rIter1++) {
+// for (; rIter2 != recup2->end(); rIter2++) {
+// if ( (*rIter1).first == (*rIter2).first ) {
+// if (distProc) *distProc = (*rIter1).first;
+// if (distVt) {
+// (*distVt).clear();
+// (*distVt).push_back((*rIter1).second);
+// (*distVt).push_back((*rIter2).second);
+// }
+// return true;
+// }
+// }
+// rIter2 = recup2->begin();
+// }
+
+// Msg(MDB_FATAL,"Error: found an edge which nodes have no common parallel boundary although it fits the conditions to be a parallel boundary edge\n");
+
+// return false;
+// }
+
+
+ // ---------------------------------------------------------------------------
+ /*!\brief Verifies whether edge pe is located at a parallel interface boundary
+ and provides information about all possible copies \ingroup internal */
+
+ bool E_isPotentialInterface(pMesh mesh, pEdge pe, std::vector<edge_comm>& distVt)
+
+ {
+ distVt.clear();
+
+ if ( !E_isPotentialInterface(mesh,pe) ) return false;
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pVertex pv1 = pe->p1;
+ pVertex pv2 = pe->p2;
+ void * temp_ptr1, *temp_ptr2;
+ int isInterface1 = EN_getDataPtr((pEntity) pv1 , tagData, &temp_ptr1);
+ int isInterface2 = EN_getDataPtr((pEntity) pv2 , tagData, &temp_ptr2);
+
+ if( !(isInterface1 && isInterface2) ) return false;
+
+ // --- check that the two nodes are on the same parallel boundary ---
+ const std::vector<std::pair<int,pVertex> > *recup1 =
+ (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+ const std::vector<std::pair<int,pVertex> > *recup2 =
+ (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+
+ std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+ std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+
+ for (; rIter1 != recup1->end(); rIter1++) {
+ for (; rIter2 != recup2->end(); rIter2++) {
+ if ( (*rIter1).first == (*rIter2).first ) {
+ edge_comm ee;
+ ee.distProc = (*rIter1).first;
+ ee.p1 = (*rIter1).second;
+ ee.p2 = (*rIter2).second;
+ ee.id1 = EN_id((pEntity) E_vertex(pe,0));
+ ee.id2 = EN_id((pEntity) E_vertex(pe,1));
+ ee.pe = pe;
+ distVt.push_back(ee);
+ }
+ }
+ rIter2 = recup2->begin();
+ }
+ return (!distVt.empty());
+ }
+
+ // -------------------------------------------------------------------
+ /*! \brief Verify whether pf may potentially be an interface \ingroup internal
+ \warning will flag false for internal boundaries !!! */
+
+ // -------------------------------------------------------------------
+
+ bool F_isPotentialInterface(pMesh mesh, pFace pf)
+ {
+ // bool check = true;
+ // for (size_t i=0;i<F_numVertices(pf);i++) check = check && V_isInterface(F_vertex(pf,i));
+ // return check;
+
+ // --- check that the mesh is 3D ---
+
+ if (mesh->tets.empty()) return false;
+
+ // --- check that the face has less than two neighbouring regions ---
+
+ int numtet = pf->getNbRegions();
+ if (numtet == 2) return false;
+ return true;
+
+ // OK : for the moment a face is always classified on a geometric face (nullmodel ...)
+
+ // --- if the face is classified on a topological face, we can still have
+ // 1. a periodic face: all nodes are periodic - ok
+ // 2. an internal boundary - check is not ok
+
+ int modelDim = GEN_type(pf->g);
+
+ if (modelDim == 2) {
+ for (int i=0;i<F_numVertices(pf);i++) {
+ if (!V_isPeriodic(F_vertex(pf,i))) return false;
+ }
+ return true;
+ }
+
+ // --- check that the face is not alone (debug) ---
+ assert(numtet);
+ return true;
+ }
+
+
+ // -------------------------------------------------------------------
+#ifdef PARALLEL
+ // bool F_isInterface(pMesh mesh, pFace pface, int * distProc,
+ // std::vector<pVertex>* distVt)
+ // {
+ // if (distProc) *distProc = -1;
+ // if (distVt) (*distVt).clear();
+
+ // if ( !F_isInterface(mesh,pface) ) return false;
+
+ // // GCREMARK: the rest of the function gives informations about the
+ // // distant partition but is just a cross-check.
+
+ // // --- check that the three nodes are on a parallel boundary ---
+ // pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ // pVertex nod[4];
+
+
+ // switch (pface->getNbNodes()) {
+
+ // case 3:
+ // {
+ // pface->getNodes(nod);
+ // void * temp_ptr1, *temp_ptr2, *temp_ptr3;
+ // int isInterface1 = EN_getDataPtr((pEntity) nod[0], tagData, &temp_ptr1);
+ // int isInterface2 = EN_getDataPtr((pEntity) nod[1], tagData, &temp_ptr2);
+ // int isInterface3 = EN_getDataPtr((pEntity) nod[2], tagData, &temp_ptr3);
+
+
+ // if( !(isInterface1 && isInterface2 && isInterface3) ) {
+ // Msg(MDB_FATAL,"Error: found a face which nodes are not all on a parallel boundary although it fits the conditions to be a parallel boundary face\n");
+ // }
+
+ // // --- check that the three nodes are on the same parallel boundary ---
+ // const std::vector<std::pair<int,pVertex> > *recup1 =
+ // (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+ // const std::vector<std::pair<int,pVertex> > *recup2 =
+ // (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+ // const std::vector<std::pair<int,pVertex> > *recup3 =
+ // (const std::vector<std::pair<int,pVertex> > *) temp_ptr3;
+ // std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+ // std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+ // std::vector<std::pair<int,pVertex> >::const_iterator rIter3 = recup3->begin();
+ // for (; rIter1 != recup1->end(); rIter1++) {
+ // for (; rIter2 != recup2->end(); rIter2++) {
+ // for (; rIter3 != recup3->end(); rIter3++) {
+ // if ( (*rIter1).first == (*rIter2).first &&
+ // (*rIter2).first == (*rIter3).first ) {
+ // if (distProc) *distProc = (*rIter1).first;
+ // if (distVt) {
+ // (*distVt).push_back((*rIter1).second);
+ // (*distVt).push_back((*rIter2).second);
+ // (*distVt).push_back((*rIter3).second);
+ // }
+ // return true;
+ // }
+ // }
+ // rIter3 = recup3->begin();
+ // }
+ // rIter2 = recup2->begin();
+ // }
+ // break;
+ // }
+
+ // case 4:
+ // {
+ // pface->getNodes(nod);
+ // void * temp_ptr1, *temp_ptr2, *temp_ptr3, *temp_ptr4;
+ // int isInterface1 = EN_getDataPtr((pEntity) nod[0], tagData, &temp_ptr1);
+ // int isInterface2 = EN_getDataPtr((pEntity) nod[1], tagData, &temp_ptr2);
+ // int isInterface3 = EN_getDataPtr((pEntity) nod[2], tagData, &temp_ptr3);
+ // int isInterface4 = EN_getDataPtr((pEntity) nod[3], tagData, &temp_ptr4);
+
+
+ // if( !(isInterface1 && isInterface2 && isInterface3 && isInterface4) ) {
+ // Msg(MDB_FATAL,"Error: found a face which nodes are not all on a parallel boundary although it fits the conditions to be a parallel boundary face\n");
+ // }
+
+ // // --- check that the three nodes are on the same parallel boundary ---
+ // const std::vector<std::pair<int,pVertex> > *recup1 =
+ // (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+ // const std::vector<std::pair<int,pVertex> > *recup2 =
+ // (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+ // const std::vector<std::pair<int,pVertex> > *recup3 =
+ // (const std::vector<std::pair<int,pVertex> > *) temp_ptr3;
+ // const std::vector<std::pair<int,pVertex> > *recup4 =
+ // (const std::vector<std::pair<int,pVertex> > *) temp_ptr4;
+ // std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+ // std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+ // std::vector<std::pair<int,pVertex> >::const_iterator rIter3 = recup3->begin();
+ // std::vector<std::pair<int,pVertex> >::const_iterator rIter4 = recup4->begin();
+ // for (; rIter1 != recup1->end(); rIter1++) {
+ // for (; rIter2 != recup2->end(); rIter2++) {
+ // for (; rIter3 != recup3->end(); rIter3++) {
+ // for (; rIter4 != recup4->end(); rIter4++) {
+ // if ( (*rIter1).first == (*rIter2).first &&
+ // (*rIter2).first == (*rIter3).first &&
+ // (*rIter3).first == (*rIter4).first ) {
+ // if (distProc) *distProc = (*rIter4).first;
+ // if (distVt) {
+ // (*distVt).push_back((*rIter1).second);
+ // (*distVt).push_back((*rIter2).second);
+ // (*distVt).push_back((*rIter3).second);
+ // (*distVt).push_back((*rIter4).second);
+ // }
+ // return true;
+ // }
+ // }
+ // rIter4 = recup4->begin();
+ // }
+ // rIter3 = recup3->begin();
+ // }
+ // rIter2 = recup2->begin();
+ // }
+ // break;
+ // }
+ // }
+
+ // Msg(MDB_FATAL,"Error: found a face which nodes have no common parallel boundary although it fits the conditions to be a parallel boundary face\n");
+
+ // return false;
+ // }
+
+#endif
+
+ /*! \brief flag face pface as potential interface and list possible communications \ingroup internal */
+
+ bool F_isPotentialInterface(pMesh mesh, pFace pface, std::vector<face_comm>& distFace)
+ {
+
+ if ( !F_isPotentialInterface(mesh,pface) ) return false;
+
+ // GCREMARK: the rest of the function gives informations about the
+ // distant partition but is just a cross-check.
+
+ // --- check that the three nodes are on a parallel boundary ---
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ pVertex nod[4];
+
+ distFace.clear();
+
+
+ switch (pface->getNbNodes()) {
+
+ case 3:
+ {
+ pface->getNodes(nod);
+ void * temp_ptr1, *temp_ptr2, *temp_ptr3;
+ int isInterface1 = EN_getDataPtr((pEntity) nod[0], tagData, &temp_ptr1);
+ int isInterface2 = EN_getDataPtr((pEntity) nod[1], tagData, &temp_ptr2);
+ int isInterface3 = EN_getDataPtr((pEntity) nod[2], tagData, &temp_ptr3);
+
+ int id1 = EN_id((pEntity) nod[0]);
+ int id2 = EN_id((pEntity) nod[1]);
+ int id3 = EN_id((pEntity) nod[2]);
+
+ if( !(isInterface1 && isInterface2 && isInterface3) ) {
+ return false;
+ //Msg(MDB_FATAL,"Error: found a face which nodes are not all on a parallel boundary although it fits the conditions to be a parallel boundary face\n");
+ }
+
+ // --- check that the three nodes are on the same parallel boundary ---
+ const std::vector<std::pair<int,pVertex> > *recup1 =
+ (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+ const std::vector<std::pair<int,pVertex> > *recup2 =
+ (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+ const std::vector<std::pair<int,pVertex> > *recup3 =
+ (const std::vector<std::pair<int,pVertex> > *) temp_ptr3;
+ std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+ std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+ std::vector<std::pair<int,pVertex> >::const_iterator rIter3 = recup3->begin();
+ for (; rIter1 != recup1->end(); rIter1++) {
+ for (; rIter2 != recup2->end(); rIter2++) {
+ for (; rIter3 != recup3->end(); rIter3++) {
+ if ( (*rIter1).first == (*rIter2).first &&
+ (*rIter2).first == (*rIter3).first ) {
+
+ face_comm fc;
+
+ fc.distProc = (*rIter1).first;
+
+ fc.p1 = (*rIter1).second;
+ fc.p2 = (*rIter2).second;
+ fc.p3 = (*rIter3).second;
+ fc.p4 = NULL;
+
+ fc.id1 = id1;
+ fc.id2 = id2;
+ fc.id3 = id3;
+ fc.id4 = -1;
+
+ fc.pf = pface;
+
+ distFace.push_back(fc);
+ }
+ }
+ rIter3 = recup3->begin();
+ }
+ rIter2 = recup2->begin();
+ }
+ break;
+ }
+
+ case 4:
+ {
+ pface->getNodes(nod);
+ void * temp_ptr1, *temp_ptr2, *temp_ptr3, *temp_ptr4;
+ int isInterface1 = EN_getDataPtr((pEntity) nod[0], tagData, &temp_ptr1);
+ int isInterface2 = EN_getDataPtr((pEntity) nod[1], tagData, &temp_ptr2);
+ int isInterface3 = EN_getDataPtr((pEntity) nod[2], tagData, &temp_ptr3);
+ int isInterface4 = EN_getDataPtr((pEntity) nod[3], tagData, &temp_ptr4);
+
+ int id1 = EN_id((pEntity) nod[0]);
+ int id2 = EN_id((pEntity) nod[1]);
+ int id3 = EN_id((pEntity) nod[2]);
+ int id4 = EN_id((pEntity) nod[3]);
+
+ if( !(isInterface1 && isInterface2 && isInterface3 && isInterface4) ) {
+ Msg(MDB_FATAL,"Error: found a face which nodes are not all on a parallel boundary although it fits the conditions to be a parallel boundary face\n");
+ }
+
+ // --- check that the three nodes are on the same parallel boundary ---
+ const std::vector<std::pair<int,pVertex> > *recup1 =
+ (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+ const std::vector<std::pair<int,pVertex> > *recup2 =
+ (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+ const std::vector<std::pair<int,pVertex> > *recup3 =
+ (const std::vector<std::pair<int,pVertex> > *) temp_ptr3;
+ const std::vector<std::pair<int,pVertex> > *recup4 =
+ (const std::vector<std::pair<int,pVertex> > *) temp_ptr4;
+ std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+ std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+ std::vector<std::pair<int,pVertex> >::const_iterator rIter3 = recup3->begin();
+ std::vector<std::pair<int,pVertex> >::const_iterator rIter4 = recup4->begin();
+ for (; rIter1 != recup1->end(); rIter1++) {
+ for (; rIter2 != recup2->end(); rIter2++) {
+ for (; rIter3 != recup3->end(); rIter3++) {
+ for (; rIter4 != recup4->end(); rIter4++) {
+ if ( (*rIter1).first == (*rIter2).first &&
+ (*rIter2).first == (*rIter3).first &&
+ (*rIter3).first == (*rIter4).first ) {
+
+ face_comm fc;
+
+ fc.distProc = (*rIter1).first;
+
+ fc.p1 = (*rIter1).second;
+ fc.p2 = (*rIter1).second;
+ fc.p3 = (*rIter2).second;
+ fc.p4 = (*rIter3).second;
+
+ fc.id1 = id1;
+ fc.id2 = id2;
+ fc.id3 = id3;
+ fc.id4 = id4;
+
+ fc.pf = pface;
+
+ distFace.push_back(fc);
+
+ }
+ }
+ rIter4 = recup4->begin();
+ }
+ rIter3 = recup3->begin();
+ }
+ rIter2 = recup2->begin();
+ }
+ break;
+ }
+ }
+
+ // Msg(MDB_FATAL,"Error: found a face which nodes have no common parallel boundary although it fits the conditions to be a parallel boundary face\n");
+
+ return (distFace.size() != 0);
+ }
+
+ // -------------------------------------------------------------------
+ /*! \brief Flag region if located at an interface. \ingroup parallel
+ \warning As we partition along edges in 2D and faces in 3D, the answer is
+ always no */
+
+ bool R_isInterface(pRegion pr) {
+ return false;
+ }
+
+ // -------------------------------------------------------------------
+ // do a tentative connection - since we send all potential interface nodes
+ // to all processors, we send the minimum information : the node id
+ //
+ // result is that we store the connected partitions for a shared node
+ // more detailed communication follows
+
+
+ void createRemotePointLists (pMesh mesh, pMeshDataId tagVertex)
+ {
+ int myrank = 0;
+ int nbproc = 1;
+
+ std::set<pVertex> bdryNodes;
+ std::set<int> bdryNodeId;
+
+#ifdef PARALLEL
+ MPI_Comm_size(MPI_COMM_WORLD, &nbproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ // --- list local nodes on parallel boundaries ---
+
+ int meshDim = (mesh->tets.empty()) ? 2 : 3;
+ if ( meshDim == 3 ) {
+ FIter fit = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fit) ) {
+ if ( F_isPotentialInterface(mesh,pf) ) {
+ for (int iv = 0; iv < F_numVertices(pf); iv++) {
+ pVertex pv = F_vertex(pf,iv);
+ bdryNodes .insert(pv);
+ bdryNodeId.insert(pv->iD);
+ }
+ }
+ }
+ } else {
+ EIter eit = M_edgeIter(mesh);
+ while ( pEdge pe = EIter_next(eit) ) {
+ if ( E_isPotentialInterface(mesh,pe) ) {
+ for (int iv = 0; iv < 2; iv++) {
+ pVertex pv = E_vertex(pe,iv);
+ bdryNodes.insert(pv);
+ bdryNodeId.insert(pv->iD);
+ }
+ }
+ }
+ }
+#endif
+
+ /* KH : temporary ? addition of all periodic nodes */
+
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicVertexID");
+
+ VIter vit = M_vertexIter(mesh);
+
+ while (pVertex pv = VIter_next(vit)) {
+
+ void* tmp_periodic = NULL;
+ int isPeriodic = EN_getDataPtr((pEntity) pv,tagPeriodic,&tmp_periodic);
+
+ if (isPeriodic) {
+
+ void* tmp_remote = NULL;
+ int hasRemote = EN_getDataPtr((pEntity) pv,tagVertex,&tmp_remote);
+
+ if (!hasRemote) {
+ std::vector<std::pair<int,pVertex> >* remote = new std::vector<std::pair<int,pVertex> >;
+ EN_attachDataPtr((pEntity) pv,tagVertex,remote);
+ }
+ else {
+ std::vector<std::pair<int,pVertex> >* remote = (std::vector<std::pair<int,pVertex> >*) tmp_remote;
+ remote->clear();
+ }
+
+ std::map<int,std::vector<int> > * conn = (std::map<int,std::vector<int> > *) tmp_periodic;
+ std::map<int,std::vector<int> >::iterator citer = conn->begin();
+ bdryNodes.insert(pv);
+ for (;citer != conn->end();++citer) bdryNodeId.insert(citer->first);
+ }
+ }
+
+#ifdef PARALLEL
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ // --- send list ---
+
+ int* sendcounts = new int[nbproc];
+ int size = bdryNodeId.size()*sizeof(int);
+
+ void* msg = malloc(size);
+ int * bufCast = reinterpret_cast<int *>(msg);
+ std::set<int>::const_iterator cIter = bdryNodeId.begin();
+ std::set<int>::const_iterator cLast = bdryNodeId.end();
+ for (;cIter!=cLast;++cIter) *(bufCast++) = *cIter;
+
+ for (int iProcDest=0; iProcDest < nbproc; iProcDest++) {
+ if ( iProcDest == myrank ) {
+ sendcounts[iProcDest] = 0;
+ continue;
+ }
+ else {
+ sendcounts[iProcDest] = 1;
+ void *buf = AP_alloc(iProcDest,669,size);
+ memcpy(buf,msg,size);
+ AP_send(buf);
+ }
+ }
+
+ free(msg);
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+ AP_flush();
+
+ // --- receive lists ---
+
+ int message = 0;
+ int count;
+ while (!AP_recv_count(&count) || message < count) {
+
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int rc;
+
+ rc = AP_recv (MPI_ANY_SOURCE, 669, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+
+ if (rc) {
+
+ int* msgCast = reinterpret_cast<int*>(msg);
+
+ std::set<int> distNodes;
+ int nbDistNodes = size / sizeof(int);
+ for (int iDistN = 0; iDistN < nbDistNodes; iDistN++) {
+ distNodes.insert(msgCast[iDistN]);
+ }
+
+ std::set<pVertex>::const_iterator vIter = bdryNodes.begin();
+ std::set<pVertex>::const_iterator vLast = bdryNodes.end();
+
+ for (;vIter!=vLast;++vIter) {
+
+ pVertex pv = *vIter;
+ int id = EN_id((pEntity) pv);
+
+ if (distNodes.find(id) != distNodes.end()) {
+ void *temp_ptr;
+ int exist = EN_getDataPtr((pEntity) pv, tagVertex, &temp_ptr);
+ std::vector<std::pair<int,pVertex> > * parts = NULL;
+ if (exist) {
+ parts = reinterpret_cast<std::vector<std::pair<int,pVertex> >*>(temp_ptr);
+ } else if (!exist) {
+ parts = new std::vector<std::pair<int,pVertex> >;
+ EN_attachDataPtr((pEntity) pv, tagVertex, parts);
+ }
+ parts->push_back(std::pair <int, MDB_Point*>(from,NULL));
+ }
+ }
+ message++;
+ AP_free(msg);
+ }
+ }
+
+ // --- wait until all have finished sending ---
+
+ AP_check_sends(AP_WAITALL);
+ delete [] sendcounts;
+
+ // GCDEBUG
+ // MPI_Barrier(MPI_COMM_WORLD);
+#endif
+ }
+
+ // -------------------------------------------------------------------
+
+ void V_createInfoInterface(pMesh mesh, pMeshDataId tagVertex)
+ {
+
+ int mysize = 1;
+ int myrank = 0;
+
+ size_t nbConnections = 0;
+
+#ifdef PARALLEL
+ MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+#endif
+
+ // --- Delete previous information ---
+ VIter vit = M_vertexIter(mesh);
+ while ( pVertex pv = VIter_next(vit) ) {
+ void * tmp_ptr;
+ if( EN_getDataPtr((pEntity) pv, tagVertex, &tmp_ptr) ) {
+ EN_deleteData((pEntity) pv, tagVertex);
+ }
+ }
+ VIter_delete(vit);
+
+ // --- Create lists of distant procs ---
+
+ createRemotePointLists(mesh, tagVertex);
+
+ // --- Send node pointers ---
+ int *sendcounts = new int[mysize];
+ for(int i=0; i<mysize; i++) sendcounts[i] = 0;
+
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicVertexID");
+ pMeshDataId tagTransfo = MD_lookupMeshDataId("PeriodicTransformation");
+
+ vit = M_vertexIter(mesh);
+ while ( pVertex pv = VIter_next(vit) ) {
+
+ std::vector<int> distProcTab;
+ int nbDistProc = V_listInterface(pv, &distProcTab);
+
+ std::set<int> distProcs;
+ distProcs.insert(distProcTab.begin(),distProcTab.end());
+
+ void* tmp_remote = NULL;
+ int haveRemote = EN_getDataPtr((pEntity) pv,tagVertex,&tmp_remote);
+ std::vector<std::pair<int,pVertex> >* remote = NULL;
+ if (haveRemote) {
+ remote = (std::vector<std::pair<int,pVertex> >*) (tmp_remote);
+ remote->clear();
+ }
+
+ void* tmp_periodic = NULL;
+ int havePeriodic = EN_getDataPtr((pEntity) pv,tagPeriodic,&tmp_periodic);
+ std::map<int,std::vector<int> >* periodic = NULL;
+
+ if (havePeriodic) {
+
+ if (!haveRemote) {
+ Msg_char(MDB_FATAL,"Periodic node %d without connection table",EN_id((pEntity) pv));
+ }
+
+ // allocate and attach transformation table
+
+ // int haveTransfo = EN_getDataPtr((pEntity) cvtx, tagTransfo, &tmp_transfo);
+ // std::map<std::pair<int,pEntity>,std::vector<int> >* trafo = NULL;
+ // if (haveTransfo) {
+ // trafo = (std::map<std::pair<int,pEntity>,std::vector<int> > *) tmp_transfo;
+ // trafo->clear();
+ // }
+ // else {
+ // trafo = new std::map<std::pair<int,pEntity>,std::vector<int> >;
+ // EN_attachDataPtr((pEntity) cvtx,periodicTransfoTag,trafo);
+ // }
+
+ // insert data on local processor
+
+ periodic = (std::map<int,std::vector<int> >*) tmp_periodic;
+ std::map<int,std::vector<int> >::const_iterator citer = periodic->begin();
+ for (;citer!=periodic->end();++citer) {
+ pVertex cvtx = mesh->find_point(citer->first);
+ if (cvtx && cvtx != pv) {
+ remote->push_back(std::make_pair(myrank,cvtx));
+ nbConnections++;
+ // trafo->insert(std::make_pair(std::make_pair(myRank,cvtx),citer->second));
+ }
+ }
+ }
+
+#ifdef PARALLEL
+
+ int nbConnections = 1;
+ if (periodic) nbConnections += periodic->size();
+ int msgSize = sizeof(pVertex) + (3 + nbConnections ) * sizeof(int);
+ void* tmp = malloc(msgSize);
+
+ pVertex *vbuf = (pVertex *) tmp;
+
+ int lId = EN_id((pEntity) pv);
+
+ *(vbuf++) = pv;
+ int* iv = (int*) (vbuf);
+
+ *(iv++) = GEN_tag (V_whatIn(pv));
+ *(iv++) = GEN_type(V_whatIn(pv));
+ *(iv++) = nbConnections;
+ *(iv++) = lId;
+
+ if (periodic) {
+ std::map<int,std::vector<int> >::const_iterator cIter = periodic->begin();
+ for (;cIter!=periodic->end();++cIter) {
+ int rId = cIter->first;
+ *(iv++) = (rId == lId) ? -rId : rId; // avoid sending once again to oneself
+ }
+ }
+
+ // make sure that we send only once to different processors
+
+ std::set<int>::iterator dIter = distProcs.begin();
+ for (;dIter!=distProcs.end();++dIter) {
+
+ int distProc = *dIter;
+ if (distProc != myrank) {
+ void *buf = AP_alloc(distProc,445,msgSize);
+ memcpy(buf,tmp,msgSize);
+ AP_send(buf);
+ sendcounts[distProc]++;
+ }
+ }
+
+ free(tmp);
+#endif
+ }
+ VIter_delete(vit);
+
+#ifdef PARALLEL
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+ AP_flush();
+
+ // --- Receive node pointers ---
+ int message=0, count;
+ while (!AP_recv_count(&count) || message<count) {
+
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int recv;
+
+ recv = AP_recv(MPI_ANY_SOURCE, 445, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if(recv) {
+
+ message++;
+ pVertex* vbuf = reinterpret_cast<pVertex*>(msg);
+ pVertex precv = *(vbuf++);
+ int* ibuf = reinterpret_cast<int*>(vbuf);
+
+ int gTag = *(ibuf++);
+ int gDim = *(ibuf++);
+ int nbConn = *(ibuf++);
+
+
+ for (int iConn=0;iConn<nbConn;iConn++) {
+
+ int pId = *(ibuf++);
+ pVertex vtx = mesh->find_point(pId);
+
+ if (vtx) {
+
+ void* tmp_remote = NULL;
+ int isInterface = EN_getDataPtr((pEntity) vtx, tagVertex, &tmp_remote);
+ assert(isInterface);
+ std::vector<std::pair<int,pVertex> > *remote = (std::vector<std::pair<int,pVertex> >*) tmp_remote;
+ remote->push_back(std::pair<int,pVertex>(from,precv));
+
+ }
+ }
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+ delete [] sendcounts;
+
+#endif
+
+ MDB_CommCheck cc;
+ exchangeDataOnVertices(mesh,cc);
+
+ }
+
+// // -------------------------------------------------------------------
+// #ifdef PARALLEL
+// void MDB_Mesh::bdryLinkRemotePoint()
+// {
+// int mysize,myrank;
+// MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+// MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+// /*send pointeurs*/
+// int *sendcounts = new int[mysize];
+// for(int i=0;i<mysize;i++)sendcounts[i]=0;
+
+// pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+// VIter vit = M_vertexIter(this);
+// pVertex pv;
+// int nsend=0;
+// while ((pv = VIter_next(vit))) {
+// void *temp_ptr;
+// int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+
+// if(isInterface) {
+// std::vector<std::pair<int , MDB_Point*> > *recup = (std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+// int numGlobal = EN_id((pEntity)pv);
+// for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+// nsend++;
+// int remoteID = (*recup)[j].first;
+// assert(remoteID != myrank);
+// void *buf = AP_alloc(remoteID,444,sizeof(point_comm));
+// point_comm *castbuf = (point_comm *) buf;
+// castbuf->p = pv;
+// castbuf->nID = myrank;
+// castbuf->numGlobal = numGlobal;
+// AP_send(buf);
+// sendcounts[remoteID]++;
+// }
+// }
+// }
+// VIter_delete(vit);
+
+// AP_flush();
+// AP_check_sends(AP_NOFLAGS);
+// // AP_reduce_nsends(sendcounts);
+
+// /*receive pointers*/
+// int message=0;
+// // while (!AP_recv_count(&count) || message<count) {
+// while (message<nsend) {
+// void *msg;
+// int from;
+// int tag;
+// int size;
+// int recv;
+// recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+// &msg, &size, &from, &tag);
+// if(recv) {
+// message++;
+// point_comm * castbuf = (point_comm*) msg;
+// pVertex precv (0);
+// precv = castbuf -> p;
+// assert(precv);
+// int recvID = castbuf -> nID;
+// int numrecv = castbuf -> numGlobal;
+
+// pVertex p = this->find_point(numrecv);
+// if(p) {
+// void *temp_ptr;
+// int isInterface = EN_getDataPtr((pEntity) p , tagData, &temp_ptr);
+// assert(isInterface);
+// std::vector<std::pair<int , MDB_Point*> > *recup =
+// (std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+// for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+// int remoteID = (*recup)[j].first;
+// if(remoteID == recvID) {
+// (*recup)[j].second = precv;
+// }
+// }
+// }
+// AP_free(msg);
+// }
+
+// }
+// AP_check_sends(AP_WAITALL);
+// MPI_Barrier(MPI_COMM_WORLD);
+// delete [] sendcounts;
+// }
+// #endif
+
+
+ // -------------------------------------------------------------------
+ /*! \brief Create edge correspondance and assure coherent orientation \ingroup parallel */
+ void E_createInfoInterface(pMesh mesh, pMeshDataId tagEdge)
+ {
+
+ int nproc = 1;
+ int myrank = 0;
+
+ size_t nbConnections = 0;
+
+#ifdef PARALLEL
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+#endif
+
+ // --- Delete previous information ---
+
+ EIter eit = M_edgeIter(mesh);
+ while ( pEdge pe = EIter_next(eit) ) {
+ void * tmp_ptr;
+ if( EN_getDataPtr((pEntity) pe, tagEdge, &tmp_ptr) ) {
+ EN_deleteData((pEntity) pe, tagEdge);
+ }
+ }
+ EIter_delete(eit);
+
+
+ // --- establish local connections and assure coherent orientation ---
+ //
+ // * coherent reorientation on other partitions assumes coherent orientation here
+ // * all periodic edges have same connections across partititions
+ // hence subsequent reorientation should remain coherent
+
+ eit = M_edgeIter(mesh);
+
+ while ( pEdge pe = EIter_next(eit) ) {
+
+ std::vector<edge_comm> remote;
+
+ int id0 = EN_id((pEntity) E_vertex(pe,0));
+ int id1 = EN_id((pEntity) E_vertex(pe,1));
+
+ std::pair<int,int> lNodeID(std::min(id0,id1),
+ std::max(id0,id1));
+
+ if (E_isPotentialInterface(mesh,pe,remote)) {
+
+ std::vector<edge_comm >::const_iterator riter = remote.begin();
+
+
+ pVertex p1Local = E_vertex(pe,0);
+ pVertex p2Local = E_vertex(pe,1);
+
+
+ for (;riter!=remote.end();++riter) {
+
+ int distProc = riter->distProc;
+
+ if (distProc == myrank) {
+
+ edge_comm comm = *riter;
+
+ pVertex p1 = comm.p1;
+ pVertex p2 = comm.p2;
+
+ pEdge remoteEdge = E_exist(p1,p2);
+
+ if (remoteEdge) {
+
+
+ // get points again, since alignment may be different from comm
+
+ pVertex p1Remote = E_vertex(remoteEdge,0);
+ pVertex p2Remote = E_vertex(remoteEdge,1);
+
+ // verify orientation
+
+ int orientation = 0;
+ if (V_corresponds(p1Remote,p1Local) && V_corresponds(p2Remote,p2Local)) orientation = 1;
+ if (V_corresponds(p1Remote,p2Local) && V_corresponds(p2Remote,p1Local)) orientation = -1;
+
+ if (orientation == 0) {
+ Msg(MDB_FATAL,
+ "Got a locally periodic edge connection from %d-%d to %d-%d which does not correspond nodewise",
+ EN_id((pEntity) p1),EN_id((pEntity) p2),EN_id((pEntity) p1Local),EN_id((pEntity) p2Local));
+ }
+
+ std::pair<int,int> rNodeID(std::min(EN_id((pEntity) p1Remote),EN_id((pEntity) p2Remote)),
+ std::max(EN_id((pEntity) p1Remote),EN_id((pEntity) p2Remote)));
+
+
+ if (rNodeID < lNodeID) {
+ lNodeID = rNodeID; // remember to what we aligned the edge
+ if (orientation == -1) {
+ int dir = E_align(pe,p2Local,p1Local);
+ if (dir != -1) std::cout << "misalignment of edges " << std::endl;
+ }
+ }
+
+ void* tmp_ptr;
+ std::multimap<int,pEdge>* list;
+
+ if(EN_getDataPtr((pEntity) pe, tagEdge, (void**)&tmp_ptr)) {
+ list = (std::multimap<int,pEdge>*) tmp_ptr;
+ }
+ else {
+ list = new std::multimap<int,pEdge> ;
+ EN_attachDataPtr((pEntity) pe,tagEdge,list);
+ }
+
+ list->insert(std::make_pair(myrank,remoteEdge));
+ nbConnections++;
+ }
+ }
+ }
+ }
+ }
+ EIter_delete(eit);
+
+#ifdef PARALLEL
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+ // --- send edge info ---
+
+ eit = M_edgeIter(mesh);
+ while ( pEdge pe = EIter_next(eit) ) {
+
+ std::vector<edge_comm> remote;
+
+ if (E_isPotentialInterface(mesh,pe,remote)) {
+
+ std::vector<edge_comm >::const_iterator riter = remote.begin();
+
+ for (;riter!=remote.end();++riter) {
+
+ int distProc = riter->distProc;
+
+ if (distProc != myrank) {
+ void *buf = AP_alloc(distProc,446,sizeof(edge_comm));
+ edge_comm *castbuf = (edge_comm *) buf;
+ castbuf->p1 = riter->p1;
+ castbuf->p2 = riter->p2;
+ castbuf->id1 = riter->id1;
+ castbuf->id2 = riter->id1;
+ castbuf->pe = pe;
+ AP_send(buf);
+ sendcounts[distProc]++;
+ }
+ }
+ }
+ }
+ EIter_delete(eit);
+
+ // --- synchronise sends ---
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+ //AP_flush();
+
+ // --- Receive edge info ---
+
+ int message=0,count;
+ while (!AP_recv_count(&count) ||message<count) {
+
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int rc;
+
+ rc=AP_recv(MPI_ANY_SOURCE,446, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+
+ if (rc) {
+ message++;
+ edge_comm * comm = (edge_comm*) msg;
+ pEdge pe = E_exist(comm->p1,comm->p2);
+ if(pe) {
+
+ int lowestRank = myrank;
+
+ // avoid connections between two edges that span full periodicity
+ // ie. periodic nodes n1 and n3 while both edges n1-n2 and n2-n3 exist
+
+ int id1 = comm->id1;
+ int id2 = comm->id2;
+
+ if (E_corresponds(pe,id1,id2)) {
+
+ std::multimap<int,pEdge>* list;
+ if(EN_getDataPtr((pEntity) pe, tagEdge, (void**)&list)) {
+ lowestRank = std::min(list->begin()->first,lowestRank);
+ }
+ else {
+ list = new std::multimap<int,pEdge>;
+ EN_attachDataPtr((pEntity) pe, tagEdge, (void*)list);
+ }
+
+ list->insert(std::pair<int,pEdge>(from,comm->pe));
+ if (from < lowestRank) {
+ int dir = E_align(pe,comm->p1,comm->p2);
+ }
+ }
+ }
+ AP_free(msg);
+ }
+ }
+
+ // --- synchronise receives ---
+
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ // --- clean ship ---
+
+ delete [] sendcounts;
+
+#endif
+
+ // --- verify !! ---
+
+ MDB_CommCheck cc;
+ exchangeDataOnEdges(mesh,cc);
+
+ }
+
+ // -------------------------------------------------------------------
+ /*! \brief Establish face to face correspondance and assure coherent orientation \ingroup parallel */
+ //
+
+ void F_createInfoInterface(pMesh mesh, pMeshDataId tagFace)
+ {
+
+ int nproc = 1;
+ int myrank = 0;
+ size_t nbConnections = 0;
+
+#ifdef PARALLEL
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+#endif
+
+ // --- delete previous information ---
+
+ FIter fit = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fit) ) {
+ void * tmp_ptr;
+ if( EN_getDataPtr((pEntity) pf, tagFace, &tmp_ptr) ) {
+ EN_deleteData((pEntity) pf, tagFace);
+ }
+ }
+ FIter_delete(fit);
+
+ // --- first establish local communication and coherent orientation ---
+ // * coherent reorientation on other partitions assumes coherent orientation here
+ // * all periodic faces have same connections across partititions
+ // hence subsequent reorientation should remain coherent
+
+
+ fit = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fit) ) {
+ int distProc = -1;
+
+ std::vector<pVertex> distVt;
+ std::vector<face_comm> rd;
+
+ if ( F_isPotentialInterface(mesh, pf, rd) ) {
+
+ std::vector<face_comm>::iterator rIter = rd.begin();
+
+ std::vector<int> lNodeID;
+ for (int i=0;i<F_numVertices(pf);i++) lNodeID.push_back(EN_id((pEntity) F_vertex(pf,i)));
+
+
+ for (;rIter!=rd.end();++rIter) {
+
+ distProc = rIter->distProc;
+
+ if (distProc == myrank) {
+
+ face_comm& comm = *rIter;
+
+ pVertex p1recv,p2recv,p3recv,p4recv;
+ int nbNodes = (comm.p4 == NULL) ? 3:4;
+
+ if (nbNodes != F_numVertices(pf)) {
+ std::cout << "Non-coherent number of vertices " << nbNodes << " vs " << F_numVertices(pf) << std::endl;
+ }
+
+ p1recv = comm.p1;
+ p2recv = comm.p2;
+ p3recv = comm.p3;
+ p4recv = comm.p4;
+
+ assert(p1recv);assert(p2recv);assert(p3recv);
+ // p4recv = nbNodes == 4 ? comm.p4 : NULL;
+
+ pFace remoteFace = F_exist(p1recv,p2recv,p3recv,p4recv);
+
+ if (remoteFace) {
+
+ // compare ordered lists of nodes
+
+ std::vector<int> rNodeID;
+ rNodeID.push_back(EN_id((pEntity) p1recv));
+ rNodeID.push_back(EN_id((pEntity) p2recv));
+ rNodeID.push_back(EN_id((pEntity) p3recv));
+ if (nbNodes == 4) rNodeID.push_back(EN_id((pEntity) p4recv));
+
+ // this is ok : only 1 periodic connection possible per face
+
+ if (rNodeID > lNodeID) {
+ lNodeID = rNodeID;
+ F_align(remoteFace,p1recv,p2recv,p3recv,p4recv);
+ }
+
+ void* tmpptr;
+ std::multimap<int,pFace>* list = NULL;
+
+ if(EN_getDataPtr((pEntity) pf , tagFace,&tmpptr)){
+ list = (std::multimap<int,pFace>*) (tmpptr);
+ } else {
+ list = new std::multimap<int,pFace>;
+ EN_attachDataPtr((pEntity) pf, tagFace, list);
+ }
+ list->insert(std::make_pair(myrank,remoteFace));
+ nbConnections++;
+ }
+ }
+ }
+ }
+ }
+
+#ifdef PARALLEL
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+ // --- send faces ---
+
+ fit = M_faceIter(mesh);
+ while ( pFace pf = FIter_next(fit) ) {
+ int distProc = -1;
+ std::vector<pVertex> distVt;
+
+ std::vector<face_comm> rd;
+
+ if ( F_isPotentialInterface(mesh, pf, rd) ) {
+
+ std::vector<face_comm>::iterator rIter = rd.begin();
+
+ for (;rIter!=rd.end();++rIter) {
+
+ distProc = rIter->distProc;
+
+ if (distProc != myrank) {
+
+ void *buf = AP_alloc(distProc,444,sizeof(face_comm));
+ face_comm *castbuf = (face_comm *) buf;
+ memcpy(buf,&(*rIter),sizeof(face_comm));
+ castbuf->distProc = myrank;
+
+ AP_send(buf);
+ sendcounts[distProc]++;
+ }
+ }
+ }
+ }
+ FIter_delete(fit);
+
+ // --- synchronise sends ---
+
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+ //AP_flush();
+
+ // --- Receive face info ---
+ int message=0, count;
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int rc;
+ rc=AP_recv(MPI_ANY_SOURCE,444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if (rc) {
+ message++;
+
+ face_comm * castbuf = (face_comm*) msg;
+
+ pVertex p1recv = castbuf -> p1;
+ pVertex p2recv = castbuf -> p2;
+ pVertex p3recv = castbuf -> p3;
+ pVertex p4recv = castbuf -> p4;
+
+ int id1recv = castbuf->id1;
+ int id2recv = castbuf->id2;
+ int id3recv = castbuf->id3;
+ int id4recv = castbuf->id4;
+
+ assert(p1recv);assert(p2recv);assert(p3recv);
+ // p4recv = nbNodes == 4 ? castbuf -> p4 : NULL;
+
+ int nprocrecv = castbuf->distProc;
+ assert(nprocrecv==from);
+
+ pFace pface = F_exist(p1recv,p2recv,p3recv,p4recv);
+
+ if (pface) {
+
+ if (F_corresponds(pface,id1recv,id2recv,id3recv,id4recv)) {
+
+ // lowest ranking processor is master
+
+ void* tmpptr;
+ std::multimap<int,pFace>* list = NULL;
+
+ if( EN_getDataPtr((pEntity) pface , tagFace,&tmpptr)){
+ list = (std::multimap<int,pFace>*) (tmpptr);
+ if (from < myrank && from < list->begin()->first) {
+ F_align(pface,p1recv,p2recv,p3recv,p4recv);
+ }
+ }
+ else {
+ if (from < myrank) F_align(pface,p1recv,p2recv,p3recv,p4recv);
+ list = new std::multimap<int,pFace>;
+ EN_attachDataPtr((pEntity) pface, tagFace, list);
+ }
+ list->insert(std::make_pair(nprocrecv,castbuf->pf));
+ }
+ }
+ AP_free(msg);
+ }
+ }
+
+ // --- synchronise receives ---
+
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ // --- clean ship ---
+
+ delete [] sendcounts;
+
+#endif
+
+ // --- verify !! ---
+
+ MDB_CommCheck cc;
+ exchangeDataOnFaces(mesh,cc);
+ }
+
+ // -------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ // #ifdef PARALLEL
+ // void UpdateIDGlobal(pMesh mesh, int IdGlobal)
+ // {
+ // int mysize,myrank;
+ // MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+ // MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ // // send pointers
+ // int *sendcounts = new int[mysize];
+ // for(int i=0; i<mysize; i++) sendcounts[i] = 0;
+
+ // pMeshDataId tagVertex = MD_lookupMeshDataId("RemotePoint");
+ // pMeshDataId tagGlob = MD_lookupMeshDataId("IdGlobal");
+
+ // VIter vit = M_vertexIter(mesh);
+ // pVertex pv;
+ // while ((pv = VIter_next(vit))) {
+ // void *temp_ptr;
+ // int isInterface = EN_getDataPtr((pEntity) pv , tagVertex, &temp_ptr);
+
+ // if(isInterface) {
+ // std::vector<std::pair<int , MDB_Point*> > *recup = (std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+ // int minproc = mysize + 10;
+ // for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+ // minproc = std::min(minproc,(*recup)[j].first);
+ // }
+ // minproc = std::min(myrank,minproc);
+ // if(minproc!=myrank) continue;
+ // int numGlobal = EN_id((pEntity) pv) + IdGlobal + 1;
+ // EN_attachDataInt((pEntity) pv, tagGlob, numGlobal);
+ // for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+ // int remoteID = (*recup)[j].first;
+ // assert(remoteID != myrank);
+ // void *buf = AP_alloc(remoteID,444,sizeof(point_comm));
+ // point_comm *castbuf = (point_comm *) buf;
+ // castbuf->p = (*recup)[j].second;
+ // castbuf->nID = myrank;
+ // castbuf->numGlobal = numGlobal;
+ // AP_send(buf);
+ // sendcounts[remoteID]++;
+ // }
+ // }
+ // }
+ // VIter_delete(vit);
+
+ // AP_check_sends(AP_NOFLAGS);
+ // AP_reduce_nsends(sendcounts);
+ // AP_flush();
+
+ // // receive pointers
+ // int message=0;
+ // int count;
+ // while (!AP_recv_count(&count) || message<count) {
+ // void *msg;
+ // int from;
+ // int tag;
+ // int size;
+ // int recv;
+ // recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+ // &msg, &size, &from, &tag);
+ // if(recv) {
+ // message++;
+ // point_comm * castbuf = (point_comm*) msg;
+ // pVertex precv (0);
+ // precv = castbuf -> p;
+ // assert(precv);
+ // //int recvID = castbuf -> nID;
+ // int numrecv = castbuf -> numGlobal;
+
+ // // DEBUG
+ // void *temp_ptr;
+ // int isInterface = EN_getDataPtr((pEntity) precv, tagVertex, &temp_ptr);
+ // assert(isInterface);
+
+ // EN_attachDataInt((pEntity) precv, tagGlob, numrecv);
+ // AP_free(msg);
+ // }
+
+ // }
+ // AP_check_sends(AP_WAITALL);
+ // MPI_Barrier(MPI_COMM_WORLD);
+ // delete [] sendcounts;
+ // }
+ // #endif
+
+ // -------------------------------------------------------------------
+
+}
diff --git a/Mesh/MeshDataBaseParallelInterface.h b/Mesh/MeshDataBaseParallelInterface.h
new file mode 100644
index 0000000..7f5fe16
--- /dev/null
+++ b/Mesh/MeshDataBaseParallelInterface.h
@@ -0,0 +1,131 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: J.-F. Remacle, C. Dobrzynski, K. Hillewaert, G. Compere
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASEPARALLELINTEFACE
+#define H_MESHDATABASEPARALLELINTEFACE
+
+#include "MeshDataBaseCommPeriodic.h"
+#include "MeshDataBaseComm.h"
+#include "MeshDataBaseInterface.h"
+
+#include <vector>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+
+#ifdef PARALLEL
+ void M_writeParallel(pMesh, const char*, int version=2);
+#endif
+
+ // -------------------------------------------------------------------
+
+ /*! \brief Return true if on a parallel or periodic interface \ingroup internal */
+ bool EN_isInterface(pEntity pv);
+
+ /*! \brief Return true if on a parallel or periodic interface \ingroup parallel */
+ bool V_isInterface(pVertex pv);
+
+ /*! \brief Return true if pv is a (periodic) copy of vertex with tag id \ingroup parallel */
+ bool V_corresponds(pVertex pv,int id);
+
+ /*! \brief Return size of the list and list is an array containing
+ proc numbers where pv exist except calling proc \ingroup parallel */
+ int V_listInterface(pVertex pv, int* list=NULL);
+
+ /*! \brief Return true if edge is //possibly// on a parallel or periodic interface \ingroup internal */
+ bool E_isPotentialInterface(pMesh, pEdge);
+
+ /*! \brief Return true if on a parallel or periodic interface \ingroup parallel */
+ bool E_isInterface(pEdge);
+
+ /*! \brief Return true if the edge corresponds either directly or periodically \ingroup parallel */
+ bool E_corresponds(pEdge,int,int);
+
+ /*! \brief Return true if on a parallel interface, distProc is
+ (one of) the proc sharing the edge and distVt is a list
+ of the pointers to the vertices on the distProc mesh \ingroup parallel */
+ bool E_isInterface(pMesh, pEdge, int * distProc,
+ std::vector<pVertex>* distVt);
+
+ /*! \brief Return true if face is potentially on a parallel interface \ingroup internal */
+ bool F_isPotentialInterface(pMesh, pFace);
+
+ /*! \brief Return true if face is on a parallel interface \ingroup parallel */
+ bool F_isInterface(pFace);
+
+ /*! \brief Return true if on a parallel interface, distProc is the
+ proc sharing the face and distVt is a list of the pointers
+ to the vertices on the distant mesh \ingroup parallel */
+ bool F_isInterface(pMesh, pFace, int * distProc,
+ std::vector<pVertex>* distVt);
+ /*! \brief Return true if on a parallel interface (always false) \ingroup parallel */
+ bool R_isInterface(pRegion pr);
+
+ // -------------------------------------------------------------------
+
+ /*! \brief Fill the attached pointer containing the distant proc
+ numbers and the distant node pointers \ingroup parallel */
+ void V_createInfoInterface(pMesh mesh, pMeshDataId tagVertex);
+
+ /*! \brief Fill the attached pointer containing the distant proc
+ numbers and the distant edge pointers \ingroup parallel */
+ void E_createInfoInterface(pMesh mesh, pMeshDataId tagEdge);
+
+ /*! \brief Fill the attached pointer containing the distant proc
+ numbers and the distant face pointers \ingroup parallel */
+ void F_createInfoInterface(pMesh mesh, pMeshDataId tagFace);
+
+// void UpdateIDGlobal(pMesh mesh, int IdGlobal);
+
+ // -------------------------------------------------------------------
+#ifdef PARALLEL
+
+ // interface elt migration
+ void Balance(pMesh mesh,MDB_DataExchanger &de);
+ void Balance2(pMesh mesh,MDB_DataExchanger &de);
+ void BalanceRandom(pMesh mesh,MDB_DataExchanger &de);
+ int BalanceManifold(pMesh mesh,MDB_DataExchanger &de);
+
+#ifdef _HAVE_PARMETIS_
+ // load balancing with metis
+ void BalanceMetis(pMesh mesh,MDB_DataExchanger &de);
+ void BalanceMetis2(pMesh mesh,MDB_DataExchanger &de);
+#endif
+
+ // migration of elt tagged tagElt
+ void loadBalancing(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de);
+ void loadBalancing2(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de);
+#endif
+
+ //Move periodic interfaces
+ void BalancePeriodic(pMesh mesh,int dim,MDB_DataExchanger &de,
+ MDB_DataExchangerPeriodic &deperiodic,std::vector<std::vector<int> >& transfo);
+
+// -------------------------------------------------------------------
+
+//migration of periodic elt
+void PeriodicInterfaceMigration(MAd::pMesh mesh,MAd::pMeshDataId tagElt,MAd::pMeshDataId tagMove,
+ MAd::pMeshDataId tagTransfo, MDB_DataExchanger &de,
+ MDB_DataExchangerPeriodic &deperiodic);
+
+
+void GroupPeriodicTetra(MAd::pMesh mesh, MDB_DataExchanger &de,
+ MDB_DataExchangerPeriodic &deperiodic);
+
+
+// -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Mesh/MshTags.h b/Mesh/MshTags.h
new file mode 100644
index 0000000..8dd536b
--- /dev/null
+++ b/Mesh/MshTags.h
@@ -0,0 +1,190 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Koen Hillewaert
+// -------------------------------------------------------------------
+
+#ifndef MSHTAGS__H
+#define MSHTAGS__H
+
+#include "MAdMessage.h"
+
+#include <string>
+#include <sstream>
+
+using namespace MAd;
+
+// Element types in .msh file format
+#define MSH_LIN_2 1
+#define MSH_TRI_3 2
+#define MSH_QUA_4 3
+#define MSH_TET_4 4
+#define MSH_HEX_8 5
+#define MSH_PRI_6 6
+#define MSH_PYR_5 7
+#define MSH_LIN_3 8
+#define MSH_TRI_6 9
+#define MSH_QUA_9 10
+#define MSH_TET_10 11
+#define MSH_HEX_27 12
+#define MSH_PRI_18 13
+#define MSH_PYR_14 14
+#define MSH_PNT 15
+#define MSH_QUA_8 16
+#define MSH_HEX_20 17
+#define MSH_PRI_15 18
+#define MSH_PYR_13 19
+#define MSH_TRI_9 20
+#define MSH_TRI_10 21
+#define MSH_TRI_12 22
+#define MSH_TRI_15 23
+#define MSH_TRI_15I 24
+#define MSH_TRI_21 25
+#define MSH_LIN_4 26
+#define MSH_LIN_5 27
+#define MSH_LIN_6 28
+#define MSH_TET_20 29
+#define MSH_TET_35 30
+#define MSH_TET_56 31
+#define MSH_TET_34 32
+#define MSH_MAX_ELEMENT_NODES 56
+
+inline
+int getNumVerticesForElementTypeMSH(int type)
+{
+ switch (type) {
+ case MSH_PNT : return 1;
+ case MSH_LIN_2 : return 2;
+ case MSH_LIN_3 : return 2 + 1;
+ case MSH_LIN_4 : return 2 + 2;
+ case MSH_LIN_5 : return 2 + 3;
+ case MSH_LIN_6 : return 2 + 4;
+ case MSH_TRI_3 : return 3;
+ case MSH_TRI_6 : return 3 + 3;
+ case MSH_TRI_9 : return 3 + 6;
+ case MSH_TRI_10 : return 3 + 6 + 1;
+ case MSH_TRI_12 : return 3 + 9;
+ case MSH_TRI_15 : return 3 + 9 + 3;
+ case MSH_TRI_15I : return 3 + 12;
+ case MSH_TRI_21 : return 3 + 12 + 6;
+ case MSH_QUA_4 : return 4;
+ case MSH_QUA_8 : return 4 + 4;
+ case MSH_QUA_9 : return 4 + 4 + 1;
+ case MSH_TET_4 : return 4;
+ case MSH_TET_10 : return 4 + 6;
+ case MSH_HEX_8 : return 8;
+ case MSH_HEX_20 : return 8 + 12;
+ case MSH_HEX_27 : return 8 + 12 + 6 + 1;
+ case MSH_PRI_6 : return 6;
+ case MSH_PRI_15 : return 6 + 9;
+ case MSH_PRI_18 : return 6 + 9 + 3;
+ case MSH_PYR_5 : return 5;
+ case MSH_PYR_13 : return 5 + 8;
+ case MSH_PYR_14 : return 5 + 8 + 1;
+ case MSH_TET_20 : return 20;
+ case MSH_TET_35 : return 35;
+ case MSH_TET_34 : return 34;
+ case MSH_TET_56 : return 56;
+ default:
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Unknown type of element %d", type);
+ }
+ return 0;
+}
+
+inline
+int getDimForElementTypeMSH(int type)
+{
+ switch (type) {
+ case MSH_PNT : return 0;
+ case MSH_LIN_2 :
+ case MSH_LIN_3 :
+ case MSH_LIN_4 :
+ case MSH_LIN_5 :
+ case MSH_LIN_6 : return 1;
+ case MSH_TRI_3 :
+ case MSH_TRI_6 :
+ case MSH_TRI_9 :
+ case MSH_TRI_10 :
+ case MSH_TRI_12 :
+ case MSH_TRI_15 :
+ case MSH_TRI_15I :
+ case MSH_TRI_21 :
+ case MSH_QUA_4 :
+ case MSH_QUA_8 :
+ case MSH_QUA_9 : return 2;
+ case MSH_TET_4 :
+ case MSH_TET_10 :
+ case MSH_HEX_8 :
+ case MSH_HEX_20 :
+ case MSH_HEX_27 :
+ case MSH_PRI_6 :
+ case MSH_PRI_15 :
+ case MSH_PRI_18 :
+ case MSH_PYR_5 :
+ case MSH_PYR_13 :
+ case MSH_PYR_14 :
+ case MSH_TET_20 :
+ case MSH_TET_35 :
+ case MSH_TET_34 :
+ case MSH_TET_56 : return 3;
+ default:
+ MAdMsgSgl::instance().error(__LINE__,__FILE__,
+ "Unknown type of element %d", type);
+ }
+ return -1;
+}
+
+inline
+std::string getElementName(int type) {
+
+ std::string name;
+
+ switch (type) {
+ case MSH_PNT : name = "Point"; break;
+ case MSH_LIN_2 : name = "Linear edge"; break;
+ case MSH_LIN_3 : name = "Quadratic edge"; break;
+ case MSH_LIN_4 : name = "Cubic edge"; break;
+ case MSH_LIN_5 : name = "Quartic edge"; break;
+ case MSH_LIN_6 : name = "Pentic edge"; break;
+ case MSH_TRI_3 : name = "Linear triangle"; break;
+ case MSH_TRI_6 : name = "Quadratic triangle"; break;
+ case MSH_TRI_9 : name = "Cubic serendipity triangle"; break;
+ case MSH_TRI_10 : name = "Cubic triangle"; break;
+ case MSH_TRI_12 : name = "Quartic serendipity triangle"; break;
+ case MSH_TRI_15 : name = "Quartic triangle"; break;
+ case MSH_TRI_15I : name = "Pentic serendipity triangle"; break;
+ case MSH_TRI_21 : name = "Pentic triangle"; break;
+ case MSH_QUA_4 : name = "Bilinear Quadrangle"; break;
+ case MSH_QUA_8 : name = "Quadratic serendipity quadrangle"; break;
+ case MSH_QUA_9 : name = "Quadratic quadrangle"; break;
+ case MSH_TET_4 : name = "Linear tetrahedron"; break;
+ case MSH_TET_10 : name = "Quadratic tetrahedron"; break;
+ case MSH_HEX_8 : name = "Trilinear hexahedron"; break;
+ case MSH_HEX_20 : name = "Quadratic edge serendipity hexahedron"; break;
+ case MSH_HEX_27 : name = "Quadratic serendipity hexahedron"; break;
+ case MSH_PRI_6 : name = "Linear prism"; break;
+ case MSH_PRI_15 : name = "Quadratic edge serendipity prism"; break;
+ case MSH_PRI_18 : name = "Quadratic serendipity prism"; break;
+ case MSH_PYR_5 : name = "Linear pyramid"; break;
+ case MSH_PYR_13 : name = "Quadratic edge serendipity pyramid"; break;
+ case MSH_PYR_14 : name = "Quadratic serendipty pyramid"; break;
+ case MSH_TET_20 : name = "Cubic tetrahedron";break;
+ case MSH_TET_35 : name = "Quartic tetrahedron";break;
+ case MSH_TET_34 : name = "Quartic serendipity tetrahedron";break;
+ case MSH_TET_56 : name = "Pentic tetrahedron";break;
+ default:
+ std::stringstream ss; break;
+ ss << "Unknown type of element (tag " << type << ")"; break;
+ name = ss.str();
+ }
+ return name;
+}
+#endif
diff --git a/Mesh/PList.h b/Mesh/PList.h
new file mode 100644
index 0000000..1df5bb2
--- /dev/null
+++ b/Mesh/PList.h
@@ -0,0 +1,59 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+/*
+ Store a list of pointers to entities
+
+ The list is stored as a standart vector:
+ - allow fast random access
+ - allow fast iterating
+ - can be allocated to a particular size
+ - slow at randomly adding/removing elements but not useful here
+*/
+
+#ifndef _H_PLIST
+#define _H_PLIST
+
+#include "MeshDataBase.h"
+
+#include <vector>
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ class PList {
+
+ public:
+
+ PList() {};
+ PList(const PList& ori)
+ {
+ entities = ori.entities;
+ };
+
+ ~PList() {};
+
+ public:
+
+ void clear() { entities.clear(); };
+
+ public:
+
+ std::vector<MDB_MeshEntity *> entities;
+
+ };
+
+ // -------------------------------------------------------------------
+
+}
+#endif
diff --git a/Mesh/ParallelUtils.cc b/Mesh/ParallelUtils.cc
new file mode 100644
index 0000000..a2df5c8
--- /dev/null
+++ b/Mesh/ParallelUtils.cc
@@ -0,0 +1,444 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "ParallelUtils.h"
+#include "assert.h"
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+#ifdef _HAVE_METIS_
+extern "C"
+{
+#include "metis.h"
+}
+#endif
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+#ifdef _HAVE_METIS_
+ void PartitionMesh(pMesh mesh, int nbPart, const char * filename)
+ {
+ printf("Partitioning the mesh in %d parts\n",nbPart);
+
+ //NN = number of nodes of the graph
+
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+ int NN = (dim == 2) ? mesh->nbTriangles : mesh->nbTets;
+ int * partitionTable = new int[NN];
+ int * xadj = new int[NN + 2];
+
+ int totCount = 0;
+
+ if(nbPart>1) {
+ MDB_ListF::iterator it2 = mesh->triangles.begin();
+ MDB_ListT::iterator it3 = mesh->tets.begin();
+
+ xadj[0] = 0;
+ for(int i = 0; i < NN; i++) {
+ int nbAdj = 0;
+ if(dim == 2) {
+ MDB_Triangle *t = *it2;
+ ++it2;
+ t->iD = i;
+ nbAdj = (t->e1->numfaces() + t->e2->numfaces() + t->e3->numfaces() - 3);
+ totCount += nbAdj;
+ }
+ else if(dim == 3) {
+ MDB_Tet *t = *it3;
+ ++it3;
+ t->iD = i;
+ nbAdj = (t->f1->getNbRegions() + t->f2->getNbRegions() +
+ t->f3->getNbRegions() + t->f4->getNbRegions() - 4);
+ totCount += nbAdj;
+ }
+ xadj[i + 1] = xadj[i] + nbAdj;
+ }
+
+ it2 = mesh->triangles.begin();
+ it3 = mesh->tets.begin();
+
+ int *adjncy = new int[totCount + 1];
+
+ int count = 0;
+
+ for(int i = 0; i < NN; i++) {
+ if(dim == 2) {
+ MDB_Triangle *t = *it2;
+ for(int j = 0; j < t->e1->numfaces(); j++) {
+ MDB_Triangle *f = t->e1->faces(j);
+ if(f != t)
+ adjncy[count++] = f->iD;
+ }
+ for(int j = 0; j < t->e2->numfaces(); j++) {
+ MDB_Triangle *f = t->e2->faces(j);
+ if(f != t)
+ adjncy[count++] = f->iD;
+ }
+ for(int j = 0; j < t->e3->numfaces(); j++) {
+ MDB_Triangle *f = t->e3->faces(j);
+ if(f != t)
+ adjncy[count++] = f->iD;
+ }
+ ++it2;
+ }
+ else if(dim == 3) {
+ MDB_Tet *t = *it3;
+ MDB_Tet *o = dynamic_cast<MDB_Tet*>(t->f1->opposite_region((MDB_Region*)t));
+ if(o)
+ adjncy[count++] = o->iD;
+ o = dynamic_cast<MDB_Tet*>(t->f2->opposite_region((MDB_Region*)t));
+ if(o)
+ adjncy[count++] = o->iD;
+ o = dynamic_cast<MDB_Tet*>(t->f3->opposite_region((MDB_Region*)t));
+ if(o)
+ adjncy[count++] = o->iD;
+ o = dynamic_cast<MDB_Tet*>(t->f4->opposite_region((MDB_Region*)t));
+ if(o)
+ adjncy[count++] = o->iD;
+ ++it3;
+ }
+ }
+
+ int wgtflag = 0;
+ int numflag = 0;
+ int options[4];
+ options[0] = 0;
+ int edgecut;
+ METIS_PartGraphKway(&NN, xadj, adjncy, 0, 0, &wgtflag,
+ &numflag, &nbPart, options, &edgecut, partitionTable);
+ delete[]adjncy;
+
+ } else {
+ for(int i = 0; i < NN; i++) {
+ partitionTable[i] = 0;
+ }
+ }
+
+ M_writeMsh(mesh,filename,2,partitionTable);
+
+ delete[]xadj;
+ };
+#endif
+
+#ifdef PARALLEL
+
+ // -------------------------------------------------------------------
+ struct edge_comm
+ {
+ pVertex p1,p2; //pointeur in dest
+ int sendID;
+ };
+ struct face_comm
+ {
+ pVertex p1,p2,p3; //pointeur in dest
+ int sendID;
+ };
+
+ // -------------------------------------------------------------------
+ void E_facesAttachId(pMesh mesh,pMeshDataId tagEdge){
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ EIter eit = M_edgeIter(mesh);
+ pEdge pe;
+ while ((pe = EIter_next(eit))) {
+ pVertex p1 = E_vertex(pe,0);
+ pVertex p2 = E_vertex(pe,1);
+ assert(p1); assert(p2);
+ assert(E_exist(p1,p2)==pe);
+ void *temp_ptr1,*temp_ptr2;
+ int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+ int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+ if(!(isInterface1 && isInterface2))continue;
+
+ const std::vector<std::pair<int , pVertex> > *recup1 = (const std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+ const std::vector<std::pair<int , pVertex> > *recup2 = (const std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+ int size1 = (*recup1).size();
+ int size2 = (*recup2).size();
+ assert(size1);assert(size2);
+ int *tab=new int[size1];
+ for(int i=0 ; i< size1 ; i++) tab[i] = (*recup1)[i].first;
+ for(int j=0 ; j<size2 ; j++) {
+ int iProc = (*recup2)[j].first;
+ int i;
+ for(i=0 ; i<size1 ; i++) {
+ if(iProc == tab[i]) break;
+ }
+ if(i < size1) {
+ pVertex remote1 = (*recup1)[i].second;
+ pVertex remote2 = (*recup2)[j].second;
+ for(int k = 0; k < pe->numfaces(); k++) {
+ pFace pface = pe->faces(k);
+ assert(pface);
+ assert(iProc != myrank);
+ void *buf = AP_alloc(iProc,444,sizeof(edge_comm));
+ edge_comm *castbuf = (edge_comm *) buf;
+ castbuf->p1 = remote1;
+ castbuf->p2 = remote2;
+ castbuf->sendID = pface->iD;
+ AP_send(buf);
+ sendcounts[iProc]++;
+ }
+ }
+ }
+ delete []tab;
+ }
+ EIter_delete(eit);
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ int message=0;
+ int count;
+
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int rc;
+ rc=AP_recv(MPI_ANY_SOURCE,444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if (rc) {
+ message++;
+ edge_comm * castbuf = (edge_comm*) msg;
+ pVertex p1recv,p2recv;
+ p1recv = castbuf -> p1;
+ p2recv = castbuf -> p2;
+ assert(p1recv);assert(p2recv);
+ int numrecv = castbuf->sendID;
+ int NN = mesh->nbTriangles;
+ if(from > myrank) {
+ if(numrecv < NN)
+ printf("from %d iD %d NN %d \n",from,numrecv,NN);
+ assert(numrecv >= NN);
+ }
+ assert(from!=myrank);
+ pEdge pe = E_exist(p1recv,p2recv);
+ if(pe) {
+ void* tmpptr;
+ int is = EN_getDataPtr((pEntity) pe , tagEdge,&tmpptr);
+ if(is){
+ std::vector<int> *recup = (std::vector<int> *) tmpptr;
+ for(unsigned int i=0 ; i<(*recup).size() ; i++) assert((*recup)[i]!=numrecv);
+ (*recup).push_back(numrecv);
+ } else {
+ std::vector<int> list;
+ list.push_back(numrecv);
+ EN_attachDataPtr((pEntity) pe,tagEdge,new std::vector<int>(list));
+ }
+ }
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ delete [] sendcounts;
+
+ eit = M_edgeIter(mesh);
+ while ((pe = EIter_next(eit))) {
+ void* tmpptr;
+ int is = EN_getDataPtr((pEntity) pe , tagEdge,&tmpptr);
+ if(is){
+ std::vector<int> *recup = (std::vector<int> *) tmpptr;
+ for(int k = 0; k < E_numFaces(pe); k++) {
+ pFace pface = E_face(pe,k);
+ int iD = pface->iD;
+ unsigned int i;
+ for(i=0 ; i<(*recup).size() ; i++) {
+ if((*recup)[i]==iD) {
+ printf("%d my %d iD %d \n",myrank,(*recup)[i],pe->numfaces());
+ }
+ assert((*recup)[i]!=iD);
+ }
+ (*recup).push_back(iD);
+ }
+ } else {
+ std::vector<int> list;
+ assert(pe->numfaces());
+ for(int k = 0; k < pe->numfaces(); k++) {
+ pFace pface = pe->faces(k);
+ list.push_back(pface->iD);
+ }
+ EN_attachDataPtr((pEntity) pe,tagEdge,new std::vector<int>(list));
+ }
+ }
+ EIter_delete(eit);
+
+ }
+
+ // -------------------------------------------------------------------
+ void F_regionsAttachId(pMesh mesh,pMeshDataId tagAdj){
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int *sendcounts = new int[nproc];
+ for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+ pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ pVertex p1 = F_vertex(pface,0);
+ pVertex p2 = F_vertex(pface,1);
+ pVertex p3 = F_vertex(pface,2);
+ assert(p1); assert(p2);assert(p3);
+ void *temp_ptr1,*temp_ptr2,*temp_ptr3;
+ int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+ int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+ int isInterface3 = EN_getDataPtr((pEntity) p3 , tagData, &temp_ptr3);
+ if(!(isInterface1 && isInterface2 && isInterface3))continue;
+
+ const std::vector<std::pair<int , pVertex> > *recup1 = (const std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+ const std::vector<std::pair<int , pVertex> > *recup2 = (const std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+ const std::vector<std::pair<int , pVertex> > *recup3 = (const std::vector<std::pair<int , pVertex> > *) temp_ptr3;
+ int size1 = (*recup1).size();
+ int size2 = (*recup2).size();
+ int size3 = (*recup3).size();
+ assert(size1);assert(size2);assert(size3);
+ int *tab=new int[size1];
+ int *tab3=new int[size3];
+ for(int i=0 ; i< size1 ; i++) tab[i] = (*recup1)[i].first;
+ for(int i=0 ; i< size3 ; i++) tab3[i] = (*recup3)[i].first;
+ for(int j=0 ; j<size2 ; j++) {
+ int iProc = (*recup2)[j].first;
+ int i,l;
+ for(i=0 ; i<size1 ; i++) {
+ if(iProc == tab[i]) break;
+ }
+ for(l=0 ; l<size3 ; l++) {
+ if(iProc == tab3[l]) break;
+ }
+ if(i < size1 && l<size3) {
+ pVertex remote1 = (*recup1)[i].second;
+ pVertex remote2 = (*recup2)[j].second;
+ pVertex remote3 = (*recup3)[l].second;
+ for(int k = 0; k < F_numRegions(pface); k++) {
+ pRegion pr = F_region(pface,k);
+ assert(pr);
+ assert(iProc != myrank);
+ void *buf = AP_alloc(iProc,444,sizeof(face_comm));
+ face_comm *castbuf = (face_comm *) buf;
+ castbuf->p1 = remote1;
+ castbuf->p2 = remote2;
+ castbuf->p3 = remote3;
+ castbuf->sendID = pr->iD;
+ AP_send(buf);
+ sendcounts[iProc]++;
+ }
+ }
+ }
+ delete []tab;
+ delete []tab3;
+ }
+ FIter_delete(fit);
+ AP_check_sends(AP_NOFLAGS);
+ AP_reduce_nsends(sendcounts);
+
+ int message=0;
+ int count;
+
+ while (!AP_recv_count(&count) || message<count) {
+ void *msg;
+ int from;
+ int tag;
+ int size;
+ int rc;
+ rc=AP_recv(MPI_ANY_SOURCE,444, AP_BLOCKING|AP_DROPOUT,
+ &msg, &size, &from, &tag);
+ if (rc) {
+ message++;
+ face_comm * castbuf = (face_comm*) msg;
+ pVertex p1recv,p2recv,p3recv;
+ p1recv = castbuf -> p1;
+ p2recv = castbuf -> p2;
+ p3recv = castbuf -> p3;
+ int numrecv = castbuf->sendID;
+ int NN = mesh->nbTets;
+ if(from > myrank) {
+ if(numrecv < NN)
+ printf("from %d iD %d NN %d \n",from,numrecv,NN);
+ assert(numrecv >= NN);
+ }
+ assert(from!=myrank);
+ // pFace pface = F_exist(2,p1recv,p2recv,p3recv,0);
+ pFace pface = F_exist(p1recv,p2recv,p3recv,0);
+ if(pface) {
+ void* tmpptr;
+ int is = EN_getDataPtr((pEntity) pface , tagAdj,&tmpptr);
+ if(is){
+ std::vector<int> *recup = (std::vector<int> *) tmpptr;
+ for(unsigned int i=0 ; i<(*recup).size() ; i++) assert((*recup)[i]!=numrecv);
+ (*recup).push_back(numrecv);
+ } else {
+ std::vector<int> newvec;
+ newvec.push_back(numrecv);
+ EN_attachDataPtr((pEntity) pface,tagAdj,new std::vector<int>(newvec));
+ }
+ }
+ AP_free(msg);
+ }
+ }
+ AP_check_sends(AP_WAITALL);
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ delete [] sendcounts;
+
+ fit = M_faceIter(mesh);
+ while ((pface = FIter_next(fit))) {
+ void* tmpptr;
+ int is = EN_getDataPtr((pEntity) pface , tagAdj,&tmpptr);
+ if(is){
+ std::vector<int> *recup = (std::vector<int> *) tmpptr;
+ for(int k = 0; k < F_numRegions(pface); k++) {
+ pRegion pr = F_region(pface,k);
+ int iD = pr->iD;
+ unsigned int i;
+ for(i=0 ; i<(*recup).size() ; i++) {
+ if((*recup)[i]==iD) {
+ printf("%d my %d iD %d \n",myrank,(*recup)[i],F_numRegions(pface));
+ }
+ assert((*recup)[i]!=iD);
+ }
+ (*recup).push_back(iD);
+ }
+ } else {
+ std::vector<int> list;
+ assert(F_numRegions(pface));
+ for(int k = 0; k < F_numRegions(pface); k++) {
+ pRegion pr = F_region(pface,k);
+ list.push_back(pr->iD);
+ }
+ EN_attachDataPtr((pEntity) pface,tagAdj,new std::vector<int>(list));
+ }
+ }
+ FIter_delete(fit);
+
+ }
+
+ // -------------------------------------------------------------------
+#endif
+
+}
diff --git a/Mesh/ParallelUtils.h b/Mesh/ParallelUtils.h
new file mode 100644
index 0000000..d6c846a
--- /dev/null
+++ b/Mesh/ParallelUtils.h
@@ -0,0 +1,30 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _PARALLELUTILS_H_
+#define _PARALLELUTILS_H_
+
+namespace MAd {
+
+#ifdef _HAVE_METIS_
+ void PartitionMesh(pMesh m, int nbPart, const char *);
+#endif
+
+#ifdef PARALLEL
+ void E_facesAttachId(pMesh mesh,pMeshDataId tagAdj);
+ void F_regionsAttachId(pMesh mesh,pMeshDataId tagAdj);
+#endif
+
+}
+
+#endif
diff --git a/Mesh/PeriodicInterfaceMigration.cc b/Mesh/PeriodicInterfaceMigration.cc
new file mode 100644
index 0000000..c40016f
--- /dev/null
+++ b/Mesh/PeriodicInterfaceMigration.cc
@@ -0,0 +1,1248 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseCommPeriodic.h"
+#include "MeshDataBaseComm.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "Mark.h"
+#include "assert.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <fstream>
+#include <iostream>
+
+int ddebug = 0;
+
+namespace MAd {
+
+ void MarkPeriodicEltVertex(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove) {
+
+ //Propagation du tagMove ie tagMove ==2
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int move;
+ int isMove = EN_getDataInt((pEntity) pv , tagMove,&move);
+
+ if(!isMove) continue;
+ if(move != 1) continue;
+
+ int numed = V_numEdges(pv);
+ for(int i=0 ; i<numed ; i++) {
+ pEdge ped = V_edge(pv,i);
+ pVertex pother = E_otherVertex(ped,pv);
+ int movother;
+ int is = EN_getDataInt((pEntity) pother , tagMove,&movother);
+
+ if(!is || (movother!=1)) EN_attachDataInt((pEntity) pother , tagMove,2);
+ }
+ }
+ VIter_delete(vit);
+
+ //tagMove == 10 : the vertex must be deleted
+ //tagMove == -2 : the vertex don't move
+ vit = M_vertexIter(mesh);
+ while ((pv = VIter_next(vit))) {
+ int move;
+ int isMove = EN_getDataInt((pEntity) pv , tagMove,&move);
+
+ if(!isMove) {
+ EN_attachDataInt((pEntity) pv , tagMove,-2);
+ } else {
+ if(abs(move)==1) continue;
+
+ int numed = V_numEdges(pv);
+ bool deleted = true;
+ for(int i=0 ; i<numed ; i++) {
+ pEdge ped = V_edge(pv,i);
+ pVertex pother = E_otherVertex(ped,pv);
+ int movother;
+ int is = EN_getDataInt((pEntity) pother , tagMove,&movother);
+
+ if((!is) || (movother < 0)) {
+ deleted = false;
+ }
+ }
+ //if(deleted) EN_attachDataInt((pEntity) pv , tagMove,10);
+ }
+ }
+ VIter_delete(vit);
+
+ }
+ bool compare(pEdge p1, pEdge p2);
+ /*renvoie la bonne transfo pour les cas 3-periodic*/
+ int EltMoveNew(const int dim,const pRegion pr,const pVertex* nod,pMeshDataId tagMove,pMeshDataId tagTransfo,std::vector<int> *vecttransfo) {
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+ int transformation = 0;
+ //if(EN_id(R_vertex(pr,0))==5 || EN_id(R_vertex(pr,1))== 5 || EN_id(R_vertex(pr,2)) ==5 ||
+ // EN_id(R_vertex(pr,3))==5 )
+ //printf("------ tet %d : %d %d %d %d\n",EN_id((pEntity) pr),EN_id(R_vertex(pr,0)),EN_id(R_vertex(pr,1)),EN_id(R_vertex(pr,2))
+ // ,EN_id(R_vertex(pr,3)));
+ //if(EN_id(R_vertex(pr,0))==28 && EN_id(R_vertex(pr,1))== 111 && EN_id(R_vertex(pr,2)) ==4 &&
+ // EN_id(R_vertex(pr,3))==8 )
+ //printf("****** tet %d : %d %d %d %d\n",EN_id((pEntity) pr),EN_id(R_vertex(pr,0)),EN_id(R_vertex(pr,1)),EN_id(R_vertex(pr,2))
+ // ,EN_id(R_vertex(pr,3)));
+
+ /*on traite les aretes dans l'ordre decroissant (au cas ou plusieurs veulent bouger vers des dest diff)*/
+ std::list<pEdge> listedge;
+ for(int j=0 ; j<6 ; j++) {
+ pEdge ped = R_edge(pr,j);
+ listedge.push_back(ped);
+ }
+ //warning: anisotropic case!!
+ listedge.sort(compare);
+
+ /*boucle sur les aretes de pr*/
+ for(std::list<pEdge>::iterator it = listedge.begin() ; it!=listedge.end() ; it++) {
+ pEdge ped = (*it);
+
+ /*les deux sommets de l'arete ped*/
+ pVertex p0 = E_vertex(ped,0);
+ pVertex p1 = E_vertex(ped,1);
+ if(EN_id(R_vertex(pr,0))==28 && EN_id(R_vertex(pr,1))== 111 && EN_id(R_vertex(pr,2)) ==4 &&
+ EN_id(R_vertex(pr,3))==8 )
+ printf("treat edge %d %d \n",EN_id((pEntity) p0),EN_id((pEntity) p1));
+
+ /*sommets periodics ?*/
+ void *temp_ptr0;
+ int isP0 = EN_getDataPtr((pEntity) p0 , tagPeriodic, &temp_ptr0);
+ if(!isP0) continue;
+ void *temp_ptr1;
+ int isP1 = EN_getDataPtr((pEntity) p1 , tagPeriodic, &temp_ptr1);
+ if(!isP1) continue;
+
+ void *tr0,*tr1;
+ int isT0 = EN_getDataPtr((pEntity) p0 ,tagTransfo, &tr0);
+ if(!isT0) continue;
+ std::vector<int> *t0 = (std::vector<int> *) tr0;
+ int isT1 = EN_getDataPtr((pEntity) p1 ,tagTransfo, &tr1);
+ std::vector<int> *t1 = (std::vector<int> *) tr1;
+ if(!isT1) continue;
+ unsigned int jj;
+ for(jj=0 ; jj<(*t0).size() ; jj++) {
+ if((*t0)[jj] != (*t1)[jj]) break;
+ }
+ if(jj!=(*t0).size()) {
+ //printf("pbs les 2 points ne bougent pas pareil!!! %d %d\n"
+ // ,EN_id((pEntity) p0),EN_id((pEntity) p1));
+ continue;
+ }
+ //if(EN_id(R_vertex(pr,0))==28 && EN_id(R_vertex(pr,1))== 111 && EN_id(R_vertex(pr,2)) ==4 &&
+ // EN_id(R_vertex(pr,3))==8 )
+ // printf("on bouge : %d %d %d\n",(*t0)[0],(*t0)[1],(*t0)[2]);
+ transformation = 1;
+ //for(int kv=0 ; kv<transfo.size() ; kv++)
+ (*vecttransfo) = *t0;
+ return(transformation);
+ } /*end j*/
+ //printf("problemmmm\n");
+ return transformation;
+ }
+ int EltMove2dNew(const int dim,const pVertex* nod,pMeshDataId tagMove,pMeshDataId tagTransfo,std::vector<int> *vecttransfo) {
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+ int transformation = 0;
+
+ for(int i=0 ; i<(dim+1) ; i++) {
+ void *temp_ptr;
+ /*sommets periodics */
+ int isPeriodic = EN_getDataPtr((pEntity) nod[i] , tagPeriodic, &temp_ptr);
+ if(!isPeriodic) continue;
+ if(ddebug) printf("test nod %d) \n",EN_id((pEntity) nod[i]));
+
+ /*transfo*/
+ void *tr0;
+ int isT0 = EN_getDataPtr((pEntity) nod[i] ,tagTransfo, &tr0);
+ if(!isT0) continue;
+ std::vector<int> *t0 = (std::vector<int> *) tr0;
+ transformation = 1;
+ //for(int kv=0 ; kv<transfo.size() ; kv++)
+ (*vecttransfo) = *t0;
+ return(transformation);
+
+ }
+ return transformation;
+ }
+ int EltMove(const int dim,const pVertex* nod,pMeshDataId tagMove,std::vector<int> *vecttransfo) {
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+ int transformation = 0;
+
+
+ if(ddebug) printf("tetra %d %d %d %d\n",nod[0]->iD,nod[1]->iD,nod[2]->iD,nod[3]->iD);
+ for(int i=0 ; i<(dim+1) ; i++) {
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) nod[i] , tagPeriodic, &temp_ptr);
+ if(!isPeriodic) continue;
+ if(ddebug) printf("test nod %d) \n",EN_id((pEntity) nod[i]));
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ unsigned int j=0;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ std::vector<int> transfo = (*recup)[j].first;
+ /*****************************************************************************/
+ /********************ancienne facon*******************************************/
+ /*****************************************************************************/
+ unsigned int kk=0;
+ for(kk = 0 ; kk<transfo.size() ; kk++) {
+ if( transfo[kk]< 0) break;
+ }
+ if(kk!=transfo.size()) continue;
+ /*****************************************************************************/
+ /*on bouge que par rapport à x*/
+ /** int somme = 0;
+ for(int kk = 0 ; kk<transfo.size() ; kk++) {
+ //if(kk==imove) continue;
+ somme += abs(transfo[kk] );
+ }
+ int inv = (imove>=0) ? 1 : -1;
+ if(inv < 0) imove = abs(imove)-1;
+ for(kk = imove ; kk<imove+1 ; kk++) {
+ if((transfo[kk] == 0) || (inv * transfo[kk] <0)) break;
+ }
+ if(kk!=imove+1 || somme >=2) continue; */
+ /*****************************************************************************/
+ /********nouvelle facon de bouger (sans pbs pour les tri-periodicite)*********/
+ /********on prend la seule transformation qui repond : ***********************/
+ /******** tous les autres points img doivent etre en mvt *********************/
+ /*****************************************************************************/
+
+ /*****************************************************************************/
+ /*****************************************************************************/
+
+ if(ddebug) printf("on peut eventuellement le bouge par %d %d %d (point %d)\n",transfo[0],transfo[1],transfo[2],EN_id((pEntity) (*recup)[j].second));
+ pVertex pImg = (*recup)[j].second;
+ int move;
+ int isMove = EN_getDataInt((pEntity) pImg ,tagMove, &move);
+ assert(isMove);
+ if(ddebug) printf("point img tagMove %d\n",move);
+ if(move==10 || move==1) continue;
+ if(ddebug) printf("on teste de bouger sur le point %d (%d)\n",EN_id((pEntity) (*recup)[j].second),move);
+ /*******************************************************************************************************/
+ /***** il faut verifier que s'il existe une img aux autres points par cette transfo elle soit fixe ****/
+ /******************************************************************************************************/
+ int k=0;//i+1;
+ for(k=i+1 ; k<(dim+1) ; k++) {
+ if(k==i) continue;
+ void *temp_ptr2;
+ int isPeriodic2 = EN_getDataPtr((pEntity) nod[k] , tagPeriodic, &temp_ptr2);
+ if(!isPeriodic2) continue;
+ if(ddebug) printf("on teste le point %d\n",EN_id((pEntity) nod[k]));
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+ unsigned int j2=0;
+ for(j2=0 ; j2<(*recup2).size() ; j2++) {
+ std::vector<int> transfo2 = (*recup2)[j2].first;
+ assert(transfo2.size()==transfo.size());
+ unsigned int k2=0;
+ for(k2 = 0 ; k2<transfo2.size() ; k2++) {
+ if( transfo2[k2] != transfo[k2] ) break;
+ }
+ if(k2!=transfo2.size()) continue;
+ pVertex pImg2 = (*recup2)[j2].second;
+ int move2;
+ int isMove2 = EN_getDataInt((pEntity) pImg2 ,tagMove, &move2);
+ assert(isMove2);
+ if(ddebug) printf("img %d (%d)\n",EN_id((pEntity) pImg2),move2);
+ if(move2==10 || move2==1) break;
+ }
+ if(j2!=(*recup2).size()) break;//si on est arrive au bout de la boucle : ce noeud est ok on passe au suivant
+ }
+ if(k==(dim+1)) { //on peut bouger
+ transformation = 1;
+ //for(int kv=0 ; kv<transfo.size() ; kv++)
+ (*vecttransfo) = transfo;
+ break;
+ }
+ }
+ if(j!=(*recup).size()) break;//on peut bouger
+ }
+ return transformation;
+ }
+
+ pFace findFace(pMesh mesh,const pVertex p1,const pVertex p2,const pVertex p3) {
+ pFace pface;
+
+ pface = F_exist(p1,p2,p3,0);
+ if(!pface) pface = F_exist(p1,p2,p3,0);
+ if(!pface) pface = F_exist(p1,p3,p2,0);
+ if(!pface) pface = F_exist(p2,p1,p3,0);
+ if(!pface) pface = F_exist(p2,p3,p1,0);
+ if(!pface) pface = F_exist(p3,p1,p2,0);
+ if(!pface) pface = F_exist(p3,p2,p1,0);
+
+ assert(pface);
+ return pface;
+
+ }
+ void TetraMove(pMesh mesh,pRegion pr,const pVertex* nodnew) {
+ pGEntity pg = EN_whatIn(pr);
+ int tag = GEN_tag(pg);
+ int dim = GEN_type(pg);
+ if(dim==3) {
+ pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+ } else {
+ printf("----pbs faces**** %d\n",dim);
+ }
+
+ pFace pface[4];
+ pface[0] = findFace(mesh,nodnew[0],nodnew[1],nodnew[2]);
+ assert(pface[0]);
+ pface[1] = findFace(mesh,nodnew[0],nodnew[1],nodnew[3]);
+ assert(pface[1]);
+ pface[2] = findFace(mesh,nodnew[1],nodnew[2],nodnew[3]);
+ assert(pface[2]);
+ pface[3] = findFace(mesh,nodnew[0],nodnew[2],nodnew[3]);
+ assert(pface[3]);
+ //if((EN_id(nodnew[0])==5 || EN_id(nodnew[1])==5 ||EN_id(nodnew[2])==5 || EN_id(nodnew[3])==5) &&
+ // (EN_id(nodnew[0])==3 || EN_id(nodnew[1])==3 || EN_id(nodnew[2])==3) || EN_id(nodnew[3])==3)
+ //printf("new tet %d %d %d %d \n",EN_id(nodnew[0]),EN_id(nodnew[1]),EN_id(nodnew[2]),EN_id(nodnew[3]));
+
+ pRegion prnew = M_createR(mesh,4,pface,pg);
+ //printf("tetnew face : %p %p %p %p\n",prnew->f1,prnew->f2,prnew->f3,prnew->f4);
+ assert(prnew);
+
+
+ return;
+ }
+
+ void TriangleMove(pMesh mesh,pFace pface,const pVertex* nodnew) {
+ pGEntity pg = EN_whatIn(pface);
+ int tag = GEN_tag(pg);
+ int dim = GEN_type(pg);
+ if(dim==2) {
+ pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+ } else {
+ printf("----pbs faces**** %d\n",dim);
+ }
+ pEdge pe[3];
+ pe[0] = E_exist(nodnew[0],nodnew[1]);
+ assert(pe[0]);
+ pe[1] = E_exist(nodnew[1],nodnew[2]);
+ assert(pe[1]);
+ pe[2] = E_exist(nodnew[0],nodnew[2]);
+ //if(!pe[2]) pe[2] = E_exist(nodnew[2],nodnew[0]);
+ assert(pe[2]);
+
+ pFace pfnew =F_exist(pe[0],pe[1],pe[2],0);
+ if(!pfnew) pfnew = M_createF(mesh,3,pe,pg);
+ //printf("tetnew face : %p\n",pfnew);
+
+ assert(pfnew);
+
+
+
+ return;
+ }
+
+ void TriangleDelete(pMesh mesh,const pVertex* nod) {
+ int i1,i2,i3;
+ for(int i=0 ; i<4 ; i++) {
+ switch(i) {
+ case 0 :
+ i1 = 0;
+ i2 = 1;
+ i3 = 2;
+ break;
+ case 1 :
+ i1 = 0;
+ i2 = 1;
+ i3 = 3;
+ break;
+ case 2 :
+ i1 = 1;
+ i2 = 2;
+ i3 = 3;
+ break;
+ case 3 :
+ i1 = 0;
+ i2 = 2;
+ i3 = 3;
+ break;
+ }
+ pFace pface = F_exist(nod[i1],nod[i2],nod[i3],0);
+ assert(pface);
+ int num = F_numRegions(pface);
+ //printf(" del? %d face %p \n",!num,pface);
+ if (!num) M_removeFace(mesh,pface);
+ }
+ return;
+ }
+
+ void numP(const int cas,int* i1,int* i2) {
+ switch(cas) {
+ case 0 :
+ *i1 = 0;
+ *i2 = 1;
+ break;
+ case 1 :
+ *i1 = 1;
+ *i2 = 2;
+ break;
+ case 2 :
+ *i1 = 2;
+ *i2 = 0;
+ break;
+ case 3 :
+ *i1 = 0;
+ *i2 = 3;
+ break;
+ case 4 :
+ *i1 = 1;
+ *i2 = 3;
+ break;
+ case 5 :
+ *i1 = 2;
+ *i2 = 3;
+ break;
+ default :
+ throw;
+ break;
+ }
+ return;
+ }
+
+ void EdgeDelete(const int nbe,pMesh mesh,const pVertex* nod) {
+ int i1,i2;
+ for(int i = 0 ; i<nbe ; i++) {
+ numP(i,&i1,&i2);
+ pEdge pedge = E_exist(nod[i1],nod[i2]);
+ //if(!pedge) pedge = E_exist(nod[i1],nod[i2]);
+ assert(pedge);
+ int num = E_numFaces(pedge);
+ if (!num) M_removeEdge(mesh,pedge);
+ }
+ return;
+ }
+
+ void EdgeMove(const int nbe,pMesh mesh,const pVertex* nod,const pVertex* nodnew) {
+ int i1,i2;
+ for(int i = 0 ; i<nbe ; i++) {
+ numP(i,&i1,&i2);
+
+ pEdge pedge = E_exist(nod[i1],nod[i2]);
+ //if(!pedge) pedge = E_exist(nod[i2],nod[i1]);
+ assert(pedge);
+ pGEntity pg = EN_whatIn(pedge);
+ int dim = GEN_type(pg);
+ int tag = GEN_tag(pg);
+ if(dim==1) {
+ pg = (pGEntity) GM_edgeByTag(mesh->model,tag);
+ } else if(dim==2) {
+ pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+ } else {
+ printf("----pbs**** %d\n",dim);
+ }
+ pEdge e = E_exist(nodnew[i1],nodnew[i2]);
+ //if(EN_id(nod[i1])==4694 || EN_id(nod[i2])==4694 || EN_id(nodnew[i1])==4694 || EN_id(nod[i2])==4694)
+ // printf("edge %d %d ---> %d %d\n",EN_id(nod[i1]),EN_id(nod[i2]),EN_id(nodnew[i1]),EN_id(nodnew[i2])) ;
+ //printf("on cree edge : %d %d\n",EN_id((pEntity) nodnew[i1]),EN_id((pEntity) nodnew[i2]));
+ //if(nodnew[i1]->iD==144 || nodnew[i2]->iD==144) printf("-------------------- on cree edge : %d %d\n",EN_id((pEntity) nodnew[i1]),EN_id((pEntity) nodnew[i2]));
+ if (!e) e = M_createE(mesh,nodnew[i1],nodnew[i2],pg);
+ }
+ return;
+ }
+
+ void VertexDelete(pMesh mesh, pMeshDataId tagMove, pMeshDataId tagTransfo){
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+
+ VIter vit = M_vertexIter(mesh);
+ pVertex pv;
+ while ((pv = VIter_next(vit))) {
+ int move;
+ int isMove = EN_getDataInt((pEntity) pv ,tagMove, &move);
+ assert(isMove);
+ EN_deleteData((pEntity)pv, tagMove);
+ // if(!(move==1 || move==10)) continue;
+
+ // printf("on delete le point %d ?\n",EN_id((pEntity) pv));
+ int num = V_numEdges(pv);
+ if(num){
+ // if(move!=10) printf("point not deleted %d (%d)\n",EN_id((pEntity) pv),move);
+ //assert(move==10);
+ continue;
+ }
+ void *ttr;
+ int isT = EN_getDataPtr((pEntity) pv , tagTransfo, &ttr);
+ if(isT) {
+ std::vector<int> *rcup = (std::vector<int> *) ttr;
+ delete rcup;
+ EN_deleteData((pEntity) pv , tagTransfo);
+ }
+
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+ if(isPeriodic) {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+ pVertex ptemp = (*recup)[j].second;
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) ptemp , tagPeriodic, &temp_ptr2);
+ assert(is);
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+ if((*recup2).size()==1) {
+ EN_deleteData((pEntity) ptemp , tagPeriodic);
+ } else {
+ std::vector<std::pair<std::vector<int> , pVertex> > vectnod;
+ for(unsigned int k=0 ; k<(*recup2).size() ; k++) {
+ if((*recup2)[k].second != pv) vectnod.push_back(std::pair<std::vector<int> , pVertex>((*recup2)[k].first,(*recup2)[k].second));
+ }
+ EN_attachDataPtr((pEntity) ptemp , tagPeriodic,
+ new std::vector<std::pair<std::vector<int> , pVertex> >(vectnod));
+ }
+ }
+ delete recup;
+ EN_deleteData((pEntity) pv , tagPeriodic);
+ }
+
+ M_removeVertex(mesh,pv);
+
+ }
+ VIter_delete(vit);
+
+ return;
+ }
+
+ void VertexMove(const int nbv,pMesh mesh,const pVertex* nod,const std::vector<int>& vecttransfo,pMeshDataId tagMove,
+ pVertex* nodnew,MDB_DataExchangerPeriodic &deperiodic) {
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+
+ std::vector<int> invvecttransfo;
+ for(unsigned k=0 ; k<vecttransfo.size() ; k++) {
+ invvecttransfo.push_back(-vecttransfo[k]);
+ }
+
+ for(int i=0 ; i<nbv ; i++) {
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) nod[i] , tagPeriodic, &temp_ptr);
+ if(!isPeriodic) {
+ //creation du point, nod[i] et nodnew[i] devient periodic
+ pGEntity pg = EN_whatIn(nod[i]);
+ pGEntity pent;
+ int dim = GEN_type(pg);
+ int tag = GEN_tag(pg);
+ if(dim == 0) {
+ pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+ } else if(dim==1) {
+ pent = (pGEntity) GM_edgeByTag(mesh->model,tag);
+ } else if(dim==2) {
+ pent = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pent = (pGEntity) GM_regionByTag(mesh->model,tag);
+ } else {
+ printf("pbs**** %d\n",dim);
+ }
+ double X,Y,Z;
+ X = nod[i]->X;
+ Y = nod[i]->Y;
+ Z = nod[i]->Z;
+ for(int k = 0 ; k<deperiodic.nbRefPeriodic() ; k++) {
+ if(vecttransfo[k]){
+ int inv1 = (vecttransfo[k] < 0) ? 1 : 0;
+ for(int nb = 0 ; nb<abs(vecttransfo[k]) ; nb++) {
+ deperiodic.fperiodic(inv1,X,Y,Z,k+1,&X,&Y,&Z);
+ }
+ }
+ }
+ nodnew[i] = M_createV(mesh,X,Y,Z,-1,pent);
+ if(ddebug) {
+ printf("nod vient de %d avec %d %d\n",EN_id((pEntity) nod[i]),vecttransfo[0],vecttransfo[1]);
+ printf("coor nod %e %e\n",nod[i]->X,nod[i]->Y);
+ printf("coor nodnew %e %e\n",nodnew[i]->X,nodnew[i]->Y);
+ }
+ std::vector<std::pair<std::vector<int> , pVertex> > vectnodperiodic;
+ vectnodperiodic.push_back(std::pair<std::vector<int> , pVertex>(vecttransfo,nodnew[i]));
+ EN_attachDataPtr((pEntity) nod[i] , tagPeriodic,
+ new std::vector<std::pair<std::vector<int> , pVertex> >(vectnodperiodic));
+ std::vector<std::pair<std::vector<int> , pVertex> > vectnodnewperiodic;
+
+ vectnodnewperiodic.push_back(std::pair<std::vector<int> , pVertex>(invvecttransfo,nod[i]));
+ EN_attachDataPtr((pEntity) nodnew[i] , tagPeriodic,
+ new std::vector<std::pair<std::vector<int> , pVertex> >(vectnodnewperiodic));
+ EN_attachDataInt((pEntity) nodnew[i] , tagMove,2);
+ if(ddebug) printf("creation non periodique %d -> %d (2)\n",EN_id((pEntity) nod[i]),EN_id((pEntity) nodnew[i]));
+
+ } else {
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ unsigned int j=0;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ std::vector<int> transfo = (*recup)[j].first;
+ assert(transfo.size()==vecttransfo.size());
+ unsigned int kt = 0;
+ for(kt = 0 ; kt < vecttransfo.size(); kt++) {
+ if(vecttransfo[kt] != transfo[kt]) break;
+ }
+ if(kt!=vecttransfo.size()) continue;
+
+ if((EN_id(nod[0])==28 && EN_id(nod[1])==111 && EN_id(nod[2])==4 && EN_id(nod[3])==8))
+ printf("le correspondant de %d est %d par %d %d\n",EN_id((pEntity) nod[i]),EN_id((pEntity)(*recup)[j].second),
+ vecttransfo[0],vecttransfo[1]);
+ if(ddebug) printf("le correspondant de %d est %d par %d %d\n",EN_id((pEntity) nod[i]),EN_id((pEntity)(*recup)[j].second),
+ vecttransfo[0],vecttransfo[1]);
+ //le point existe
+ nodnew[i] = (*recup)[j].second;
+ break;
+ }
+ if(j==(*recup).size()) {
+ //printf("ARGGGGGGGGGGGGGG point %d (%e %e) par %d %d\n",EN_id((pEntity) nod[i]),nod[i]->X,nod[i]->Y,
+ // vecttransfo[0],vecttransfo[1]);
+ //le point n'existe pas mais nod est periodic
+ pGEntity pg = EN_whatIn(nod[i]);
+ pGEntity pent;
+ int dim = GEN_type(pg);
+ int tag = GEN_tag(pg);
+ if(dim == 0) {
+ pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+ } else if(dim==1) {
+ pent = (pGEntity) GM_edgeByTag(mesh->model,tag);
+ } else if(dim==2) {
+ pent = (pGEntity) GM_faceByTag(mesh->model,tag);
+ } else if(dim==3) {
+ pent = (pGEntity) GM_regionByTag(mesh->model,tag);
+ } else {
+ printf("pbs**** %d\n",dim);
+ }
+ double X,Y,Z;
+ X = nod[i]->X;
+ Y = nod[i]->Y;
+ Z = nod[i]->Z;
+ for(int k = 0 ; k<deperiodic.nbRefPeriodic() ; k++) {
+ if(vecttransfo[k]){
+ int inv1 = (vecttransfo[k] < 0) ? 1 : 0;
+ for(int nb = 0 ; nb<abs(vecttransfo[k]) ; nb++) {
+ deperiodic.fperiodic(inv1,X,Y,Z,k+1,&X,&Y,&Z);
+ }
+ }
+ }
+ nodnew[i] = M_createV(mesh,X,Y,Z,-1,pent);
+ //printf("on cree le point %p : %e %e \n",nodnew[i],X,Y);
+ std::vector<std::pair<std::vector<int> , pVertex> > vectnodnewperiodic;
+ //printf("1) on ajoute le point %d (%e %e) a la liste de %d (%e %e) par %d %d\n",EN_id((pEntity) nod[i])
+ // ,nod[i]->X,nod[i]->Y
+ // ,EN_id((pEntity) nodnew[i]),nodnew[i]->X,nodnew[i]->Y
+ // ,invvecttransfo[0],invvecttransfo[1]);
+ vectnodnewperiodic.push_back(std::pair<std::vector<int> , pVertex>(invvecttransfo,nod[i]));
+ for(j=0 ; j<(*recup).size() ; j++) {
+ std::vector<int> transfo = (*recup)[j].first;
+ pVertex ptemp = (*recup)[j].second;
+ void *temp_ptr2;
+ int is = EN_getDataPtr((pEntity) ptemp , tagPeriodic, &temp_ptr2);
+ assert(is);
+ //#warning: calcule la bonne transformation
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+#ifdef DEBUG
+ unsigned int k=0;
+ for(k=0 ; k<(*recup2).size() ; k++) {
+ std::vector<int> transfo2 = (*recup2)[k].first;
+ int kk=0;
+ for(kk = 0 ; kk<deperiodic.nbRefPeriodic() ; kk++) {
+ if(transfo[kk]!=(-1) * transfo2[kk]) break;
+ }
+ if(kk<deperiodic.nbRefPeriodic()) continue;
+ //printf(" %p (%e %e %e) -- %p (%e %e %e)\n",(*recup2)[k].second,(*recup2)[k].second->X,(*recup2)[k].second->Y,(*recup2)[k].second->Z,nod[i],nod[i]->X,nod[i]->Y,nod[i]->Z);
+ assert((*recup2)[k].second == nod[i]);
+ break;
+ }
+ assert(k!=(*recup2).size());
+#endif
+ std::vector<int> newtransfo;
+ std::vector<int> invnewtransfo;
+ for(unsigned int kn = 0 ; kn < transfo.size() ; kn++){
+ invnewtransfo.push_back(vecttransfo[kn] - transfo[kn]);
+ newtransfo.push_back(-(vecttransfo[kn] - transfo[kn]));
+ }
+ //printf("2) on ajoute le point %d (%e %e) a la liste de %d (%e %e) par %d %d\n",EN_id((pEntity) ptemp)
+ // ,ptemp->X,ptemp->Y
+ // ,EN_id((pEntity) nodnew[i]),nodnew[i]->X,nodnew[i]->Y
+ // ,newtransfo[0],newtransfo[1]);
+ vectnodnewperiodic.push_back(std::pair<std::vector<int> , pVertex>(newtransfo,ptemp));
+ //printf("3) on ajoute le point %d (%e %e) a la liste de %d (%e %e) par %d %d\n",EN_id((pEntity) nodnew[i])
+ // ,nodnew[i]->X,nodnew[i]->Y
+ // ,EN_id((pEntity) ptemp),ptemp->X,ptemp->Y
+ // ,invnewtransfo[0],invnewtransfo[1]);
+ (*recup2).push_back(std::pair<std::vector<int> , pVertex>(invnewtransfo,nodnew[i]));
+ }
+ EN_attachDataPtr((pEntity) nodnew[i] , tagPeriodic,
+ new std::vector<std::pair<std::vector<int> , pVertex> >(vectnodnewperiodic));
+ EN_attachDataInt((pEntity) nodnew[i] , tagMove,2);
+ (*recup).push_back(std::pair<std::vector<int> , pVertex>(vecttransfo,nodnew[i]));
+ //printf("4) on ajoute le point %d (%e %e) a la liste de %d (%e %e) par %d %d\n",EN_id((pEntity) nodnew[i])
+ // ,nodnew[i]->X,nodnew[i]->Y
+ // ,EN_id((pEntity) nod[i]),nod[i]->X,nod[i]->Y
+ // ,vecttransfo[0],vecttransfo[1]);
+
+ } else {
+ //le point existe rien a faire pour l'instant
+ }
+ }//end if periodic
+ }// end for i
+ return;
+ }
+
+ void MovePeriodicTriangles(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove,pMeshDataId tagTransfo, MDB_DataExchanger &de,
+ MDB_DataExchangerPeriodic &deperiodic) {
+
+ int nmodif = 0;
+ EIter eit;
+ pEdge pedge;
+
+ do {
+ printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ while : nb modif = %d\n",nmodif);
+ //if(nmodif) break;
+ nmodif = 0;
+ eit = M_edgeIter(mesh);
+ while ((pedge = EIter_next(eit))) {
+ pVertex p[2];
+ p[0] = pedge->p1;
+ p[1] = pedge->p2;
+ int move1,move2;
+ int isMove1 = EN_getDataInt((pEntity) p[0] ,tagMove, &move1);
+ int isMove2 = EN_getDataInt((pEntity) p[1] ,tagMove, &move2);
+ assert(isMove1 && isMove2);
+ if(!(move1 == 1 || move1 == 10 || move2==1 || move2 == 10)) continue;
+ //l'arete doit bouger
+ if(E_numFaces(pedge)!=1) continue;
+ pFace pface = E_face(pedge,0);
+ assert(pface);
+ pVertex nod[3];
+ pface->getNodes(nod);
+
+ int tmp;
+ int isChange = EN_getDataInt((pEntity) pface , tagElt, &tmp);
+ if(!isChange) continue;
+
+ // printf("test edge ------------- : %d (%d) -- %d (%d)\n",EN_id((pEntity)p[0]),move1,EN_id((pEntity)p[1]),move2);
+ // printf("tr(%d %d %d) \n\n",EN_id((pEntity)nod[0]),EN_id((pEntity)nod[1]),EN_id((pEntity)nod[2]));
+
+ //test si on peut bouger le triangle issu de cette arete
+ std::vector<int> vecttransfo;
+ int transformation = EltMove2dNew(2,nod,tagMove,tagTransfo,&vecttransfo);
+ if(!transformation) continue;
+ //printf("------------- edge : %d (%d) -- %d (%d)\n",EN_id((pEntity)p[0]),move1,EN_id((pEntity)p[1]),move2);
+ //printf("on a le droit de bouger (%d %d %d) selon %d %d\n\n",EN_id((pEntity)nod[0]),EN_id((pEntity)nod[1]),EN_id((pEntity)nod[2]),
+ // vecttransfo[0],vecttransfo[1]);
+
+
+ //si oui on le bouge => creation des points, edges, face + delete face, edges, points
+ // + mise a jour des tagPeriodic et des tagMove (ie points deviennent fixes : -2)
+
+ //bouge des points : s'il n'existe pas on le cree, sinon on donne son pointeur
+ pVertex nodnew[3];
+ VertexMove(3,mesh,nod,vecttransfo,tagMove,nodnew,deperiodic);
+
+ //creation des edges
+ EdgeMove(3,mesh,nod,nodnew);
+ //printf("on bouge les points (%f %f) (%f %f) (%f %f) \n",nod[0]->X,nod[0]->Y,
+ // nod[1]->X,nod[1]->Y,
+ // nod[2]->X,nod[2]->Y);
+ //printf("vers les points (%f %f) (%f %f) (%f %f) \n",nodnew[0]->X,nodnew[0]->Y,
+ // nodnew[1]->X,nodnew[1]->Y,
+ // nodnew[2]->X,nodnew[2]->Y);
+ //creation/delete des triangles
+ TriangleMove(mesh,pface,nodnew);
+ int is = EN_getDataInt((pEntity) pface , tagElt, &tmp);
+ assert(is);
+ EN_deleteData((pEntity) pface , tagElt);
+ M_removeFace(mesh,pface);
+
+ EdgeDelete(3,mesh,nod);
+
+ nmodif++;
+ }
+ EIter_delete(eit);
+ } while (nmodif);
+
+ //check si plus de tr a bouger
+
+ }
+
+ void MovePeriodicTetras(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove ,pMeshDataId tagTransfo,
+ MDB_DataExchanger &de,
+ MDB_DataExchangerPeriodic &deperiodic) {
+
+ int nmodif = 0;
+ FIter fit;
+ pFace pface;
+
+ do {
+ printf(" Tets $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ while : nb modif = %d\n",nmodif);
+ //M_writeSMS(mesh,"chk.msh",10);
+ //CheckMshPeriodic(mesh);
+
+ // //if(nmodif) break;
+ nmodif = 0;
+
+ // //check adj
+ // fit = M_faceIter(mesh);
+ // while ((pface = FIter_next(fit))) {
+ // assert(!pface->deleted);
+ // int num = F_numRegions(pface);
+ // if(!num) {
+ // printf("face %p dim %d\n",pface,GEN_type(pface->g));
+ // exit(0);
+ // continue;
+ // }
+ // }
+ // FIter_delete(fit);
+
+
+ fit = M_faceIter(mesh);
+ while ((pface = FIter_next(fit))) {
+
+ if(pface->deleted) continue;
+ pVertex p[3];
+ pface->getNodes(p);
+
+ int move1,move2,move3;
+ int isMove1 = EN_getDataInt((pEntity) p[0] ,tagMove, &move1);
+ int isMove2 = EN_getDataInt((pEntity) p[1] ,tagMove, &move2);
+ int isMove3 = EN_getDataInt((pEntity) p[2] ,tagMove, &move3);
+ assert(isMove1 && isMove2 && isMove3);
+ // if((p[0]->iD==5 || p[1]->iD==5 || p[2]->iD==5) && (p[0]->iD==3 || p[2]->iD==3 || p[1]->iD==3))
+ // printf("*** face %d %d %d : %d %d %d\n",p[0]->iD,p[1]->iD,p[2]->iD,move1,move2,move3) ;
+
+ if(!(move1 == 1 || move1 == 10 || move2==1 || move2 == 10 || move3==1 || move3 == 10 )) continue;
+ if(F_numRegions(pface)<1) printf("face %p pbs\n",(void*)pface);
+ assert(F_numRegions(pface)>=1);
+ if(F_numRegions(pface)==2) continue;
+
+ if((p[0]->iD==0 && p[1]->iD==0 && p[2]->iD==0) ||
+ (p[0]->iD==0 && p[2]->iD==0 && p[1]->iD==0) ||
+ (p[1]->iD==0 && p[2]->iD==0 && p[0]->iD==0) ||
+ (p[1]->iD==0 && p[0]->iD==0 && p[2]->iD==0) ||
+ (p[2]->iD==0 && p[1]->iD==0 && p[0]->iD==0) ||
+ (p[2]->iD==0 && p[0]->iD==0 && p[1]->iD==0)) ddebug = 1;
+ else if(p[0]->iD==0 || p[1]->iD==0 || p[2]->iD==0)ddebug = 1;
+ else ddebug = 0;
+
+ pRegion pr = F_region(pface,0);
+ assert(pr);
+ pVertex nod[4];
+ pr->getNodes(nod);
+
+ int tmp;
+ int isChange = EN_getDataInt((pEntity) pr , tagElt, &tmp);
+ if(!isChange) continue;
+
+ if(ddebug) printf("test face ------------- : %d (%d) -- %d (%d) -- %d(%d)\n",EN_id((pEntity)p[0]),move1,
+ EN_id((pEntity)p[1]),move2,
+ EN_id((pEntity)p[2]),move3);
+
+ if(ddebug) printf("tet : %d %d %d %d\n",EN_id((pEntity)nod[0]),EN_id((pEntity)nod[1]),
+ EN_id((pEntity)nod[2]),EN_id((pEntity)nod[3]));
+ if(ddebug) printf("tet face : %p %p %p %p\n",(void*)(pr->getFace(0)),(void*)(pr->getFace(1)),(void*)(pr->getFace(2)),(void*)(pr->getFace(3)));
+
+ //test si on peut bouger le tetra issu de cette face
+ std::vector<int> vecttransfo;
+ int transformation = EltMoveNew(3,pr,nod,tagMove,tagTransfo,&vecttransfo);
+ /*ancienne version*/
+ //int transformation = EltMove(3,nod,tagMove,&vecttransfo);
+
+ if(ddebug) printf("on bouge ? %d\n",transformation);
+ if(!transformation) continue;
+
+
+ //Orientation!!!!!!
+
+ pVertex nodnew[4];
+ VertexMove(4,mesh,nod,vecttransfo,tagMove,nodnew,deperiodic);
+ if((EN_id(nodnew[0])==23 && EN_id(nodnew[1])==148 && EN_id(nodnew[2])==3 && EN_id(nodnew[3])==5))
+ printf("tet %d %d %d %d: %d?\n",EN_id(nod[0]),EN_id(nod[1]),EN_id(nod[2]),EN_id(nod[3]),isChange);
+ // printf("tetnew : %d %d %d %d\n",EN_id((pEntity)nodnew[0]),EN_id((pEntity)nodnew[1]),
+ // EN_id((pEntity)nodnew[2]),EN_id((pEntity)nodnew[3]));
+ //
+ //creation des edges
+ EdgeMove(6,mesh,nod,nodnew);
+
+ //creation/delete des triangles
+ for(int i=0 ; i<4 ; i++) {
+ pVertex nodtmp[3];
+ switch(i) {
+ case 0 :
+ nodtmp[0] = nodnew[0];
+ nodtmp[1] = nodnew[1];
+ nodtmp[2] = nodnew[2];
+ break;
+ case 1 :
+ nodtmp[0] = nodnew[0];
+ nodtmp[1] = nodnew[1];
+ nodtmp[2] = nodnew[3];
+ break;
+ case 2 :
+ nodtmp[0] = nodnew[1];
+ nodtmp[1] = nodnew[2];
+ nodtmp[2] = nodnew[3];
+ break;
+ case 3 :
+ nodtmp[0] = nodnew[0];
+ nodtmp[1] = nodnew[2];
+ nodtmp[2] = nodnew[3];
+ break;
+ }
+ TriangleMove(mesh,pface,nodtmp);
+ }
+
+ TetraMove(mesh,pr,nodnew);
+
+ int is = EN_getDataInt((pEntity) pr , tagElt, &tmp);
+ assert(is);
+ EN_deleteData((pEntity) pr , tagElt);
+ M_removeRegion(mesh,pr);
+
+ TriangleDelete(mesh,nod);
+ EdgeDelete(6,mesh,nod);
+
+
+
+ nmodif++;
+ }
+ FIter_delete(fit);
+
+ //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$MAJ des refs
+ fit = M_faceIter(mesh);
+ while ((pface = FIter_next(fit))) {
+ assert(!pface->deleted);
+ int num = F_numRegions(pface);
+ if(!num) {
+ printf("face %p dim %d\n",(void*)pface,GEN_type(pface->g));
+ M_removeFace(mesh,pface);
+ continue;
+ }
+ int dim = GEN_type(pface->g);
+ if(dim == 2) {
+ int num = F_numRegions(pface);
+ if(num == 2) {
+ //puts("enlever la ref");
+ pRegion pr = F_region(pface,0);
+ // pGEntity pg = EN_whatIn(pface);
+ pGEntity pgr = EN_whatIn(pr);
+ int tagr = GEN_tag(pgr);
+ int dimr = GEN_type(pgr);
+ if(dimr==3) {
+ pface->g = (pGEntity) GM_regionByTag(mesh->model,tagr);
+ assert( GEN_type(pface->g)==3);
+ } else {
+ printf("----pbs faces**** %d\n",dim);
+ }
+
+ } else if(!num) {
+ M_removeFace(mesh,pface);
+ }
+ if(!(F_numRegions(pface)==1 || GEN_type(pface->g)!=2)) {
+ printf("face %p %d %d %d\n",(void*)pface,F_numRegions(pface),GEN_type(pface->g),pface->deleted);
+ }
+ assert(F_numRegions(pface)==1 || GEN_type(pface->g)!=2 || pface->deleted);
+ }
+ }
+ FIter_delete(fit);
+ EIter eit = M_edgeIter(mesh);
+ pEdge ped;
+ while ((ped = EIter_next(eit))) {
+ int num = E_numFaces(ped);
+ if(!num) {
+ printf("edge dim %d\n",GEN_type(ped->g));
+ M_removeEdge(mesh,ped);
+ continue;
+ }
+
+ }
+ EIter_delete(eit);
+ //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ End MAJ des refs
+
+
+ } while (nmodif);
+
+ }
+
+ void PeriodicInterfaceMigration(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove,
+ pMeshDataId tagTransfo,MDB_DataExchanger &de,
+ MDB_DataExchangerPeriodic &deperiodic) {
+
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+
+ /* 1) marked vertex*/
+ MarkPeriodicEltVertex(mesh,tagElt,tagMove);
+
+ /* 2) move elements*/
+ if(dim==2) MovePeriodicTriangles(mesh,tagElt,tagMove,tagTransfo,de,deperiodic);
+ else MovePeriodicTetras(mesh,tagElt,tagMove,tagTransfo,de,deperiodic);
+
+ /* 3) delete vertex*/
+ VertexDelete(mesh,tagMove,tagTransfo);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ int EltMoveInverse(const int dim,const pVertex* nod,pMeshDataId tagMove,std::vector<int> *vecttransfo) {
+ pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+ int transformation = 0;
+
+ for(int i=0 ; i<(dim+1) ; i++) {
+ void *temp_ptr;
+ int isPeriodic = EN_getDataPtr((pEntity) nod[i] , tagPeriodic, &temp_ptr);
+ if(!isPeriodic) continue;
+ //printf("test nod %d)\n",EN_id((pEntity) nod[i]));
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+ unsigned int j=0;
+ for(j=0 ; j<(*recup).size() ; j++) {
+ std::vector<int> transfo = (*recup)[j].first;
+ unsigned int kk=0;
+ for(kk = 0 ; kk<transfo.size() ; kk++) {
+ if( transfo[kk]> 0) break;
+ }
+ if(kk!=transfo.size()) continue;
+ //printf("on peut eventuellement le bouge par %d %d (point %d)\n",transfo[0],transfo[1],EN_id((pEntity) (*recup)[j].second));
+ pVertex pImg = (*recup)[j].second;
+ int move;
+ int isMove = EN_getDataInt((pEntity) pImg ,tagMove, &move);
+ assert(isMove);
+ if(move==10 || move==1) continue;
+ //printf("on teste de bouger sur le point %d (%d)\n",EN_id((pEntity) (*recup)[j].second),move);
+ int k=i+1;
+ for(k=i+1 ; k<(dim+1) ; k++) {
+ void *temp_ptr2;
+ int isPeriodic2 = EN_getDataPtr((pEntity) nod[k] , tagPeriodic, &temp_ptr2);
+ if(!isPeriodic2) continue;
+ //printf("on teste le point %d\n",EN_id((pEntity) nod[k]));
+ std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+ unsigned int j2=0;
+ for(j2=0 ; j2<(*recup2).size() ; j2++) {
+ std::vector<int> transfo2 = (*recup2)[j2].first;
+ assert(transfo2.size()==transfo.size());
+ unsigned int k2=0;
+ for(k2 = 0 ; k2<transfo2.size() ; k2++) {
+ if( transfo2[k2] != transfo[k2]) break;
+ }
+ if(k2!=transfo2.size()) continue;
+ pVertex pImg2 = (*recup2)[j2].second;
+ int move2;
+ int isMove2 = EN_getDataInt((pEntity) pImg2 ,tagMove, &move2);
+ assert(isMove2);
+ //printf("img %d (%d)\n",EN_id((pEntity) pImg2),move2);
+ if(move2==10 || move2==1) break;
+ }
+ if(j2!=(*recup2).size()) break;//si on est arrive au bout de la boucle : ce noeud est ok on passe au suivant
+ }
+ if(k==(dim+1)) { //on peut bouger
+ transformation = 1;
+ //for(int kv=0 ; kv<transfo.size() ; kv++)
+ (*vecttransfo) = transfo;
+ break;
+ }
+ }
+ if(j!=(*recup).size()) break;//on peut bouger
+ }
+ return transformation;
+ }
+
+
+
+
+
+ void MovePeriodicTetrasInverse(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove, MDB_DataExchanger &de,
+ MDB_DataExchangerPeriodic &deperiodic) {
+
+ int nmodif = 0;
+ FIter fit;
+ pFace pface;
+
+ do {
+ printf("Inverse $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ while : nb modif = %d\n",nmodif);
+ // //if(nmodif) break;
+ nmodif = 0;
+
+ fit = M_faceIter(mesh);
+ while ((pface = FIter_next(fit))) {
+
+ if(pface->deleted) continue;
+ pVertex p[3];
+ pface->getNodes(p);
+ int move1,move2,move3;
+ int isMove1 = EN_getDataInt((pEntity) p[0] ,tagMove, &move1);
+ int isMove2 = EN_getDataInt((pEntity) p[1] ,tagMove, &move2);
+ int isMove3 = EN_getDataInt((pEntity) p[2] ,tagMove, &move3);
+ assert(isMove1 && isMove2 && isMove3);
+ if(!(move1 == 1 || move1 == 10 || move2==1 || move2 == 10 || move3==1 || move3 == 10 )) continue;
+ if(F_numRegions(pface)==2) continue;
+
+ pRegion pr = F_region(pface,0);
+ assert(pr);
+ pVertex nod[4];
+ pr->getNodes(nod);
+
+ int tmp;
+ int isChange = EN_getDataInt((pEntity) pr , tagElt, &tmp);
+ if(!isChange) continue;
+
+ //printf("test face ------------- : %d (%d) -- %d (%d) -- %d(%d)\n",EN_id((pEntity)p[0]),move1,
+ // EN_id((pEntity)p[1]),move2,
+ // EN_id((pEntity)p[2]),move3);
+
+ //printf("tet : %d %d %d %d\n",EN_id((pEntity)nod[0]),EN_id((pEntity)nod[1]),
+ // EN_id((pEntity)nod[2]),EN_id((pEntity)nod[3]));
+ //printf("tet face : %p %p %p %p\n",pr->f1,pr->f2,pr->f3,pr->f4);
+
+ //test si on peut bouger le tetra issu de cette face
+ std::vector<int> vecttransfo;
+ int transformation = EltMoveInverse(3,nod,tagMove,&vecttransfo);
+ //printf("on bouge ? %d\n",transformation);
+ if(!transformation) continue;
+
+
+ //Orientation!!!!!!
+
+ pVertex nodnew[4];
+ VertexMove(4,mesh,nod,vecttransfo,tagMove,nodnew,deperiodic);
+ // printf("tetnew : %d %d %d %d\n",EN_id((pEntity)nodnew[0]),EN_id((pEntity)nodnew[1]),
+ // EN_id((pEntity)nodnew[2]),EN_id((pEntity)nodnew[3]));
+ //
+ //creation des edges
+ EdgeMove(6,mesh,nod,nodnew);
+
+ //creation/delete des triangles
+ for(int i=0 ; i<4 ; i++) {
+ pVertex nodtmp[3];
+ switch(i) {
+ case 0 :
+ nodtmp[0] = nodnew[0];
+ nodtmp[1] = nodnew[1];
+ nodtmp[2] = nodnew[2];
+ break;
+ case 1 :
+ nodtmp[0] = nodnew[0];
+ nodtmp[1] = nodnew[1];
+ nodtmp[2] = nodnew[3];
+ break;
+ case 2 :
+ nodtmp[0] = nodnew[1];
+ nodtmp[1] = nodnew[2];
+ nodtmp[2] = nodnew[3];
+ break;
+ case 3 :
+ nodtmp[0] = nodnew[0];
+ nodtmp[1] = nodnew[2];
+ nodtmp[2] = nodnew[3];
+ break;
+ }
+ TriangleMove(mesh,pface,nodtmp);
+ }
+
+ TetraMove(mesh,pr,nodnew);
+
+ int is = EN_getDataInt((pEntity) pr , tagElt, &tmp);
+ assert(is);
+ EN_deleteData((pEntity) pr , tagElt);
+ M_removeRegion(mesh,pr);
+
+ TriangleDelete(mesh,nod);
+ EdgeDelete(6,mesh,nod);
+
+ nmodif++;
+ }
+ FIter_delete(fit);
+ } while (nmodif);
+
+ //MAJ des refs
+ fit = M_faceIter(mesh);
+ while ((pface = FIter_next(fit))) {
+ assert(!pface->deleted);
+ int num = F_numRegions(pface);
+ if(!num) {
+ printf("face %p dim %d\n",(void*)pface,GEN_type(pface->g));
+ M_removeFace(mesh,pface);
+ continue;
+ }
+ int dim = GEN_type(pface->g);
+ if(dim == 2) {
+ int num = F_numRegions(pface);
+ if(num == 2) {
+ //puts("enlever la ref");
+ pRegion pr = F_region(pface,0);
+ // pGEntity pg = EN_whatIn(pface);
+ pGEntity pgr = EN_whatIn(pr);
+ int tagr = GEN_tag(pgr);
+ int dimr = GEN_type(pgr);
+ if(dimr==3) {
+ pface->g = (pGEntity) GM_regionByTag(mesh->model,tagr);
+ assert( GEN_type(pface->g)==3);
+ } else {
+ printf("----pbs faces**** %d\n",dim);
+ }
+
+ } else if(!num) {
+ M_removeFace(mesh,pface);
+ }
+ if(!(F_numRegions(pface)==1 || GEN_type(pface->g)!=2)) {
+ printf("face %p %d %d %d\n",(void*)pface,F_numRegions(pface),GEN_type(pface->g),pface->deleted);
+ }
+ assert(F_numRegions(pface)==1 || GEN_type(pface->g)!=2 || pface->deleted);
+ }
+ }
+ FIter_delete(fit);
+ EIter eit = M_edgeIter(mesh);
+ pEdge ped;
+ while ((ped = EIter_next(eit))) {
+ int num = E_numFaces(ped);
+ if(!num) {
+ printf("edge dim %d\n",GEN_type(ped->g));
+ M_removeEdge(mesh,ped);
+ continue;
+ }
+
+ }
+ EIter_delete(eit);
+ }
+
+
+ void GroupPeriodicTetra(pMesh mesh, MDB_DataExchanger &de,
+ MDB_DataExchangerPeriodic &deperiodic) {
+
+ pMeshDataId tagMove = MD_newMeshDataId("TagMovePeriodic");
+ pMeshDataId tagElt = MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+
+ int maxiter = 5;
+ int iter = 1;
+ while(MarkGroupPeriodicTets(mesh,tagElt,tagMove) && iter++ < maxiter) {
+ printf("group iter %d\n",iter-1);
+ /* 1) marked vertex*/
+ MarkPeriodicEltVertex(mesh,tagElt,tagMove);
+
+ /* 2) move elements*/
+ MovePeriodicTetrasInverse(mesh,tagElt,tagMove,de,deperiodic);
+
+ /* 3) delete vertex*/
+ VertexDelete(mesh,tagMove,tagMove);
+
+ }
+ MD_deleteMeshDataId(tagMove);
+ MD_deleteMeshDataId(tagElt);
+
+ return;
+ }
+
+} // End of namespace MAd
diff --git a/Mesh/metisAdaptiveRepart.cc b/Mesh/metisAdaptiveRepart.cc
new file mode 100644
index 0000000..a16e228
--- /dev/null
+++ b/Mesh/metisAdaptiveRepart.cc
@@ -0,0 +1,293 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifdef PARALLEL
+#ifdef _HAVE_PARMETIS_
+
+#include "mpi.h" // has to be included before "parmetis.h"
+extern "C" {
+#include "parmetis.h"
+}
+#include "autopack.h"
+
+#include "assert.h"
+#include "MeshDataBase.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "ParallelUtils.h"
+
+namespace MAd {
+
+ // -------------------------------------------------------------------
+ void metisAdaptiveRepart(pMesh mesh,pMeshDataId tagElt) {
+
+ int nproc,myrank;
+ MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+ int dim = (mesh->tets.empty()) ? 2 : 3;
+ int NN = (dim == 2) ? mesh->nbTriangles : mesh->nbTets;
+
+ // ------------------------------------------------
+ // Creation of 'tab' which contains the number of elements for each proc
+
+ int *tab = new int[nproc];
+ int sendnum = NN;
+ if(myrank) {
+ MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);
+ } else {
+ MPI_Status status;
+ tab[0] = sendnum;
+ for(int i=1 ; i<nproc ; i++) {
+ MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+ }
+ }
+ MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+
+ // ------------------------------------------------
+ // Creation of 'vtxdist' which contains the starting element id on each proc
+
+ int *vtxdist = new int[nproc+1];
+ int pos = 0;
+ for(int i=0 ; i<=nproc ; i++) {
+ vtxdist[i] = pos;
+ if(i<nproc) pos += tab[i];
+ }
+
+ // ------------------------------------------------
+ // Global numbering of the elements
+
+ int mypos = 0;
+ for(int i=0; i<myrank; i++) mypos += tab[i];
+
+ if(dim==2) {
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ int i=0;
+ while ((pface = FIter_next(fit))) {
+ pface->iD = i + mypos;
+ i++;
+ }
+ FIter_delete(fit);
+ }
+ else if(dim==3){
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ int i=0;
+ while ((pr = RIter_next(rit))) {
+ pr->iD = i + mypos;
+ i++;
+ }
+ RIter_delete(rit);
+ }
+
+ // ------------------------------------------------
+ // Creation of the graph of the mesh
+
+ // --- determine the neighborhood of elements ---
+
+ pMeshDataId tagAdj = MD_newMeshDataId("AdjGlobal");
+ if(dim==2) E_facesAttachId (mesh,tagAdj);
+ else if(dim==3) F_regionsAttachId(mesh,tagAdj);
+
+ // --- count the adjencies of elements ---
+
+ int *xadj = new int[NN + 1]; // xadj[i] = xadj[i-1] + nb adjencies of element 'i'
+ xadj[0] = 0;
+
+ int totCount = 0;
+
+ if(dim==2) {
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ int i=0;
+ while ((pface = FIter_next(fit))) {
+ int nbAdj = 0;
+ assert(!pface->deleted);
+ pface->iD = i + mypos;
+ for(int k=0 ; k<3 ; k++) {
+ pEdge pe = F_edge(pface,k);
+ void* tmpptr;
+ int is = EN_getDataPtr((pEntity) pe , tagAdj,&tmpptr);
+ assert(is);
+ std::vector<int> *recup = (std::vector<int> *) tmpptr;
+ nbAdj+=(*recup).size();
+ }
+ nbAdj -= 3;
+ totCount += nbAdj;
+ xadj[i + 1] = xadj[i] + nbAdj;
+ i++;
+ }
+ FIter_delete(fit);
+ }
+ else if(dim==3){
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ int i=0;
+ while ((pr = RIter_next(rit))) {
+ int nbAdj = 0;
+ for(int k=0 ; k<4 ; k++) {
+ pFace pface = R_face(pr,k);
+ void* tmpptr;
+ int is = EN_getDataPtr((pEntity) pface , tagAdj,&tmpptr);
+ assert(is);
+ std::vector<int> *recup = (std::vector<int> *) tmpptr;
+ nbAdj+=(*recup).size();
+ }
+ nbAdj -= 4;
+ totCount += nbAdj;
+ xadj[i + 1] = xadj[i] + nbAdj;
+ i++;
+ }
+ RIter_delete(rit);
+ }
+
+ // --- determine the adjencies ---
+
+ int *adjncy = new int[totCount + 1];
+
+ int count = 0;
+ if(dim==2) {
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ int i=0;
+ while ((pface = FIter_next(fit))) {
+ assert(!pface->deleted);
+ for(int k=0 ; k<3 ; k++) {
+ pEdge pe = F_edge(pface,k);
+ void* tmpptr;
+ int is = EN_getDataPtr((pEntity) pe , tagAdj,&tmpptr);
+ assert(is);
+ std::vector<int> *recup = (std::vector<int> *) tmpptr;
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+ int iDrecup = (*recup)[j];
+ if(iDrecup != pface->iD)
+ adjncy[count++] = iDrecup;
+ }
+ }
+ i++;
+ assert(count==(xadj[i]));
+ }
+ FIter_delete(fit);
+ }
+ else {
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ int i=0;
+ while ((pr = RIter_next(rit))) {
+ assert(!pr->deleted);
+ for(int k=0 ; k<4 ; k++) {
+ pFace pface = R_face(pr,k);
+ void* tmpptr;
+ int is = EN_getDataPtr((pEntity) pface , tagAdj,&tmpptr);
+ assert(is);
+ std::vector<int> *recup = (std::vector<int> *) tmpptr;
+ for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+ int iDrecup = (*recup)[j];
+ if(iDrecup != pr->iD)
+ adjncy[count++] = iDrecup;
+ }
+ }
+ i++;
+ assert(count==(xadj[i]));
+ }
+ RIter_delete(rit);
+ }
+
+ // ------------------------------------------------
+ // Call ParMetis to adapt the graph
+
+ int wgtflag = 0;
+ int numflag = 0;
+ int ncon = 1;
+ float itr = 1000.0;
+ int options[1]; options[0] = 0;
+ int edgecut = 0;
+ float *tpwgts, ubvec[1];
+ tpwgts = (float *) malloc((nproc * ncon) * sizeof(float));
+ for (int i=0; i<nproc*ncon; i++) tpwgts[i] = 1.0/(float)(nproc);
+ ubvec[0] = 1.05;
+ MPI_Comm comm = MPI_COMM_WORLD;
+ int *partitionVector = new int[NN]; // ParMetis output: will contain the destinations of the elements
+ ParMETIS_V3_AdaptiveRepart(vtxdist, xadj, adjncy, NULL, NULL, NULL,&wgtflag,
+ &numflag,&ncon,&nproc,tpwgts, ubvec,&itr,
+ options,&edgecut, partitionVector,&comm);
+
+ /* ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, NULL, NULL,&wgtflag,
+ &numflag,&ncon,&nproc,tpwgts, ubvec,
+ options,&edgecut, partitionVector,&comm);
+ */
+
+ // ------------------------------------------------
+ // Tag elements to be migrated
+
+ if(dim==2) {
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ int num = pface->iD - mypos;
+ int dest = partitionVector[num];
+ if(dest == myrank) continue;
+ EN_attachDataInt((pEntity) pface ,tagElt, dest + 1);
+ }
+ FIter_delete(fit);
+ }
+ else if(dim==3) {
+ RIter rit = M_regionIter(mesh);
+ pRegion pr;
+ while ((pr = RIter_next(rit))) {
+ int num = pr->iD - mypos;
+ int dest = partitionVector[num];
+ if(dest == myrank) continue;
+ EN_attachDataInt((pEntity) pr ,tagElt, dest + 1);
+ }
+ RIter_delete(rit);
+ }
+
+ // ------------------------------------------------
+ // Do some cleaning
+
+ delete [] tab;
+ delete [] vtxdist;
+ delete [] xadj;
+ delete [] partitionVector;
+
+ if(dim==2) {
+ EIter eit = M_edgeIter(mesh);
+ pEdge pe;
+ while ((pe = EIter_next(eit))) {
+ void* tmpptr;
+ int is = EN_getDataPtr((pEntity) pe , tagAdj,&tmpptr);
+ assert(is);
+ EN_deleteData((pEntity) pe,tagAdj);
+ }
+ EIter_delete(eit);
+ } else if(dim==3) {
+ FIter fit = M_faceIter(mesh);
+ pFace pface;
+ while ((pface = FIter_next(fit))) {
+ void* tmpptr;
+ int is = EN_getDataPtr((pEntity) pface , tagAdj,&tmpptr);
+ assert(is);
+ EN_deleteData((pEntity) pface,tagAdj);
+ }
+ FIter_delete(fit);
+ }
+ MD_deleteMeshDataId(tagAdj);
+ }
+
+ // -------------------------------------------------------------------
+}
+
+#endif
+#endif
+
diff --git a/Mesh/metisAdaptiveRepart.h b/Mesh/metisAdaptiveRepart.h
new file mode 100644
index 0000000..98e8e9a
--- /dev/null
+++ b/Mesh/metisAdaptiveRepart.h
@@ -0,0 +1,32 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifdef PARALLEL
+#ifndef H_METISADAPTIVEREPART
+#define H_METISADAPTIVEREPART
+
+#include "MSops.h"
+
+namespace MAd {
+
+#ifdef _HAVE_PARMETIS_
+ //! Repartition (adapt) the graph of the elements over the
+ //! set of processors and attach the destination to the
+ //! elements under the tag 'tagElt' \ingroup parallel
+ extern void metisAdaptiveRepart(pMesh mesh, pMeshDataId tagElt);
+#endif
+
+}
+
+#endif
+#endif
diff --git a/README b/README
new file mode 100755
index 0000000..06b5cb4
--- /dev/null
+++ b/README
@@ -0,0 +1,30 @@
+MAdLib 1.0 - README file.
+
+See the Copyright.txt, License.txt and Credits.txt files for copyright,
+license and authors informations. You should have received a copy of
+these files along with MAdLib. If not, see <http://www.madlib.be/license/>.
+
+Please report bugs and problems to <contrib at madlib.be>.
+
+To compile and install the MAdLib library, simply type
+ ./configure;
+ make;
+ make install;
+
+If you want to compile and install some benchmark executables, type
+ ./configure;
+ make bench;
+ make install-bin;
+
+The documentation is generated and installed automatically with the
+previous compilations if you have Doxygen installed but you can also
+generate it (in doc/) by
+ make doc;
+
+Note that you need a linear system solver for the benchmarks that include
+the global node repositioning algorithm, like 'moveIt/example/tube' (for inst. PETSc)
+and a library to compute the distance to a cloud of points (for inst. ANN)
+for benchmarks including local size fields.
+
+To see what options are available, type
+ ./configure --help
diff --git a/Tutorial/MAdLibInterface.cpp b/Tutorial/MAdLibInterface.cpp
new file mode 100644
index 0000000..aa7764b
--- /dev/null
+++ b/Tutorial/MAdLibInterface.cpp
@@ -0,0 +1,444 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+// -------------------------------------------------------------------
+// Author: Gaetan Compere
+//
+// This file provides an example of an interface to MAdLib as it
+// could be implemented in a physical solver requiring mesh adaptivity.
+// -------------------------------------------------------------------
+
+#include "MAdLibInterface.h"
+using namespace MAd;
+
+// -------------------------------------------------------------------
+// This is an example of a callback function that takes care of a
+// nodal solution when local mesh modifications are applied.
+// This function will be registered by 'MAdLibInterface' and will
+// then be called during every local mesh modification.
+// --------------------------------------------------------------------
+void Solver_CBFunction (pPList before, pPList after, void *data,
+ operationType type, pEntity ppp) {
+
+ // Data can point to the object of type 'MAdLibInterface' for instance,
+ // depending on what pointer was given when registering the callback function
+ // It is not used in this example
+ MAdLibInterface * mi = static_cast<MAdLibInterface *>(data);
+
+ // The data id used to identify the data attached to mesh entities
+ pMeshDataId dataId = MD_lookupMeshDataId("SolutionTag");
+
+ // Do the right manipulation on data according to the mesh modification
+ // that is currently applied
+ switch (type) {
+ case MAd_ESPLIT:
+ // Edge split case:
+ // - 'before' contains the split edge (not deleted yet)
+ // - 'after' contains the two new edges
+ // - 'ppp' contains the new vertex
+ {
+ // find the edge to be deleted
+ void * temp = NULL;
+ pEdge pE = (pEdge) PList_next(before,&temp);
+
+ // get coordinates and data at old nodes
+ double data0 = 0.;
+ pVertex pV0 = E_vertex((pEdge)pE, 0);
+ int gotit0 = EN_getDataDbl((pEntity)pV0, dataId, &data0);
+
+ double data1 = 0.;
+ pVertex pV1 = E_vertex((pEdge)pE, 1);
+ int gotit1 = EN_getDataDbl((pEntity)pV1, dataId, &data1);
+
+ if ( !gotit0 || !gotit1) {
+ printf("Error: one of the nodes has no data attached to\n");
+ throw;
+ }
+
+ // interpolate the data at the new vertex (here linear interpolation)
+ double t = E_linearParams(pE,(pVertex)ppp);
+ double newData = (1.-t) * data0 + t * data1;
+
+ // attach this data to the new vertex
+ EN_attachDataDbl(ppp, dataId, newData);
+ }
+ break;
+ case MAd_ECOLLAPSE:
+ // Edge collapse case:
+ // - 'before' contains the regions (3D) or faces (2D) of the cavity
+ // before the edge collapse (not deleted yet)
+ // - 'after' contains the regions (3D) or faces (2D) of the cavity
+ // after the edge collapse
+ // - 'ppp' contains the vertex to be deleted (not deleted yet)
+ {
+ // remove the data on deleted vertex
+ EN_deleteData(ppp, dataId);
+ }
+ break;
+ case MAd_FSWAP:
+ // Face swap case:
+ // - 'before' contains the regions of the cavity before the face swap (not deleted yet)
+ // - 'after' contains the regions of the cavity after the face swap
+ // - 'ppp' contains the swapped face (not deleted yet)
+ {
+ // nothing to be done for nodal solutions
+ }
+ break;
+ case MAd_ESWAP:
+ // Edge swap case:
+ // - 'before' contains the regions (3D) or faces (2D) of the cavity
+ // before the edge swap (not deleted yet)
+ // - 'after' contains the regions (3D) or faces (2D) of the cavity
+ // after the edge swap
+ // - 'ppp' contains the swapped edge (not deleted yet)
+ {
+ // nothing to be done for nodal solutions
+ }
+ break;
+ default:
+ printf("Error: no callback function should be called with this operation: %d",type);
+ throw;
+ }
+};
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+MAdLibInterface::MAdLibInterface()
+{}
+
+//-----------------------------------------------------------------------------
+MAdLibInterface::~MAdLibInterface()
+{}
+
+//-----------------------------------------------------------------------------
+// Main routine for adaptation
+void MAdLibInterface::adaptMesh()
+{
+ //-----------------------------------------------------
+ // Step 1: Prepare for adaptation
+ //-----------------------------------------------------
+
+ // 1. Delete mesh/solution dependent data in the solver
+ solver->deleteData();
+
+ // 2.A. Build the MAdLib geometrical model.
+ pGModel MAdModel = NULL;
+ GM_create(&MAdModel,"theModel");
+ exportToMAdModel(solver->getModel(), MAdModel);
+
+ // 2.B. Build the MAdLib mesh.
+ pMesh MAdMesh = M_new(MAdModel);
+ exportToMAdMesh(solver->getMesh(), MAdMesh);
+
+ // 3. Transfer solution to the MAdLib mesh as an attached data
+ attachSolutionToMesh(MAdMesh);
+ solver->deallocateSolution();
+
+ // 4. Delete the solver mesh.
+ solver->deleteMesh();
+
+ // 5. Build the size field used in adaptation
+ PWLSField * sizeField = new PWLSField(MAdMesh);
+ buildSizeField(sizeField);
+
+ //-----------------------------------------------------
+ // Step 2: Run the adaptation
+ //-----------------------------------------------------
+
+ // 6.A. Build the adaptation tool
+ MeshAdapter * adapter = new MeshAdapter(MAdMesh,sizeField);
+
+ // 6.B. Register the callback function(s) of the solver
+ adapter->addCallback(Solver_CBFunction,(void*)this);
+
+ // 6.C. Edit the adaptation parameters if necessary
+ adapter->setEdgeLenSqBounds( 1.0/3.0, 3.0 );
+ adapter->setNoSwapQuality( 0.1 );
+ adapter->setSliverQuality( 0.02 );
+ adapter->setSliverPermissionInESplit( true, 10. );
+ adapter->setSliverPermissionInECollapse( true, 0.1 );
+
+ // 6.D. Run the adaptation procedure
+ adapter->run();
+
+ // 6.E. Optional output
+ adapter->printStatistics(std::cout);
+ M_writeMsh(MAdMesh,"adapted_mesh.msh",2);
+
+ // 6.F. Clean the adaptation objects
+ delete adapter;
+ delete sizeField;
+
+ //-----------------------------------------------------
+ // Step 3: Rebuild solver data and mesh
+ //-----------------------------------------------------
+
+ // 7. Rebuild the solver mesh
+ importFromMAdModel(MAdModel, solver->getModel());
+ importFromMAdMesh(MAdMesh, solver->getMesh());
+
+ // 8. Get the solution from the MAdLib mesh
+ solver->allocateSolution();
+ getSolutionFromMesh(MAdMesh);
+
+ // 9. Delete MAdLib mesh
+ delete MAdMesh;
+ delete MAdModel;
+
+ // 10. Build mesh/solution dependent data in the solver
+ solver->allocateAndComputeData();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// Converts a MAdLib mesh into a 'Solver_mesh'
+void MAdLibInterface::importFromMAdMesh(const MAd::pMesh MAdMesh,
+ Solver_mesh * solverMesh)
+{
+ MAdToSolverIds.clear();
+ SolverToMAdIds.clear();
+
+ // --- Mesh dimension ---
+ int dim = M_dim(MAdMesh);
+
+ // --- Mesh size ---
+ int numVertices = M_numVertices(MAdMesh);
+ int numElements;
+ if ( dim == 3 ) numElements = M_numRegions(MAdMesh);
+ if ( dim == 2 ) numElements = M_numFaces(MAdMesh);
+
+ solverMesh->allocate(numVertices,numElements);
+
+ // --- Build vertices ---
+ int solver_Id = 0; // will allow consecutive ids for the solver mesh
+ VIter vit = M_vertexIter(MAdMesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ // get MAdLib mesh id
+ int MAd_Id = EN_id((pEntity)pv);
+
+ // get coordinates
+ double xyz[3];
+ V_coord(pv,xyz);
+
+ // add node in solver mesh
+ solverMesh->addNode(solver_Id,xyz[0],xyz[1],xyz[2]);
+
+ // fill in id's tables
+ MAdToSolverIds[MAd_Id] = solver_Id;
+ SolverToMAdIds[solver_Id] = MAd_Id;
+
+ solver_Id++;
+ }
+ VIter_delete(vit);
+
+ // --- Build elements ---
+ int solver_elem_Id = 0;
+ if (dim==3) {
+ RIter rit = M_regionIter(MAdMesh);
+ while (pRegion pr = RIter_next(rit))
+ {
+ // get list of node id's in the solver mesh
+ int nodes[4];
+ pPList rVerts = R_vertices(pr);
+ void * temp = NULL;
+ int iN = 0;
+ while ( pVertex pv = (pVertex)PList_next(rVerts,&temp) )
+ {
+ int MAd_Id = EN_id((pEntity)pv);
+ nodes[iN++] = MAdToSolverIds[MAd_Id];
+ }
+ PList_delete(rVerts);
+
+ // add the element to the solver mesh
+ solverMesh->addElement(solver_elem_Id, nodes);
+ solver_elem_Id++;
+ }
+ RIter_delete(rit);
+ }
+ else if (dim==2) {
+ FIter fit = M_faceIter(MAdMesh);
+ while (pFace pf = FIter_next(fit))
+ {
+ // get list of node id's in the solver mesh
+ int nodes[3];
+ pPList fVerts = F_vertices(pf,1);
+ void * temp = NULL;
+ int iN = 0;
+ while ( pVertex pv = (pVertex)PList_next(fVerts,&temp) )
+ {
+ int MAd_Id = EN_id((pEntity)pv);
+ nodes[iN++] = MAdToSolverIds[MAd_Id];
+ }
+ PList_delete(fVerts);
+
+ // add the element to the solver mesh
+ solverMesh->addElement(solver_elem_Id, nodes);
+ solver_elem_Id++;
+ }
+ FIter_delete(fit);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Converts a 'Solver_mesh' into a MAdLib mesh
+void MAdLibInterface::exportToMAdMesh(const Solver_mesh * solverMesh,
+ MAd::pMesh MAdMesh)
+{
+ // --- Build the vertices ---
+ MAdToSolverIds.clear();
+ SolverToMAdIds.clear();
+ int nVerts = solverMesh->nVertices();
+ const double ** xyz = solverMesh->getCoordinates();
+ for (int iV=0; iV < nVerts; iV++) {
+ MAdMesh->add_point(iV+1,xyz[iV][0],xyz[iV][1],xyz[iV][2]);
+ SolverToMAdIds[iV] = iV+1;
+ MAdToSolverIds[iV+1] = iV;
+ }
+
+ // --- Build the elements ---
+ int dim = solverMesh->getDim();
+ int nElems = solverMesh->nElements();
+ if (dim==3)
+ {
+ const int ** elements = solverMesh->getElements();
+ const int * elemGeoTags = solverMesh->getElemGeoTags();
+ for (int iC=0; iC < nElems; iC++) {
+ pGRegion geom = GM_regionByTag(MAdMesh->model,
+ elemGeoTags[iC]);
+ MAdMesh->add_tet(elements[iC][0], elements[iC][1],
+ elements[iC][2], elements[iC][3],
+ (pGEntity)geom);
+ }
+ }
+ else if (dim==2)
+ {
+ const int ** elements = solverMesh->getElements();
+ const int * elemGeoTags = solverMesh->getElemGeoTags();
+ for (int iC=0; iC < nElems; iC++) {
+ pGFace geom = GM_faceByTag(MAdMesh->model,
+ elemGeoTags[iC]);
+ MAdMesh->add_triangle(elements[iC][0], elements[iC][1],
+ elements[iC][2], (pGEntity)geom);
+ }
+ }
+
+ /*
+ Here, the entities of the MAdLib mesh sould be classified
+ on their corresponding geometrical entities, like for boundary
+ faces in 3D for instance. The implementation of this step
+ is highly dependent on the implementation of Solver_mesh and
+ Solver_model so it is up to the reader to add the right
+ instructions here.
+
+ Note that the geometrical entities have been created in the
+ execution of 'exportToMAdModel'. Any mesh entity can be
+ associated to a geometrical entity using the EN_setWhatIn(...)
+ function of the MAdLib mesh interface.
+
+ Note that all the steps involving geometrical entities can be
+ replaced by appropriate constraints on boundary mesh entities
+ (see AdaptInterface.h) but no mesh modification will therefore
+ be applied on the boundaries, which can be problematic for some
+ computations.
+ */
+
+ MAdMesh->classify_unclassified_entities();
+ MAdMesh->destroyStandAloneEntities();
+}
+
+//-----------------------------------------------------------------------------
+// Create in MAdModel all geometrical entities listed in solverModel.
+void MAdLibInterface::exportToMAdModel(const Solver_model * solverModel,
+ MAd::pGModel MAdModel)
+{
+ std::set<std::pair<int,int> > geometry = solverModel->getAllGeoEntities();
+ std::set<std::pair<int,int> >::const_iterator geoIter = geometry.begin();
+ for (; geoIter != geometry.end(); geoIter++) {
+ int dim = (*geoIter).first;
+ int id = (*geoIter).second;
+ GM_entityByTag(MAdModel,dim,id);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Build a field of prescribed edges lengths on the domain.
+void MAdLibInterface::buildSizeField(MAd::PWLSField * sizeField)
+{
+ // First option: keep actual edges lengths
+ sizeField->setCurrentSize();
+
+ // Second option: compute it from solver functions
+ VIter vit = M_vertexIter(sizeField->getMesh());
+ while (pVertex pv = VIter_next(vit))
+ {
+ // get solver point id
+ int MAd_Id = EN_id((pEntity)pv);
+ int solver_Id = MAdToSolverIds[MAd_Id];
+
+ // get the edge length prescribed by the solver
+ double length = solver->prescribedEdgeLength(solver_Id);
+
+ // fill in the size field
+ sizeField->setSize((pEntity)pv, length);
+ }
+ VIter_delete(vit);
+}
+
+//-----------------------------------------------------------------------------
+void MAdLibInterface::attachSolutionToMesh(MAd::pMesh MAdMesh)
+{
+ // Get the solution database. Here we assume that it is a nodal solution.
+ const Solver_solution * solution = solver->getSolution();
+
+ // The data id used to identify the data attached to mesh entities
+ pMeshDataId dataId = MD_lookupMeshDataId("SolutionTag");
+
+ VIter vit = M_vertexIter(MAdMesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ // get solver point id
+ int MAd_Id = EN_id((pEntity)pv);
+ int solver_Id = MAdToSolverIds[MAd_Id];
+
+ double data = (*solution)[solver_Id];
+
+ // attach data to the mesh vertex
+ EN_attachDataDbl((pEntity)pv,dataId,data);
+ }
+ VIter_delete(vit);
+}
+
+//-----------------------------------------------------------------------------
+void MAdLibInterface::getSolutionFromMesh(MAd::pMesh MAdMesh)
+{
+ // Get the solution database. Here we assume that it is a nodal solution.
+ Solver_solution * solution = solver->getSolution();
+
+ // The data id used to identify the data attached to mesh entities
+ pMeshDataId dataId = MD_lookupMeshDataId("SolutionTag");
+
+ VIter vit = M_vertexIter(MAdMesh);
+ while (pVertex pv = VIter_next(vit))
+ {
+ // get solver point id
+ pPoint pp = V_point(pv);
+ int MAdId = P_id(pp);
+ int solver_Id = MAdToSolverIds[MAdId];
+
+ // get attached data and delete it
+ double data;
+ EN_getDataDbl((pEntity)pv,dataId,&data);
+ EN_deleteData((pEntity)pv,dataId);
+
+ *(*solution)[solver_Id] = data;
+ }
+ VIter_delete(vit);
+}
+
+//-----------------------------------------------------------------------------
diff --git a/Tutorial/MAdLibInterface.h b/Tutorial/MAdLibInterface.h
new file mode 100644
index 0000000..c80f187
--- /dev/null
+++ b/Tutorial/MAdLibInterface.h
@@ -0,0 +1,139 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information.
+// You should have received a copy of these files along with MAdLib.
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+// -------------------------------------------------------------------
+// Author: Gaetan Compere
+//
+// This file provides an example of an interface to MAdLib as it
+// could be implemented in a physical solver requiring mesh adaptivity.
+// -------------------------------------------------------------------
+
+#ifndef __MADLIBINTERFACE_H
+#define __MADLIBINTERFACE_H
+
+#include "ModelInterface.h"
+#include "MeshDataBaseInterface.h"
+#include "AdaptInterface.h"
+#include "PWLinearSField.h"
+#include <utility>
+#include <set>
+
+//-----------------------------------------------------------------------------
+// For this example, what is needed in the solver side ?
+//-----------------------------------------------------------------------------
+
+/*
+Solver class containing the solver geometrical model if any.
+ ( Note that all the steps involving geometrical entities can be
+ replaced by appropriate constraints on boundary mesh entities
+ (see AdaptInterface.h) but no mesh modification will therefore
+ be applied on the boundaries, which can be problematic for some
+ computations. )
+*/
+class Solver_model
+{
+public:
+ void addGeoEntity(int dim, int id);
+ std::set<std::pair<int,int> > getAllGeoEntities() const;
+ // return a set of pairs(dimension,id)
+ // each pair representing a geometric entity.
+};
+
+/*
+ Solver class containing the solver mesh
+*/
+class Solver_mesh
+{
+public:
+ void allocate (int nNodes, int nElements) {}
+ void addNode (int id, double x, double y, double z) {}
+ void addElement (int id, int * nodes) {}
+ int getDim() const {return -1;}
+ int nVertices() const {return -1;}
+ int nElements() const {return -1;}
+ const double ** getCoordinates() const {return NULL;}
+ const int ** getElements() const {return NULL;}
+ const int * getElemGeoTags() const {return NULL;}
+};
+
+/*
+ Solver solution. We assume a nodal solution but the current example can be
+ easily extended to other discretizations.
+*/
+class Solver_solution
+{
+public:
+ double * operator[](int i) {return NULL;}
+ const double operator[](int i) const {return 0.;}
+};
+
+/*
+ Solver class containing pointers to solver data, solution and mesh
+*/
+class Solver
+{
+public:
+ Solver_model * getModel() {return model;}
+ Solver_mesh * getMesh() {return mesh;}
+ Solver_solution * getSolution() {return solution;}
+ void deleteMesh() {}
+ void deallocateSolution() {}
+ void allocateSolution() {}
+ // optional functions:
+ void deleteData() {}
+ void allocateAndComputeData() {}
+ double prescribedEdgeLength(int node) {return 0.;}
+private:
+ Solver_model * model;
+ Solver_mesh * mesh;
+ Solver_solution * solution;
+};
+
+//-----------------------------------------------------------------------------
+// Class interfacing MAdLib with 'Solver'
+//-----------------------------------------------------------------------------
+class MAdLibInterface {
+
+public:
+
+ MAdLibInterface();
+ ~MAdLibInterface();
+
+ void adaptMesh();
+
+private:
+
+ // Mesh to mesh conversion
+ void importFromMAdMesh(const MAd::pMesh, Solver_mesh *);
+ void exportToMAdMesh(const Solver_mesh *, MAd::pMesh);
+ void importFromMAdModel(const MAd::pGModel, Solver_model *);
+ void exportToMAdModel(const Solver_model *, MAd::pGModel);
+
+ // Size field construction
+ void buildSizeField(MAd::PWLSField *);
+
+ // Solution to solution conversion
+ void attachSolutionToMesh(MAd::pMesh);
+ void getSolutionFromMesh(MAd::pMesh);
+
+private:
+
+ // The solver that needs mesh adaptivity
+ Solver * solver;
+
+ // Correspondancy tables between nodal id's in the solver
+ // and in the MAdLib mesh
+ std::map<int,int> MAdToSolverIds;
+ std::map<int,int> SolverToMAdIds;
+};
+
+//-----------------------------------------------------------------------------
+
+#endif
+
diff --git a/Tutorial/Makefile b/Tutorial/Makefile
new file mode 100644
index 0000000..b32d126
--- /dev/null
+++ b/Tutorial/Makefile
@@ -0,0 +1,53 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../variables
+
+INC = ${MAdLib_INCLUDES}\
+ ${DASH}I$(MAdROOT)/Tutorial\
+ ${DASH}I$(MAdROOT)/Geo\
+ ${DASH}I$(MAdROOT)/Mesh\
+ ${DASH}I$(MAdROOT)/Common\
+ ${DASH}I$(MAdROOT)/Adapt\
+ ${DASH}I$(MAdROOT)/Adapt/constraint\
+ ${DASH}I$(MAdROOT)/Adapt/operator\
+ ${DASH}I$(MAdROOT)/Adapt/output\
+ ${DASH}I$(MAdROOT)/Adapt/quality\
+ ${DASH}I$(MAdROOT)/Adapt/repositioning\
+ ${DASH}I$(MAdROOT)/Adapt/sizeField\
+ ${DASH}I$(MAdROOT)/Adapt/utils
+
+CXXFLAGS = ${OPTIM} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = MAdLibInterface.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+.cc${OBJEXT}:
+ ${CXX} ${CXXFLAGS} ${DASH}c $< ${DASH}o $@
+
+build: ${OBJ}
+
+clean:
+ ${RM} */*.o *.o *.obj
+
+purge:
+
+depend:
+ (sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+ ${CXX} -MM ${CXXFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+ ) > Makefile.new
+ cp Makefile Makefile.bak
+ cp Makefile.new Makefile
+ rm -f Makefile.new
\ No newline at end of file
diff --git a/configure b/configure
new file mode 100755
index 0000000..5dc1d33
--- /dev/null
+++ b/configure
@@ -0,0 +1,7596 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.63 for MAdLib 1.2.3.
+#
+# Report bugs to <contrib at madlib.be>.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+ if (eval ":") 2>/dev/null; then
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+
+ if test $as_have_required = yes && (eval ":
+(as_func_return () {
+ (exit \$1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+ as_lineno_1=\$LINENO
+ as_lineno_2=\$LINENO
+ test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+ test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+ :
+else
+ as_candidate_shells=
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ case $as_dir in
+ /*)
+ for as_base in sh bash ksh sh5; do
+ as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+ done;;
+ esac
+done
+IFS=$as_save_IFS
+
+
+ for as_shell in $as_candidate_shells $SHELL; do
+ # Try only shells that exist, to save several forks.
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+ CONFIG_SHELL=$as_shell
+ as_have_required=yes
+ if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+ (exit $1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+ break
+fi
+
+fi
+
+ done
+
+ if test "x$CONFIG_SHELL" != x; then
+ for as_var in BASH_ENV ENV
+ do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+ done
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+ if test $as_have_required = no; then
+ echo This script requires a shell more modern than all the
+ echo shells that I found on your system. Please install a
+ echo modern shell, or manually run the script under such a
+ echo shell if you do have one.
+ { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+ (exit \$1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+ echo No shell found that supports shell functions.
+ echo Please tell bug-autoconf at gnu.org about your system,
+ echo including any error possibly output before this message.
+ echo This can help us improve future autoconf versions.
+ echo Configuration will now proceed without shell functions.
+}
+
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line after each line using $LINENO; the second 'sed'
+ # does the real work. The second script uses 'N' to pair each
+ # line-number line with the line containing $LINENO, and appends
+ # trailing '-' during substitution so that $LINENO is not a special
+ # case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # scripts with optimization help from Paolo Bonzini. Blame Lee
+ # E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+ case `echo 'x\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ *) ECHO_C='\c';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME='MAdLib'
+PACKAGE_TARNAME='madlib'
+PACKAGE_VERSION='1.2.3'
+PACKAGE_STRING='MAdLib 1.2.3'
+PACKAGE_BUGREPORT='contrib at madlib.be'
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+MAdLib_BENCHDIRS
+MAdLib_INCLUDES
+MAdLib_LIBS
+MAdLib_DIRS
+MAdLib_TMPDIR
+MAdROOT
+MAdLib_DEFS
+LIBEXT
+LINKER
+OPTIM
+FLAGS
+HOSTNAME
+UNAME
+DOXYGEN
+DOX
+EGREP
+GREP
+CXXCPP
+AR
+RANLIB
+CPP
+ac_ct_CXX
+CXXFLAGS
+CXX
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_blas_lapack_prefix
+with_mpi_prefix
+with_autopack_prefix
+with_metis_prefix
+with_parmetis_prefix
+with_gmsh_prefix
+with_occ_prefix
+with_sparskit_prefix
+with_petsc_prefix
+with_parser_prefix
+enable_blas_lapack
+enable_ann
+enable_mathex
+enable_mpi
+enable_metis
+enable_parmetis
+enable_gmm
+enable_gmsh
+enable_occ
+enable_petsc
+enable_parser
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CXX
+CXXFLAGS
+CCC
+CPP
+CXXCPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
+ { (exit 1); exit 1; }; }
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
+ { (exit 1); exit 1; }; }
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
+ { (exit 1); exit 1; }; }
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
+ { (exit 1); exit 1; }; }
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { $as_echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { $as_echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2
+ { (exit 1); exit 1; }; } ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ { $as_echo "$as_me: error: working directory cannot be determined" >&2
+ { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ { $as_echo "$as_me: error: pwd does not report name of working directory" >&2
+ { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2
+ { (exit 1); exit 1; }; }
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures MAdLib 1.2.3 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/madlib]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of MAdLib 1.2.3:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-blas-lapack use Blas/Lapack for linear algebra (default=yes)
+ --enable-ann use ANN library (default=no)
+ --enable-mathex use Mathex library (default=yes)
+ --enable-mpi enable MPI support (default=no)
+ --enable-metis use Metis partitioner (default=no)
+ --enable-parmetis use ParMetis partitioner (default=no)
+ --enable-gmm compile gmm++ linear solvers (default=no)
+ --enable-gmsh use Gmsh geometric model (default=no)
+ --enable-occ use OpenCascade geometric model (through Gmsh)
+ (default=no)
+ --enable-petsc use PETSc if available (default=no)
+ --enable-parser use Parser (restricted, CENAERO, Belgium) if
+ available (default=no)
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-blas-lapack-prefix=PFX
+ prefix where BLAS and LAPACK are installed
+ --with-mpi-prefix=PFX prefix where MPI is installed
+ --with-autopack-prefix=PFX
+ prefix where Autopack is installed
+ --with-metis-prefix=PFX prefix where Metis is installed
+ --with-parmetis-prefix=PFX
+ prefix where ParMetis is installed
+ --with-gmsh-prefix=PFX prefix where Gmsh is installed
+ --with-occ-prefix=PFX prefix where OpenCascade is installed
+ --with-sparskit-prefix=PFX
+ prefix where Sparskit is installed
+ --with-petsc-prefix=PFX prefix where PETSc is installed
+ --with-parser-prefix=PFX
+ prefix where the parser is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CXX C++ compiler command
+ CXXFLAGS C++ compiler flags
+ CPP C preprocessor
+ CXXCPP C++ preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <contrib at madlib.be>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+MAdLib configure 1.2.3
+generated by GNU Autoconf 2.63
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by MAdLib $as_me 1.2.3, which was
+generated by GNU Autoconf 2.63. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args '$ac_arg'"
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) $as_unset $ac_var ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ ac_site_file1=$CONFIG_SITE
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test -r "$ac_site_file"; then
+ { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+# Check whether --with-blas-lapack-prefix was given.
+if test "${with_blas_lapack_prefix+set}" = set; then
+ withval=$with_blas_lapack_prefix; BLAS_LAPACK_PREFIX=$withval
+fi
+
+
+# Check whether --with-mpi-prefix was given.
+if test "${with_mpi_prefix+set}" = set; then
+ withval=$with_mpi_prefix; MPI_PREFIX=$withval
+fi
+
+
+# Check whether --with-autopack-prefix was given.
+if test "${with_autopack_prefix+set}" = set; then
+ withval=$with_autopack_prefix; AUTOPACK_PREFIX=$withval
+fi
+
+
+# Check whether --with-metis-prefix was given.
+if test "${with_metis_prefix+set}" = set; then
+ withval=$with_metis_prefix; METIS_PREFIX=$withval
+fi
+
+
+# Check whether --with-parmetis-prefix was given.
+if test "${with_parmetis_prefix+set}" = set; then
+ withval=$with_parmetis_prefix; PARMETIS_PREFIX=$withval
+fi
+
+
+# Check whether --with-gmsh-prefix was given.
+if test "${with_gmsh_prefix+set}" = set; then
+ withval=$with_gmsh_prefix; GMSH_PREFIX=$withval
+fi
+
+
+# Check whether --with-occ-prefix was given.
+if test "${with_occ_prefix+set}" = set; then
+ withval=$with_occ_prefix; OCC_PREFIX=$withval
+fi
+
+
+# Check whether --with-sparskit-prefix was given.
+if test "${with_sparskit_prefix+set}" = set; then
+ withval=$with_sparskit_prefix; SPARSKIT_PREFIX=$withval
+fi
+
+
+# Check whether --with-petsc-prefix was given.
+if test "${with_petsc_prefix+set}" = set; then
+ withval=$with_petsc_prefix; PETSC_PREFIX=$withval
+fi
+
+
+# Check whether --with-parser-prefix was given.
+if test "${with_parser_prefix+set}" = set; then
+ withval=$with_parser_prefix; PARSER_PREFIX=$withval
+fi
+
+
+# Check whether --enable-blas-lapack was given.
+if test "${enable_blas_lapack+set}" = set; then
+ enableval=$enable_blas_lapack;
+fi
+
+# Check whether --enable-ann was given.
+if test "${enable_ann+set}" = set; then
+ enableval=$enable_ann;
+fi
+
+# Check whether --enable-mathex was given.
+if test "${enable_mathex+set}" = set; then
+ enableval=$enable_mathex;
+fi
+
+# Check whether --enable-mpi was given.
+if test "${enable_mpi+set}" = set; then
+ enableval=$enable_mpi;
+fi
+
+# Check whether --enable-metis was given.
+if test "${enable_metis+set}" = set; then
+ enableval=$enable_metis;
+fi
+
+# Check whether --enable-parmetis was given.
+if test "${enable_parmetis+set}" = set; then
+ enableval=$enable_parmetis;
+fi
+
+# Check whether --enable-gmm was given.
+if test "${enable_gmm+set}" = set; then
+ enableval=$enable_gmm;
+fi
+
+# Check whether --enable-gmsh was given.
+if test "${enable_gmsh+set}" = set; then
+ enableval=$enable_gmsh;
+fi
+
+# Check whether --enable-occ was given.
+if test "${enable_occ+set}" = set; then
+ enableval=$enable_occ;
+fi
+
+# Check whether --enable-petsc was given.
+if test "${enable_petsc+set}" = set; then
+ enableval=$enable_petsc;
+fi
+
+# Check whether --enable-parser was given.
+if test "${enable_parser+set}" = set; then
+ enableval=$enable_parser;
+fi
+
+
+if test "x$enable_ann" != "xyes"; then
+ enable_ann=no;
+fi
+if test "x$enable_mpi" != "xyes"; then
+ enable_mpi=no;
+fi
+if test "x$enable_metis" != "xyes"; then
+ enable_metis=no;
+fi
+if test "x$enable_parmetis" != "xyes"; then
+ enable_parmetis=no;
+fi
+if test "x$enable_gmm" != "xyes"; then
+ enable_gmm=no;
+fi
+if test "x$enable_gmsh" != "xyes"; then
+ enable_gmsh=no;
+ enable_occ=no;
+fi
+if test "x$enable_occ" != "xyes"; then
+ enable_occ=no;
+fi
+if test "x$enable_petsc" != "xyes"; then
+ enable_petsc=no;
+fi
+if test "x$enable_parser" != "xyes"; then
+ enable_parser=no;
+fi
+
+UNAME=`uname`
+HOSTNAME=`hostname`
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:$LINENO: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compiler --version >&5") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compiler -v >&5") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compiler -V >&5") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+if test -z "$ac_file"; then
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_compiler_gnu=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_g=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ CFLAGS=""
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ :
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_g=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_c89=$ac_arg
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:$LINENO: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:$LINENO: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+ if test -n "$CCC"; then
+ CXX=$CCC
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CXX+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+ { $as_echo "$as_me:$LINENO: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CXX" && break
+ done
+fi
+if test -z "$CXX"; then
+ ac_ct_CXX=$CXX
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CXX"; then
+ ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CXX="$ac_prog"
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+ { $as_echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CXX" && break
+done
+
+ if test "x$ac_ct_CXX" = x; then
+ CXX="g++"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CXX=$ac_ct_CXX
+ fi
+fi
+
+ fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:$LINENO: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compiler --version >&5") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compiler -v >&5") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compiler -V >&5") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_compiler_gnu=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GXX=yes
+else
+ GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if test "${ac_cv_prog_cxx_g+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+ ac_cxx_werror_flag=yes
+ ac_cv_prog_cxx_g=no
+ CXXFLAGS="-g"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cxx_g=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ CXXFLAGS=""
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ :
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+ CXXFLAGS="-g"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cxx_g=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+ CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+if test "x${CC}" = "x" -o "x${CXX}" = "x" ; then
+ { { $as_echo "$as_me:$LINENO: error: Could not find required compilers, aborting." >&5
+$as_echo "$as_me: error: Could not find required compilers, aborting." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+if test "x$enable_petsc" != "xno"; then
+
+{ $as_echo "$as_me:$LINENO: checking for main in -lpetsc" >&5
+$as_echo_n "checking for main in -lpetsc... " >&6; }
+if test "${ac_cv_lib_petsc_main+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpetsc -lpetsc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_petsc_main=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_petsc_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_petsc_main" >&5
+$as_echo "$ac_cv_lib_petsc_main" >&6; }
+if test "x$ac_cv_lib_petsc_main" = x""yes; then
+ PETSC="yes"
+fi
+
+ if test "x${PETSC}" = "xyes"; then
+ CXX="mpic++.openmpi"
+ LINKER="mpic++.openmpi"
+ fi
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ :
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ # Broken: success on invalid input.
+continue
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:$LINENO: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ :
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ # Broken: success on invalid input.
+continue
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+LINKER="${CXX}"
+
+FLAGS="-D_FORTIFY_SOURCE=0 -ansi "
+OPTIM="${CXXFLAGS}"
+CXXFLAGS=""
+
+MAdLib_DEFS=""
+
+case "$UNAME" in
+ CYGWIN*)
+ if test "x$enable_cygwin" != "xyes"; then
+ UNAME="${UNAME}-no-cygwin"
+ CC="${CC} -mno-cygwin"
+ CXX="${CXX} -mno-cygwin"
+ LINKER="${LINKER} -mno-cygwin"
+ fi
+ ;;
+esac
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+
+MAdROOT=`pwd`
+MAdLib_TMPDIR="/tmp/$USER/MAdLib"
+MAdLib_DIRS="Common Geo Mesh Adapt"
+MAdLib_LIBS="-L${MAdROOT}/lib -lMAdLib"
+MAdLib_INCLUDES=""
+MAdLib_BENCHDIRS="Benchmarks/checkMesh Benchmarks/meshInfo Benchmarks/optimize Benchmarks/moveIt"
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for main in -lm" >&5
+$as_echo_n "checking for main in -lm... " >&6; }
+if test "${ac_cv_lib_m_main+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_m_main=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_m_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_m_main" >&5
+$as_echo "$ac_cv_lib_m_main" >&6; }
+if test "x$ac_cv_lib_m_main" = x""yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+
+if test "x$enable_gmm" != "xno"; then
+ { $as_echo "$as_me:$LINENO: checking for Contrib/gmm/gmm.h" >&5
+$as_echo_n "checking for Contrib/gmm/gmm.h... " >&6; }
+if test "${ac_cv_file_Contrib_gmm_gmm_h+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ test "$cross_compiling" = yes &&
+ { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+$as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+ { (exit 1); exit 1; }; }
+if test -r "Contrib/gmm/gmm.h"; then
+ ac_cv_file_Contrib_gmm_gmm_h=yes
+else
+ ac_cv_file_Contrib_gmm_gmm_h=no
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_file_Contrib_gmm_gmm_h" >&5
+$as_echo "$ac_cv_file_Contrib_gmm_gmm_h" >&6; }
+if test "x$ac_cv_file_Contrib_gmm_gmm_h" = x""yes; then
+ GMM="yes"
+fi
+
+ if test "x${GMM}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_GMM_"
+ MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/gmm"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_GMM_ 1
+_ACEOF
+
+ BO="${BO} Gmm"
+ echo "********************************************************************"
+ echo " You are building a version of MAdLib that contains the gmm++"
+ echo " linear solvers. Gmm++ is available under the GNU LGPL."
+ echo " To disable gmm++, run configure again with the --disable-gmm"
+ echo " option."
+ echo "********************************************************************"
+ fi
+fi
+
+if test "x$enable_gmsh" != "xno"; then
+ if test "x${GMSH_PREFIX}" != "x"; then
+ LDFLAGS="-L${GMSH_PREFIX} -L${GMSH_PREFIX}/lib ${LDFLAGS}"
+ fi
+ as_ac_File=`$as_echo "ac_cv_file_"${GMSH_PREFIX}/include/gmsh/Gmsh.h"" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for \"${GMSH_PREFIX}/include/gmsh/Gmsh.h\"" >&5
+$as_echo_n "checking for \"${GMSH_PREFIX}/include/gmsh/Gmsh.h\"... " >&6; }
+if { as_var=$as_ac_File; eval "test \"\${$as_var+set}\" = set"; }; then
+ $as_echo_n "(cached) " >&6
+else
+ test "$cross_compiling" = yes &&
+ { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+$as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+ { (exit 1); exit 1; }; }
+if test -r ""${GMSH_PREFIX}/include/gmsh/Gmsh.h""; then
+ eval "$as_ac_File=yes"
+else
+ eval "$as_ac_File=no"
+fi
+fi
+ac_res=`eval 'as_val=${'$as_ac_File'}
+ $as_echo "$as_val"'`
+ { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_File'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
+ GMSH="yes"
+fi
+
+ if test "x${GMSH}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_GMSH_"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_GMSH_ 1
+_ACEOF
+
+ BO="${BO} Gmsh"
+ if test "x${GMSH_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lGmsh"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${GMSH_PREFIX} -L${GMSH_PREFIX}/lib -lGmsh"
+ FLAGS="${FLAGS} -I${GMSH_PREFIX} -I${GMSH_PREFIX}/include"
+ fi
+ echo "********************************************************************"
+ echo " You are building a version of MAdLib that uses Gmsh and. Gmsh is "
+ echo " available under the GNU GPL."
+ echo " To disable Gmsh, run configure again with"
+ echo " the --disable-gmsh and --disable-gsl options."
+ echo " Note that you should disable Chaco and Metis in Gmsh or add"
+ echo " the corresponding libraries in the current version of MAdLib."
+ echo "********************************************************************"
+ fi
+fi
+
+if test "x$enable_occ" != "xno"; then
+ if test "x${OCC_PREFIX}" != "x"; then
+ LDFLAGS="-L${OCC_PREFIX} -L${OCC_PREFIX}/lib ${LDFLAGS}"
+ fi
+ { $as_echo "$as_me:$LINENO: checking for main in -lTKernel" >&5
+$as_echo_n "checking for main in -lTKernel... " >&6; }
+if test "${ac_cv_lib_TKernel_main+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lTKernel -lTKernel $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_TKernel_main=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_TKernel_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_TKernel_main" >&5
+$as_echo "$ac_cv_lib_TKernel_main" >&6; }
+if test "x$ac_cv_lib_TKernel_main" = x""yes; then
+ OCC="yes"
+fi
+
+ if test "x${OCC}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_OCC_"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_OCC_ 1
+_ACEOF
+
+ BO="${BO} OpenCascade"
+ if test "x${OCC_PREFIX}" != "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -L${OCC_PREFIX}/lib "
+ FLAGS="${FLAGS} -I${OCC_PREFIX}/include"
+ fi
+ # DataExchange (subset; see occ/ros/adm/make/Makefile for more info)
+ MAdLib_LIBS="${MAdLib_LIBS} -lTKSTEP -lTKSTEP209 -lTKSTEPAttr -lTKSTEPBase -lTKIGES -lTKXSBase"
+ # ModelingAlgorithms
+ MAdLib_LIBS="${MAdLib_LIBS} -lTKOffset -lTKFeat -lTKFillet -lTKBool -lTKShHealing"
+ MAdLib_LIBS="${MAdLib_LIBS} -lTKMesh -lTKHLR -lTKBO -lTKPrim -lTKTopAlgo -lTKGeomAlgo"
+ # ModelingData
+ MAdLib_LIBS="${MAdLib_LIBS} -lTKBRep -lTKGeomBase -lTKG3d -lTKG2d"
+ # FoundationClasses
+ MAdLib_LIBS="${MAdLib_LIBS} -lTKAdvTools -lTKMath -lTKernel"
+
+ #MAdLib_LIBS="${MAdLib_LIBS} -lTKAdvTools -lTKBO -lTKBool -lTKBRep -lTKernel -lTKFeat -lTKFillet -lTKG2d -lTKG3d -lTKGeomAlgo -lTKGeomBase -lTKHLR -lTKIGES -lTKMath -lTKMesh -lTKOffset -lTKPrim -lTKShHealing -lTKSTEP209 -lTKSTEP -lTKSTEPAttr -lTKSTEPBase -lTKTopAlgo -lTKXSBase"
+ fi
+fi
+
+if test "x$enable_ann" != "xno"; then
+ { $as_echo "$as_me:$LINENO: checking for Contrib/ANN/include/ANN/ANN.h" >&5
+$as_echo_n "checking for Contrib/ANN/include/ANN/ANN.h... " >&6; }
+if test "${ac_cv_file_Contrib_ANN_include_ANN_ANN_h+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ test "$cross_compiling" = yes &&
+ { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+$as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+ { (exit 1); exit 1; }; }
+if test -r "Contrib/ANN/include/ANN/ANN.h"; then
+ ac_cv_file_Contrib_ANN_include_ANN_ANN_h=yes
+else
+ ac_cv_file_Contrib_ANN_include_ANN_ANN_h=no
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_file_Contrib_ANN_include_ANN_ANN_h" >&5
+$as_echo "$ac_cv_file_Contrib_ANN_include_ANN_ANN_h" >&6; }
+if test "x$ac_cv_file_Contrib_ANN_include_ANN_ANN_h" = x""yes; then
+ ANN="yes"
+fi
+
+ if test "x${ANN}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_ANN_"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_ANN_ 1
+_ACEOF
+
+ BO="${BO} Ann"
+ MAdLib_DIRS="Contrib/ANN ${MAdLib_DIRS}"
+ MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/ANN/include"
+ MAdLib_LIBS="${MAdLib_LIBS} -lMAdANN"
+ FLAGS="${FLAGS} -I${MAdROOT}/Contrib/ANN/include"
+ echo "********************************************************************"
+ echo " You are building a version of MAdLib that uses ANN, the"
+ echo " Approximate Nearest Neighbor library. ANN is available under the"
+ echo " GNU LGPL. To disable ANN, run configure again with the"
+ echo " --disable-ann option."
+ echo "********************************************************************"
+ fi
+fi
+
+if test "x$enable_mathex" != "xno"; then
+ { $as_echo "$as_me:$LINENO: checking for Contrib/mathex/mathex.h" >&5
+$as_echo_n "checking for Contrib/mathex/mathex.h... " >&6; }
+if test "${ac_cv_file_Contrib_mathex_mathex_h+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ test "$cross_compiling" = yes &&
+ { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+$as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+ { (exit 1); exit 1; }; }
+if test -r "Contrib/mathex/mathex.h"; then
+ ac_cv_file_Contrib_mathex_mathex_h=yes
+else
+ ac_cv_file_Contrib_mathex_mathex_h=no
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_file_Contrib_mathex_mathex_h" >&5
+$as_echo "$ac_cv_file_Contrib_mathex_mathex_h" >&6; }
+if test "x$ac_cv_file_Contrib_mathex_mathex_h" = x""yes; then
+ MATHEX="yes"
+fi
+
+ if test "x${MATHEX}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_MATHEX_"
+ MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/mathex"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_MATHEX_ 1
+_ACEOF
+
+ BO="${BO} Mathex"
+ echo "********************************************************************"
+ echo " You are building a version of MAdLib that contains Mathex."
+ echo " Mathex is available under the GNU LGPL. To disable Mathex, run "
+ echo " configure again with the --disable-mathex option."
+ echo "********************************************************************"
+ fi
+fi
+
+if test "x$enable_petsc" != "xno"; then
+ if test "x${PETSC_PREFIX}" != "x"; then
+ LDFLAGS="-L${PETSC_PREFIX} -L${PETSC_PREFIX}/lib ${LDFLAGS}"
+ fi
+ { $as_echo "$as_me:$LINENO: checking for main in -lpetsc" >&5
+$as_echo_n "checking for main in -lpetsc... " >&6; }
+if test "${ac_cv_lib_petsc_main+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpetsc -lpetsc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_petsc_main=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_petsc_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_petsc_main" >&5
+$as_echo "$ac_cv_lib_petsc_main" >&6; }
+if test "x$ac_cv_lib_petsc_main" = x""yes; then
+ PETSC="yes"
+fi
+
+ if test "x${PETSC}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PETSC_"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_PETSC_ 1
+_ACEOF
+
+ BO="${BO} PETSc"
+ if test "x${PETSC_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lpetsc -lpetscksp -lpetscmat -lpetscvec "
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${PETSC_PREFIX} -L${PETSC_PREFIX}/lib -lpetsc -lpetscksp -lpetscmat -lpetscvec "
+ FLAGS="${FLAGS} -I${PETSC_PREFIX} -I${PETSC_PREFIX}/include"
+ fi
+ fi
+fi
+
+if test "x$enable_metis" != "xno"; then
+ if test "x${METIS_PREFIX}" != "x"; then
+ LDFLAGS="-L${METIS_PREFIX} -L${METIS_PREFIX}/lib ${LDFLAGS}"
+ fi
+ { $as_echo "$as_me:$LINENO: checking for main in -lmetis" >&5
+$as_echo_n "checking for main in -lmetis... " >&6; }
+if test "${ac_cv_lib_metis_main+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmetis -lmetis $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_metis_main=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_metis_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_metis_main" >&5
+$as_echo "$ac_cv_lib_metis_main" >&6; }
+if test "x$ac_cv_lib_metis_main" = x""yes; then
+ METIS="yes"
+fi
+
+ if test "x${METIS}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_METIS_"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_METIS_ 1
+_ACEOF
+
+ BO="${BO} Metis"
+ if test "x${METIS_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lmetis"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${METIS_PREFIX} -L${METIS_PREFIX}/lib -lmetis"
+ FLAGS="${FLAGS} -I${METIS_PREFIX} -I${METIS_PREFIX}/include"
+ fi
+ fi
+fi
+
+if test "x$enable_parmetis" != "xno"; then
+ if test "x${PARMETIS_PREFIX}" != "x"; then
+ LDFLAGS="-L${PARMETIS_PREFIX} -L${PARMETIS_PREFIX}/lib ${LDFLAGS}"
+ fi
+ { $as_echo "$as_me:$LINENO: checking for main in -lmetis" >&5
+$as_echo_n "checking for main in -lmetis... " >&6; }
+if test "${ac_cv_lib_metis_main+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmetis -lmetis $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_metis_main=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_metis_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_metis_main" >&5
+$as_echo "$ac_cv_lib_metis_main" >&6; }
+if test "x$ac_cv_lib_metis_main" = x""yes; then
+ METIS="yes"
+fi
+
+ { $as_echo "$as_me:$LINENO: checking for main in -lparmetis" >&5
+$as_echo_n "checking for main in -lparmetis... " >&6; }
+if test "${ac_cv_lib_parmetis_main+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lparmetis -lparmetis $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_parmetis_main=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_parmetis_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_parmetis_main" >&5
+$as_echo "$ac_cv_lib_parmetis_main" >&6; }
+if test "x$ac_cv_lib_parmetis_main" = x""yes; then
+ PARMETIS="yes"
+fi
+
+ if test "x${METIS}" = "xyes"; then
+ if test "x${PARMETIS}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PARMETIS_"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_PARMETIS_ 1
+_ACEOF
+
+ BO="${BO} Parmetis"
+ if test "x${PARMETIS_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lparmetis -lmetis"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${PARMETIS_PREFIX} -L${PARMETIS_PREFIX}/lib -lparmetis -lmetis"
+ FLAGS="${FLAGS} -I${PARMETIS_PREFIX} -I${PARMETIS_PREFIX}/include"
+ fi
+ fi
+ fi
+fi
+
+
+ if test "x${BLAS_LAPACK_PREFIX}" != "x"; then
+ LDFLAGS="-L${BLAS_LAPACK_PREFIX} -L${BLAS_LAPACK_PREFIX}/lib ${LDFLAGS}"
+ fi
+ { $as_echo "$as_me:$LINENO: checking for cblas_dgemm in -lcblas" >&5
+$as_echo_n "checking for cblas_dgemm in -lcblas... " >&6; }
+if test "${ac_cv_lib_cblas_cblas_dgemm+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcblas $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cblas_dgemm ();
+int
+main ()
+{
+return cblas_dgemm ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_cblas_cblas_dgemm=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_cblas_cblas_dgemm=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_cblas_cblas_dgemm" >&5
+$as_echo "$ac_cv_lib_cblas_cblas_dgemm" >&6; }
+if test "x$ac_cv_lib_cblas_cblas_dgemm" = x""yes; then
+ CBLAS="yes" BLAS_LIBS="-lcblas"
+fi
+
+ if test "x${CBLAS}" != "xyes"; then
+ { $as_echo "$as_me:$LINENO: checking for cblas_dgemm in -lcblas" >&5
+$as_echo_n "checking for cblas_dgemm in -lcblas... " >&6; }
+if test "${ac_cv_lib_cblas_cblas_dgemm+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcblas -latlas $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cblas_dgemm ();
+int
+main ()
+{
+return cblas_dgemm ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_cblas_cblas_dgemm=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_cblas_cblas_dgemm=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_cblas_cblas_dgemm" >&5
+$as_echo "$ac_cv_lib_cblas_cblas_dgemm" >&6; }
+if test "x$ac_cv_lib_cblas_cblas_dgemm" = x""yes; then
+ CBLAS="yes" BLAS_LIBS="-lcblas -latlas"
+fi
+
+ fi
+ if test "x${CBLAS}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_BLAS_ 1
+_ACEOF
+
+ BO="${BO} Cblas"
+ else
+ if test "x${GSL}" = "xyes"; then
+ BLAS_LIBS="-lgslcblas"
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_BLAS_ 1
+_ACEOF
+
+ BO="${BO} Cblas"
+ fi
+ fi
+
+if test "x${FM}" = "xyes" -o "x${GSL}" != "xyes"; then
+ { $as_echo "$as_me:$LINENO: checking for ATL_xerbla in -latlas" >&5
+$as_echo_n "checking for ATL_xerbla in -latlas... " >&6; }
+if test "${ac_cv_lib_atlas_ATL_xerbla+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-latlas $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ATL_xerbla ();
+int
+main ()
+{
+return ATL_xerbla ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_atlas_ATL_xerbla=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_atlas_ATL_xerbla=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_atlas_ATL_xerbla" >&5
+$as_echo "$ac_cv_lib_atlas_ATL_xerbla" >&6; }
+if test "x$ac_cv_lib_atlas_ATL_xerbla" = x""yes; then
+ { $as_echo "$as_me:$LINENO: checking for dgemm_ in -lf77blas" >&5
+$as_echo_n "checking for dgemm_ in -lf77blas... " >&6; }
+if test "${ac_cv_lib_f77blas_dgemm_+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lf77blas -latlas $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dgemm_ ();
+int
+main ()
+{
+return dgemm_ ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_f77blas_dgemm_=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_f77blas_dgemm_=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_f77blas_dgemm_" >&5
+$as_echo "$ac_cv_lib_f77blas_dgemm_" >&6; }
+if test "x$ac_cv_lib_f77blas_dgemm_" = x""yes; then
+ BLAS="yes" BLAS_LIBS="${BLAS_LIBS} -lf77blas -latlas"
+fi
+
+fi
+
+ if test "x${BLAS}" != "xyes"; then
+ { $as_echo "$as_me:$LINENO: checking for dgemm_ in -lblas" >&5
+$as_echo_n "checking for dgemm_ in -lblas... " >&6; }
+if test "${ac_cv_lib_blas_dgemm_+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lblas $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dgemm_ ();
+int
+main ()
+{
+return dgemm_ ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_blas_dgemm_=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_blas_dgemm_=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_blas_dgemm_" >&5
+$as_echo "$ac_cv_lib_blas_dgemm_" >&6; }
+if test "x$ac_cv_lib_blas_dgemm_" = x""yes; then
+ BLAS="yes" BLAS_LIBS="${BLAS_LIBS} -lblas"
+fi
+
+ fi
+ if test "x${BLAS}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_BLAS"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_BLAS 1
+_ACEOF
+
+ BO="${BO} Blas"
+ { $as_echo "$as_me:$LINENO: checking for dbdsqr_ in -llapack" >&5
+$as_echo_n "checking for dbdsqr_ in -llapack... " >&6; }
+if test "${ac_cv_lib_lapack_dbdsqr_+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-llapack ${BLAS_LIBS} $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dbdsqr_ ();
+int
+main ()
+{
+return dbdsqr_ ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_lapack_dbdsqr_=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_lapack_dbdsqr_=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_lapack_dbdsqr_" >&5
+$as_echo "$ac_cv_lib_lapack_dbdsqr_" >&6; }
+if test "x$ac_cv_lib_lapack_dbdsqr_" = x""yes; then
+ LAPACK="yes" BLAS_LIBS="-llapack ${BLAS_LIBS}"
+fi
+
+ if test "x${LAPACK}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_LAPACK_"
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_LAPACK"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_LAPACK 1
+_ACEOF
+
+ BO="${BO} Lapack"
+ fi
+ fi
+fi
+
+if test "x${BLAS_LIBS}" != "x"; then
+ if test "x${BLAS_LAPACK_PREFIX}" != "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -L${BLAS_LAPACK_PREFIX} -L${BLAS_LAPACK_PREFIX}/lib ${BLAS_LIBS}"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} ${BLAS_LIBS}"
+ fi
+fi
+
+if test "x$enable_mpi" = "xyes"; then
+ if test "x${MPI_PREFIX}" != "x"; then
+ LDFLAGS="-L${MPI_PREFIX}/lib ${LDFLAGS}"
+ fi
+ { $as_echo "$as_me:$LINENO: checking for main in -lmpi" >&5
+$as_echo_n "checking for main in -lmpi... " >&6; }
+if test "${ac_cv_lib_mpi_main+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmpi $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_mpi_main=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_mpi_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_mpi_main" >&5
+$as_echo "$ac_cv_lib_mpi_main" >&6; }
+if test "x$ac_cv_lib_mpi_main" = x""yes; then
+ MPI="yes"
+fi
+
+ if test "x${MPI}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_MPI_ -DPARALLEL"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_MPI_ 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define PARALLEL 1
+_ACEOF
+
+ BO="${BO} Mpi"
+ echo "********************************************************************"
+ echo "Warning: MAdLib is configured with MPI enabled. It may be necessary"
+ echo "to specify the values of the CXX and LINKER variables."
+ echo "********************************************************************"
+ if test "x${MPI_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lmpi"
+ FLAGS="${FLAGS} -I/usr/include/mpi"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${MPI_PREFIX}/lib -lmpi"
+ FLAGS="${FLAGS} -I${MPI_PREFIX}/include"
+ fi
+ fi
+fi
+
+if test "x$enable_mpi" = "xyes"; then
+ if test "x${AUTOPACK_PREFIX}" != "x"; then
+ LDFLAGS="-L${AUTOPACK_PREFIX}/lib ${LDFLAGS}"
+ fi
+ { $as_echo "$as_me:$LINENO: checking for main in -lautopack" >&5
+$as_echo_n "checking for main in -lautopack... " >&6; }
+if test "${ac_cv_lib_autopack_main+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lautopack $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_autopack_main=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_autopack_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_autopack_main" >&5
+$as_echo "$ac_cv_lib_autopack_main" >&6; }
+if test "x$ac_cv_lib_autopack_main" = x""yes; then
+ AUTOPACK="yes"
+fi
+
+ if test "x${AUTOPACK}" = "xyes"; then
+ BO="${BO} Autopack"
+ if test "x${AUTOPACK_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lautopack"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${AUTOPACK_PREFIX}/lib -lautopack"
+ FLAGS="${FLAGS} -I${AUTOPACK_PREFIX}/include"
+ fi
+ fi
+fi
+
+if test "x$enable_parser" = "xyes"; then
+ if test "x${PARSER_PREFIX}" != "x"; then
+ LDFLAGS="-L${PARSER_PREFIX}/lib ${LDFLAGS}"
+ fi
+ { $as_echo "$as_me:$LINENO: checking for main in -lParser" >&5
+$as_echo_n "checking for main in -lParser... " >&6; }
+if test "${ac_cv_lib_Parser_main+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lParser $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_lib_Parser_main=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_Parser_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_Parser_main" >&5
+$as_echo "$ac_cv_lib_Parser_main" >&6; }
+if test "x$ac_cv_lib_Parser_main" = x""yes; then
+ PARSER="yes"
+fi
+
+ if test "x${PARSER}" = "xyes"; then
+ BO="${BO} Parser"
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PARSER_"
+ cat >>confdefs.h <<\_ACEOF
+#define _HAVE_PARSER_ 1
+_ACEOF
+
+ if test "x${PARSER_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lParser"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${PARSER_PREFIX}/lib -lParser"
+ FLAGS="${FLAGS} -I${PARSER_PREFIX}/include"
+ fi
+ fi
+fi
+
+case "$UNAME" in
+ Darwin*)
+ RANLIB=true
+ AR="libtool -o"
+ LIBEXT=".a"
+ ;;
+ Linux*)
+ RANLIB=true
+ AR="${CXX} -shared -o"
+ LIBEXT=".so"
+ CXXFLAGS="${CXXFLAGS} -fPIC"
+ ;;
+ *)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_AR+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ case $AR in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_AR="$AR" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+AR=$ac_cv_path_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:$LINENO: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "x${AR}" = "x:"; then
+ { { $as_echo "$as_me:$LINENO: error: Could not find the library archiver, aborting." >&5
+$as_echo "$as_me: error: Could not find the library archiver, aborting." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ AR="${AR} ruvs"
+ LIBEXT=".a"
+ ;;
+esac
+
+MAdLib_LIBS="${MAdLib_LIBS} -lm"
+
+case "$UNAME" in
+
+ CYGWIN* | MINGW*)
+ LINKER="${LINKER} -mwindows -Wl,--stack,16777216"
+ if test "x$enable_cygwin" != "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_DLL 1
+_ACEOF
+
+ BO="${BO} NoDll"
+ fi
+ if test "x${OCC}" = "xyes"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lwinspool -lws2_32"
+ fi
+ if test "x$enable_gui" != "xno"; then
+ MAdLib_LIBS="${MAdLib_LIBS} Fltk/Win32Icon.res"
+ fi
+ ;;
+
+ Darwin*)
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_DLL 1
+_ACEOF
+
+ BO="${BO} NoDll"
+ if test "x$enable_universal" = "xyes"; then
+ FLAGS="-arch ppc -arch i386 ${FLAGS}"
+ fi
+ if test "x$enable_gui" = "xno"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -framework ApplicationServices"
+ fi
+ ;;
+
+ AIX*)
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_DLL 1
+_ACEOF
+
+ BO="${BO} NoDll"
+ FLAGS="-D_BSD ${FLAGS}"
+ ;;
+
+ IRIX*)
+ case "${CXX}" in
+ *CC*)
+ FLAGS="-LANG:std -OPT:Olimit=0 -DOLDCINCLUDE ${FLAGS}"
+ AR="${CXX} -ar -o"
+ LINKER="${CXX}"
+ ;;
+ esac
+ ;;
+
+ OSF1*)
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_SOCKLEN_T"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_SOCKLEN_T 1
+_ACEOF
+
+ BO="${BO} NoSocklenT"
+ case "${CXX}" in
+ *cxx*)
+ FLAGS="-D__USE_STD_IOSTREAM ${FLAGS}"
+ ;;
+ esac
+ ;;
+
+ SunOS*)
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_DLL 1
+_ACEOF
+
+ BO="${BO} NoDll"
+ MAdLib_LIBS="${MAdLib_LIBS} -lsocket -lnsl -ldl"
+ ;;
+
+ HP-UX*)
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_DLL 1
+_ACEOF
+
+ BO="${BO} NoDll"
+ ;;
+
+esac
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+ if test "${ac_cv_prog_CXXCPP+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CXXCPP needs to be expanded
+ for CXXCPP in "$CXX -E" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ :
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ # Broken: success on invalid input.
+continue
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+ CXXCPP=$ac_cv_prog_CXXCPP
+else
+ ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:$LINENO: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ :
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ # Broken: success on invalid input.
+continue
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }; }
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ ac_count=`expr $ac_count + 1`
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:$LINENO: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ ac_count=`expr $ac_count + 1`
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_header_stdc=yes
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ eval "$as_ac_Header=yes"
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+ $as_echo "$as_val"'`
+ { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_Header'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:$LINENO: checking size of size_t" >&5
+$as_echo_n "checking size of size_t... " >&6; }
+if test "${ac_cv_sizeof_size_t+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (size_t))) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (size_t))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_hi=$ac_mid; break
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_lo=`expr $ac_mid + 1`
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (size_t))) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (size_t))) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_lo=$ac_mid; break
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_hi=`expr '(' $ac_mid ')' - 1`
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (size_t))) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_hi=$ac_mid
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_size_t=$ac_lo;;
+'') if test "$ac_cv_type_size_t" = yes; then
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (size_t)
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute sizeof (size_t)
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }; }
+ else
+ ac_cv_sizeof_size_t=0
+ fi ;;
+esac
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+static long int longval () { return (long int) (sizeof (size_t)); }
+static unsigned long int ulongval () { return (long int) (sizeof (size_t)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ return 1;
+ if (((long int) (sizeof (size_t))) < 0)
+ {
+ long int i = longval ();
+ if (i != ((long int) (sizeof (size_t))))
+ return 1;
+ fprintf (f, "%ld", i);
+ }
+ else
+ {
+ unsigned long int i = ulongval ();
+ if (i != ((long int) (sizeof (size_t))))
+ return 1;
+ fprintf (f, "%lu", i);
+ }
+ /* Do not output a trailing newline, as this causes \r\n confusion
+ on some platforms. */
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_sizeof_size_t=`cat conftest.val`
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_size_t" = yes; then
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (size_t)
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute sizeof (size_t)
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }; }
+ else
+ ac_cv_sizeof_size_t=0
+ fi
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_sizeof_size_t" >&5
+$as_echo "$ac_cv_sizeof_size_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t
+_ACEOF
+
+
+if test $ac_cv_sizeof_size_t != 4; then
+ if test $ac_cv_sizeof_size_t != 8; then
+ { $as_echo "$as_me:$LINENO: WARNING: Unsupported size of size_t - this may affect FNV hashing." >&5
+$as_echo "$as_me: WARNING: Unsupported size of size_t - this may affect FNV hashing." >&2;}
+ else
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_64BIT_SIZE_T"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_64BIT_SIZE_T 1
+_ACEOF
+
+ BO="${BO} Have64BitSizeT"
+ if test "x${OCC}" = "xyes"; then
+ FLAGS="${FLAGS} -D_OCC64"
+ fi
+ fi
+fi
+
+DOX=""
+# Extract the first word of "doxygen", so it can be a program name with args.
+set dummy doxygen; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DOX+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DOX"; then
+ ac_cv_prog_DOX="$DOX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DOX=""yes""
+ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_DOX" && ac_cv_prog_DOX=""no""
+fi
+fi
+DOX=$ac_cv_prog_DOX
+if test -n "$DOX"; then
+ { $as_echo "$as_me:$LINENO: result: $DOX" >&5
+$as_echo "$DOX" >&6; }
+else
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+if test "x${DOX}" = "xyes"; then
+ DOXYGEN="doxygen"
+else
+ DOXYGEN=""
+fi
+
+
+ac_config_headers="$ac_config_headers MAdConfig.h:MAdConfig.h.in"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files variables"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) $as_unset $ac_var ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ test "x$cache_file" != "x/dev/null" &&
+ { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ cat confcache >$cache_file
+ else
+ { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line after each line using $LINENO; the second 'sed'
+ # does the real work. The second script uses 'N' to pair each
+ # line-number line with the line containing $LINENO, and appends
+ # trailing '-' during substitution so that $LINENO is not a special
+ # case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # scripts with optimization help from Paolo Bonzini. Blame Lee
+ # E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+ case `echo 'x\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ *) ECHO_C='\c';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by MAdLib $as_me 1.2.3, which was
+generated by GNU Autoconf 2.63. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTION]... [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-autoconf at gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_version="\\
+MAdLib config.status 1.2.3
+configured by $0, generated by GNU Autoconf 2.63,
+ with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2008 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ CONFIG_FILES="$CONFIG_FILES '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ { $as_echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { $as_echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "MAdConfig.h") CONFIG_HEADERS="$CONFIG_HEADERS MAdConfig.h:MAdConfig.h.in" ;;
+ "variables") CONFIG_FILES="$CONFIG_FILES variables" ;;
+
+ *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp=
+ trap 'exit_status=$?
+ { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} ||
+{
+ $as_echo "$as_me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr='
'
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+ { (exit 1); exit 1; }; }
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+ { (exit 1); exit 1; }; }
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+ { (exit 1); exit 1; }; }
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\).*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\).*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+ || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5
+$as_echo "$as_me: error: could not setup config files machinery" >&2;}
+ { (exit 1); exit 1; }; }
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[ ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_t"; then
+ break
+ elif $ac_last_try; then
+ { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;}
+ { (exit 1); exit 1; }; }
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5
+$as_echo "$as_me: error: could not setup config headers machinery" >&2;}
+ { (exit 1); exit 1; }; }
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5
+$as_echo "$as_me: error: invalid tag $ac_tag" >&2;}
+ { (exit 1); exit 1; }; };;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ ac_file_inputs="$ac_file_inputs '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:$LINENO: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$tmp/stdin" \
+ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+ { (exit 1); exit 1; }; } ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ { as_dir="$ac_dir"
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+$as_echo "$as_me: error: cannot create directory $as_dir" >&2;}
+ { (exit 1); exit 1; }; }; }
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+ { (exit 1); exit 1; }; }
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined." >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined." >&2;}
+
+ rm -f "$tmp/stdin"
+ case $ac_file in
+ -) cat "$tmp/out" && rm -f "$tmp/out";;
+ *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+ esac \
+ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+ } >"$tmp/config.h" \
+ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+ { (exit 1); exit 1; }; }
+ if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$tmp/config.h" "$ac_file" \
+ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+ || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5
+$as_echo "$as_me: error: could not create -" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ ;;
+
+
+ esac
+
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;}
+ { (exit 1); exit 1; }; }
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+echo "********************************************************************"
+echo "MAdLib is configured for"
+echo " - OS : ${UNAME} on ${HOSTNAME}"
+echo " - C++ compiler : ${CXX}"
+echo " - Exe linker : ${LINKER}"
+echo " - Lib linker : ${AR}"
+echo " - Optimization : ${OPTIM}"
+echo " - C++ flags : ${CXXFLAGS}"
+echo " - Build options: ${BO}"
+echo "********************************************************************"
+echo "Edit 'variables' and 'MAdConfig.h' to fine-tune the config"
+echo "********************************************************************"
+
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..6ff1238
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,694 @@
+dnl -------------------------------------------------------------------
+dnl MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+
+dnl See the Copyright.txt and License.txt files for license information.
+dnl You should have received a copy of these files along with MAdLib.
+dnl If not, see <http://www.madlib.be/license/>
+
+dnl Please report all bugs and problems to <contrib at madlib.be>
+
+dnl Authors: Gaetan Compere, Jean-Francois Remacle
+dnl -------------------------------------------------------------------
+
+dnl Process this file with autoconf to produce the configure script.
+
+dnl Check that this is the MAdLib source tree
+dnl AC_INIT(Mesh/MeshDataBaseInterface.h)
+AC_INIT([MAdLib], [1.2.3], [contrib at madlib.be])
+
+dnl Parse '--with' command-line options
+AC_ARG_WITH(blas-lapack-prefix,
+ AC_HELP_STRING([--with-blas-lapack-prefix=PFX],
+ [prefix where BLAS and LAPACK are installed]),
+ [BLAS_LAPACK_PREFIX=$withval])
+dnl AC_ARG_WITH(gsl-prefix,
+dnl AC_HELP_STRING([--with-gsl-prefix=PFX],
+dnl [prefix where the GSL is installed]),
+dnl [GSL_PREFIX=$withval])
+AC_ARG_WITH(mpi-prefix,
+ AC_HELP_STRING([--with-mpi-prefix=PFX],
+ [prefix where MPI is installed]),
+ [MPI_PREFIX=$withval])
+AC_ARG_WITH(autopack-prefix,
+ AC_HELP_STRING([--with-autopack-prefix=PFX],
+ [prefix where Autopack is installed]),
+ [AUTOPACK_PREFIX=$withval])
+AC_ARG_WITH(metis-prefix,
+ AC_HELP_STRING([--with-metis-prefix=PFX],
+ [prefix where Metis is installed]),
+ [METIS_PREFIX=$withval])
+AC_ARG_WITH(parmetis-prefix,
+ AC_HELP_STRING([--with-parmetis-prefix=PFX],
+ [prefix where ParMetis is installed]),
+ [PARMETIS_PREFIX=$withval])
+AC_ARG_WITH(gmsh-prefix,
+ AC_HELP_STRING([--with-gmsh-prefix=PFX],
+ [prefix where Gmsh is installed]),
+ [GMSH_PREFIX=$withval])
+AC_ARG_WITH(occ-prefix,
+ AC_HELP_STRING([--with-occ-prefix=PFX],
+ [prefix where OpenCascade is installed]),
+ [OCC_PREFIX=$withval])
+AC_ARG_WITH(sparskit-prefix,
+ AC_HELP_STRING([--with-sparskit-prefix=PFX],
+ [prefix where Sparskit is installed]),
+ [SPARSKIT_PREFIX=$withval])
+AC_ARG_WITH(petsc-prefix,
+ AC_HELP_STRING([--with-petsc-prefix=PFX],
+ [prefix where PETSc is installed]),
+ [PETSC_PREFIX=$withval])
+AC_ARG_WITH(parser-prefix,
+ AC_HELP_STRING([--with-parser-prefix=PFX],
+ [prefix where the parser is installed]),
+ [PARSER_PREFIX=$withval])
+
+dnl Parse '--enable' command line options
+AC_ARG_ENABLE(blas-lapack,
+ AC_HELP_STRING([--enable-blas-lapack],
+ [use Blas/Lapack for linear algebra (default=yes)]))
+AC_ARG_ENABLE(ann,
+ AC_HELP_STRING([--enable-ann],
+ [use ANN library (default=no)]))
+AC_ARG_ENABLE(mathex,
+ AC_HELP_STRING([--enable-mathex],
+ [use Mathex library (default=yes)]))
+dnl AC_ARG_ENABLE(gsl,
+dnl AC_HELP_STRING([--enable-gsl],
+dnl [use GSL as numerical toolkit (default=no)]))
+AC_ARG_ENABLE(mpi,
+ AC_HELP_STRING([--enable-mpi],
+ [enable MPI support (default=no)]))
+AC_ARG_ENABLE(metis,
+ AC_HELP_STRING([--enable-metis],
+ [use Metis partitioner (default=no)]))
+AC_ARG_ENABLE(parmetis,
+ AC_HELP_STRING([--enable-parmetis],
+ [use ParMetis partitioner (default=no)]))
+AC_ARG_ENABLE(gmm,
+ AC_HELP_STRING([--enable-gmm],
+ [compile gmm++ linear solvers (default=no)]))
+AC_ARG_ENABLE(gmsh,
+ AC_HELP_STRING([--enable-gmsh],
+ [use Gmsh geometric model (default=no)]))
+AC_ARG_ENABLE(occ,
+ AC_HELP_STRING([--enable-occ],
+ [use OpenCascade geometric model (through Gmsh) (default=no)]))
+AC_ARG_ENABLE(petsc,
+ AC_HELP_STRING([--enable-petsc],
+ [use PETSc if available (default=no)]))
+AC_ARG_ENABLE(parser,
+ AC_HELP_STRING([--enable-parser],
+ [use Parser (restricted, CENAERO, Belgium) if available (default=no)]))
+
+dnl Disable options when disabled by default and not marked as enabled
+if test "x$enable_ann" != "xyes"; then
+ enable_ann=no;
+fi
+dnl if test "x$enable_gsl" != "xyes"; then
+dnl enable_gsl=no;
+dnl fi
+if test "x$enable_mpi" != "xyes"; then
+ enable_mpi=no;
+fi
+if test "x$enable_metis" != "xyes"; then
+ enable_metis=no;
+fi
+if test "x$enable_parmetis" != "xyes"; then
+ enable_parmetis=no;
+fi
+if test "x$enable_gmm" != "xyes"; then
+ enable_gmm=no;
+fi
+if test "x$enable_gmsh" != "xyes"; then
+ enable_gmsh=no;
+ enable_occ=no;
+fi
+if test "x$enable_occ" != "xyes"; then
+ enable_occ=no;
+fi
+if test "x$enable_petsc" != "xyes"; then
+ enable_petsc=no;
+fi
+if test "x$enable_parser" != "xyes"; then
+ enable_parser=no;
+fi
+
+dnl Get the operating system and machine names
+UNAME=`uname`
+HOSTNAME=`hostname`
+
+dnl Check for default compilers
+AC_PROG_CC
+AC_PROG_CXX
+if test "x${CC}" = "x" -o "x${CXX}" = "x" ; then
+ AC_MSG_ERROR([Could not find required compilers, aborting.])
+fi
+
+dnl Change the compiler if PETSc is used
+if test "x$enable_petsc" != "xno"; then
+ AC_CHECK_LIB(petsc,main,PETSC="yes",[],-lpetsc)
+ if test "x${PETSC}" = "xyes"; then
+ CXX="mpic++.openmpi"
+ LINKER="mpic++.openmpi"
+ fi
+fi
+
+dnl Set preprocessor and linker
+AC_PROG_CPP
+LINKER="${CXX}"
+
+dnl Set default compiler flags
+FLAGS="-D_FORTIFY_SOURCE=0 -ansi "
+OPTIM="${CXXFLAGS}"
+CXXFLAGS=""
+
+dnl Set default definitions
+MAdLib_DEFS=""
+
+dnl Take care of no-cygwin option before doing any other tests
+case "$UNAME" in
+ CYGWIN*)
+ if test "x$enable_cygwin" != "xyes"; then
+ UNAME="${UNAME}-no-cygwin"
+ CC="${CC} -mno-cygwin"
+ CXX="${CXX} -mno-cygwin"
+ LINKER="${LINKER} -mno-cygwin"
+ fi
+ ;;
+esac
+
+dnl Use c++ for all compilation tests
+AC_LANG(C++)
+
+dnl See if we need a .exe extension on executables
+AC_EXEEXT
+
+dnl Locate sources
+MAdROOT=`pwd`
+MAdLib_TMPDIR="/tmp/$USER/MAdLib"
+MAdLib_DIRS="Common Geo Mesh Adapt"
+MAdLib_LIBS="-L${MAdROOT}/lib -lMAdLib"
+MAdLib_INCLUDES=""
+dnl MAdLib_LIBS="-L${MAdROOT}/lib -lMAdAdapt -lMAdMesh -lMAdGeo -lMAdCommon"
+MAdLib_BENCHDIRS="Benchmarks/checkMesh Benchmarks/meshInfo Benchmarks/optimize Benchmarks/moveIt"
+
+dnl Check for standard math library (no rule given if found, so gets
+dnl added to $LIBS, used for further checks)
+AC_CHECK_LIB(m,main)
+
+dnl Check for gmm++ linear solver
+if test "x$enable_gmm" != "xno"; then
+ AC_CHECK_FILE(Contrib/gmm/gmm.h,GMM="yes")
+ if test "x${GMM}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_GMM_"
+ MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/gmm"
+ AC_DEFINE(_HAVE_GMM_)
+ BO="${BO} Gmm"
+ echo "********************************************************************"
+ echo " You are building a version of MAdLib that contains the gmm++"
+ echo " linear solvers. Gmm++ is available under the GNU LGPL."
+ echo " To disable gmm++, run configure again with the --disable-gmm"
+ echo " option."
+ echo "********************************************************************"
+ fi
+fi
+
+dnl Check for Gmsh
+if test "x$enable_gmsh" != "xno"; then
+ if test "x${GMSH_PREFIX}" != "x"; then
+ LDFLAGS="-L${GMSH_PREFIX} -L${GMSH_PREFIX}/lib ${LDFLAGS}"
+ fi
+ AC_CHECK_FILE("${GMSH_PREFIX}/include/gmsh/Gmsh.h",GMSH="yes")
+dnl AC_CHECK_LIB(Gmsh,main,GMSH="yes",[],-lGmsh)
+ if test "x${GMSH}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_GMSH_"
+ AC_DEFINE(_HAVE_GMSH_)
+ BO="${BO} Gmsh"
+ if test "x${GMSH_PREFIX}" = "x"; then
+dnl MAdLib_LIBS="${MAdLib_LIBS} -lGmsh -lgsl"
+ MAdLib_LIBS="${MAdLib_LIBS} -lGmsh"
+ else
+dnl MAdLib_LIBS="${MAdLib_LIBS} -L${GMSH_PREFIX} -L${GMSH_PREFIX}/lib -lGmsh -lgsl"
+ MAdLib_LIBS="${MAdLib_LIBS} -L${GMSH_PREFIX} -L${GMSH_PREFIX}/lib -lGmsh"
+ FLAGS="${FLAGS} -I${GMSH_PREFIX} -I${GMSH_PREFIX}/include"
+ fi
+dnl echo "********************************************************************"
+dnl echo " You are building a version of MAdLib that uses Gmsh and"
+dnl echo " the GNU GSL. Gmsh and the GNU GSL are available under the GNU GPL."
+dnl echo " To disable Gmsh and the GNU GSL, run configure again with"
+dnl echo " the --disable-gmsh and --disable-gsl options."
+dnl echo " Note that you should disable Chaco and Metis in Gmsh or add"
+dnl echo " the corresponding libraries in the current version of MAdLib."
+dnl echo "********************************************************************"
+ echo "********************************************************************"
+ echo " You are building a version of MAdLib that uses Gmsh and. Gmsh is "
+ echo " available under the GNU GPL."
+ echo " To disable Gmsh, run configure again with"
+ echo " the --disable-gmsh and --disable-gsl options."
+ echo " Note that you should disable Chaco and Metis in Gmsh or add"
+ echo " the corresponding libraries in the current version of MAdLib."
+ echo "********************************************************************"
+ fi
+fi
+
+dnl Check for OpenCascade
+if test "x$enable_occ" != "xno"; then
+ if test "x${OCC_PREFIX}" != "x"; then
+ LDFLAGS="-L${OCC_PREFIX} -L${OCC_PREFIX}/lib ${LDFLAGS}"
+ fi
+dnl AC_CHECK_FILE("${OCC_PREFIX}/inc/Geom_Curve.hxx",OCC="yes")
+ AC_CHECK_LIB(TKernel,main,OCC="yes",[],-lTKernel)
+ if test "x${OCC}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_OCC_"
+ AC_DEFINE(_HAVE_OCC_)
+ BO="${BO} OpenCascade"
+ if test "x${OCC_PREFIX}" != "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -L${OCC_PREFIX}/lib "
+ FLAGS="${FLAGS} -I${OCC_PREFIX}/include"
+ fi
+ # DataExchange (subset; see occ/ros/adm/make/Makefile for more info)
+ MAdLib_LIBS="${MAdLib_LIBS} -lTKSTEP -lTKSTEP209 -lTKSTEPAttr -lTKSTEPBase -lTKIGES -lTKXSBase"
+ # ModelingAlgorithms
+ MAdLib_LIBS="${MAdLib_LIBS} -lTKOffset -lTKFeat -lTKFillet -lTKBool -lTKShHealing"
+ MAdLib_LIBS="${MAdLib_LIBS} -lTKMesh -lTKHLR -lTKBO -lTKPrim -lTKTopAlgo -lTKGeomAlgo"
+ # ModelingData
+ MAdLib_LIBS="${MAdLib_LIBS} -lTKBRep -lTKGeomBase -lTKG3d -lTKG2d"
+ # FoundationClasses
+ MAdLib_LIBS="${MAdLib_LIBS} -lTKAdvTools -lTKMath -lTKernel"
+
+ #MAdLib_LIBS="${MAdLib_LIBS} -lTKAdvTools -lTKBO -lTKBool -lTKBRep -lTKernel -lTKFeat -lTKFillet -lTKG2d -lTKG3d -lTKGeomAlgo -lTKGeomBase -lTKHLR -lTKIGES -lTKMath -lTKMesh -lTKOffset -lTKPrim -lTKShHealing -lTKSTEP209 -lTKSTEP -lTKSTEPAttr -lTKSTEPBase -lTKTopAlgo -lTKXSBase"
+ fi
+fi
+
+dnl Check for ANN, the Approximate Nearest Neighbor library
+if test "x$enable_ann" != "xno"; then
+ AC_CHECK_FILE(Contrib/ANN/include/ANN/ANN.h,ANN="yes")
+ if test "x${ANN}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_ANN_"
+ AC_DEFINE(_HAVE_ANN_)
+ BO="${BO} Ann"
+ MAdLib_DIRS="Contrib/ANN ${MAdLib_DIRS}"
+ MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/ANN/include"
+ MAdLib_LIBS="${MAdLib_LIBS} -lMAdANN"
+ FLAGS="${FLAGS} -I${MAdROOT}/Contrib/ANN/include"
+ echo "********************************************************************"
+ echo " You are building a version of MAdLib that uses ANN, the"
+ echo " Approximate Nearest Neighbor library. ANN is available under the"
+ echo " GNU LGPL. To disable ANN, run configure again with the"
+ echo " --disable-ann option."
+ echo "********************************************************************"
+ fi
+fi
+
+dnl Check for Mathex
+if test "x$enable_mathex" != "xno"; then
+ AC_CHECK_FILE(Contrib/mathex/mathex.h,MATHEX="yes")
+ if test "x${MATHEX}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_MATHEX_"
+ MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/mathex"
+ AC_DEFINE(_HAVE_MATHEX_)
+ BO="${BO} Mathex"
+ echo "********************************************************************"
+ echo " You are building a version of MAdLib that contains Mathex."
+ echo " Mathex is available under the GNU LGPL. To disable Mathex, run "
+ echo " configure again with the --disable-mathex option."
+ echo "********************************************************************"
+ fi
+fi
+
+dnl Check for PETSc solvers
+if test "x$enable_petsc" != "xno"; then
+ if test "x${PETSC_PREFIX}" != "x"; then
+ LDFLAGS="-L${PETSC_PREFIX} -L${PETSC_PREFIX}/lib ${LDFLAGS}"
+ fi
+ AC_CHECK_LIB(petsc,main,PETSC="yes",[],-lpetsc)
+ if test "x${PETSC}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PETSC_"
+ AC_DEFINE(_HAVE_PETSC_)
+ BO="${BO} PETSc"
+ if test "x${PETSC_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lpetsc -lpetscksp -lpetscmat -lpetscvec "
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${PETSC_PREFIX} -L${PETSC_PREFIX}/lib -lpetsc -lpetscksp -lpetscmat -lpetscvec "
+ FLAGS="${FLAGS} -I${PETSC_PREFIX} -I${PETSC_PREFIX}/include"
+ fi
+ fi
+fi
+
+dnl Check for Metis partitionner
+if test "x$enable_metis" != "xno"; then
+ if test "x${METIS_PREFIX}" != "x"; then
+ LDFLAGS="-L${METIS_PREFIX} -L${METIS_PREFIX}/lib ${LDFLAGS}"
+ fi
+ AC_CHECK_LIB(metis,main,METIS="yes",[],-lmetis)
+ if test "x${METIS}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_METIS_"
+ AC_DEFINE(_HAVE_METIS_)
+ BO="${BO} Metis"
+ if test "x${METIS_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lmetis"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${METIS_PREFIX} -L${METIS_PREFIX}/lib -lmetis"
+ FLAGS="${FLAGS} -I${METIS_PREFIX} -I${METIS_PREFIX}/include"
+ fi
+ fi
+fi
+
+dnl Check for ParMetis partitionner
+if test "x$enable_parmetis" != "xno"; then
+ if test "x${PARMETIS_PREFIX}" != "x"; then
+ LDFLAGS="-L${PARMETIS_PREFIX} -L${PARMETIS_PREFIX}/lib ${LDFLAGS}"
+ fi
+ AC_CHECK_LIB(metis,main,METIS="yes",[],-lmetis)
+ AC_CHECK_LIB(parmetis,main,PARMETIS="yes",[],-lparmetis)
+ if test "x${METIS}" = "xyes"; then
+ if test "x${PARMETIS}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PARMETIS_"
+ AC_DEFINE(_HAVE_PARMETIS_)
+ BO="${BO} Parmetis"
+ if test "x${PARMETIS_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lparmetis -lmetis"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${PARMETIS_PREFIX} -L${PARMETIS_PREFIX}/lib -lparmetis -lmetis"
+ FLAGS="${FLAGS} -I${PARMETIS_PREFIX} -I${PARMETIS_PREFIX}/include"
+ fi
+ fi
+ fi
+fi
+
+dnl Check for GSL
+dnl if test "x$enable_gsl" != "xno"; then
+dnl if test "x${GSL_PREFIX}" != "x"; then
+dnl LDFLAGS="-L${GSL_PREFIX} -L${GSL_PREFIX}/lib ${LDFLAGS}"
+dnl fi
+dnl AC_CHECK_LIB(gsl,main,GSL="yes",[],-lgslcblas)
+dnl if test "x${GSL}" = "xyes"; then
+dnl MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_GSL_"
+dnl AC_DEFINE(_HAVE_GSL_)
+dnl BO="${BO} Gsl"
+dnl if test "x${GSL_PREFIX}" = "x"; then
+dnl MAdLib_LIBS="${MAdLib_LIBS} -lgsl"
+dnl else
+dnl MAdLib_LIBS="${MAdLib_LIBS} -L${GSL_PREFIX} -L${GSL_PREFIX}/lib -lgsl"
+dnl FLAGS="${FLAGS} -I${GSL_PREFIX} -I${GSL_PREFIX}/include"
+dnl fi
+dnl fi
+dnl fi
+
+dnl Check for C version of BLAS
+ if test "x${BLAS_LAPACK_PREFIX}" != "x"; then
+ LDFLAGS="-L${BLAS_LAPACK_PREFIX} -L${BLAS_LAPACK_PREFIX}/lib ${LDFLAGS}"
+ fi
+ AC_CHECK_LIB(cblas,cblas_dgemm,CBLAS="yes" BLAS_LIBS="-lcblas")
+ if test "x${CBLAS}" != "xyes"; then
+ AC_CHECK_LIB(cblas,cblas_dgemm,CBLAS="yes" BLAS_LIBS="-lcblas -latlas",[],-latlas)
+ fi
+ if test "x${CBLAS}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+ AC_DEFINE(_HAVE_BLAS_)
+ BO="${BO} Cblas"
+ else
+ if test "x${GSL}" = "xyes"; then
+ dnl use unoptimized gsl version
+ BLAS_LIBS="-lgslcblas"
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+ AC_DEFINE(_HAVE_BLAS_)
+ BO="${BO} Cblas"
+ fi
+ fi
+
+dnl Check for Fortran version of blas and lapack (only used when not
+dnl using GSL, or of FourierModel is linked in)
+if test "x${FM}" = "xyes" -o "x${GSL}" != "xyes"; then
+dnl AC_PROG_F77
+dnl case "${F77}" in
+dnl *gfortran*)
+dnl F77LIB="-lgfortran"
+dnl ;;
+dnl *g77*)
+dnl F77LIB="-lg2c"
+dnl ;;
+dnl *)
+dnl F77LIB=""
+dnl ;;
+dnl esac
+dnl LDFLAGS="${LDFLAGS} ${F77LIB}"
+ AC_CHECK_LIB(atlas,ATL_xerbla,
+ AC_CHECK_LIB(f77blas,dgemm_,
+ [BLAS="yes" BLAS_LIBS="${BLAS_LIBS} -lf77blas -latlas"],[],-latlas))
+ if test "x${BLAS}" != "xyes"; then
+ AC_CHECK_LIB(blas,dgemm_,[BLAS="yes" BLAS_LIBS="${BLAS_LIBS} -lblas"])
+ fi
+ if test "x${BLAS}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_BLAS"
+ AC_DEFINE(HAVE_BLAS)
+ BO="${BO} Blas"
+ AC_CHECK_LIB(lapack,dbdsqr_,
+ [LAPACK="yes" BLAS_LIBS="-llapack ${BLAS_LIBS}"],[],${BLAS_LIBS})
+ if test "x${LAPACK}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_LAPACK_"
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_LAPACK"
+ AC_DEFINE(HAVE_LAPACK)
+ BO="${BO} Lapack"
+ fi
+ fi
+fi
+
+if test "x${BLAS_LIBS}" != "x"; then
+ if test "x${BLAS_LAPACK_PREFIX}" != "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -L${BLAS_LAPACK_PREFIX} -L${BLAS_LAPACK_PREFIX}/lib ${BLAS_LIBS}"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} ${BLAS_LIBS}"
+ fi
+fi
+
+dnl Check for MPI
+if test "x$enable_mpi" = "xyes"; then
+ if test "x${MPI_PREFIX}" != "x"; then
+ LDFLAGS="-L${MPI_PREFIX}/lib ${LDFLAGS}"
+ fi
+ AC_CHECK_LIB(mpi,main,MPI="yes")
+ if test "x${MPI}" = "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_MPI_ -DPARALLEL"
+ AC_DEFINE(_HAVE_MPI_)
+ AC_DEFINE(PARALLEL)
+ BO="${BO} Mpi"
+ echo "********************************************************************"
+ echo "Warning: MAdLib is configured with MPI enabled. It may be necessary"
+ echo "to specify the values of the CXX and LINKER variables."
+ echo "********************************************************************"
+ if test "x${MPI_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lmpi"
+ FLAGS="${FLAGS} -I/usr/include/mpi"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${MPI_PREFIX}/lib -lmpi"
+ FLAGS="${FLAGS} -I${MPI_PREFIX}/include"
+ fi
+ fi
+fi
+
+dnl Check for Autopack
+if test "x$enable_mpi" = "xyes"; then
+ if test "x${AUTOPACK_PREFIX}" != "x"; then
+ LDFLAGS="-L${AUTOPACK_PREFIX}/lib ${LDFLAGS}"
+ fi
+ AC_CHECK_LIB(autopack,main,AUTOPACK="yes")
+ if test "x${AUTOPACK}" = "xyes"; then
+ BO="${BO} Autopack"
+ if test "x${AUTOPACK_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lautopack"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${AUTOPACK_PREFIX}/lib -lautopack"
+ FLAGS="${FLAGS} -I${AUTOPACK_PREFIX}/include"
+ fi
+ fi
+fi
+
+dnl Check for Parser
+if test "x$enable_parser" = "xyes"; then
+ if test "x${PARSER_PREFIX}" != "x"; then
+ LDFLAGS="-L${PARSER_PREFIX}/lib ${LDFLAGS}"
+ fi
+ AC_CHECK_LIB(Parser,main,PARSER="yes")
+ if test "x${PARSER}" = "xyes"; then
+ BO="${BO} Parser"
+ MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PARSER_"
+ AC_DEFINE(_HAVE_PARSER_)
+ if test "x${PARSER_PREFIX}" = "x"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lParser"
+ else
+ MAdLib_LIBS="${MAdLib_LIBS} -L${PARSER_PREFIX}/lib -lParser"
+ FLAGS="${FLAGS} -I${PARSER_PREFIX}/include"
+ fi
+ fi
+fi
+
+dnl How to build static libraries?
+dnl Done after every AC_CHECK_LIB, otherwise AC_CHECK_LIB fails-> to be fixed
+case "$UNAME" in
+ Darwin*)
+ RANLIB=true
+ AR="libtool -o"
+ LIBEXT=".a"
+ ;;
+ Linux*)
+ RANLIB=true
+ AR="${CXX} -shared -o"
+ LIBEXT=".so"
+ CXXFLAGS="${CXXFLAGS} -fPIC"
+ ;;
+ *)
+ AC_PROG_RANLIB
+ AC_PATH_PROG(AR, ar)
+ if test "x${AR}" = "x:"; then
+ AC_MSG_ERROR([Could not find the library archiver, aborting.])
+ fi
+ AR="${AR} ruvs"
+ LIBEXT=".a"
+ ;;
+esac
+
+dnl Finish link line
+MAdLib_LIBS="${MAdLib_LIBS} -lm"
+
+dnl Modify defaults according to OS
+case "$UNAME" in
+
+ CYGWIN* | MINGW*)
+ dnl increase stack size to 16Mb to avoid stack overflows in
+ dnl recursive tet classification for large 3D Delaunay grids
+ LINKER="${LINKER} -mwindows -Wl,--stack,16777216"
+ if test "x$enable_cygwin" != "xyes"; then
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+ AC_DEFINE(HAVE_NO_DLL)
+ BO="${BO} NoDll"
+ fi
+ if test "x${OCC}" = "xyes"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -lwinspool -lws2_32"
+ fi
+ if test "x$enable_gui" != "xno"; then
+ MAdLib_LIBS="${MAdLib_LIBS} Fltk/Win32Icon.res"
+ fi
+ ;;
+
+ Darwin*)
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+ AC_DEFINE(HAVE_NO_DLL)
+ BO="${BO} NoDll"
+ if test "x$enable_universal" = "xyes"; then
+ FLAGS="-arch ppc -arch i386 ${FLAGS}"
+ fi
+ if test "x$enable_gui" = "xno"; then
+ MAdLib_LIBS="${MAdLib_LIBS} -framework ApplicationServices"
+ fi
+ ;;
+
+ AIX*)
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+ AC_DEFINE(HAVE_NO_DLL)
+ BO="${BO} NoDll"
+ FLAGS="-D_BSD ${FLAGS}"
+ ;;
+
+ IRIX*)
+ dnl options for native SGI compiler
+ case "${CXX}" in
+ *CC*)
+ dnl add "-mips3 -n32" to FLAGS, AR and LINKER for portable 32 bit exe
+ dnl "-DOLDCINCLUDE" is for Netgen
+ FLAGS="-LANG:std -OPT:Olimit=0 -DOLDCINCLUDE ${FLAGS}"
+ AR="${CXX} -ar -o"
+ LINKER="${CXX}"
+ ;;
+ esac
+ ;;
+
+ OSF1*)
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_SOCKLEN_T"
+ AC_DEFINE(HAVE_NO_SOCKLEN_T)
+ BO="${BO} NoSocklenT"
+ dnl options for native DEC compiler
+ case "${CXX}" in
+ *cxx*)
+ FLAGS="-D__USE_STD_IOSTREAM ${FLAGS}"
+ ;;
+ esac
+ ;;
+
+ SunOS*)
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+ AC_DEFINE(HAVE_NO_DLL)
+ BO="${BO} NoDll"
+ MAdLib_LIBS="${MAdLib_LIBS} -lsocket -lnsl -ldl"
+ ;;
+
+ HP-UX*)
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+ AC_DEFINE(HAVE_NO_DLL)
+ BO="${BO} NoDll"
+ ;;
+
+esac
+
+dnl Check sizeof size_t (flag as 64 if not 32)
+AC_CHECK_SIZEOF([size_t])
+if test $ac_cv_sizeof_size_t != 4; then
+ if test $ac_cv_sizeof_size_t != 8; then
+ AC_MSG_WARN([Unsupported size of size_t - this may affect FNV hashing.])
+ else
+ MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_64BIT_SIZE_T"
+ AC_DEFINE(HAVE_64BIT_SIZE_T)
+ BO="${BO} Have64BitSizeT"
+ if test "x${OCC}" = "xyes"; then
+ FLAGS="${FLAGS} -D_OCC64"
+ fi
+ fi
+fi
+
+dnl Check for Doxygen (to produce the documentation)
+DOX=""
+AC_CHECK_PROG(DOX,doxygen,"yes","no")
+if test "x${DOX}" = "xyes"; then
+ DOXYGEN="doxygen"
+else
+ DOXYGEN=""
+fi
+AC_SUBST(DOXYGEN)
+
+AC_CONFIG_HEADER(MAdConfig.h:MAdConfig.h.in)
+
+dnl Write output
+AC_SUBST(UNAME)
+AC_SUBST(HOSTNAME)
+AC_SUBST(FLAGS)
+AC_SUBST(OPTIM)
+AC_SUBST(CXX)
+AC_SUBST(CXXFLAGS)
+AC_SUBST(LINKER)
+AC_SUBST(AR)
+AC_SUBST(LIBEXT)
+AC_SUBST(MAdLib_DEFS)
+AC_SUBST(MAdROOT)
+AC_SUBST(MAdLib_TMPDIR)
+AC_SUBST(MAdLib_DIRS)
+AC_SUBST(MAdLib_LIBS)
+AC_SUBST(MAdLib_INCLUDES)
+AC_SUBST(MAdLib_BENCHDIRS)
+AC_CONFIG_FILES([variables])
+AC_OUTPUT
+
+dnl Print some information
+echo "********************************************************************"
+echo "MAdLib is configured for"
+echo " - OS : ${UNAME} on ${HOSTNAME}"
+echo " - C++ compiler : ${CXX}"
+echo " - Exe linker : ${LINKER}"
+echo " - Lib linker : ${AR}"
+echo " - Optimization : ${OPTIM}"
+echo " - C++ flags : ${CXXFLAGS}"
+echo " - Build options: ${BO}"
+echo "********************************************************************"
+echo "Edit 'variables' and 'MAdConfig.h' to fine-tune the config"
+echo "********************************************************************"
+
diff --git a/doxygen.config b/doxygen.config
new file mode 100644
index 0000000..35140bb
--- /dev/null
+++ b/doxygen.config
@@ -0,0 +1,76 @@
+
+# Automatically generated by buildUtil
+PROJECT_NAME = MAdLib
+OUTPUT_DIRECTORY = ./doc
+OUTPUT_LANGUAGE = English
+INPUT = Common Geo Mesh Adapt
+FILE_PATTERNS = *.h *.c *.cc *.cpp *.ipp
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+ALWAYS_DETAILED_SEC = NO
+FULL_PATH_NAMES = NO
+INTERNAL_DOCS = NO
+CLASS_DIAGRAMS = YES
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+CASE_SENSE_NAMES = YES
+SHORT_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+VERBATIM_HEADERS = NO
+SHOW_INCLUDE_FILES = YES
+JAVADOC_AUTOBRIEF = NO
+INHERIT_DOCS = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 4
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+MAX_INITIALIZER_LINES = 30
+OPTIMIZE_OUTPUT_FOR_C = NO
+SHOW_USED_FILES = YES
+QUIET = YES
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+RECURSIVE = YES
+FILTER_SOURCE_FILES = NO
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 2
+GENERATE_HTML = YES
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+GENERATE_LATEX = NO
+COMPACT_LATEX = NO
+PAPER_TYPE = letter
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = YES
+GENERATE_RTF = NO
+GENERATE_MAN = NO
+MAN_LINKS = YES
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+ALLEXTERNALS = NO
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+SEARCHENGINE = NO
diff --git a/variables.in b/variables.in
new file mode 100644
index 0000000..e85843b
--- /dev/null
+++ b/variables.in
@@ -0,0 +1,90 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information.
+# You should have received a copy of these files along with MAdLib.
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+# OS and host
+UNAME=@UNAME@
+HOSTNAME=@HOSTNAME@
+
+# The names of the C and C++ compilers
+CC=@CC@
+CXX=@CXX@
+
+# If you need to link to dynamic libraries installed in non-standard
+# locations and are using the GNU linker, you may want to add
+# '-Wl,--rpath,/path/to/dynamic/library' to the 'LINKER' variable
+# below. Alternatively, you could edit the 'LD_LIBARY_PATH'
+# environement variable or use the 'ldconfig' program.
+LINKER=@LINKER@
+
+# All compiler flags except optimization flags
+FLAGS=@FLAGS@
+
+# Flag for c++ compiler
+CXXFLAGS=@CXXFLAGS@
+
+# Additional system includes
+SYSINCLUDE=
+
+# Compiler optimization flags
+OPTIM=@OPTIM@
+
+# MAdLib definitions
+MAdLib_DEFS=@MAdLib_DEFS@
+
+# MAdLib root directory
+MAdROOT=@MAdROOT@
+
+# MAdLib subdirectories
+MAdLib_TMPDIR=@MAdLib_TMPDIR@
+
+# MAdLib subdirectories
+MAdLib_DIRS=@MAdLib_DIRS@
+
+# MAdLib libraries
+MAdLib_LIBS=@MAdLib_LIBS@
+
+# MAdLib include directories
+MAdLib_INCLUDES=@MAdLib_INCLUDES@
+
+# MAdLib benchmarks subdirectories
+MAdLib_BENCHDIRS=@MAdLib_BENCHDIRS@
+
+# How you create a static library on this machine
+AR=@AR@
+ARFLAGS=
+RANLIB=@RANLIB@
+
+# The symbol used in front of compiler flags
+DASH=-
+
+# The extension to use for object files, libraries and executables
+OBJEXT=.o
+LIBEXT=@LIBEXT@
+EXEEXT=@EXEEXT@
+
+# File handling commands
+RM=rm -f
+
+# Documentation genration
+DOXYGEN=@DOXYGEN@
+
+# Installation directories
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+datadir=@datadir@
+datarootdir=@datarootdir@
+includedir=@includedir@
+libdir=@libdir@
+docdir=@docdir@
+mandir=@mandir@
+infodir=@infodir@
--
MAdLib, a mesh adaptation library.
More information about the Pkg-scicomp-commits
mailing list