<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2016 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* 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 2 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, write to the Free Software Foundation, Inc., 51  *
* Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.                   *
*******************************************************************************
*                            SOFA :: Applications                             *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include <iostream>
#include <sstream>
#include <fstream>
#include <sofa/helper/ArgumentParser.h>
#include <sofa/helper/UnitTest.h>
#include <sofa/helper/vector_algebra.h>
#include <sofa/helper/vector.h>
#include <sofa/helper/BackTrace.h>
#include <sofa/helper/system/PluginManager.h>

#include <sofa/simulation/Node.h>
#include <sofa/simulation/Simulation.h>
#include <SofaSimulationTree/init.h>
#include <SofaSimulationTree/TreeSimulation.h>

#include <sofa/gui/GUIManager.h>
#include <sofa/gui/Main.h>
#include <sofa/helper/system/FileRepository.h>

#include <SofaComponentBase/initComponentBase.h>
#include <SofaComponentCommon/initComponentCommon.h>
#include <SofaComponentGeneral/initComponentGeneral.h>
#include <SofaComponentAdvanced/initComponentAdvanced.h>
#include <SofaComponentMisc/initComponentMisc.h>
#include <SofaMiscMapping/SubsetMultiMapping.h>
#include <SofaBaseTopology/MeshTopology.h>
#include <SofaBaseTopology/EdgeSetTopologyContainer.h>
#include <SofaBaseTopology/RegularGridTopology.h>
#include <SofaBaseCollision/SphereModel.h>
#include <SofaGeneralTopology/CubeTopology.h>
#include <SofaBaseVisual/VisualStyle.h>
#include <SofaImplicitOdeSolver/EulerImplicitSolver.h>
#include <SofaBaseLinearSolver/CGLinearSolver.h>

//Using double by default, if you have SOFA_FLOAT in use in you sofa-default.cfg, then it will be FLOAT.
#include <sofa/component/typedef/Sofa_typedef.h>

#include <utility>

using namespace sofa;
using namespace sofa::helper;
using helper::vector;
using namespace sofa::simulation;
using namespace sofa::core::objectmodel;
using namespace sofa::component::container;
using namespace sofa::component::topology;
using namespace sofa::component::collision;
using namespace sofa::component::visualmodel;
using namespace sofa::component::mapping;
using namespace sofa::component::forcefield;

typedef SReal Scalar;
typedef Vec<3,SReal> Vec3;
typedef Vec<1,SReal> Vec1;
typedef component::odesolver::EulerImplicitSolver EulerImplicitSolver;
typedef component::linearsolver::CGLinearSolver<component::linearsolver::GraphScatteredMatrix, component::linearsolver::GraphScatteredVector> CGLinearSolver;

bool startAnim = true;
bool verbose = false;
SReal complianceValue = 0.1;
Vec3 gravity(0,-1,0);
SReal dt = 0.01;

/// helper for more compact component creation
template<class Component>
typename Component::SPtr addNew( Node::SPtr parentNode, std::string name="" )
{
    typename Component::SPtr component = New<Component>();
    parentNode->addObject(component);
    component->setName(parentNode->getName()+"_"+name);
    return component;
}

/// Create an assembly of a siff hexahedral grid with other objects
simulation::Node::SPtr createGridScene(Vec3 startPoint, Vec3 endPoint, unsigned numX, unsigned numY, unsigned numZ, double totalMass/*, double stiffnessValue, double dampingRatio=0.0*/ )
{
    using helper::vector;

    // The graph root node
    Node::SPtr  root = simulation::getSimulation()->createNewGraph("root");
    root->setGravity( Coord3(0,-10,0) );
    root->setAnimate(false);
    root->setDt(0.01);
    addVisualStyle(root)->setShowVisual(false).setShowCollision(false).setShowMapping(true).setShowBehavior(true);

    Node::SPtr simulatedScene = root->createChild("simulatedScene");

    EulerImplicitSolver::SPtr eulerImplicitSolver = New<EulerImplicitSolver>();
    simulatedScene->addObject( eulerImplicitSolver );
    CGLinearSolver::SPtr cgLinearSolver = New<CGLinearSolver>();
    simulatedScene->addObject(cgLinearSolver);

    // The rigid object
    Node::SPtr rigidNode = simulatedScene->createChild("rigidNode");
    MechanicalObjectRigid3::SPtr rigid_dof = addNew<MechanicalObjectRigid3>(rigidNode, "dof");
    UniformMassRigid3::SPtr rigid_mass = addNew<UniformMassRigid3>(rigidNode,"mass");
    FixedConstraintRigid3::SPtr rigid_fixedConstraint = addNew<FixedConstraintRigid3>(rigidNode,"fixedConstraint");

    // Particles mapped to the rigid object
    Node::SPtr mappedParticles = rigidNode->createChild("mappedParticles");
    MechanicalObject3::SPtr mappedParticles_dof = addNew< MechanicalObject3>(mappedParticles,"dof");
    RigidMappingRigid3_to_3::SPtr mappedParticles_mapping = addNew<RigidMappingRigid3_to_3>(mappedParticles,"mapping");
    mappedParticles_mapping->setModels( rigid_dof.get(), mappedParticles_dof.get() );

    // The independent particles
    Node::SPtr independentParticles = simulatedScene->createChild("independentParticles");
    MechanicalObject3::SPtr independentParticles_dof = addNew< MechanicalObject3>(independentParticles,"dof");

    // The deformable grid, connected to its 2 parents using a MultiMapping
    Node::SPtr deformableGrid = independentParticles->createChild("deformableGrid"); // first parent
    mappedParticles->addChild(deformableGrid);                                       // second parent

    RegularGridTopology::SPtr deformableGrid_grid = addNew<RegularGridTopology>( deformableGrid, "grid" );
    deformableGrid_grid->setNumVertices(numX,numY,numZ);
    deformableGrid_grid->setPos(startPoint[0],endPoint[0],startPoint[1],endPoint[1],startPoint[2],endPoint[2]);

    MechanicalObject3::SPtr deformableGrid_dof = addNew< MechanicalObject3>(deformableGrid,"dof");

    SubsetMultiMapping3_to_3::SPtr deformableGrid_mapping = addNew<SubsetMultiMapping3_to_3>(deformableGrid,"mapping");
    deformableGrid_mapping->addInputModel(independentParticles_dof.get()); // first parent
    deformableGrid_mapping->addInputModel(mappedParticles_dof.get());      // second parent
    deformableGrid_mapping->addOutputModel(deformableGrid_dof.get());

    UniformMass3::SPtr mass = addNew<UniformMass3>(deformableGrid,"mass" );
    mass->mass.setValue( totalMass/(numX*numY*numZ) );

    HexahedronFEMForceField3::SPtr hexaFem = addNew<HexahedronFEMForceField3>(deformableGrid, "hexaFEM");
    hexaFem->f_youngModulus.setValue(1000);
    hexaFem->f_poissonRatio.setValue(0.4);

    // ======  Set up the multimapping and its parents, based on its child
    deformableGrid_grid->init();  // initialize the grid, so that the particles are located in space
    deformableGrid_dof->init();   // create the state vectors
    MechanicalObject3::ReadVecCoord  xgrid = deformableGrid_dof->readPositions(); //    cerr<<"xgrid = " << xgrid << endl;

    // create the rigid frames and their bounding boxes
    unsigned numRigid = 2;
    vector<sofa::defaulttype::BoundingBox> boxes(numRigid);
    vector< vector<unsigned> > indices(numRigid); // indices of the particles in each box
    double eps = (endPoint[0]-startPoint[0])/(numX*2);

    // first box, x=xmin
    boxes[0] = sofa::defaulttype::BoundingBox(sofa::defaulttype::Vec3d(startPoint[0]-eps, startPoint[1]-eps, startPoint[2]-eps),
                           sofa::defaulttype::Vec3d(startPoint[0]+eps,   endPoint[1]+eps,   endPoint[2]+eps));

    // second box, x=xmax
    boxes[1] = sofa::defaulttype::BoundingBox(sofa::defaulttype::Vec3d(endPoint[0]-eps, startPoint[1]-eps, startPoint[2]-eps),
                           sofa::defaulttype::Vec3d(endPoint[0]+eps,   endPoint[1]+eps,   endPoint[2]+eps));
    rigid_dof->resize(numRigid);
    MechanicalObjectRigid3::WriteVecCoord xrigid = rigid_dof->writePositions();
    xrigid[0].getCenter()=sofa::defaulttype::Vec3d(startPoint[0], 0.5*(startPoint[1]+endPoint[1]), 0.5*(startPoint[2]+endPoint[2]));
    xrigid[1].getCenter()=sofa::defaulttype::Vec3d(  endPoint[0], 0.5*(startPoint[1]+endPoint[1]), 0.5*(startPoint[2]+endPoint[2]));

    // find the particles in each box
    vector<bool> isFree(xgrid.size(),true);
    unsigned numMapped = 0;
    for(unsigned i=0; i<xgrid.size(); i++){
        for(unsigned b=0; b<numRigid; b++ )
        {
            if( isFree[i] && boxes[b].contains(xgrid[i]) )
            {
                indices[b].push_back(i); // associate the particle with the box
                isFree[i] = false;
                numMapped++;
            }
        }
    }

    // distribution of the grid particles to the different parents (independent particle or solids.
    vector< std::pair<MechanicalObject3*,unsigned> > parentParticles(xgrid.size());

    // Copy the independent particles to their parent DOF
    independentParticles_dof->resize( numX*numY*numZ - numMapped );
    MechanicalObject3::WriteVecCoord xindependent = independentParticles_dof->writePositions(); // parent positions
    unsigned independentIndex=0;
    for( unsigned i=0; i<xgrid.size(); i++ ){
        if( isFree[i] ){
            parentParticles[i]=std::make_pair(independentParticles_dof.get(),independentIndex);
            xindependent[independentIndex] = xgrid[i];
            independentIndex++;
        }
    }

    // Mapped particles. The RigidMapping requires to cluster the particles based on their parent frame.
    mappedParticles_dof->resize(numMapped);
    MechanicalObject3::WriteVecCoord xmapped = mappedParticles_dof->writePositions(); // parent positions
    mappedParticles_mapping->globalToLocalCoords.setValue(true);                      // to define the mapped positions in world coordinates

    vector<unsigned>& rigidIndexPerPoint = *mappedParticles_mapping->rigidIndexPerPoint.beginEdit(); // to set to which rigid frame is attached each mapped particle
    rigidIndexPerPoint.clear();
    rigidIndexPerPoint.reserve( numMapped );
    unsigned mappedIndex=0;
    for( unsigned b=0; b<numRigid; b++ )
    {
        const vector<unsigned>& ind = indices[b];
        for(unsigned i=0; i<ind.size(); i++)
        {
            rigidIndexPerPoint.push_back( b );
            parentParticles[ind[i]]=std::make_pair(mappedParticles_dof.get(),mappedIndex);
            xmapped[mappedIndex] = xgrid[ ind[i] ];
            mappedIndex++;
        }
    }
    mappedParticles_mapping->rigidIndexPerPoint.endEdit();

    // Declare all the particles to the multimapping
    for( unsigned i=0; i<xgrid.size(); i++ )
    {
        deformableGrid_mapping->addPoint( parentParticles[i].first, parentParticles[i].second );
    }

    return root;
}

int main(int argc, char** argv)
{
    sofa::simulation::tree::init();
    sofa::helper::BackTrace::autodump();
    sofa::core::ExecParams::defaultInstance()->setAspectID(0);

    sofa::helper::parse("This is a SOFA application. Here are the command line arguments")
    .option(&startAnim,'a',"start","start the animation loop")
    .option(&verbose,'v',"verbose","print debug info")
    (argc,argv);

    sofa::component::initComponentBase();
    sofa::component::initComponentCommon();
    sofa::component::initComponentGeneral();
    sofa::component::initComponentAdvanced();
    sofa::component::initComponentMisc();
    sofa::gui::initMain();

    if (int err = sofa::gui::GUIManager::Init(argv[0],"")) return err;
    if (int err=sofa::gui::GUIManager::createGUI(NULL)) return err;
    sofa::gui::GUIManager::SetDimension(800,600);

    sofa::simulation::setSimulation(new sofa::simulation::tree::TreeSimulation());

    //=================================================
    sofa::simulation::Node::SPtr groot = createGridScene(Vec3(0,0,0), Vec3(5,1,1), 6,2,2, 1.0 );
    //=================================================

    sofa::simulation::getSimulation()->init(groot.get());
    sofa::gui::GUIManager::SetScene(groot);

#ifdef PS3
	groot->setAnimate(true);
#endif

    // Run the main loop
    if (int err = sofa::gui::GUIManager::MainLoop(groot))
        return err;

    sofa::simulation::getSimulation()->unload(groot);
    sofa::gui::GUIManager::closeGUI();

    sofa::simulation::tree::cleanup();
    return 0;
}

<commit_msg>[CLEAN] Fix compilation problem because of previous commit.<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2016 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* 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 2 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, write to the Free Software Foundation, Inc., 51  *
* Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.                   *
*******************************************************************************
*                            SOFA :: Applications                             *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include <iostream>
#include <sstream>
#include <fstream>
#include <sofa/helper/ArgumentParser.h>
#include <sofa/helper/UnitTest.h>
#include <sofa/helper/vector_algebra.h>
#include <sofa/helper/vector.h>
#include <sofa/helper/BackTrace.h>
#include <sofa/helper/system/PluginManager.h>

#include <sofa/simulation/Node.h>
#include <sofa/simulation/Simulation.h>
#include <SofaSimulationTree/init.h>
#include <SofaSimulationTree/TreeSimulation.h>

#include <sofa/gui/GUIManager.h>
#include <sofa/gui/Main.h>
#include <sofa/helper/system/FileRepository.h>

#include <SofaComponentBase/initComponentBase.h>
#include <SofaComponentCommon/initComponentCommon.h>
#include <SofaComponentGeneral/initComponentGeneral.h>
#include <SofaComponentAdvanced/initComponentAdvanced.h>
#include <SofaComponentMisc/initComponentMisc.h>
#include <SofaMiscMapping/SubsetMultiMapping.h>
#include <SofaBaseTopology/MeshTopology.h>
#include <SofaBaseTopology/EdgeSetTopologyContainer.h>
#include <SofaBaseTopology/RegularGridTopology.h>
#include <SofaBaseCollision/SphereModel.h>
#include <SofaGeneralTopology/CubeTopology.h>
#include <SofaBaseVisual/VisualStyle.h>
#include <SofaImplicitOdeSolver/EulerImplicitSolver.h>
#include <SofaBaseLinearSolver/CGLinearSolver.h>

//Using double by default, if you have SOFA_FLOAT in use in you sofa-default.cfg, then it will be FLOAT.
#include <sofa/component/typedef/Sofa_typedef.h>

#include <utility>

using namespace sofa;
using namespace sofa::helper;
using helper::vector;
using namespace sofa::simulation;
using namespace sofa::core::objectmodel;
using namespace sofa::component::container;
using namespace sofa::component::topology;
using namespace sofa::component::collision;
using namespace sofa::component::visualmodel;
using namespace sofa::component::mapping;
using namespace sofa::component::forcefield;

typedef SReal Scalar;
typedef Vec<3,SReal> Vec3;
typedef Vec<1,SReal> Vec1;
typedef component::odesolver::EulerImplicitSolver EulerImplicitSolver;
typedef component::linearsolver::CGLinearSolver<component::linearsolver::GraphScatteredMatrix, component::linearsolver::GraphScatteredVector> CGLinearSolver;

bool startAnim = true;
bool verbose = false;
SReal complianceValue = 0.1;
Vec3 gravity(0,-1,0);
SReal dt = 0.01;

/// helper for more compact component creation
template<class Component>
typename Component::SPtr addNew( Node::SPtr parentNode, std::string name="" )
{
    typename Component::SPtr component = New<Component>();
    parentNode->addObject(component);
    component->setName(parentNode->getName()+"_"+name);
    return component;
}

/// Create an assembly of a siff hexahedral grid with other objects
simulation::Node::SPtr createGridScene(Vec3 startPoint, Vec3 endPoint, unsigned numX, unsigned numY, unsigned numZ, double totalMass/*, double stiffnessValue, double dampingRatio=0.0*/ )
{
    using helper::vector;

    // The graph root node
    Node::SPtr  root = simulation::getSimulation()->createNewGraph("root");
    root->setGravity( Coord3(0,-10,0) );
    root->setAnimate(false);
    root->setDt(0.01);
    addVisualStyle(root)->setShowVisual(false).setShowCollision(false).setShowMapping(true).setShowBehavior(true);

    Node::SPtr simulatedScene = root->createChild("simulatedScene");

    EulerImplicitSolver::SPtr eulerImplicitSolver = New<EulerImplicitSolver>();
    simulatedScene->addObject( eulerImplicitSolver );
    CGLinearSolver::SPtr cgLinearSolver = New<CGLinearSolver>();
    simulatedScene->addObject(cgLinearSolver);

    // The rigid object
    Node::SPtr rigidNode = simulatedScene->createChild("rigidNode");
    MechanicalObjectRigid3::SPtr rigid_dof = addNew<MechanicalObjectRigid3>(rigidNode, "dof");
    UniformMassRigid3::SPtr rigid_mass = addNew<UniformMassRigid3>(rigidNode,"mass");
    FixedConstraintRigid3::SPtr rigid_fixedConstraint = addNew<FixedConstraintRigid3>(rigidNode,"fixedConstraint");

    // Particles mapped to the rigid object
    Node::SPtr mappedParticles = rigidNode->createChild("mappedParticles");
    MechanicalObject3::SPtr mappedParticles_dof = addNew< MechanicalObject3>(mappedParticles,"dof");
    RigidMappingRigid3_to_3::SPtr mappedParticles_mapping = addNew<RigidMappingRigid3_to_3>(mappedParticles,"mapping");
    mappedParticles_mapping->setModels( rigid_dof.get(), mappedParticles_dof.get() );

    // The independent particles
    Node::SPtr independentParticles = simulatedScene->createChild("independentParticles");
    MechanicalObject3::SPtr independentParticles_dof = addNew< MechanicalObject3>(independentParticles,"dof");

    // The deformable grid, connected to its 2 parents using a MultiMapping
    Node::SPtr deformableGrid = independentParticles->createChild("deformableGrid"); // first parent
    mappedParticles->addChild(deformableGrid);                                       // second parent

    RegularGridTopology::SPtr deformableGrid_grid = addNew<RegularGridTopology>( deformableGrid, "grid" );
    deformableGrid_grid->setNumVertices(numX,numY,numZ);
    deformableGrid_grid->setPos(startPoint[0],endPoint[0],startPoint[1],endPoint[1],startPoint[2],endPoint[2]);

    MechanicalObject3::SPtr deformableGrid_dof = addNew< MechanicalObject3>(deformableGrid,"dof");

    SubsetMultiMapping3_to_3::SPtr deformableGrid_mapping = addNew<SubsetMultiMapping3_to_3>(deformableGrid,"mapping");
    deformableGrid_mapping->addInputModel(independentParticles_dof.get()); // first parent
    deformableGrid_mapping->addInputModel(mappedParticles_dof.get());      // second parent
    deformableGrid_mapping->addOutputModel(deformableGrid_dof.get());

    UniformMass3::SPtr mass = addNew<UniformMass3>(deformableGrid,"mass" );
    mass->d_mass.setValue( totalMass/(numX*numY*numZ) );

    HexahedronFEMForceField3::SPtr hexaFem = addNew<HexahedronFEMForceField3>(deformableGrid, "hexaFEM");
    hexaFem->f_youngModulus.setValue(1000);
    hexaFem->f_poissonRatio.setValue(0.4);

    // ======  Set up the multimapping and its parents, based on its child
    deformableGrid_grid->init();  // initialize the grid, so that the particles are located in space
    deformableGrid_dof->init();   // create the state vectors
    MechanicalObject3::ReadVecCoord  xgrid = deformableGrid_dof->readPositions(); //    cerr<<"xgrid = " << xgrid << endl;

    // create the rigid frames and their bounding boxes
    unsigned numRigid = 2;
    vector<sofa::defaulttype::BoundingBox> boxes(numRigid);
    vector< vector<unsigned> > indices(numRigid); // indices of the particles in each box
    double eps = (endPoint[0]-startPoint[0])/(numX*2);

    // first box, x=xmin
    boxes[0] = sofa::defaulttype::BoundingBox(sofa::defaulttype::Vec3d(startPoint[0]-eps, startPoint[1]-eps, startPoint[2]-eps),
                           sofa::defaulttype::Vec3d(startPoint[0]+eps,   endPoint[1]+eps,   endPoint[2]+eps));

    // second box, x=xmax
    boxes[1] = sofa::defaulttype::BoundingBox(sofa::defaulttype::Vec3d(endPoint[0]-eps, startPoint[1]-eps, startPoint[2]-eps),
                           sofa::defaulttype::Vec3d(endPoint[0]+eps,   endPoint[1]+eps,   endPoint[2]+eps));
    rigid_dof->resize(numRigid);
    MechanicalObjectRigid3::WriteVecCoord xrigid = rigid_dof->writePositions();
    xrigid[0].getCenter()=sofa::defaulttype::Vec3d(startPoint[0], 0.5*(startPoint[1]+endPoint[1]), 0.5*(startPoint[2]+endPoint[2]));
    xrigid[1].getCenter()=sofa::defaulttype::Vec3d(  endPoint[0], 0.5*(startPoint[1]+endPoint[1]), 0.5*(startPoint[2]+endPoint[2]));

    // find the particles in each box
    vector<bool> isFree(xgrid.size(),true);
    unsigned numMapped = 0;
    for(unsigned i=0; i<xgrid.size(); i++){
        for(unsigned b=0; b<numRigid; b++ )
        {
            if( isFree[i] && boxes[b].contains(xgrid[i]) )
            {
                indices[b].push_back(i); // associate the particle with the box
                isFree[i] = false;
                numMapped++;
            }
        }
    }

    // distribution of the grid particles to the different parents (independent particle or solids.
    vector< std::pair<MechanicalObject3*,unsigned> > parentParticles(xgrid.size());

    // Copy the independent particles to their parent DOF
    independentParticles_dof->resize( numX*numY*numZ - numMapped );
    MechanicalObject3::WriteVecCoord xindependent = independentParticles_dof->writePositions(); // parent positions
    unsigned independentIndex=0;
    for( unsigned i=0; i<xgrid.size(); i++ ){
        if( isFree[i] ){
            parentParticles[i]=std::make_pair(independentParticles_dof.get(),independentIndex);
            xindependent[independentIndex] = xgrid[i];
            independentIndex++;
        }
    }

    // Mapped particles. The RigidMapping requires to cluster the particles based on their parent frame.
    mappedParticles_dof->resize(numMapped);
    MechanicalObject3::WriteVecCoord xmapped = mappedParticles_dof->writePositions(); // parent positions
    mappedParticles_mapping->globalToLocalCoords.setValue(true);                      // to define the mapped positions in world coordinates

    vector<unsigned>& rigidIndexPerPoint = *mappedParticles_mapping->rigidIndexPerPoint.beginEdit(); // to set to which rigid frame is attached each mapped particle
    rigidIndexPerPoint.clear();
    rigidIndexPerPoint.reserve( numMapped );
    unsigned mappedIndex=0;
    for( unsigned b=0; b<numRigid; b++ )
    {
        const vector<unsigned>& ind = indices[b];
        for(unsigned i=0; i<ind.size(); i++)
        {
            rigidIndexPerPoint.push_back( b );
            parentParticles[ind[i]]=std::make_pair(mappedParticles_dof.get(),mappedIndex);
            xmapped[mappedIndex] = xgrid[ ind[i] ];
            mappedIndex++;
        }
    }
    mappedParticles_mapping->rigidIndexPerPoint.endEdit();

    // Declare all the particles to the multimapping
    for( unsigned i=0; i<xgrid.size(); i++ )
    {
        deformableGrid_mapping->addPoint( parentParticles[i].first, parentParticles[i].second );
    }

    return root;
}

int main(int argc, char** argv)
{
    sofa::simulation::tree::init();
    sofa::helper::BackTrace::autodump();
    sofa::core::ExecParams::defaultInstance()->setAspectID(0);

    sofa::helper::parse("This is a SOFA application. Here are the command line arguments")
    .option(&startAnim,'a',"start","start the animation loop")
    .option(&verbose,'v',"verbose","print debug info")
    (argc,argv);

    sofa::component::initComponentBase();
    sofa::component::initComponentCommon();
    sofa::component::initComponentGeneral();
    sofa::component::initComponentAdvanced();
    sofa::component::initComponentMisc();
    sofa::gui::initMain();

    if (int err = sofa::gui::GUIManager::Init(argv[0],"")) return err;
    if (int err=sofa::gui::GUIManager::createGUI(NULL)) return err;
    sofa::gui::GUIManager::SetDimension(800,600);

    sofa::simulation::setSimulation(new sofa::simulation::tree::TreeSimulation());

    //=================================================
    sofa::simulation::Node::SPtr groot = createGridScene(Vec3(0,0,0), Vec3(5,1,1), 6,2,2, 1.0 );
    //=================================================

    sofa::simulation::getSimulation()->init(groot.get());
    sofa::gui::GUIManager::SetScene(groot);

#ifdef PS3
    groot->setAnimate(true);
#endif

    // Run the main loop
    if (int err = sofa::gui::GUIManager::MainLoop(groot))
        return err;

    sofa::simulation::getSimulation()->unload(groot);
    sofa::gui::GUIManager::closeGUI();

    sofa::simulation::tree::cleanup();
    return 0;
}

<|endoftext|>


<commit_before><commit_msg>Linux: Implement WebCursorInfo::TypeNone (i.e., invisible) cursor.<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: usrpref.hxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 12:50:12 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *
 ************************************************************************/
#ifndef _USRPREF_HXX
#define _USRPREF_HXX

#ifndef _UTL_CONFIGITEM_HXX_
#include <unotools/configitem.hxx>
#endif
#ifndef _FLDUPDE_HXX
#include <fldupde.hxx>
#endif
#include "viewopt.hxx"

#ifndef _VCL_FLDUNIT_HXX
#include <vcl/fldunit.hxx>
#endif

/* -----------------------------28.09.00 09:45--------------------------------

 ---------------------------------------------------------------------------*/
class SwMasterUsrPref;
class SwContentViewConfig : public utl::ConfigItem
{
    SwMasterUsrPref&        rParent;
    BOOL                    bWeb;

    com::sun::star::uno::Sequence<rtl::OUString> GetPropertyNames();
    public:
        SwContentViewConfig(BOOL bWeb, SwMasterUsrPref& rParent);
        ~SwContentViewConfig();

    // utl::ConfigItem
    virtual void    Notify( const com::sun::star::uno::Sequence< rtl::OUString > &rPropertyNames );
    virtual void    Commit();

    void                    Load();
    void                    SetModified(){ConfigItem::SetModified();}
};
/* -----------------------------28.09.00 09:45--------------------------------

 ---------------------------------------------------------------------------*/
class SwLayoutViewConfig : public utl::ConfigItem
{
    SwMasterUsrPref&    rParent;
    BOOL                bWeb;

    com::sun::star::uno::Sequence<rtl::OUString> GetPropertyNames();
    public:
        SwLayoutViewConfig(BOOL bWeb, SwMasterUsrPref& rParent);
        ~SwLayoutViewConfig();

    virtual void            Commit();
    void                    Load();
    void                    SetModified(){ConfigItem::SetModified();}
};
/* -----------------------------19.01.01 13:06--------------------------------

 ---------------------------------------------------------------------------*/
class SwGridConfig : public utl::ConfigItem
{
    SwMasterUsrPref&    rParent;
    BOOL                bWeb;

    com::sun::star::uno::Sequence<rtl::OUString> GetPropertyNames();
    public:
        SwGridConfig(BOOL bWeb, SwMasterUsrPref& rParent);
        ~SwGridConfig();

    virtual void            Commit();
    void                    Load();
    void                    SetModified(){ConfigItem::SetModified();}
};
/* -----------------------------19.01.01 13:06--------------------------------

 ---------------------------------------------------------------------------*/
class SwCursorConfig : public utl::ConfigItem
{
    SwMasterUsrPref&    rParent;

    com::sun::star::uno::Sequence<rtl::OUString> GetPropertyNames();
    public:
        SwCursorConfig(SwMasterUsrPref& rParent);
        ~SwCursorConfig();

    virtual void            Commit();
    void                    Load();
    void                    SetModified(){ConfigItem::SetModified();}
};
/* -----------------------------28.09.00 09:45--------------------------------

 ---------------------------------------------------------------------------*/
class SwWebColorConfig : public utl::ConfigItem
{
    SwMasterUsrPref&        rParent;
    com::sun::star::uno::Sequence<rtl::OUString> aPropNames;

    public:
        SwWebColorConfig(SwMasterUsrPref& rParent);
        ~SwWebColorConfig();

    virtual void            Commit();
    void                    Load();
    void                    SetModified(){ConfigItem::SetModified();}
};
/* -----------------------------28.09.00 09:45--------------------------------

 ---------------------------------------------------------------------------*/
class SwMasterUsrPref : public SwViewOption
{
    friend class SwContentViewConfig;
    friend class SwLayoutViewConfig;
    friend class SwGridConfig;
    friend class SwCursorConfig;
    friend class SwWebColorConfig;

    SwContentViewConfig aContentConfig;
    SwLayoutViewConfig  aLayoutConfig;
    SwGridConfig        aGridConfig;
    SwCursorConfig      aCursorConfig;
    SwWebColorConfig*   pWebColorConfig;

    sal_Int32   nFldUpdateFlags;    //udpate of fields and charts
    sal_Int32   nLinkUpdateMode;
    FieldUnit   eUserMetric;
    FieldUnit   eHScrollMetric;
    sal_Bool    bIsHScrollMetricSet;
    FieldUnit   eVScrollMetric;
    sal_Bool    bIsVScrollMetricSet;

    sal_Int32   nDefTab;            //default tab stop distance

public:
    SwMasterUsrPref(BOOL bWeb);
    ~SwMasterUsrPref();

    void SetUsrPref(const SwViewOption &rCopy);

    void Commit()
        {
            aContentConfig.Commit();
            aLayoutConfig.Commit();
            aGridConfig.Commit();
            aCursorConfig.Commit();
            if(pWebColorConfig)
                pWebColorConfig->Commit();
        }
    void SetModified()
        {
            aContentConfig.SetModified();
            aLayoutConfig.SetModified();
            aGridConfig.SetModified();
            aCursorConfig.SetModified();
            if(pWebColorConfig)
                pWebColorConfig->SetModified();
        }

    void SetUpdateLinkMode(sal_Int32 nSet, sal_Bool bNoModify = sal_False)
        {
            nLinkUpdateMode = nSet;
            if(!bNoModify)
                aContentConfig.SetModified();
        }
    sal_Int32 GetUpdateLinkMode() const {return nLinkUpdateMode; }

    void SetUpdateFields(BOOL bSet, sal_Bool bNoModify = sal_False)
        {
            if(bSet && nFldUpdateFlags == AUTOUPD_OFF)
            {
                nFldUpdateFlags = AUTOUPD_FIELD_ONLY;
                if(!bNoModify)
                    aContentConfig.SetModified();
             }
            else if(!bSet)
            {
                nFldUpdateFlags = AUTOUPD_OFF;
                if(!bNoModify)
                    aContentConfig.SetModified();
            }
        };
    sal_Bool IsUpdateFields()const {return nFldUpdateFlags != AUTOUPD_OFF; }

    sal_Int32   GetFldUpdateFlags()const {return nFldUpdateFlags;}
    void        SetFldUpdateFlags(sal_Int32 nSet, sal_Bool bNoModify = sal_False)
        {
            nFldUpdateFlags = nSet;
            if(!bNoModify)
                aContentConfig.SetModified();
        }

    void SetUpdateCharts(BOOL bSet, sal_Bool bNoModify = sal_False)
        {
            if(bSet)
            {
                nFldUpdateFlags = AUTOUPD_FIELD_AND_CHARTS;
                if(!bNoModify)
                    aContentConfig.SetModified();
             }
             else if(nFldUpdateFlags == AUTOUPD_FIELD_AND_CHARTS)
             {
                nFldUpdateFlags = AUTOUPD_FIELD_ONLY;
                if(!bNoModify)
                    aContentConfig.SetModified();
             }
        };
    sal_Bool IsUpdateCharts()const {return nFldUpdateFlags == AUTOUPD_FIELD_AND_CHARTS; }

    FieldUnit   GetMetric() const { return eUserMetric;}
    void        SetMetric(FieldUnit eSet, sal_Bool bNoModify = sal_False)
                {
                    eUserMetric = eSet;
                    if(!bNoModify)
                        aLayoutConfig.SetModified();
                }

    sal_Bool    IsHScrollMetric()const {return bIsHScrollMetricSet;}
    FieldUnit   GetHScrollMetric() const { return bIsHScrollMetricSet ? eHScrollMetric : eUserMetric;}
    void        SetHScrollMetric(FieldUnit eSet, sal_Bool bNoModify = sal_False)
                {
                    eHScrollMetric = eSet; bIsHScrollMetricSet = sal_True;
                    if(!bNoModify)
                        aLayoutConfig.SetModified();
                }

    sal_Bool    IsVScrollMetric()const {return bIsVScrollMetricSet;}
    FieldUnit   GetVScrollMetric() const { return bIsVScrollMetricSet ? eVScrollMetric : eUserMetric;}
    void        SetVScrollMetric(FieldUnit eSet, sal_Bool bNoModify = sal_False)
                {
                    eVScrollMetric = eSet; bIsVScrollMetricSet = sal_True;
                    if(!bNoModify)
                        aLayoutConfig.SetModified();
                }

    sal_Int32   GetDefTab() const { return nDefTab;}
    void        SetDefTab( sal_Int32  nSet, sal_Bool bNoModify = sal_False )
                {
                    nDefTab = nSet;
                    if(!bNoModify)
                        aLayoutConfig.SetModified();
                }

};

#endif

<commit_msg>INTEGRATION: CWS swwarnings (1.10.710); FILE MERGED 2007/08/20 15:53:43 tl 1.10.710.2: RESYNC: (1.10-1.11); FILE MERGED 2007/03/26 12:09:10 tl 1.10.710.1: #i69287# warning-free code<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: usrpref.hxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: hr $ $Date: 2007-09-27 12:13:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *
 ************************************************************************/
#ifndef _USRPREF_HXX
#define _USRPREF_HXX

#ifndef _UTL_CONFIGITEM_HXX_
#include <unotools/configitem.hxx>
#endif
#ifndef _FLDUPDE_HXX
#include <fldupde.hxx>
#endif
#include "viewopt.hxx"

#ifndef _VCL_FLDUNIT_HXX
#include <vcl/fldunit.hxx>
#endif

/* -----------------------------28.09.00 09:45--------------------------------

 ---------------------------------------------------------------------------*/
class SwMasterUsrPref;
class SwContentViewConfig : public utl::ConfigItem
{
    SwMasterUsrPref&        rParent;
    BOOL                    bWeb;

    com::sun::star::uno::Sequence<rtl::OUString> GetPropertyNames();
    public:
        SwContentViewConfig(BOOL bWeb, SwMasterUsrPref& rParent);
        ~SwContentViewConfig();

    // utl::ConfigItem
    virtual void    Notify( const com::sun::star::uno::Sequence< rtl::OUString > &rPropertyNames );
    virtual void    Commit();

    void                    Load();
    void                    SetModified(){ConfigItem::SetModified();}
};
/* -----------------------------28.09.00 09:45--------------------------------

 ---------------------------------------------------------------------------*/
class SwLayoutViewConfig : public utl::ConfigItem
{
    SwMasterUsrPref&    rParent;
    BOOL                bWeb;

    com::sun::star::uno::Sequence<rtl::OUString> GetPropertyNames();
    public:
        SwLayoutViewConfig(BOOL bWeb, SwMasterUsrPref& rParent);
        ~SwLayoutViewConfig();

    virtual void            Commit();
    void                    Load();
    void                    SetModified(){ConfigItem::SetModified();}
};
/* -----------------------------19.01.01 13:06--------------------------------

 ---------------------------------------------------------------------------*/
class SwGridConfig : public utl::ConfigItem
{
    SwMasterUsrPref&    rParent;
    BOOL                bWeb;

    com::sun::star::uno::Sequence<rtl::OUString> GetPropertyNames();
    public:
        SwGridConfig(BOOL bWeb, SwMasterUsrPref& rParent);
        ~SwGridConfig();

    virtual void            Commit();
    void                    Load();
    void                    SetModified(){ConfigItem::SetModified();}
};
/* -----------------------------19.01.01 13:06--------------------------------

 ---------------------------------------------------------------------------*/
class SwCursorConfig : public utl::ConfigItem
{
    SwMasterUsrPref&    rParent;

    com::sun::star::uno::Sequence<rtl::OUString> GetPropertyNames();
    public:
        SwCursorConfig(SwMasterUsrPref& rParent);
        ~SwCursorConfig();

    virtual void            Commit();
    void                    Load();
    void                    SetModified(){ConfigItem::SetModified();}
};
/* -----------------------------28.09.00 09:45--------------------------------

 ---------------------------------------------------------------------------*/
class SwWebColorConfig : public utl::ConfigItem
{
    SwMasterUsrPref&        rParent;
    com::sun::star::uno::Sequence<rtl::OUString> aPropNames;

    public:
        SwWebColorConfig(SwMasterUsrPref& rParent);
        ~SwWebColorConfig();

    virtual void            Commit();
    void                    Load();
    void                    SetModified(){ConfigItem::SetModified();}
};
/* -----------------------------28.09.00 09:45--------------------------------

 ---------------------------------------------------------------------------*/
class SwMasterUsrPref : public SwViewOption
{
    friend class SwContentViewConfig;
    friend class SwLayoutViewConfig;
    friend class SwGridConfig;
    friend class SwCursorConfig;
    friend class SwWebColorConfig;

    SwContentViewConfig aContentConfig;
    SwLayoutViewConfig  aLayoutConfig;
    SwGridConfig        aGridConfig;
    SwCursorConfig      aCursorConfig;
    SwWebColorConfig*   pWebColorConfig;

    SwFldUpdateFlags eFldUpdateFlags;    //udpate of fields and charts
    sal_Int32   nLinkUpdateMode;
    FieldUnit   eUserMetric;
    FieldUnit   eHScrollMetric;
    sal_Bool    bIsHScrollMetricSet;
    FieldUnit   eVScrollMetric;
    sal_Bool    bIsVScrollMetricSet;

    sal_Int32   nDefTab;            //default tab stop distance

public:
    SwMasterUsrPref(BOOL bWeb);
    ~SwMasterUsrPref();

    void SetUsrPref(const SwViewOption &rCopy);

    void Commit()
        {
            aContentConfig.Commit();
            aLayoutConfig.Commit();
            aGridConfig.Commit();
            aCursorConfig.Commit();
            if(pWebColorConfig)
                pWebColorConfig->Commit();
        }
    void SetModified()
        {
            aContentConfig.SetModified();
            aLayoutConfig.SetModified();
            aGridConfig.SetModified();
            aCursorConfig.SetModified();
            if(pWebColorConfig)
                pWebColorConfig->SetModified();
        }

    void SetUpdateLinkMode(sal_Int32 nSet, sal_Bool bNoModify = sal_False)
        {
            nLinkUpdateMode = nSet;
            if(!bNoModify)
                aContentConfig.SetModified();
        }
    sal_Int32 GetUpdateLinkMode() const {return nLinkUpdateMode; }

    void SetUpdateFields(BOOL bSet, sal_Bool bNoModify = sal_False)
        {
            if(bSet && eFldUpdateFlags == AUTOUPD_OFF)
            {
                eFldUpdateFlags = AUTOUPD_FIELD_ONLY;
                if(!bNoModify)
                    aContentConfig.SetModified();
             }
            else if(!bSet)
            {
                eFldUpdateFlags = AUTOUPD_OFF;
                if(!bNoModify)
                    aContentConfig.SetModified();
            }
        };
    sal_Bool IsUpdateFields()const {return eFldUpdateFlags != AUTOUPD_OFF; }

    SwFldUpdateFlags   GetFldUpdateFlags()const {return eFldUpdateFlags;}
    void        SetFldUpdateFlags(SwFldUpdateFlags eSet, sal_Bool bNoModify = sal_False)
        {
            eFldUpdateFlags = eSet;
            if(!bNoModify)
                aContentConfig.SetModified();
        }

    void SetUpdateCharts(BOOL bSet, sal_Bool bNoModify = sal_False)
        {
            if(bSet)
            {
                eFldUpdateFlags = AUTOUPD_FIELD_AND_CHARTS;
                if(!bNoModify)
                    aContentConfig.SetModified();
             }
             else if(eFldUpdateFlags == AUTOUPD_FIELD_AND_CHARTS)
             {
                eFldUpdateFlags = AUTOUPD_FIELD_ONLY;
                if(!bNoModify)
                    aContentConfig.SetModified();
             }
        };
    sal_Bool IsUpdateCharts()const {return eFldUpdateFlags == AUTOUPD_FIELD_AND_CHARTS; }

    FieldUnit   GetMetric() const { return eUserMetric;}
    void        SetMetric(FieldUnit eSet, sal_Bool bNoModify = sal_False)
                {
                    eUserMetric = eSet;
                    if(!bNoModify)
                        aLayoutConfig.SetModified();
                }

    sal_Bool    IsHScrollMetric()const {return bIsHScrollMetricSet;}
    FieldUnit   GetHScrollMetric() const { return bIsHScrollMetricSet ? eHScrollMetric : eUserMetric;}
    void        SetHScrollMetric(FieldUnit eSet, sal_Bool bNoModify = sal_False)
                {
                    eHScrollMetric = eSet; bIsHScrollMetricSet = sal_True;
                    if(!bNoModify)
                        aLayoutConfig.SetModified();
                }

    sal_Bool    IsVScrollMetric()const {return bIsVScrollMetricSet;}
    FieldUnit   GetVScrollMetric() const { return bIsVScrollMetricSet ? eVScrollMetric : eUserMetric;}
    void        SetVScrollMetric(FieldUnit eSet, sal_Bool bNoModify = sal_False)
                {
                    eVScrollMetric = eSet; bIsVScrollMetricSet = sal_True;
                    if(!bNoModify)
                        aLayoutConfig.SetModified();
                }

    sal_Int32   GetDefTab() const { return nDefTab;}
    void        SetDefTab( sal_Int32  nSet, sal_Bool bNoModify = sal_False )
                {
                    nDefTab = nSet;
                    if(!bNoModify)
                        aLayoutConfig.SetModified();
                }

};

#endif

<|endoftext|>


<commit_before>
#include "density_clustering.hpp"
#include "tools.hpp"

#include <sstream>
#include <fstream>
#include <iterator>
#include <utility>
#include <functional>
#include <algorithm>
#include <limits>

#include <time.h>

#include <omp.h>
#include <boost/program_options.hpp>

namespace b_po = boost::program_options;

void
log(std::string msg) {
  std::cout << msg << std::endl;
}

void
log(std::string name, float value) {
  std::cout << name << ": " << value << std::endl;
}

std::vector<std::size_t>
calculate_populations(const CoordsPointer<float>& coords_pointer,
                      const std::size_t n_rows,
                      const std::size_t n_cols,
                      const float radius) {

  // provide easy access to coordinates data
  // and give hint to compiler that it is readily
  // aligned for vectorization
  //
  // DC_MEM_ALIGNMENT is defined during cmake and
  // set depending on usage of SSE2, SSE4_1, AVX or Xeon Phi
  #if defined(__INTEL_COMPILER)
  float* coords = coords_pointer.get();
  __assume_aligned(coords, DC_MEM_ALIGNMENT);
  #else
  // assume gnu compiler
  float* coords = (float*) __builtin_assume_aligned(coords_pointer.get(), DC_MEM_ALIGNMENT);
  #endif

  std::vector<std::size_t> pops(n_rows, 1);
  const float rad2 = radius * radius;
  std::size_t i, j, k;
  float dist, c;
  #pragma omp parallel for default(shared) private(i,j,k,c,dist) firstprivate(n_rows,n_cols,rad2) schedule(dynamic)
  for (i=0; i < n_rows; ++i) {
    for (j=i+1; j < n_rows; ++j) {
      dist = 0.0f;
      for (k=0; k < n_cols; ++k) {
        c = coords[i*n_cols+k] - coords[j*n_cols+k];
        dist += c*c;
      }
      if (dist < rad2) {
        pops[i] += 1;
      }
    }
  }
  return pops;
}

std::vector<float>
calculate_densities(const std::vector<std::size_t>& pops) {
  std::size_t i;
  const std::size_t n_frames = pops.size();
  const float max_pop = (float) ( * std::max_element(pops.begin(), pops.end()));
  std::vector<float> dens(n_frames);
  #pragma omp parallel for default(shared) private(i) firstprivate(max_pop, n_frames)
  for (i=0; i < n_frames; ++i) {
    dens[i] = (float) pops[i] / max_pop;
  }
  return dens;
}

/*
 * returns the smallest squared distance between two clusters defined
 * by ids in 'frames_cluster_1' and 'frames_cluster_2' based on the
 * given coordinate set.
 */
float
cluster_min_dist2(const CoordsPointer<float>& coords_pointer,
                  std::size_t n_cols,
                  const std::vector<std::size_t>& frames_cluster_1,
                  const std::vector<std::size_t>& frames_cluster_2) {
  #if defined(__INTEL_COMPILER)
  float* coords = coords_pointer.get();
  __assume_aligned(coords, DC_MEM_ALIGNMENT);
  #else // assume gnu compiler
  float* coords = (float*) __builtin_assume_aligned(coords_pointer.get(), DC_MEM_ALIGNMENT);
  #endif
  std::size_t n_frames_1 = frames_cluster_1.size();
  std::size_t n_frames_2 = frames_cluster_2.size();
  std::size_t i,j,c;
  float dist,d;
  float min_dist = std::numeric_limits<float>::max();
  #pragma omp parallel for \
    default(shared) \
    private(i,j,c,d,dist) \
    firstprivate(n_frames_1,n_frames_2,n_cols) \
    collapse(2) \
    reduction(min: min_dist)
  for (i=0; i < n_frames_1; ++i) {
    for (j=0; j < n_frames_2; ++j) {
      dist = 0.0f;
      for (c=0; c < n_cols; ++c) {
        d = coords[frames_cluster_1[i]*n_cols+c] - coords[frames_cluster_2[j]*n_cols+c];
        dist += d*d;
      }
      if (dist < min_dist) {
        min_dist = dist;
      }
    }
  }
  return min_dist;
}

const std::pair<std::size_t, float>
nearest_neighbor(const CoordsPointer<float>& coords_pointer,
                 const std::vector<Density>& sorted_density,
                 std::size_t n_cols,
                 std::size_t frame_id,
                 std::pair<std::size_t, std::size_t> search_range) {

  #if defined(__INTEL_COMPILER)
  float* coords = coords_pointer.get();
  __assume_aligned(coords, DC_MEM_ALIGNMENT);
  #else // assume gnu compiler
  float* coords = (float*) __builtin_assume_aligned(coords_pointer.get(), DC_MEM_ALIGNMENT);
  #endif
  std::size_t c,j;
  float d, dist;
  std::vector<float> distances(search_range.second-search_range.first);
  #pragma omp parallel for default(shared) private(dist,j,c,d) firstprivate(n_cols)
  for (j=search_range.first; j < search_range.second; ++j) {
    dist = 0.0f;
    for (c=0; c < n_cols; ++c) {
      d = coords[sorted_density[frame_id].first*n_cols+c] - coords[sorted_density[j].first*n_cols+c];
      dist += d*d;
    }
    distances[j-search_range.first] = dist;
  }
  if (distances.size() == 0) {
    return {0, 0.0f};
  } else {
    std::size_t min_ndx = std::min_element(distances.begin(), distances.end()) - distances.begin();
    return {min_ndx+search_range.first, distances[min_ndx]};
  }
}

std::vector<std::size_t>
density_clustering(const std::vector<float>& dens,
                   const float density_threshold,
                   const float density_radius,
                   const CoordsPointer<float>& coords_pointer,
                   const std::size_t n_rows,
                   const std::size_t n_cols) {

  std::vector<Density> density_sorted;
  for (std::size_t i=0; i < dens.size(); ++i) {
    density_sorted.push_back({i, dens[i]});
  }
  // sort for density: highest to lowest
  std::sort(density_sorted.begin(),
            density_sorted.end(),
            [] (const Density& d1, const Density& d2) -> bool {return d1.second > d2.second;});
  auto lb = std::lower_bound(density_sorted.begin(),
                             density_sorted.end(),
                             Density(0, density_threshold),
                             [](const Density& d1, const Density& d2) -> bool {return d1.second > d2.second;});
  std::size_t last_frame_below_threshold = (lb - density_sorted.begin());
  // find initial clusters
//////////////////////////

  std::vector<std::size_t> clustering;

  std::cout << "computing sigma ..." << std::endl;
  // compute sigma as standard deviation of nearest-neighbor distances
  float sigma = 0.0f;
  for (std::size_t i=0; i < n_rows; ++i) {
    if (i % 1000 == 0) std::cout << i << " / " << n_rows << std::endl;
    sigma += nearest_neighbor(coords_pointer, density_sorted, n_cols, i, {0,n_rows}).second;
  }
  sigma /= n_rows;

  std::cout << "sigma: " << sigma << std::endl;

  exit(2);

  std::size_t n_clusters = 1;
  std::map<std::size_t, std::vector<std::size_t>> clusters;
  // initialize with highest populated frame
  clusters[1] = {density_sorted[0].first};

  for (std::size_t i=1; i < last_frame_below_threshold; ++i) {
    // find (existing) cluster for this frame
    std::vector<std::size_t> fake_cluster = {i};
    float min_dist2 = std::numeric_limits<float>::max();
    std::size_t min_clust = 0;
    for (auto& cluster: clusters) {
      float dist2 = cluster_min_dist2(coords_pointer, n_cols, fake_cluster, cluster.second);
      if (dist2 < min_dist2) {
        min_dist2 = dist2;
        min_clust = cluster.first;
      }
    }
    // decide on new cluster vs appending
    if (min_dist2 < sigma*sigma) {
      // in range of cluster: append
      //TODO
    } else {
      // outside every cluster-bound: new cluster from this frame
      //TODO
    }
  }

  exit(3);

//  for (std::size_t i=1; i < last_frame_below_threshold; ++i) {
//    // nn_pair:  first := index in traj,  second := distance to reference (i)
//    auto nn_pair = nearest_neighbor(coords_pointer, density_sorted, n_cols, i, {0,i});
//    if (nn_pair.second < density_radius*density_radius) {
//      // add to existing cluster of frame with 'min_dist'
//      clustering[density_sorted[i].first] = clustering[density_sorted[nn_pair.first].first];
//    } else {
//      // create new cluster
//      ++n_clusters;
//      clustering[density_sorted[i].first] = n_clusters;
//    }
//  }
/////////////////////////

  // find nearest neighbors for all unassigned frames
  std::map<std::size_t, std::size_t> nearest_neighbors;
  for (std::size_t i=last_frame_below_threshold; i < density_sorted.size(); ++i) {
    if (i % 100 == 0) std::cout << i << "  /  " << density_sorted.size() << std::endl;
    // nn_pair:  first := index in traj,  second := distance to reference (i)
    auto nn_pair = nearest_neighbor(coords_pointer, density_sorted, n_cols, i, {0, density_sorted.size()});
    nearest_neighbors[i] = nn_pair.first;
  }
  log("assign frames to clusters");
  // assign clusters to unassigned frames via neighbor-info
  bool nothing_happened = true;
  while (nearest_neighbors.size() > 0 && ( ! nothing_happened)) {
    nothing_happened = true;
    // it:  first := index in traj,  second := distance to reference (i)
    for (auto it=nearest_neighbors.begin(); it != nearest_neighbors.end(); ++it) {
      if (clustering[it->second] != 0) {
        clustering[it->first] = it->second;
        nearest_neighbors.erase(it);
        nothing_happened = false;
      }
    }
  }
  return clustering;
}

////////

int main(int argc, char* argv[]) {

  b_po::variables_map args;
  b_po::options_description desc (std::string(argv[0]).append(
    "\n\n"
    "perform clustering of MD data based on phase space densities.\n"
    "densities are approximated by counting neighboring frames inside\n"
    "a n-dimensional hypersphere of specified radius.\n"
    "distances are measured with n-dim P2-norm.\n"
    "\n"
    "options"));
  desc.add_options()
    ("help,h", b_po::bool_switch()->default_value(false), "show this help.")
    // required
    ("file,f", b_po::value<std::string>()->required(), "input (required): phase space coordinates (space separated ASCII).")
    ("output,o", b_po::value<std::string>()->required(), "output (required): clustering information.")
    ("radius,r", b_po::value<float>()->required(), "parameter (required): hypersphere radius.")
    ("threshold,t", b_po::value<float>()->required(), "parameter (required, elem. of [0.0, 1.0]): density threshold for clustering.")
    // optional
    ("population,p", b_po::value<std::string>(), "output (optional): population per frame.")
    ("density,d", b_po::value<std::string>(), "output (optional): density per frame.")
    ("density-input,D", b_po::value<std::string>(), "input (optional): reuse density info.")
    // defaults
    ("nthreads,n", b_po::value<int>()->default_value(0), "number of OpenMP threads. default: 0; i.e. use OMP_NUM_THREADS env-variable.")
    ("verbose,v", b_po::bool_switch()->default_value(false), "verbose mode: print max density, runtime information, etc. to STDOUT.")
  ;

  try {
    b_po::store(b_po::command_line_parser(argc, argv).options(desc).run(), args);
    b_po::notify(args);
  } catch (b_po::error& e) {
    if ( ! args["help"].as<bool>()) {
      std::cout << "\n" << e.what() << "\n\n" << std::endl;
    }
    std::cout << desc << std::endl;
    return 2;
  }

  if (args["help"].as<bool>()) {
    std::cout << desc << std::endl;
    return 1;
  }

  ////

  const std::string input_file = args["file"].as<std::string>();
  const std::string output_file = args["output"].as<std::string>();

  const float radius = args["radius"].as<float>();
  const float threshold = args["threshold"].as<float>();

  // setup OpenMP
  const int n_threads = args["nthreads"].as<int>();
  if (n_threads > 0) {
    omp_set_num_threads(n_threads);
  }

  bool verbose = args["verbose"].as<bool>();

  CoordsPointer<float> coords_pointer;
  std::size_t n_rows;
  std::size_t n_cols;
  std::tie(coords_pointer, n_rows, n_cols) = read_coords<float>(input_file);

  std::vector<float> densities;

  if (args.count("density-input")) {
    if (verbose) {
      log("re-using density data.");
    }
    // reuse density info
    std::ifstream ifs(args["density-input"].as<std::string>());
    if (ifs.fail()) {
      std::cerr << "error: cannot open file '" << args["density-input"].as<std::string>() << "'" << std::endl;
      return 3;
    } else {
      while(ifs.good()) {
        float buf;
        ifs >> buf;
        densities.push_back(buf);
      }
    }
  } else {
    if (verbose) {
      log("calculating densities");
    }
    densities = calculate_densities(
                  calculate_populations(coords_pointer, n_rows, n_cols, radius));
    if (args.count("density")) {
      std::ofstream ofs(args["density"].as<std::string>());
      ofs << std::scientific;
      for (float d: densities) {
        ofs << d << "\n";
      }
    }
  }

  if (verbose) {
    log("calculating clusters");
  }
  std::vector<std::size_t> clustering = density_clustering(densities, threshold, radius, coords_pointer, n_rows, n_cols);
  // write clusters to file
  {
    std::ofstream ofs(output_file);
    if (ofs.fail()) {
      std::cerr << "error: cannot open file '" << output_file << "' for writing." << std::endl;
      return 3;
    }
    for (std::size_t i: clustering) {
      ofs << i << "\n";
    }
  }
  return 0;
}

<commit_msg>prepare merge<commit_after>
#include "density_clustering.hpp"
#include "tools.hpp"

#include <sstream>
#include <fstream>
#include <iterator>
#include <utility>
#include <functional>
#include <algorithm>
#include <limits>

#include <time.h>

#include <omp.h>
#include <boost/program_options.hpp>

namespace b_po = boost::program_options;

void
log(std::string msg) {
  std::cout << msg << std::endl;
}

void
log(std::string name, float value) {
  std::cout << name << ": " << value << std::endl;
}

std::vector<std::size_t>
calculate_populations(const CoordsPointer<float>& coords_pointer,
                      const std::size_t n_rows,
                      const std::size_t n_cols,
                      const float radius) {

  // provide easy access to coordinates data
  // and give hint to compiler that it is readily
  // aligned for vectorization
  //
  // DC_MEM_ALIGNMENT is defined during cmake and
  // set depending on usage of SSE2, SSE4_1, AVX or Xeon Phi
  #if defined(__INTEL_COMPILER)
  float* coords = coords_pointer.get();
  __assume_aligned(coords, DC_MEM_ALIGNMENT);
  #else
  // assume gnu compiler
  float* coords = (float*) __builtin_assume_aligned(coords_pointer.get(), DC_MEM_ALIGNMENT);
  #endif

  std::vector<std::size_t> pops(n_rows, 1);
  const float rad2 = radius * radius;
  std::size_t i, j, k;
  float dist, c;
  #pragma omp parallel for default(shared) private(i,j,k,c,dist) firstprivate(n_rows,n_cols,rad2) schedule(dynamic)
  for (i=0; i < n_rows; ++i) {
    for (j=i+1; j < n_rows; ++j) {
      dist = 0.0f;
      for (k=0; k < n_cols; ++k) {
        c = coords[i*n_cols+k] - coords[j*n_cols+k];
        dist += c*c;
      }
      if (dist < rad2) {
        pops[i] += 1;
      }
    }
  }
  return pops;
}

std::vector<float>
calculate_densities(const std::vector<std::size_t>& pops) {
  std::size_t i;
  const std::size_t n_frames = pops.size();
  const float max_pop = (float) ( * std::max_element(pops.begin(), pops.end()));
  std::vector<float> dens(n_frames);
  #pragma omp parallel for default(shared) private(i) firstprivate(max_pop, n_frames)
  for (i=0; i < n_frames; ++i) {
    dens[i] = (float) pops[i] / max_pop;
  }
  return dens;
}

/*
 * returns the smallest squared distance between two clusters defined
 * by ids in 'frames_cluster_1' and 'frames_cluster_2' based on the
 * given coordinate set.
 */
float
cluster_min_dist2(const CoordsPointer<float>& coords_pointer,
                  std::size_t n_cols,
                  const std::vector<std::size_t>& frames_cluster_1,
                  const std::vector<std::size_t>& frames_cluster_2) {
  #if defined(__INTEL_COMPILER)
  float* coords = coords_pointer.get();
  __assume_aligned(coords, DC_MEM_ALIGNMENT);
  #else // assume gnu compiler
  float* coords = (float*) __builtin_assume_aligned(coords_pointer.get(), DC_MEM_ALIGNMENT);
  #endif
  std::size_t n_frames_1 = frames_cluster_1.size();
  std::size_t n_frames_2 = frames_cluster_2.size();
  std::size_t i,j,c;
  float dist,d;
  float min_dist = std::numeric_limits<float>::max();
  #pragma omp parallel for \
    default(shared) \
    private(i,j,c,d,dist) \
    firstprivate(n_frames_1,n_frames_2,n_cols) \
    collapse(2) \
    reduction(min: min_dist)
  for (i=0; i < n_frames_1; ++i) {
    for (j=0; j < n_frames_2; ++j) {
      dist = 0.0f;
      for (c=0; c < n_cols; ++c) {
        d = coords[frames_cluster_1[i]*n_cols+c] - coords[frames_cluster_2[j]*n_cols+c];
        dist += d*d;
      }
      if (dist < min_dist) {
        min_dist = dist;
      }
    }
  }
  return min_dist;
}

const std::pair<std::size_t, float>
nearest_neighbor(const CoordsPointer<float>& coords_pointer,
                 const std::vector<Density>& sorted_density,
                 std::size_t n_cols,
                 std::size_t frame_id,
                 std::pair<std::size_t, std::size_t> search_range) {

  #if defined(__INTEL_COMPILER)
  float* coords = coords_pointer.get();
  __assume_aligned(coords, DC_MEM_ALIGNMENT);
  #else // assume gnu compiler
  float* coords = (float*) __builtin_assume_aligned(coords_pointer.get(), DC_MEM_ALIGNMENT);
  #endif
  std::size_t c,j;
  float d, dist;
  std::vector<float> distances(search_range.second-search_range.first);
  #pragma omp parallel for default(shared) private(dist,j,c,d) firstprivate(n_cols)
  for (j=search_range.first; j < search_range.second; ++j) {
    if (frame_id == j) {
      continue;
    }
    dist = 0.0f;
    for (c=0; c < n_cols; ++c) {
      d = coords[sorted_density[frame_id].first*n_cols+c] - coords[sorted_density[j].first*n_cols+c];
      dist += d*d;
    }
    distances[j-search_range.first] = dist;
  }
  if (distances.size() == 0) {
    return {0, 0.0f};
  } else {
    std::size_t min_ndx = std::min_element(distances.begin(), distances.end()) - distances.begin();
    return {min_ndx+search_range.first, distances[min_ndx]};
  }
}

std::vector<std::size_t>
density_clustering(const std::vector<float>& dens,
                   const float density_threshold,
                   const float density_radius,
                   const CoordsPointer<float>& coords_pointer,
                   const std::size_t n_rows,
                   const std::size_t n_cols) {

  std::vector<Density> density_sorted;
  for (std::size_t i=0; i < dens.size(); ++i) {
    density_sorted.push_back({i, dens[i]});
  }
  // sort for density: highest to lowest
  std::sort(density_sorted.begin(),
            density_sorted.end(),
            [] (const Density& d1, const Density& d2) -> bool {return d1.second > d2.second;});
  auto lb = std::lower_bound(density_sorted.begin(),
                             density_sorted.end(),
                             Density(0, density_threshold),
                             [](const Density& d1, const Density& d2) -> bool {return d1.second > d2.second;});
  std::size_t last_frame_below_threshold = (lb - density_sorted.begin());
  // find initial clusters
//////////////////////////

  std::vector<std::size_t> clustering;

  std::cout << "computing sigma ..." << std::endl;
  // compute sigma as standard deviation of nearest-neighbor distances
  float sigma = 0.0f;
  for (std::size_t i=0; i < n_rows; ++i) {
    if (i % 1000 == 0) std::cout << i << " / " << n_rows << "; sum(sigma): " << sigma << std::endl;
    sigma += nearest_neighbor(coords_pointer, density_sorted, n_cols, i, {0,n_rows}).second;
  }
  sigma /= n_rows;

  std::cout << "sigma: " << sigma << std::endl;

  exit(2);

  std::size_t n_clusters = 1;
  std::map<std::size_t, std::vector<std::size_t>> clusters;
  // initialize with highest populated frame
  clusters[1] = {density_sorted[0].first};

  for (std::size_t i=1; i < last_frame_below_threshold; ++i) {
    // find (existing) cluster for this frame
    std::vector<std::size_t> fake_cluster = {i};
    float min_dist2 = std::numeric_limits<float>::max();
    std::size_t min_clust = 0;
    for (auto& cluster: clusters) {
      float dist2 = cluster_min_dist2(coords_pointer, n_cols, fake_cluster, cluster.second);
      if (dist2 < min_dist2) {
        min_dist2 = dist2;
        min_clust = cluster.first;
      }
    }
    // decide on new cluster vs appending
    if (min_dist2 < sigma*sigma) {
      // in range of cluster: append
      //TODO
    } else {
      // outside every cluster-bound: new cluster from this frame
      //TODO
    }
  }

  exit(3);

//  for (std::size_t i=1; i < last_frame_below_threshold; ++i) {
//    // nn_pair:  first := index in traj,  second := distance to reference (i)
//    auto nn_pair = nearest_neighbor(coords_pointer, density_sorted, n_cols, i, {0,i});
//    if (nn_pair.second < density_radius*density_radius) {
//      // add to existing cluster of frame with 'min_dist'
//      clustering[density_sorted[i].first] = clustering[density_sorted[nn_pair.first].first];
//    } else {
//      // create new cluster
//      ++n_clusters;
//      clustering[density_sorted[i].first] = n_clusters;
//    }
//  }
/////////////////////////

  // find nearest neighbors for all unassigned frames
  std::map<std::size_t, std::size_t> nearest_neighbors;
  for (std::size_t i=last_frame_below_threshold; i < density_sorted.size(); ++i) {
    if (i % 100 == 0) std::cout << i << "  /  " << density_sorted.size() << std::endl;
    // nn_pair:  first := index in traj,  second := distance to reference (i)
    auto nn_pair = nearest_neighbor(coords_pointer, density_sorted, n_cols, i, {0, density_sorted.size()});
    nearest_neighbors[i] = nn_pair.first;
  }
  log("assign frames to clusters");
  // assign clusters to unassigned frames via neighbor-info
  bool nothing_happened = true;
  while (nearest_neighbors.size() > 0 && ( ! nothing_happened)) {
    nothing_happened = true;
    // it:  first := index in traj,  second := distance to reference (i)
    for (auto it=nearest_neighbors.begin(); it != nearest_neighbors.end(); ++it) {
      if (clustering[it->second] != 0) {
        clustering[it->first] = it->second;
        nearest_neighbors.erase(it);
        nothing_happened = false;
      }
    }
  }
  return clustering;
}

////////

int main(int argc, char* argv[]) {

  b_po::variables_map args;
  b_po::options_description desc (std::string(argv[0]).append(
    "\n\n"
    "perform clustering of MD data based on phase space densities.\n"
    "densities are approximated by counting neighboring frames inside\n"
    "a n-dimensional hypersphere of specified radius.\n"
    "distances are measured with n-dim P2-norm.\n"
    "\n"
    "options"));
  desc.add_options()
    ("help,h", b_po::bool_switch()->default_value(false), "show this help.")
    // required
    ("file,f", b_po::value<std::string>()->required(), "input (required): phase space coordinates (space separated ASCII).")
    ("output,o", b_po::value<std::string>()->required(), "output (required): clustering information.")
    ("radius,r", b_po::value<float>()->required(), "parameter (required): hypersphere radius.")
    ("threshold,t", b_po::value<float>()->required(), "parameter (required, elem. of [0.0, 1.0]): density threshold for clustering.")
    // optional
    ("population,p", b_po::value<std::string>(), "output (optional): population per frame.")
    ("density,d", b_po::value<std::string>(), "output (optional): density per frame.")
    ("density-input,D", b_po::value<std::string>(), "input (optional): reuse density info.")
    // defaults
    ("nthreads,n", b_po::value<int>()->default_value(0), "number of OpenMP threads. default: 0; i.e. use OMP_NUM_THREADS env-variable.")
    ("verbose,v", b_po::bool_switch()->default_value(false), "verbose mode: print max density, runtime information, etc. to STDOUT.")
  ;

  try {
    b_po::store(b_po::command_line_parser(argc, argv).options(desc).run(), args);
    b_po::notify(args);
  } catch (b_po::error& e) {
    if ( ! args["help"].as<bool>()) {
      std::cout << "\n" << e.what() << "\n\n" << std::endl;
    }
    std::cout << desc << std::endl;
    return 2;
  }

  if (args["help"].as<bool>()) {
    std::cout << desc << std::endl;
    return 1;
  }

  ////

  const std::string input_file = args["file"].as<std::string>();
  const std::string output_file = args["output"].as<std::string>();

  const float radius = args["radius"].as<float>();
  const float threshold = args["threshold"].as<float>();

  // setup OpenMP
  const int n_threads = args["nthreads"].as<int>();
  if (n_threads > 0) {
    omp_set_num_threads(n_threads);
  }

  bool verbose = args["verbose"].as<bool>();

  CoordsPointer<float> coords_pointer;
  std::size_t n_rows;
  std::size_t n_cols;
  std::tie(coords_pointer, n_rows, n_cols) = read_coords<float>(input_file);

  std::vector<float> densities;

  if (args.count("density-input")) {
    if (verbose) {
      log("re-using density data.");
    }
    // reuse density info
    std::ifstream ifs(args["density-input"].as<std::string>());
    if (ifs.fail()) {
      std::cerr << "error: cannot open file '" << args["density-input"].as<std::string>() << "'" << std::endl;
      return 3;
    } else {
      while(ifs.good()) {
        float buf;
        ifs >> buf;
        densities.push_back(buf);
      }
    }
  } else {
    if (verbose) {
      log("calculating densities");
    }
    densities = calculate_densities(
                  calculate_populations(coords_pointer, n_rows, n_cols, radius));
    if (args.count("density")) {
      std::ofstream ofs(args["density"].as<std::string>());
      ofs << std::scientific;
      for (float d: densities) {
        ofs << d << "\n";
      }
    }
  }

  if (verbose) {
    log("calculating clusters");
  }
  std::vector<std::size_t> clustering = density_clustering(densities, threshold, radius, coords_pointer, n_rows, n_cols);
  // write clusters to file
  {
    std::ofstream ofs(output_file);
    if (ofs.fail()) {
      std::cerr << "error: cannot open file '" << output_file << "' for writing." << std::endl;
      return 3;
    }
    for (std::size_t i: clustering) {
      ofs << i << "\n";
    }
  }
  return 0;
}

<|endoftext|>


<commit_before>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "prototypes.h"
#include "mixerr.h"

extern "C" {
	double rtdispatch(char *fname, double *pp, int n_args, void **inst)
	{
		double rv;

		rv = checkInsts(fname, pp, n_args, inst);
		return rv;
	}
}

<commit_msg>The file/function was no longer being used -- BGG<commit_after><|endoftext|>


<commit_before>/** \file   LocalDataDB.cc
 *  \brief  Implementation of the LocalDataDB class.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2020 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "LocalDataDB.h"
#include "Compiler.h"
#include "DbConnection.h"
#include "StringUtil.h"
#include "UBTools.h"

LocalDataDB::LocalDataDB(const OpenMode open_mode) {
    db_connection_ = new DbConnection(UBTools::GetTuelibPath() + "local_data.sq3" /* must be the same path as in fetch_marc_updates.py */,
                                      (open_mode == READ_WRITE) ? DbConnection::CREATE : DbConnection::READONLY);
    if (open_mode == READ_ONLY)
        return;

    db_connection_->queryOrDie("CREATE TABLE IF NOT EXISTS local_data ("
                               "    title_ppn TEXT PRIMARY KEY,"
                               "    local_fields BLOB NOT NULL"
                               ") WITHOUT ROWID");
    db_connection_->queryOrDie("CREATE UNIQUE INDEX IF NOT EXISTS local_data_index ON local_data (title_ppn)");

    db_connection_->queryOrDie("CREATE TABLE IF NOT EXISTS local_ppns_to_title_ppns_map ("
                               "    local_ppn TEXT PRIMARY KEY,"
                               "    title_ppn TEXT NOT NULL,"
                               "    FOREIGN KEY(title_ppn) REFERENCES local_data(title_ppn)"
                               ") WITHOUT ROWID");
    db_connection_->queryOrDie("CREATE UNIQUE INDEX IF NOT EXISTS local_ppns_to_title_ppns_mapindex "
                               "ON local_ppns_to_title_ppns_map (local_ppn)");
}

LocalDataDB::~LocalDataDB() {
    delete db_connection_;
}

void LocalDataDB::clear() {
    db_connection_->queryOrDie("DROP TABLE IF EXISTSlocal_data");
    db_connection_->queryOrDie("DROP TABLE IF EXISTSlocal_ppns_to_title_ppns_map");
}

static std::vector<std::string> BlobToLocalFieldsVector(const std::string &local_fields_blob, const std::string &title_ppn) {
    std::vector<std::string> local_fields;

    size_t processed_size(0);
    do {
        // Convert the 4 character hex string to the size of the following field contents:
        const size_t field_contents_size(StringUtil::ToUnsignedLong(local_fields_blob.substr(processed_size, 4), 16));
        processed_size += 4;

        // Sanity check:
        if (unlikely(processed_size + field_contents_size > local_fields_blob.size()))
            LOG_ERROR("inconsistent blob length for record with PPN " + title_ppn + " (1)");

        local_fields.emplace_back(local_fields_blob.substr(processed_size, field_contents_size));
        processed_size += field_contents_size;
    } while (processed_size < local_fields_blob.size());

    // Sanity check:
    if (unlikely(processed_size != local_fields_blob.size()))
        LOG_ERROR("inconsistent blob length for record with PPN " + title_ppn + " (2))");

    return local_fields;
}

std::vector<std::string> ExtractLocalPPNsFromLocalFieldsVector(const std::vector<std::string> &local_fields) {
    std::vector<std::string> local_ppns;

    for (const auto &local_field : local_fields) {
        if (StringUtil::StartsWith(local_field, "001 "))
            local_ppns.emplace_back(local_field.substr(__builtin_strlen("001 ")));
    }

    return local_ppns;
}

static std::string ConvertLocalFieldsVectorToBlob(const std::vector<std::string> &local_fields) {
    std::string local_fields_blob;
    for (const auto &local_field : local_fields) {
        local_fields_blob += StringUtil::ToString(local_field.length(), /* radix = */16,
                                                  /* width = */4, /* padding_char = */'0');
        local_fields_blob += local_field;
    }

    return local_fields_blob;
}

void LocalDataDB::insertOrReplace(const std::string &title_ppn, const std::vector<std::string> &local_fields) {
    // 1. Clear out any local PPNs associated with "title_ppn":
    db_connection_->queryOrDie("SELECT local_fields FROM local_data WHERE title_ppn = "
                               + db_connection_->escapeAndQuoteString(title_ppn));
    auto result_set(db_connection_->getLastResultSet());
    if (not result_set.empty()) {
        const auto row(result_set.getNextRow());
        const auto previous_local_fields(BlobToLocalFieldsVector(row["local_fields"], title_ppn));
        const auto local_ppns(ExtractLocalPPNsFromLocalFieldsVector(previous_local_fields));
        for (const auto &local_ppn : local_ppns)
            db_connection_->queryOrDie("DELETE FROM local_ppns_to_title_ppns_map WHERE local_ppn="
                                       + db_connection_->escapeAndQuoteString(local_ppn));
    }

    // 2. Replace or insert the local data keyed by the title PPN's:
    db_connection_->queryOrDie("REPLACE INTO local_data (title_ppn, local_fields) VALUES("
                               + db_connection_->escapeAndQuoteString(title_ppn) + ","
                               + db_connection_->sqliteEscapeBlobData(ConvertLocalFieldsVectorToBlob(local_fields)) + ")");

    // 3. Insert the mappings from the local PPN's to the title PPN's:
    for (const auto &local_ppn : ExtractLocalPPNsFromLocalFieldsVector(local_fields)) {
        db_connection_->queryOrDie("INSERT INTO local_ppns_to_title_ppns_map (local_ppn, title_ppn) VALUES("
                                   + db_connection_->escapeAndQuoteString(local_ppn) + ","
                                   + db_connection_->escapeAndQuoteString(title_ppn) + ")");
    }
}

std::vector<std::string> LocalDataDB::getLocalFields(const std::string &title_ppn) const {
    db_connection_->queryOrDie("SELECT local_fields FROM local_data WHERE title_ppn = "
                               + db_connection_->escapeAndQuoteString(title_ppn));
    auto result_set(db_connection_->getLastResultSet());
    if (result_set.empty())
        return {}; // empty vector

    const auto row(result_set.getNextRow());
    return BlobToLocalFieldsVector(row["local_fields"], title_ppn);
}

bool LocalDataDB::removeTitleDataSet(const std::string &title_ppn) {
    // 1. Clear out any local PPNs associated with "title_ppn":
    db_connection_->queryOrDie("SELECT local_fields FROM local_data WHERE title_ppn = "
                               + db_connection_->escapeAndQuoteString(title_ppn));
    auto result_set(db_connection_->getLastResultSet());
    if (result_set.empty())
        return false;

    const auto row(result_set.getNextRow());
    const auto previous_local_fields(BlobToLocalFieldsVector(row["local_fields"], title_ppn));
    const auto local_ppns(ExtractLocalPPNsFromLocalFieldsVector(previous_local_fields));
    for (const auto &local_ppn : local_ppns)
        db_connection_->queryOrDie("DELETE FROM local_ppns_to_title_ppns_map WHERE local_ppn="
                                   + db_connection_->escapeAndQuoteString(local_ppn));

    // 2. Delete the local data for the title PPN:
    db_connection_->queryOrDie("DELETE FROM local_data WHERE title_ppn = "
                               + db_connection_->escapeAndQuoteString(title_ppn));

    return true;
}

// Removes all fields from "local_fields" that are associated w/ "local_ppn".
static std::vector<std::string> RemoveLocalDataSet(const std::string &local_ppn,
                                                   const std::vector<std::string> &local_fields)
{
    std::vector<std::string> filtered_local_fields;
    filtered_local_fields.reserve(local_fields.size());

    bool skipping(false);
    for (const auto &local_field : local_fields) {
        if (StringUtil::StartsWith(local_field, "001 "))
            skipping = local_field.substr(__builtin_strlen("001 ")) == local_ppn;
        if (not skipping)
            filtered_local_fields.emplace_back(local_field);
    }

    return filtered_local_fields;
}

bool LocalDataDB::removeLocalDataSet(const std::string &local_ppn) {
    // 1. Determine the title PPN associated w/ the local PPN:
    db_connection_->queryOrDie("SELECT title_ppn FROM local_ppns_to_title_ppns_map WHERE local_ppn="
                               + db_connection_->escapeAndQuoteString(local_ppn));
    auto result_set(db_connection_->getLastResultSet());
    if (result_set.empty())
        return false;
    const auto row(result_set.getNextRow());
    const auto title_ppn(row["title_ppn"]);

    // 2. Retrieve the local data associated w/ the title PPN:
    auto local_fields(getLocalFields(title_ppn));

    // 3. Remove the local data associsted w/ the local PPN:
    const auto filtered_local_fields(RemoveLocalDataSet(local_ppn, local_fields));

    // 4. Update our SQL tables:
    db_connection_->queryOrDie("DELETE FROM local_ppns_to_title_ppns_map WHERE ocal_ppn="
                               + db_connection_->escapeAndQuoteString(local_ppn));
    if (filtered_local_fields.empty())
        db_connection_->queryOrDie("DELETE FROM local_fields WHERE title_ppn="
                                   + db_connection_->escapeAndQuoteString(title_ppn));
    else
        db_connection_->queryOrDie("REPLACE INTO local_data (titel_ppn, local_fields) VALUES("
                                   + db_connection_->escapeAndQuoteString(title_ppn) + ","
                                   + db_connection_->sqliteEscapeBlobData(ConvertLocalFieldsVectorToBlob(local_fields)) + ")");

    return true;
}
<commit_msg>Various typo fixes.<commit_after>/** \file   LocalDataDB.cc
 *  \brief  Implementation of the LocalDataDB class.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2020 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "LocalDataDB.h"
#include "Compiler.h"
#include "DbConnection.h"
#include "StringUtil.h"
#include "UBTools.h"

LocalDataDB::LocalDataDB(const OpenMode open_mode) {
    db_connection_ = new DbConnection(UBTools::GetTuelibPath() + "local_data.sq3" /* must be the same path as in fetch_marc_updates.py */,
                                      (open_mode == READ_WRITE) ? DbConnection::CREATE : DbConnection::READONLY);
    if (open_mode == READ_ONLY)
        return;

    db_connection_->queryOrDie("CREATE TABLE IF NOT EXISTS local_data ("
                               "    title_ppn TEXT PRIMARY KEY,"
                               "    local_fields BLOB NOT NULL"
                               ") WITHOUT ROWID");
    db_connection_->queryOrDie("CREATE UNIQUE INDEX IF NOT EXISTS local_data_index ON local_data (title_ppn)");

    db_connection_->queryOrDie("CREATE TABLE IF NOT EXISTS local_ppns_to_title_ppns_map ("
                               "    local_ppn TEXT PRIMARY KEY,"
                               "    title_ppn TEXT NOT NULL,"
                               "    FOREIGN KEY(title_ppn) REFERENCES local_data(title_ppn)"
                               ") WITHOUT ROWID");
    db_connection_->queryOrDie("CREATE UNIQUE INDEX IF NOT EXISTS local_ppns_to_title_ppns_mapindex "
                               "ON local_ppns_to_title_ppns_map (local_ppn)");
}

LocalDataDB::~LocalDataDB() {
    delete db_connection_;
}

void LocalDataDB::clear() {
    db_connection_->queryOrDie("DROP TABLE IF EXISTS local_data");
    db_connection_->queryOrDie("DROP TABLE IF EXISTS local_ppns_to_title_ppns_map");
}

static std::vector<std::string> BlobToLocalFieldsVector(const std::string &local_fields_blob, const std::string &title_ppn) {
    std::vector<std::string> local_fields;

    size_t processed_size(0);
    do {
        // Convert the 4 character hex string to the size of the following field contents:
        const size_t field_contents_size(StringUtil::ToUnsignedLong(local_fields_blob.substr(processed_size, 4), 16));
        processed_size += 4;

        // Sanity check:
        if (unlikely(processed_size + field_contents_size > local_fields_blob.size()))
            LOG_ERROR("inconsistent blob length for record with PPN " + title_ppn + " (1)");

        local_fields.emplace_back(local_fields_blob.substr(processed_size, field_contents_size));
        processed_size += field_contents_size;
    } while (processed_size < local_fields_blob.size());

    // Sanity check:
    if (unlikely(processed_size != local_fields_blob.size()))
        LOG_ERROR("inconsistent blob length for record with PPN " + title_ppn + " (2))");

    return local_fields;
}

std::vector<std::string> ExtractLocalPPNsFromLocalFieldsVector(const std::vector<std::string> &local_fields) {
    std::vector<std::string> local_ppns;

    for (const auto &local_field : local_fields) {
        if (StringUtil::StartsWith(local_field, "001 "))
            local_ppns.emplace_back(local_field.substr(__builtin_strlen("001 ")));
    }

    return local_ppns;
}

static std::string ConvertLocalFieldsVectorToBlob(const std::vector<std::string> &local_fields) {
    std::string local_fields_blob;
    for (const auto &local_field : local_fields) {
        local_fields_blob += StringUtil::ToString(local_field.length(), /* radix = */16,
                                                  /* width = */4, /* padding_char = */'0');
        local_fields_blob += local_field;
    }

    return local_fields_blob;
}

void LocalDataDB::insertOrReplace(const std::string &title_ppn, const std::vector<std::string> &local_fields) {
    // 1. Clear out any local PPNs associated with "title_ppn":
    db_connection_->queryOrDie("SELECT local_fields FROM local_data WHERE title_ppn = "
                               + db_connection_->escapeAndQuoteString(title_ppn));
    auto result_set(db_connection_->getLastResultSet());
    if (not result_set.empty()) {
        const auto row(result_set.getNextRow());
        const auto previous_local_fields(BlobToLocalFieldsVector(row["local_fields"], title_ppn));
        const auto local_ppns(ExtractLocalPPNsFromLocalFieldsVector(previous_local_fields));
        for (const auto &local_ppn : local_ppns)
            db_connection_->queryOrDie("DELETE FROM local_ppns_to_title_ppns_map WHERE local_ppn="
                                       + db_connection_->escapeAndQuoteString(local_ppn));
    }

    // 2. Replace or insert the local data keyed by the title PPN's:
    db_connection_->queryOrDie("REPLACE INTO local_data (title_ppn, local_fields) VALUES("
                               + db_connection_->escapeAndQuoteString(title_ppn) + ","
                               + db_connection_->sqliteEscapeBlobData(ConvertLocalFieldsVectorToBlob(local_fields)) + ")");

    // 3. Insert the mappings from the local PPN's to the title PPN's:
    for (const auto &local_ppn : ExtractLocalPPNsFromLocalFieldsVector(local_fields)) {
        db_connection_->queryOrDie("INSERT INTO local_ppns_to_title_ppns_map (local_ppn, title_ppn) VALUES("
                                   + db_connection_->escapeAndQuoteString(local_ppn) + ","
                                   + db_connection_->escapeAndQuoteString(title_ppn) + ")");
    }
}

std::vector<std::string> LocalDataDB::getLocalFields(const std::string &title_ppn) const {
    db_connection_->queryOrDie("SELECT local_fields FROM local_data WHERE title_ppn = "
                               + db_connection_->escapeAndQuoteString(title_ppn));
    auto result_set(db_connection_->getLastResultSet());
    if (result_set.empty())
        return {}; // empty vector

    const auto row(result_set.getNextRow());
    return BlobToLocalFieldsVector(row["local_fields"], title_ppn);
}

bool LocalDataDB::removeTitleDataSet(const std::string &title_ppn) {
    // 1. Clear out any local PPNs associated with "title_ppn":
    db_connection_->queryOrDie("SELECT local_fields FROM local_data WHERE title_ppn = "
                               + db_connection_->escapeAndQuoteString(title_ppn));
    auto result_set(db_connection_->getLastResultSet());
    if (result_set.empty())
        return false;

    const auto row(result_set.getNextRow());
    const auto previous_local_fields(BlobToLocalFieldsVector(row["local_fields"], title_ppn));
    const auto local_ppns(ExtractLocalPPNsFromLocalFieldsVector(previous_local_fields));
    for (const auto &local_ppn : local_ppns)
        db_connection_->queryOrDie("DELETE FROM local_ppns_to_title_ppns_map WHERE local_ppn="
                                   + db_connection_->escapeAndQuoteString(local_ppn));

    // 2. Delete the local data for the title PPN:
    db_connection_->queryOrDie("DELETE FROM local_data WHERE title_ppn = "
                               + db_connection_->escapeAndQuoteString(title_ppn));

    return true;
}

// Removes all fields from "local_fields" that are associated w/ "local_ppn".
static std::vector<std::string> RemoveLocalDataSet(const std::string &local_ppn,
                                                   const std::vector<std::string> &local_fields)
{
    std::vector<std::string> filtered_local_fields;
    filtered_local_fields.reserve(local_fields.size());

    bool skipping(false);
    for (const auto &local_field : local_fields) {
        if (StringUtil::StartsWith(local_field, "001 "))
            skipping = local_field.substr(__builtin_strlen("001 ")) == local_ppn;
        if (not skipping)
            filtered_local_fields.emplace_back(local_field);
    }

    return filtered_local_fields;
}

bool LocalDataDB::removeLocalDataSet(const std::string &local_ppn) {
    // 1. Determine the title PPN associated w/ the local PPN:
    db_connection_->queryOrDie("SELECT title_ppn FROM local_ppns_to_title_ppns_map WHERE local_ppn="
                               + db_connection_->escapeAndQuoteString(local_ppn));
    auto result_set(db_connection_->getLastResultSet());
    if (result_set.empty())
        return false;
    const auto row(result_set.getNextRow());
    const auto title_ppn(row["title_ppn"]);

    // 2. Retrieve the local data associated w/ the title PPN:
    auto local_fields(getLocalFields(title_ppn));

    // 3. Remove the local data associated w/ the local PPN:
    const auto filtered_local_fields(RemoveLocalDataSet(local_ppn, local_fields));

    // 4. Update our SQL tables:
    db_connection_->queryOrDie("DELETE FROM local_ppns_to_title_ppns_map WHERE local_ppn="
                               + db_connection_->escapeAndQuoteString(local_ppn));
    if (filtered_local_fields.empty())
        db_connection_->queryOrDie("DELETE FROM local_fields WHERE title_ppn="
                                   + db_connection_->escapeAndQuoteString(title_ppn));
    else
        db_connection_->queryOrDie("REPLACE INTO local_data (titel_ppn, local_fields) VALUES("
                                   + db_connection_->escapeAndQuoteString(title_ppn) + ","
                                   + db_connection_->sqliteEscapeBlobData(ConvertLocalFieldsVectorToBlob(local_fields)) + ")");

    return true;
}
<|endoftext|>