LCOV - code coverage report
Current view: top level - coupling/interface/impl/SimpleMD - SimpleMDSolverInterface.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 16 117 13.7 %
Date: 2026-02-16 14:39:39 Functions: 3 22 13.6 %

          Line data    Source code
       1             : // Copyright (C) 2015 Technische Universitaet Muenchen
       2             : // This file is part of the Mamico project. For conditions of distribution
       3             : // and use, please see the copyright notice in Mamico's main folder, or at
       4             : // www5.in.tum.de/mamico
       5             : #ifndef _MOLECULARDYNAMICS_COUPLING_INTERFACE_SIMPLEMDSOLVERINTERFACE_CPP_
       6             : #define _MOLECULARDYNAMICS_COUPLING_INTERFACE_SIMPLEMDSOLVERINTERFACE_CPP_
       7             : #include "simplemd/BoundaryTreatment.h"
       8             : #include "simplemd/MolecularDynamicsDefinitions.h"
       9             : #include "simplemd/cell-mappings/LennardJonesForceMapping.h"
      10             : #include "simplemd/cell-mappings/LennardJonesPotentialEnergyMapping.h"
      11             : #include "simplemd/cell-mappings/ResetPotentialEnergyMapping.h"
      12             : #include "simplemd/services/ExternalForceService.h"
      13             : #include "simplemd/services/MolecularPropertiesService.h"
      14             : #include "simplemd/services/ParallelTopologyService.h"
      15             : #include "simplemd/services/MoleculeService.h"
      16             : 
      17             : #include "coupling/CouplingMDDefinitions.h"
      18             : #include "coupling/interface/MDSolverInterface.h"
      19             : #include "coupling/interface/impl/SimpleMD/SimpleMDMoleculeIterator.h"
      20             : #include "coupling/interface/impl/SimpleMD/SimpleMDLinkedCellWrapper.h"
      21             : 
      22             : namespace coupling {
      23             : namespace interface {
      24             : 
      25             : /** general MD solver interface for SimpleMD.
      26             :  *  @author Philipp Neumann
      27             :  */
      28             : class SimpleMDSolverInterface : public MDSolverInterface<SimpleMDLinkedCellWrapper, MD_DIM> {
      29             : private:
      30             :   std::vector<SimpleMDLinkedCellWrapper*> _linkedCells;
      31             :   simplemd::services::ParallelTopologyService& _parallelTopologyService;
      32             :   simplemd::services::MoleculeService& _moleculeService;
      33             :   const simplemd::services::MolecularPropertiesService& _molecularPropertiesService;
      34             :   /** used for the synchronization of molecules in boundary regions and between different processes when
      35             :    *  mass was inserted/ deleted by the coupling.
      36             :    */
      37             :   simplemd::BoundaryTreatment& _boundaryTreatment;
      38             :   const tarch::la::Vector<MD_LINKED_CELL_NEIGHBOURS, simplemd::BoundaryType>& _localBoundaryInformation;
      39             : 
      40             :   /** number of linked cells in each coupling cell */
      41             : 
      42             :   const double _sigma6;
      43             :   const double _epsilon;
      44             :   const double _cutoffRadiusSquared;
      45             :   const double _cutoffEnergy;
      46             : 
      47             :   const double _dt;
      48             : 
      49             :   tarch::la::Vector<MD_DIM, unsigned int>
      50             :   computeNumberOfLinkedCellsPerCouplingCells(const tarch::la::Vector<MD_DIM, unsigned int>& localNumberOfCouplingCells) const {
      51             :     tarch::la::Vector<MD_DIM, unsigned int> numberOfLinkedCells(0);
      52             :     for (unsigned int d = 0; d < MD_DIM; d++) {
      53             :       numberOfLinkedCells[d] = _moleculeService.getContainer().getLocalNumberOfCells()[d] / localNumberOfCouplingCells[d];
      54             : #if (COUPLING_MD_ERROR == COUPLING_MD_YES)
      55             :       if (numberOfLinkedCells[d] * localNumberOfCouplingCells[d] != _moleculeService.getContainer().getLocalNumberOfCells()[d]) {
      56             :         std::cout << "ERROR coupling::interface::SimpleMDSolverInterface: Number of linked cells is not a multiple of the coupling cells!" << std::endl;
      57             :         std::cout << "Number linked cells: " << numberOfLinkedCells << ", coupling cells: " << localNumberOfCouplingCells << std::endl;
      58             :         std::cout << "Local number of linked cells: " << _moleculeService.getContainer().getLocalNumberOfCells() << std::endl;
      59             :         exit(EXIT_FAILURE);
      60             :       }
      61             : #endif
      62             :     }
      63             :     return numberOfLinkedCells;
      64             :   }
      65             : 
      66             :   /** Though this method is available in LennardJonesPotentialEnergyMapping, I re-implemented it at
      67             :    *  this stage, as the latter always fetches the epsilon,sigma-parameters first. This is nice for
      68             :    *  simulations where parameters are changed over time; however for static simulations it just slows
      69             :    *  down...
      70             :    */
      71           0 :   double getPotentialEnergy(const tarch::la::Vector<MD_DIM, double>& position1, const tarch::la::Vector<MD_DIM, double>& position2) const {
      72           0 :     const tarch::la::Vector<MD_DIM, double> distance(position2 - position1);
      73           0 :     const double r2 = tarch::la::dot(distance, distance);
      74             :     // if we are in the near distance, do computation, otherwise return 0.0
      75           0 :     if (r2 <= _cutoffRadiusSquared) {
      76           0 :       const double r6 = r2 * r2 * r2;
      77           0 :       const double energyBuffer = 4.0 * _epsilon * (_sigma6 / r6) * ((_sigma6 / r6) - 1.0) - _cutoffEnergy;
      78           0 :       return 0.5 * energyBuffer;
      79             :     } else {
      80             :       return 0.0;
      81             :     }
      82             :   }
      83             : 
      84           0 :   tarch::la::Vector<MD_DIM, double> getLennardJonesForce(const tarch::la::Vector<MD_DIM, double>& position1,
      85             :                                                          const tarch::la::Vector<MD_DIM, double>& position2) const {
      86           0 :     const tarch::la::Vector<MD_DIM, double> rij(position2 - position1);
      87           0 :     const double rij2 = tarch::la::dot(rij, rij);
      88             : #if (MD_ERROR == MD_YES)
      89           0 :     if (rij2 == 0.0) {
      90           0 :       std::cout << "ERROR cellmappings::LennardJonesForceMapping::getLennardJonesForce(): Particle positions are identical!" << std::endl;
      91           0 :       exit(EXIT_FAILURE);
      92             :     }
      93             : #endif
      94             : 
      95           0 :     if (rij2 <= _cutoffRadiusSquared) {
      96           0 :       const double rij6 = rij2 * rij2 * rij2;
      97           0 :       return 24.0 * _epsilon / rij2 * (_sigma6 / rij6) * (1.0 - 2.0 * (_sigma6 / rij6)) * rij;
      98             :     } else {
      99           0 :       return tarch::la::Vector<MD_DIM, double>(0.0);
     100             :     }
     101             :   }
     102             : 
     103             : public:
     104          12 :   SimpleMDSolverInterface(simplemd::BoundaryTreatment& boundaryTreatment, simplemd::services::ParallelTopologyService& parallelTopologyService,
     105             :                           simplemd::services::MoleculeService& moleculeService,
     106             :                           const simplemd::services::MolecularPropertiesService& molecularPropertiesService,
     107             :                           const tarch::la::Vector<MD_LINKED_CELL_NEIGHBOURS, simplemd::BoundaryType>& localBoundaryInformation, const double& dt)
     108          12 :       : _parallelTopologyService(parallelTopologyService), _moleculeService(moleculeService), _molecularPropertiesService(molecularPropertiesService),
     109          12 :         _boundaryTreatment(boundaryTreatment), _localBoundaryInformation(localBoundaryInformation),
     110          12 :         _sigma6(molecularPropertiesService.getMolecularProperties().getSigma() * molecularPropertiesService.getMolecularProperties().getSigma() *
     111          12 :                 molecularPropertiesService.getMolecularProperties().getSigma() * molecularPropertiesService.getMolecularProperties().getSigma() *
     112          12 :                 molecularPropertiesService.getMolecularProperties().getSigma() * molecularPropertiesService.getMolecularProperties().getSigma()),
     113          12 :         _epsilon(molecularPropertiesService.getMolecularProperties().getEpsilon()),
     114          12 :         _cutoffRadiusSquared(molecularPropertiesService.getMolecularProperties().getCutOffRadius() *
     115          12 :                              molecularPropertiesService.getMolecularProperties().getCutOffRadius()),
     116          12 :         _cutoffEnergy(4.0 * _epsilon * _sigma6 / (_cutoffRadiusSquared * _cutoffRadiusSquared * _cutoffRadiusSquared) *
     117          12 :                       (_sigma6 / (_cutoffRadiusSquared * _cutoffRadiusSquared * _cutoffRadiusSquared) - 1.0)),
     118          24 :         _dt(dt) {}
     119          24 :   ~SimpleMDSolverInterface() {
     120          12 :     for (auto linkedCell : _linkedCells) {
     121           0 :       if (linkedCell != nullptr)
     122           0 :         delete linkedCell;
     123             :     }
     124          12 :     _linkedCells.clear();
     125          24 :   }
     126             : 
     127           0 :   SimpleMDLinkedCellWrapper& getLinkedCell(const CellIndex_T& couplingCellIndex, const tarch::la::Vector<MD_DIM, unsigned int>& linkedCellInCouplingCell,
     128             :                                            const tarch::la::Vector<MD_DIM, unsigned int>& linkedCellsPerCouplingCell) {
     129             :     // no linked cells found in outer region!
     130             : 
     131           0 :     tarch::la::Vector<MD_DIM, unsigned int> index(_moleculeService.getContainer().getLocalIndexOfFirstCell());
     132           0 :     for (unsigned int d = 0; d < MD_DIM; d++) {
     133           0 :       index[d] = index[d] + couplingCellIndex.get()[d] * linkedCellsPerCouplingCell[d] + linkedCellInCouplingCell[d];
     134             :     }
     135           0 :     _linkedCells.push_back(new SimpleMDLinkedCellWrapper(index));
     136           0 :     return *_linkedCells.back();
     137             :   }
     138             : 
     139             :   /** returns the global size of the box-shaped MD domain */
     140           0 :   tarch::la::Vector<MD_DIM, double> getGlobalMDDomainSize() const { return _parallelTopologyService.getGlobalDomainSize(); }
     141             : 
     142             :   /** returns the offset (i.e. lower,left corner) of MD domain */
     143           0 :   tarch::la::Vector<MD_DIM, double> getGlobalMDDomainOffset() const { return _parallelTopologyService.getGlobalDomainOffset(); }
     144             : 
     145           0 :   double getMoleculeMass() const { return _molecularPropertiesService.getMolecularProperties().getMass(); }
     146             : 
     147           0 :   double getKB() const { return _molecularPropertiesService.getMolecularProperties().getKB(); }
     148             : 
     149           0 :   double getMoleculeSigma() const { return _molecularPropertiesService.getMolecularProperties().getSigma(); }
     150             : 
     151           0 :   double getMoleculeEpsilon() const { return _molecularPropertiesService.getMolecularProperties().getEpsilon(); }
     152             : 
     153           0 :   void getInitialVelocity(const tarch::la::Vector<MD_DIM, double>& meanVelocity, const double& kB, const double& temperature,
     154             :                           tarch::la::Vector<MD_DIM, double>& initialVelocity) const {
     155           0 :     _moleculeService.getInitialVelocity(meanVelocity, kB, temperature, _molecularPropertiesService, initialVelocity);
     156           0 :   }
     157             : 
     158           0 :   void deleteMoleculeFromMDSimulation(const coupling::interface::Molecule<MD_DIM>& molecule, SimpleMDLinkedCellWrapper& cellWrapper) {
     159           0 :     auto cell = _moleculeService.getContainer()[cellWrapper.getCellIndex()];
     160           0 :     auto it = cell.begin();
     161           0 :     const tarch::la::Vector<MD_DIM, double> moleculePosition = molecule.getPosition();
     162           0 :     while (it != cell.end()) {
     163           0 :       const tarch::la::Vector<MD_DIM, double>& itPosition(it->getConstPosition());
     164           0 :       if (moleculePosition == itPosition) {
     165           0 :         cell.remove(it.getIndex());
     166           0 :         it--;
     167           0 :         return;
     168             :       }
     169           0 :       it++;
     170             :     }
     171             : 
     172           0 :     std::cout << "Could not delete molecule at position " << moleculePosition << "!" << std::endl;
     173           0 :     exit(EXIT_FAILURE);
     174             :   }
     175             : 
     176           0 :   void addMoleculeToMDSimulation(const coupling::interface::Molecule<MD_DIM>& molecule) {
     177           0 :     const tarch::la::Vector<MD_DIM, double> position = molecule.getPosition();
     178           0 :     const tarch::la::Vector<MD_DIM, double> velocity = molecule.getVelocity();
     179           0 :     const tarch::la::Vector<MD_DIM, double> force = molecule.getForce();
     180           0 :     const double potentialEnergy = molecule.getPotentialEnergy();
     181           0 :     simplemd::Molecule newMolecule(position, velocity);
     182           0 :     newMolecule.setForce(force);
     183           0 :     newMolecule.setPotentialEnergy(potentialEnergy);
     184           0 :     newMolecule.setID(_moleculeService.getNextMoleculeID());
     185             :     // add molecule to MoleculeContainer
     186           0 :     _moleculeService.getContainer().insert(newMolecule);
     187           0 :   }
     188             : 
     189           0 :   tarch::la::Vector<MD_DIM, unsigned int> getLinkedCellIndexForMoleculePosition(const tarch::la::Vector<MD_DIM, double>& position) {
     190           0 :     return _moleculeService.getContainer().getLocalCellIndexVector(_moleculeService.getContainer().positionToCellIndex(position));
     191             :   }
     192             : 
     193           0 :   void setupPotentialEnergyLandscape(const tarch::la::Vector<MD_DIM, unsigned int>& indexOfFirstCouplingCell,
     194             :                                      const tarch::la::Vector<MD_DIM, unsigned int>& rangeCouplingCells,
     195             :                                      const tarch::la::Vector<MD_DIM, unsigned int>& linkedCellsPerCouplingCell) {
     196           0 :     simplemd::cellmappings::ResetPotentialEnergyMapping resetPotentialEnergyMapping;
     197           0 :     simplemd::cellmappings::LennardJonesPotentialEnergyMapping potentialEnergyMapping(_molecularPropertiesService);
     198           0 :     tarch::la::Vector<MD_DIM, unsigned int> rangeLinkedCellsExtended(0);
     199           0 :     tarch::la::Vector<MD_DIM, unsigned int> firstLinkedCell(0);
     200             :     // compute coordinates of the first linked cell and the range of linked cells to be considered
     201           0 :     for (unsigned int d = 0; d < MD_DIM; d++) {
     202             : #if (COUPLING_MD_DEBUG == COUPLING_MD_YES)
     203             :       if (indexOfFirstCouplingCell[d] == 0) {
     204             :         std::cout << "ERROR setupPotentialEnergyLandscape: " << indexOfFirstCouplingCell[d] << std::endl;
     205             :         exit(EXIT_FAILURE);
     206             :       }
     207             : #endif
     208             : 
     209           0 :       firstLinkedCell[d] = (indexOfFirstCouplingCell[d] - 1) * linkedCellsPerCouplingCell[d];
     210             :       // we need to loop over one more layer of linked cells since firstLinkedCell(d) already starts one linked cell earlier
     211             :       // (e.g. already in linked cell ghost layer)
     212           0 :       rangeLinkedCellsExtended[d] = rangeCouplingCells[d] * linkedCellsPerCouplingCell[d] + _moleculeService.getContainer().getLocalIndexOfFirstCell()[d];
     213             :     }
     214             : 
     215             :     // reset potential energy first for the molecules in all relevant linked cells
     216           0 :     _moleculeService.getContainer().iterateCells(resetPotentialEnergyMapping, firstLinkedCell, rangeLinkedCellsExtended);
     217             : 
     218             :     // compute potential energy in these cells
     219           0 :     _moleculeService.getContainer().iterateCellPairs(potentialEnergyMapping, firstLinkedCell, rangeLinkedCellsExtended);
     220           0 :   }
     221             : 
     222           0 :   void calculateForceAndEnergy(coupling::interface::Molecule<MD_DIM>& molecule) {
     223           0 :     const tarch::la::Vector<MD_DIM, double> position = molecule.getPosition();
     224           0 :     const tarch::la::Vector<MD_DIM, unsigned int> linkedCellIndex = getLinkedCellIndexForMoleculePosition(position);
     225             : #if (COUPLING_MD_ERROR == COUPLING_MD_YES)
     226           0 :     for (unsigned int d = 0; d < MD_DIM; d++) {
     227           0 :       if ((linkedCellIndex[d] < 1) || (linkedCellIndex[d] > _moleculeService.getContainer().getLocalNumberOfCells()[d])) {
     228           0 :         std::cout << "ERROR coupling::interface/impl/SimpleMD/SimpleMDSolverInterface::calculateForceAndEnergy(): linkedCellIndex out of range!" << std::endl;
     229           0 :         std::cout << "LinkedCellIndex=" << linkedCellIndex << std::endl;
     230           0 :         exit(EXIT_FAILURE);
     231             :       }
     232             :     }
     233             : #endif
     234           0 :     tarch::la::Vector<MD_DIM, double> forceOld(0.0);
     235           0 :     double energy = 0.0;
     236           0 :     molecule.setPotentialEnergy(0.0);
     237             : 
     238           0 :     tarch::la::Vector<MD_DIM, unsigned int> loopIndex(0);
     239             : 
     240             : // loop over all relevant linked cells and compute force and energy contributions
     241             : #if (MD_DIM > 2)
     242           0 :     for (loopIndex[2] = linkedCellIndex[2] - 1; loopIndex[2] < linkedCellIndex[2] + 2; loopIndex[2]++) {
     243             : #endif
     244             : #if (MD_DIM > 1)
     245           0 :       for (loopIndex[1] = linkedCellIndex[1] - 1; loopIndex[1] < linkedCellIndex[1] + 2; loopIndex[1]++) {
     246             : #endif
     247           0 :         for (loopIndex[0] = linkedCellIndex[0] - 1; loopIndex[0] < linkedCellIndex[0] + 2; loopIndex[0]++) {
     248             : 
     249             :           // loop over all molecules in each cell
     250           0 :           const simplemd::LinkedCell& thisCell = _moleculeService.getContainer()[loopIndex];
     251           0 :           for (auto it = thisCell.begin(); it != thisCell.end(); it++) {
     252           0 :             forceOld += getLennardJonesForce(position, it->getConstPosition());
     253           0 :             energy += getPotentialEnergy(position, it->getConstPosition());
     254             :           }
     255             :         }
     256             : #if (MD_DIM > 1)
     257             :       }
     258             : #endif
     259             : #if (MD_DIM > 2)
     260             :     }
     261             : #endif
     262             :     // set force in forceOld-entry
     263           0 :     molecule.setForce(forceOld);
     264             :     // set total potential energy
     265           0 :     molecule.setPotentialEnergy(energy);
     266           0 :   }
     267             : 
     268           0 :   void synchronizeMoleculesAfterMassModification() {
     269           0 :     _boundaryTreatment.emptyGhostBoundaryCells();
     270             : #if (TEST_TCHIPEV == MD_NO)
     271           0 :     _boundaryTreatment.fillBoundaryCells(_localBoundaryInformation, _parallelTopologyService);
     272             : #else
     273             :     _boundaryTreatment.putBoundaryParticlesToInnerCellsAndFillBoundaryCells(_localBoundaryInformation, _parallelTopologyService);
     274             : #endif
     275           0 :   }
     276             : 
     277           0 :   void synchronizeMoleculesAfterMomentumModification() {}
     278             : 
     279           0 :   double getDt() { return _dt; }
     280             : 
     281           0 :   coupling::interface::MoleculeIterator<SimpleMDLinkedCellWrapper, MD_DIM>* getMoleculeIterator(SimpleMDLinkedCellWrapper& cellWrapper) {
     282           0 :     return new coupling::interface::SimpleMDMoleculeIterator(cellWrapper, _moleculeService);
     283             :   }
     284             : };
     285             : 
     286             : } // namespace interface
     287             : } // namespace coupling
     288             : #endif // _MOLECULARDYNAMICS_COUPLING_INTERFACE_SIMPLEMDSOLVERINTERFACE_CPP_

Generated by: LCOV version 1.14