LCOV - code coverage report
Current view: top level - coupling/cell-mappings - ZhouBoundaryForce.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 87 0
Test Date: 2026-08-21 15:14:06 Functions: 0.0 % 12 0

            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_CELLMAPPINGS_ZHOUBOUNDARYFORCE_H_
       6              : #define _MOLECULARDYNAMICS_COUPLING_CELLMAPPINGS_ZHOUBOUNDARYFORCE_H_
       7              : 
       8              : #include "coupling/interface/MDSolverInterface.h"
       9              : #include "coupling/interface/Molecule.h"
      10              : #include "coupling/interface/MoleculeIterator.h"
      11              : #include <cmath>
      12              : #include <iostream>
      13              : 
      14              : namespace coupling {
      15              : namespace cellmappings {
      16              : template <class LinkedCell, unsigned int dim> class ZhouBoundaryForce;
      17              : }
      18              : } // namespace coupling
      19              : 
      20              : /** applies the Zhou boundary force to all molecules assuming a cut-off radius
      21              :  *r_c=2.5. We only consider molecules in the outermost coupling cell. Thus,
      22              :  *the current method will only be employed to molecules within a
      23              :  *distance=min(r_c,size of coupling cell). The force is based on the research
      24              :  *paper: W.J. Zhou, H.B. Luan, Y.L. He, J. Sun, W.Q. Tao. A study on boundary
      25              :  *force model used in multiscale simulations with non-periodic boundary
      26              :  *condition Microfluid Nanofluid 16(3): 587-595, 2014
      27              :  *
      28              :  *  The force is computed based on an interpolation formula which has been
      29              :  *obtained from various MD simulation runs at different temperature and density
      30              :  *values. The investigated range is:
      31              :  *  0.4*m*sigma-3<density<0.9*m*sigma-3, 1.3*eps/kB<temperature<3.9*eps/kB.
      32              :  *  Moreover, only 3D simulations have been considered in this study.
      33              :  *      @brief This class applies the Zhou boundary force to all molecules
      34              :  *assuming a cut-off radius r_c=2.5.
      35              :  *      @tparam LinkedCell cell type
      36              :  *      @tparam dim Number of dimensions; it can be 1, 2 or 3
      37              :  *  @author Philipp Neumann
      38              :  *      \todo Philipp please take a look on this class
      39              :  */
      40              : template <class LinkedCell, unsigned int dim> class coupling::cellmappings::ZhouBoundaryForce {
      41              : public:
      42              :   /** currently, we support constant temperature and density and 3D only. To be
      43              :    *extended
      44              :    *    @param density
      45              :    *    @param temperature
      46              :    *    @param epsilon
      47              :    *    @param sigma
      48              :    *    @param boundary
      49              :    *    @param domainOffset
      50              :    *    @param domainSize
      51              :    *    @param mdSolverInterface
      52              :    */
      53            0 :   ZhouBoundaryForce(const double& density, const double& temperature, const double& epsilon, const double& sigma,
      54              :                     const tarch::la::Vector<2 * dim, bool>& boundary, const tarch::la::Vector<dim, double>& domainOffset,
      55              :                     const tarch::la::Vector<dim, double>& domainSize, coupling::interface::MDSolverInterface<LinkedCell, dim>* const mdSolverInterface)
      56            0 :       : _boundary(boundary), _domainLowerLeft(domainOffset), _domainUpperRight(domainSize + domainOffset), _mdSolverInterface(mdSolverInterface),
      57            0 :         _p1(getP1(density, temperature)), _p2(getP2(density, temperature)), _p3(getP3(density, temperature)), _q1(getQ1(density)), _q2(getQ2(density)),
      58            0 :         _q3(getQ3(density)), _forceFactor(epsilon / sigma), _sigma(sigma),
      59              :         /** Fixed step width for numerical integration of boundary force term */
      60            0 :         _energyResolution(1000), _energyTable(new double[_energyResolution]) {
      61              :     // simple trapezoidal integration scheme
      62            0 :     double force(0);
      63            0 :     double energy(0);
      64            0 :     double dx(2.5 * sigma / (_energyResolution - 1));
      65            0 :     for (unsigned int i = 0; i < _energyResolution; i++) {
      66            0 :       force = getScalarBoundaryForce(2.5 - i * dx);
      67            0 :       _energyTable[i] = energy + force / 2 * dx;
      68            0 :       energy += force * dx;
      69              :     }
      70              : 
      71              :     // for(unsigned int i=0;i<_energyResolution;i++){
      72              :     //   std::cout << "_energyTable[" << i << "] = " << _energyTable[i] <<
      73              :     //   std::endl;
      74              :     // }
      75              :     // for(double pos = 0; pos <= 2.5; pos += .25/_energyResolution){
      76              :     //   std::cout << "getPotentialEnergy(" << pos << ") = " <<
      77              :     //   getPotentialEnergy(pos) << std::endl;
      78              :     // }
      79            0 :   }
      80              : 
      81              :   /** Destructor */
      82            0 :   ~ZhouBoundaryForce() { delete[] _energyTable; }
      83              : 
      84              :   /** empty function
      85              :    */
      86              :   void beginCellIteration() {}
      87              : 
      88              :   /** empty function
      89              :    */
      90              :   void endCellIteration() {}
      91              : 
      92              :   /** extracts position and force of each molecule, add boundary force and
      93              :    *applies it to Molecule
      94              :    *    @param cell
      95              :    */
      96            0 :   void handleCell(LinkedCell& cell) {
      97            0 :     coupling::interface::MoleculeIterator<LinkedCell, dim>* it = _mdSolverInterface->getMoleculeIterator(cell);
      98            0 :     it->begin();
      99            0 :     while (it->continueIteration()) {
     100            0 :       coupling::interface::Molecule<dim>& wrapper(it->get());
     101              :       // std::cout << "apply force to Molecule " << wrapper.getPosition() <<
     102              :       // std::endl;
     103              : 
     104              :       // extract position and force of each molecule
     105            0 :       const tarch::la::Vector<dim, double> position(wrapper.getPosition());
     106            0 :       tarch::la::Vector<dim, double> force(wrapper.getForce());
     107              :       // add boundary force
     108            0 :       force = force + getBoundaryForces(position);
     109            0 :       wrapper.setForce(force);
     110              : 
     111            0 :       it->next();
     112              :     }
     113            0 :     delete it;
     114            0 :   }
     115              : 
     116              :   /** returns the potential energy
     117              :    *    @param position
     118              :    *    @return energy
     119              :    */
     120            0 :   double getPotentialEnergy(const tarch::la::Vector<dim, double>& position) const {
     121            0 :     double energy(0);
     122            0 :     const double distance = 2.5 * _sigma;
     123            0 :     for (unsigned int d = 0; d < dim; d++) {
     124            0 :       if (_boundary[2 * d] && (position[d] - _domainLowerLeft[d] < distance)) {
     125            0 :         energy += getPotentialEnergy((position[d] - _domainLowerLeft[d]) / _sigma);
     126              :       }
     127            0 :       if (_boundary[2 * d + 1] && (_domainUpperRight[d] - position[d] < distance)) {
     128            0 :         energy += getPotentialEnergy((_domainUpperRight[d] - position[d]) / _sigma);
     129              :       }
     130              :     }
     131            0 :     return energy;
     132              :   }
     133              : 
     134              :   /** checks the boundary flags for open boundaries. If an open boundary is
     135              :    *encountered and this molecule is close to that boundary (distance smaller
     136              :    *than 2.5, cf. Zhou paper), the respective force contribution in that
     137              :    *dimension is added/subtracted.
     138              :    *    @param position
     139              :    *    @return force
     140              :    */
     141            0 :   tarch::la::Vector<dim, double> getBoundaryForces(const tarch::la::Vector<dim, double>& position) const {
     142            0 :     tarch::la::Vector<dim, double> force(0.0);
     143            0 :     const double distance = 2.5 * _sigma;
     144              : 
     145            0 :     for (unsigned int d = 0; d < dim; d++) {
     146              :       // for left/lower/back boundary: add force; for right/upper/front
     147              :       // boundary: subtract force value
     148            0 :       if (_boundary[2 * d] && (position[d] - _domainLowerLeft[d] < distance)) {
     149            0 :         force[d] += _forceFactor * getScalarBoundaryForce((position[d] - _domainLowerLeft[d]) / _sigma);
     150              :       }
     151            0 :       if (_boundary[2 * d + 1] && (_domainUpperRight[d] - position[d] < distance)) {
     152            0 :         force[d] -= _forceFactor * getScalarBoundaryForce((_domainUpperRight[d] - position[d]) / _sigma);
     153              :       }
     154              :     }
     155            0 :     return force;
     156              :   }
     157              : 
     158              : private:
     159              :   /** perform interpolation between nearest energy lookup table values
     160              :    *    @param rw
     161              :    *    @return nearest energy to the ????
     162              :    */
     163            0 :   double getPotentialEnergy(double rw) const {
     164            0 :     double dx(2.5 * _sigma / (_energyResolution - 1));
     165            0 :     int upper = (int)((2.5 - rw) / 2.5 * (_energyResolution - 1) - .5);
     166            0 :     int lower = (int)((2.5 - rw) / 2.5 * (_energyResolution - 1) + .5);
     167            0 :     return _energyTable[lower] * ((2.5 - upper * dx - rw) / dx) + _energyTable[upper] * ((rw - 2.5 + lower * dx) / dx);
     168              :   }
     169              : 
     170              :   /** evaluates the force expression for a scalar component of the force vector.
     171              :    *We thus add up dimensional contributions if several boundaries are located
     172              :    *beside each other.
     173              :    *    @param rw
     174              :    *    @return Scalar boundary force
     175              :    */
     176            0 :   double getScalarBoundaryForce(double rw) const {
     177            0 :     if (rw < 1.04) {
     178            0 :       return _p1 + _p2 * exp(pow((rw + 0.25), 3.4)) * cos(_p3 * rw);
     179              :     } else {
     180            0 :       return -1.0 / (_q1 + _q2 * (2.5 - rw) * (2.5 - rw) + _q3 / ((2.5 - rw) * (2.5 - rw)));
     181              :     }
     182              :   }
     183              : 
     184              :   /** computes and returns the coefficient p1 according to Zhou-paper
     185              :    *    @param density
     186              :    *    @param temperature
     187              :    *    @return p1
     188              :    */
     189            0 :   double getP1(const double& density, const double& temperature) const {
     190            0 :     const double logrho = log(density);
     191            0 :     const double T2 = temperature * temperature;
     192            0 :     const double T3 = T2 * temperature;
     193              : 
     194              :     // an additional factor 10**-5 is in the expression 4.599/(...) -> private
     195              :     // communication with Wenjing Zhou (typo in paper)
     196            0 :     const double p1 = (-18.953 + 53.369 * temperature - 1.253 * T2 + 4.599 / 100000.0 * T3 + 59.871 * logrho + 19.737 * logrho * logrho) /
     197            0 :                       (1.0 + 2.592 * temperature - 0.557 * T2 + 0.049 * T3 - 13.912 * logrho + 18.657 * logrho * logrho);
     198            0 :     return p1;
     199              :   }
     200              : 
     201              :   /** computes and returns the coefficient p2 according to Zhou-paper
     202              :    *    @param density
     203              :    *    @param temperature
     204              :    *    @return p2
     205              :    */
     206            0 :   double getP2(const double& density, const double& temperature) const {
     207            0 :     const double logrho = log(density);
     208            0 :     const double T2 = temperature * temperature;
     209            0 :     const double T3 = T2 * temperature;
     210              : 
     211            0 :     const double p2 = (-0.094 + 2.808 * temperature - 0.019 * T2 - 0.001 * T3 + 2.823 * logrho + 2.071 * logrho * logrho) /
     212            0 :                       (1.0 + 0.168 * temperature - 0.013 * T2 - 4.323 * logrho + 2.557 * logrho * logrho - 2.155 * logrho * logrho * logrho);
     213            0 :     return p2;
     214              :   }
     215              : 
     216              :   /** computes and returns the coefficient p3 according to Zhou-paper
     217              :    *    @param density
     218              :    *    @param temperature
     219              :    *    @return p3
     220              :    */
     221            0 :   double getP3(const double& density, const double& temperature) const {
     222            0 :     const double T394 = pow(temperature, 0.394);
     223            0 :     const double rho17437 = pow(density, 17.437);
     224            0 :     const double p3 = 3.934 + 0.099 * T394 - 0.097 * rho17437 + 0.075 * T394 * rho17437;
     225            0 :     return p3;
     226              :   }
     227              : 
     228              :   /** computes and returns the coefficient q1 according to Zhou-paper
     229              :    *    @param density
     230              :    *    @return q1
     231              :    */
     232            0 :   double getQ1(const double& density) const {
     233            0 :     const double rho2 = density * density;
     234            0 :     const double rho3 = rho2 * density;
     235            0 :     const double rho4 = rho2 * rho2;
     236            0 :     return -30.471 + 113.879 * density - 207.205 * rho2 + 184.242 * rho3 - 62.879 * rho4;
     237              :   }
     238              : 
     239              :   /** computes and returns the coefficient q2 according to Zhou-paper
     240              :    *    @param density
     241              :    *    @return q2
     242              :    */
     243            0 :   double getQ2(const double& density) const {
     244            0 :     const double rho2 = density * density;
     245            0 :     const double rho3 = rho2 * density;
     246            0 :     const double rho4 = rho2 * rho2;
     247            0 :     return 6.938 - 25.788 * density + 46.773 * rho2 - 41.768 * rho3 + 14.394 * rho4;
     248              :   }
     249              : 
     250              :   /** computes and returns the coefficient q3 according to Zhou-paper
     251              :    *    @param density
     252              :    *    @return q3
     253              :    */
     254            0 :   double getQ3(const double& density) const {
     255            0 :     const double rho2 = density * density;
     256            0 :     const double rho3 = rho2 * density;
     257            0 :     const double rho4 = rho2 * rho2;
     258            0 :     return 39.634 - 147.821 * density + 269.519 * rho2 - 239.066 * rho3 + 81.439 * rho4;
     259              :   }
     260              : 
     261              :   /** an entry is true, if this is an open boundary. For enumeration of
     262              :    * boundaries, see BoundaryForceConfiguration */
     263              :   const tarch::la::Vector<2 * dim, bool> _boundary;
     264              :   /** lower left corner of MD domain */
     265              :   const tarch::la::Vector<dim, double> _domainLowerLeft;
     266              :   /** upper right corner of MD domain */
     267              :   const tarch::la::Vector<dim, double> _domainUpperRight;
     268              : 
     269              :   coupling::interface::MDSolverInterface<LinkedCell, dim>* const _mdSolverInterface;
     270              :   // helper variables to speed up evaluation, see Zhou paper
     271              :   const double _p1;
     272              :   const double _p2;
     273              :   const double _p3;
     274              :   const double _q1;
     275              :   const double _q2;
     276              :   const double _q3;
     277              : 
     278              :   /** factor to scale the force according to MD units */
     279              :   const double _forceFactor;
     280              :   /** factor to scale length according to MD units */
     281              :   const double _sigma;
     282              : 
     283              :   const unsigned int _energyResolution;
     284              :   double* _energyTable;
     285              : };
     286              : #endif // _MOLECULARDYNAMICS_COUPLING_CELLMAPPINGS_ZHOUBOUNDARYFORCE_H_
        

Generated by: LCOV version 2.0-1