LCOV - code coverage report
Current view: top level - multicolvar - VolumeCavity.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 194 248 78.2 %
Date: 2026-03-30 13:16:06 Functions: 10 12 83.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2014-2023 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "core/ActionRegister.h"
      23             : #include "core/PlumedMain.h"
      24             : #include "core/Atoms.h"
      25             : #include "tools/Units.h"
      26             : #include "tools/Pbc.h"
      27             : #include "ActionVolume.h"
      28             : 
      29             : //+PLUMEDOC VOLUMES CAVITY
      30             : /*
      31             : This quantity can be used to calculate functions of the distribution of collective variables for the atoms that lie in a box defined by the positions of four atoms.
      32             : 
      33             : Each of the base quantities calculated by a multicolvar can can be assigned to a particular point in three
      34             : dimensional space. For example, if we have the coordination numbers for all the atoms in the
      35             : system each coordination number can be assumed to lie on the position of the central atom.
      36             : Because each base quantity can be assigned to a particular point in space we can calculate functions of the
      37             : distribution of base quantities in a particular part of the box by using:
      38             : 
      39             : \f[
      40             : \overline{s}_{\tau} = \frac{ \sum_i f(s_i) w(u_i,v_i,w_i) }{ \sum_i w(u_i,v_i,w_i) }
      41             : \f]
      42             : 
      43             : where the sum is over the collective variables, \f$s_i\f$, each of which can be thought to be at \f$ (u_i,v_i,z_i)\f$.
      44             : The function \f$(s_i)\f$ can be any of the usual LESS_THAN, MORE_THAN, WITHIN etc that are used in all other multicolvars.
      45             : Notice that here (at variance with what is done in \ref AROUND) we have transformed from the usual \f$(x_i,y_i,z_i)\f$
      46             : position to a position in \f$ (u_i,v_i,z_i)\f$.  This is done using a rotation matrix as follows:
      47             : 
      48             : \f[
      49             : \left(
      50             : \begin{matrix}
      51             :  u_i \\
      52             :  v_i \\
      53             :  w_i
      54             : \end{matrix}
      55             : \right) = \mathbf{R}
      56             : \left(
      57             : \begin{matrix}
      58             :  x_i - x_o \\
      59             :  y_i - y_o \\
      60             :  z_i - z_o
      61             : \end{matrix}
      62             : \right)
      63             : \f]
      64             : 
      65             : where \f$\mathbf{R}\f$ is a rotation matrix that is calculated by constructing a set of three orthonormal vectors from the
      66             : reference positions specified by the user. The first of these unit vectors points from the first reference atom to the second.
      67             : The second is then the normal to the plane containing atoms 1,2 and 3 and the the third is the unit vector orthogonal to
      68             : these first two vectors.  \f$(x_o,y_o,z_o)\f$, meanwhile, specifies the position of the first reference atom.
      69             : 
      70             : In the previous function \f$ w(u_i,v_i,w_i) \f$ measures whether or not the system is in the subregion of interest. It
      71             : is equal to:
      72             : 
      73             : \f[
      74             : w(u_i,v_i,w_i) = \int_{0}^{u'} \int_{0}^{v'} \int_{0}^{w'} \textrm{d}u\textrm{d}v\textrm{d}w
      75             :    K\left( \frac{u - u_i}{\sigma} \right)K\left( \frac{v - v_i}{\sigma} \right)K\left( \frac{w - w_i}{\sigma} \right)
      76             : \f]
      77             : 
      78             : where \f$K\f$ is one of the kernel functions described on \ref histogrambead and \f$\sigma\f$ is a bandwidth parameter.
      79             : The vector connecting atom 1 to atom 4 is used to define the extent of the box in each of the \f$u\f$, \f$v\f$ and \f$w\f$
      80             : directions.  Essentially the vector connecting atom 1 to atom 4 is projected onto the three unit vectors
      81             : described above and the resulting projections determine the \f$u'\f$, \f$v'\f$ and \f$w'\f$ parameters in the above expression.
      82             : 
      83             : \par Examples
      84             : 
      85             : The following commands tell plumed to calculate the number of atoms in an ion channel in a protein.
      86             : The extent of the channel is calculated from the positions of atoms 1, 4, 5 and 11. The final value will be labeled cav.
      87             : 
      88             : \plumedfile
      89             : d1: DENSITY SPECIES=20-500
      90             : CAVITY DATA=d1 ATOMS=1,4,5,11 SIGMA=0.1 LABEL=cav
      91             : \endplumedfile
      92             : 
      93             : The following command tells plumed to calculate the coordination numbers (with other water molecules) for the water
      94             : molecules in the protein channel described above.  The average coordination number and the number of coordination
      95             : numbers more than 4 is then calculated.  The values of these two quantities are given the labels cav.mean and cav.morethan
      96             : 
      97             : \plumedfile
      98             : d1: COORDINATIONNUMBER SPECIES=20-500 R_0=0.1
      99             : CAVITY DATA=d1 ATOMS=1,4,5,11 SIGMA=0.1 MEAN MORE_THAN={RATIONAL R_0=4} LABEL=cav
     100             : \endplumedfile
     101             : 
     102             : */
     103             : //+ENDPLUMEDOC
     104             : 
     105             : namespace PLMD {
     106             : namespace multicolvar {
     107             : 
     108             : class VolumeCavity : public ActionVolume {
     109             : private:
     110             :   bool boxout;
     111             :   OFile boxfile;
     112             :   double lenunit;
     113             :   double jacob_det;
     114             :   double len_bi, len_cross, len_perp, sigma;
     115             :   Vector origin, bi, cross, perp;
     116             :   std::vector<Vector> dlbi, dlcross, dlperp;
     117             :   std::vector<Tensor> dbi, dcross, dperp;
     118             : public:
     119             :   static void registerKeywords( Keywords& keys );
     120             :   explicit VolumeCavity(const ActionOptions& ao);
     121             :   ~VolumeCavity();
     122             :   void setupRegions() override;
     123             :   void update() override;
     124             :   double calculateNumberInside( const Vector& cpos, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders ) const override;
     125             : };
     126             : 
     127       13789 : PLUMED_REGISTER_ACTION(VolumeCavity,"CAVITY")
     128             : 
     129           6 : void VolumeCavity::registerKeywords( Keywords& keys ) {
     130           6 :   ActionVolume::registerKeywords( keys );
     131          12 :   keys.add("atoms","ATOMS","the positions of four atoms that define spatial extent of the cavity");
     132          12 :   keys.addFlag("PRINT_BOX",false,"write out the positions of the corners of the box to an xyz file");
     133          12 :   keys.add("optional","FILE","the file on which to write out the box coordinates");
     134          12 :   keys.add("optional","UNITS","( default=nm ) the units in which to write out the corners of the box");
     135           6 : }
     136             : 
     137           2 : VolumeCavity::VolumeCavity(const ActionOptions& ao):
     138             :   Action(ao),
     139             :   ActionVolume(ao),
     140           2 :   boxout(false),
     141           2 :   lenunit(1.0),
     142           2 :   dlbi(4),
     143           2 :   dlcross(4),
     144           2 :   dlperp(4),
     145           2 :   dbi(3),
     146           2 :   dcross(3),
     147           4 :   dperp(3) {
     148             :   std::vector<AtomNumber> atoms;
     149           4 :   parseAtomList("ATOMS",atoms);
     150           2 :   if( atoms.size()!=4 ) {
     151           0 :     error("number of atoms should be equal to four");
     152             :   }
     153             : 
     154           2 :   log.printf("  boundaries for region are calculated based on positions of atoms : ");
     155          10 :   for(unsigned i=0; i<atoms.size(); ++i) {
     156           8 :     log.printf("%d ",atoms[i].serial() );
     157             :   }
     158           2 :   log.printf("\n");
     159             : 
     160           2 :   boxout=false;
     161           2 :   parseFlag("PRINT_BOX",boxout);
     162           2 :   if(boxout) {
     163             :     std::string boxfname;
     164           0 :     parse("FILE",boxfname);
     165           0 :     if(boxfname.length()==0) {
     166           0 :       error("no name for box file specified");
     167             :     }
     168             :     std::string unitname;
     169           0 :     parse("UNITS",unitname);
     170           0 :     if ( unitname.length()>0 ) {
     171           0 :       Units u;
     172           0 :       u.setLength(unitname);
     173           0 :       lenunit=plumed.getAtoms().getUnits().getLength()/u.getLength();
     174           0 :     } else {
     175             :       unitname="nm";
     176             :     }
     177           0 :     boxfile.link(*this);
     178           0 :     boxfile.open( boxfname );
     179           0 :     log.printf("  printing box coordinates on file named %s in %s \n",boxfname.c_str(), unitname.c_str() );
     180             :   }
     181             : 
     182           2 :   checkRead();
     183           2 :   requestAtoms(atoms);
     184             :   // We have to readd the dependency because requestAtoms removes it
     185           2 :   addDependency( getPntrToMultiColvar() );
     186           2 : }
     187             : 
     188           4 : VolumeCavity::~VolumeCavity() {
     189           4 : }
     190             : 
     191        1620 : void VolumeCavity::setupRegions() {
     192             :   // Make some space for things
     193        1620 :   Vector d1, d2, d3;
     194             : 
     195             :   // Retrieve the sigma value
     196        1620 :   sigma=getSigma();
     197             :   // Set the position of the origin
     198        1620 :   origin=getPosition(0);
     199             : 
     200             :   // Get two vectors
     201        1620 :   d1 = pbcDistance(origin,getPosition(1));
     202        1620 :   double d1l=d1.modulo();
     203        1620 :   d2 = pbcDistance(origin,getPosition(2));
     204             : 
     205             :   // Find the vector connecting the origin to the top corner of
     206             :   // the subregion
     207        1620 :   d3 = pbcDistance(origin,getPosition(3));
     208             : 
     209             :   // Create a set of unit vectors
     210        1620 :   bi = d1 / d1l;
     211        1620 :   len_bi=dotProduct( d3, bi );
     212        1620 :   cross = crossProduct( d1, d2 );
     213        1620 :   double crossmod=cross.modulo();
     214        1620 :   cross = cross / crossmod;
     215        1620 :   len_cross=dotProduct( d3, cross );
     216        1620 :   perp = crossProduct( cross, bi );
     217        1620 :   len_perp=dotProduct( d3, perp );
     218             : 
     219             :   // Calculate derivatives of box shape with respect to atoms
     220        1620 :   double d1l3=d1l*d1l*d1l;
     221        1620 :   dbi[0](0,0) = ( -(d1[1]*d1[1]+d1[2]*d1[2])/d1l3 );   // dx/dx
     222        1620 :   dbi[0](0,1) = (  d1[0]*d1[1]/d1l3 );                 // dx/dy
     223        1620 :   dbi[0](0,2) = (  d1[0]*d1[2]/d1l3 );                 // dx/dz
     224        1620 :   dbi[0](1,0) = (  d1[1]*d1[0]/d1l3 );                 // dy/dx
     225        1620 :   dbi[0](1,1) = ( -(d1[0]*d1[0]+d1[2]*d1[2])/d1l3 );   // dy/dy
     226        1620 :   dbi[0](1,2) = (  d1[1]*d1[2]/d1l3 );
     227        1620 :   dbi[0](2,0) = (  d1[2]*d1[0]/d1l3 );
     228        1620 :   dbi[0](2,1) = (  d1[2]*d1[1]/d1l3 );
     229        1620 :   dbi[0](2,2) = ( -(d1[1]*d1[1]+d1[0]*d1[0])/d1l3 );
     230             : 
     231        1620 :   dbi[1](0,0) = ( (d1[1]*d1[1]+d1[2]*d1[2])/d1l3 );
     232        1620 :   dbi[1](0,1) = ( -d1[0]*d1[1]/d1l3 );
     233        1620 :   dbi[1](0,2) = ( -d1[0]*d1[2]/d1l3 );
     234        1620 :   dbi[1](1,0) = ( -d1[1]*d1[0]/d1l3 );
     235        1620 :   dbi[1](1,1) = ( (d1[0]*d1[0]+d1[2]*d1[2])/d1l3 );
     236        1620 :   dbi[1](1,2) = ( -d1[1]*d1[2]/d1l3 );
     237        1620 :   dbi[1](2,0) = ( -d1[2]*d1[0]/d1l3 );
     238        1620 :   dbi[1](2,1) = ( -d1[2]*d1[1]/d1l3 );
     239        1620 :   dbi[1](2,2) = ( (d1[1]*d1[1]+d1[0]*d1[0])/d1l3 );
     240        1620 :   dbi[2].zero();
     241             : 
     242        1620 :   Tensor tcderiv;
     243        1620 :   double cmod3=crossmod*crossmod*crossmod;
     244        1620 :   Vector ucross=crossmod*cross;
     245        1620 :   tcderiv.setCol( 0, crossProduct( d1, Vector(-1.0,0.0,0.0) ) + crossProduct( Vector(-1.0,0.0,0.0), d2 ) );
     246        1620 :   tcderiv.setCol( 1, crossProduct( d1, Vector(0.0,-1.0,0.0) ) + crossProduct( Vector(0.0,-1.0,0.0), d2 ) );
     247        1620 :   tcderiv.setCol( 2, crossProduct( d1, Vector(0.0,0.0,-1.0) ) + crossProduct( Vector(0.0,0.0,-1.0), d2 ) );
     248        1620 :   dcross[0](0,0)=( tcderiv(0,0)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 );    // dx/dx
     249        1620 :   dcross[0](0,1)=( tcderiv(0,1)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 );    // dx/dy
     250        1620 :   dcross[0](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 );    // dx/dz
     251        1620 :   dcross[0](1,0)=( tcderiv(1,0)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 );    // dy/dx
     252        1620 :   dcross[0](1,1)=( tcderiv(1,1)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 );    // dy/dy
     253        1620 :   dcross[0](1,2)=( tcderiv(1,2)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 );    // dy/dz
     254        1620 :   dcross[0](2,0)=( tcderiv(2,0)/crossmod - ucross[2]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 );    // dz/dx
     255        1620 :   dcross[0](2,1)=( tcderiv(2,1)/crossmod - ucross[2]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 );    // dz/dy
     256        1620 :   dcross[0](2,2)=( tcderiv(2,2)/crossmod - ucross[2]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 );    // dz/dz
     257             : 
     258        1620 :   tcderiv.setCol( 0, crossProduct( Vector(1.0,0.0,0.0), d2 ) );
     259        1620 :   tcderiv.setCol( 1, crossProduct( Vector(0.0,1.0,0.0), d2 ) );
     260        1620 :   tcderiv.setCol( 2, crossProduct( Vector(0.0,0.0,1.0), d2 ) );
     261        1620 :   dcross[1](0,0)=( tcderiv(0,0)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 );    // dx/dx
     262        1620 :   dcross[1](0,1)=( tcderiv(0,1)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 );    // dx/dy
     263        1620 :   dcross[1](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 );    // dx/dz
     264        1620 :   dcross[1](1,0)=( tcderiv(1,0)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 );    // dy/dx
     265        1620 :   dcross[1](1,1)=( tcderiv(1,1)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 );    // dy/dy
     266        1620 :   dcross[1](1,2)=( tcderiv(1,2)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 );    // dy/dz
     267        1620 :   dcross[1](2,0)=( tcderiv(2,0)/crossmod - ucross[2]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 );    // dz/dx
     268        1620 :   dcross[1](2,1)=( tcderiv(2,1)/crossmod - ucross[2]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 );    // dz/dy
     269        1620 :   dcross[1](2,2)=( tcderiv(2,2)/crossmod - ucross[2]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 );    // dz/dz
     270             : 
     271        1620 :   tcderiv.setCol( 0, crossProduct( d1, Vector(1.0,0.0,0.0) ) );
     272        1620 :   tcderiv.setCol( 1, crossProduct( d1, Vector(0.0,1.0,0.0) ) );
     273        1620 :   tcderiv.setCol( 2, crossProduct( d1, Vector(0.0,0.0,1.0) ) );
     274        1620 :   dcross[2](0,0)=( tcderiv(0,0)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 );    // dx/dx
     275        1620 :   dcross[2](0,1)=( tcderiv(0,1)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 );    // dx/dy
     276        1620 :   dcross[2](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 );    // dx/dz
     277        1620 :   dcross[2](1,0)=( tcderiv(1,0)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 );    // dy/dx
     278        1620 :   dcross[2](1,1)=( tcderiv(1,1)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 );    // dy/dy
     279        1620 :   dcross[2](1,2)=( tcderiv(1,2)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 );    // dy/dz
     280        1620 :   dcross[2](2,0)=( tcderiv(2,0)/crossmod - ucross[2]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 );    // dz/dx
     281        1620 :   dcross[2](2,1)=( tcderiv(2,1)/crossmod - ucross[2]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 );    // dz/dy
     282        1620 :   dcross[2](2,2)=( tcderiv(2,2)/crossmod - ucross[2]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 );    // dz/dz
     283             : 
     284        1620 :   dperp[0].setCol( 0, ( crossProduct( dcross[0].getCol(0), bi ) + crossProduct( cross, dbi[0].getCol(0) ) ) );
     285        1620 :   dperp[0].setCol( 1, ( crossProduct( dcross[0].getCol(1), bi ) + crossProduct( cross, dbi[0].getCol(1) ) ) );
     286        1620 :   dperp[0].setCol( 2, ( crossProduct( dcross[0].getCol(2), bi ) + crossProduct( cross, dbi[0].getCol(2) ) ) );
     287             : 
     288        1620 :   dperp[1].setCol( 0, ( crossProduct( dcross[1].getCol(0), bi ) + crossProduct( cross, dbi[1].getCol(0) ) ) );
     289        1620 :   dperp[1].setCol( 1, ( crossProduct( dcross[1].getCol(1), bi ) + crossProduct( cross, dbi[1].getCol(1) ) ) );
     290        1620 :   dperp[1].setCol( 2, ( crossProduct( dcross[1].getCol(2), bi ) + crossProduct( cross, dbi[1].getCol(2) ) ) );
     291             : 
     292        1620 :   dperp[2].setCol( 0, ( crossProduct( dcross[2].getCol(0), bi ) ) );
     293        1620 :   dperp[2].setCol( 1, ( crossProduct( dcross[2].getCol(1), bi ) ) );
     294        1620 :   dperp[2].setCol( 2, ( crossProduct( dcross[2].getCol(2), bi ) ) );
     295             : 
     296             :   // Ensure that all lengths are positive
     297        1620 :   if( len_bi<0 ) {
     298           0 :     bi=-bi;
     299           0 :     len_bi=-len_bi;
     300           0 :     for(unsigned i=0; i<3; ++i) {
     301           0 :       dbi[i]*=-1.0;
     302             :     }
     303             :   }
     304        1620 :   if( len_cross<0 ) {
     305           0 :     cross=-cross;
     306           0 :     len_cross=-len_cross;
     307           0 :     for(unsigned i=0; i<3; ++i) {
     308           0 :       dcross[i]*=-1.0;
     309             :     }
     310             :   }
     311        1620 :   if( len_perp<0 ) {
     312           0 :     perp=-perp;
     313           0 :     len_perp=-len_perp;
     314           0 :     for(unsigned i=0; i<3; ++i) {
     315           0 :       dperp[i]*=-1.0;
     316             :     }
     317             :   }
     318        1620 :   if( len_bi<=0 || len_cross<=0 || len_perp<=0 ) {
     319           0 :     plumed_merror("Invalid box coordinates");
     320             :   }
     321             : 
     322             :   // Now derivatives of lengths
     323        1620 :   Tensor dd3( Tensor::identity() );
     324        1620 :   dlbi[0] = matmul(d3,dbi[0]) - matmul(bi,dd3);
     325        1620 :   dlbi[1] = matmul(d3,dbi[1]);
     326        1620 :   dlbi[2] = matmul(d3,dbi[2]);
     327        1620 :   dlbi[3] = matmul(bi,dd3);
     328             : 
     329        1620 :   dlcross[0] = matmul(d3,dcross[0]) - matmul(cross,dd3);
     330        1620 :   dlcross[1] = matmul(d3,dcross[1]);
     331        1620 :   dlcross[2] = matmul(d3,dcross[2]);
     332        1620 :   dlcross[3] = matmul(cross,dd3);
     333             : 
     334        1620 :   dlperp[0] = matmul(d3,dperp[0]) - matmul(perp,dd3);
     335        1620 :   dlperp[1] = matmul(d3,dperp[1]);
     336        1620 :   dlperp[2] = matmul(d3,dperp[2]);
     337        1620 :   dlperp[3] = matmul(perp,dd3);
     338             : 
     339             :   // Need to calculate the jacobian
     340        1620 :   Tensor jacob;
     341        1620 :   jacob(0,0)=bi[0];
     342        1620 :   jacob(1,0)=bi[1];
     343        1620 :   jacob(2,0)=bi[2];
     344        1620 :   jacob(0,1)=cross[0];
     345        1620 :   jacob(1,1)=cross[1];
     346        1620 :   jacob(2,1)=cross[2];
     347        1620 :   jacob(0,2)=perp[0];
     348        1620 :   jacob(1,2)=perp[1];
     349        1620 :   jacob(2,2)=perp[2];
     350        1620 :   jacob_det = std::fabs( jacob.determinant() );
     351        1620 : }
     352             : 
     353         120 : void VolumeCavity::update() {
     354         120 :   if(boxout) {
     355           0 :     boxfile.printf("%d\n",8);
     356           0 :     const Tensor & t(getPbc().getBox());
     357           0 :     if(getPbc().isOrthorombic()) {
     358           0 :       boxfile.printf(" %f %f %f\n",lenunit*t(0,0),lenunit*t(1,1),lenunit*t(2,2));
     359             :     } else {
     360           0 :       boxfile.printf(" %f %f %f %f %f %f %f %f %f\n",
     361           0 :                      lenunit*t(0,0),lenunit*t(0,1),lenunit*t(0,2),
     362           0 :                      lenunit*t(1,0),lenunit*t(1,1),lenunit*t(1,2),
     363           0 :                      lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2)
     364             :                     );
     365             :     }
     366           0 :     boxfile.printf("AR %f %f %f \n",lenunit*origin[0],lenunit*origin[1],lenunit*origin[2]);
     367           0 :     Vector ut, vt, wt;
     368           0 :     ut = origin + len_bi*bi;
     369           0 :     vt = origin + len_cross*cross;
     370           0 :     wt = origin + len_perp*perp;
     371           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]), lenunit*(ut[1]), lenunit*(ut[2]) );
     372           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]), lenunit*(vt[1]), lenunit*(vt[2]) );
     373           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(wt[0]), lenunit*(wt[1]), lenunit*(wt[2]) );
     374           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_bi*bi[0]),
     375           0 :                    lenunit*(vt[1]+len_bi*bi[1]),
     376           0 :                    lenunit*(vt[2]+len_bi*bi[2]) );
     377           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]+len_perp*perp[0]),
     378           0 :                    lenunit*(ut[1]+len_perp*perp[1]),
     379           0 :                    lenunit*(ut[2]+len_perp*perp[2]) );
     380           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]),
     381           0 :                    lenunit*(vt[1]+len_perp*perp[1]),
     382           0 :                    lenunit*(vt[2]+len_perp*perp[2]) );
     383           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]+len_bi*bi[0]),
     384           0 :                    lenunit*(vt[1]+len_perp*perp[1]+len_bi*bi[1]),
     385           0 :                    lenunit*(vt[2]+len_perp*perp[2]+len_bi*bi[2]) );
     386             :   }
     387         120 : }
     388             : 
     389        1620 : double VolumeCavity::calculateNumberInside( const Vector& cpos, Vector& derivatives, Tensor& vir, std::vector<Vector>& rderiv ) const {
     390             :   // Setup the histogram bead
     391        1620 :   HistogramBead bead;
     392             :   bead.isNotPeriodic();
     393        1620 :   bead.setKernelType( getKernelType() );
     394             : 
     395             :   // Calculate distance of atom from origin of new coordinate frame
     396        1620 :   Vector datom=pbcDistance( origin, cpos );
     397             :   double ucontr, uder, vcontr, vder, wcontr, wder;
     398             : 
     399             :   // Calculate contribution from integral along bi
     400        1620 :   bead.set( 0, len_bi, sigma );
     401        1620 :   double upos=dotProduct( datom, bi );
     402        1620 :   ucontr=bead.calculate( upos, uder );
     403        1620 :   double udlen=bead.uboundDerivative( upos );
     404        1620 :   double uder2 = bead.lboundDerivative( upos ) - udlen;
     405             : 
     406             :   // Calculate contribution from integral along cross
     407        1620 :   bead.set( 0, len_cross, sigma );
     408        1620 :   double vpos=dotProduct( datom, cross );
     409        1620 :   vcontr=bead.calculate( vpos, vder );
     410        1620 :   double vdlen=bead.uboundDerivative( vpos );
     411        1620 :   double vder2 = bead.lboundDerivative( vpos ) - vdlen;
     412             : 
     413             :   // Calculate contribution from integral along perp
     414        1620 :   bead.set( 0, len_perp, sigma );
     415        1620 :   double wpos=dotProduct( datom, perp );
     416        1620 :   wcontr=bead.calculate( wpos, wder );
     417        1620 :   double wdlen=bead.uboundDerivative( wpos );
     418        1620 :   double wder2 = bead.lboundDerivative( wpos ) - wdlen;
     419             : 
     420        1620 :   Vector dfd;
     421        1620 :   dfd[0]=uder*vcontr*wcontr;
     422        1620 :   dfd[1]=ucontr*vder*wcontr;
     423        1620 :   dfd[2]=ucontr*vcontr*wder;
     424        1620 :   derivatives[0] = (dfd[0]*bi[0]+dfd[1]*cross[0]+dfd[2]*perp[0]);
     425        1620 :   derivatives[1] = (dfd[0]*bi[1]+dfd[1]*cross[1]+dfd[2]*perp[1]);
     426        1620 :   derivatives[2] = (dfd[0]*bi[2]+dfd[1]*cross[2]+dfd[2]*perp[2]);
     427        1620 :   double tot = ucontr*vcontr*wcontr*jacob_det;
     428             : 
     429             :   // Add reference atom derivatives
     430        1620 :   dfd[0]=uder2*vcontr*wcontr;
     431        1620 :   dfd[1]=ucontr*vder2*wcontr;
     432        1620 :   dfd[2]=ucontr*vcontr*wder2;
     433        1620 :   Vector dfld;
     434        1620 :   dfld[0]=udlen*vcontr*wcontr;
     435        1620 :   dfld[1]=ucontr*vdlen*wcontr;
     436        1620 :   dfld[2]=ucontr*vcontr*wdlen;
     437        1620 :   rderiv[0] = dfd[0]*matmul(datom,dbi[0]) + dfd[1]*matmul(datom,dcross[0]) + dfd[2]*matmul(datom,dperp[0]) +
     438        3240 :               dfld[0]*dlbi[0] + dfld[1]*dlcross[0] + dfld[2]*dlperp[0] - derivatives;
     439        1620 :   rderiv[1] = dfd[0]*matmul(datom,dbi[1]) + dfd[1]*matmul(datom,dcross[1]) + dfd[2]*matmul(datom,dperp[1]) +
     440        3240 :               dfld[0]*dlbi[1] + dfld[1]*dlcross[1] + dfld[2]*dlperp[1];
     441        1620 :   rderiv[2] = dfd[0]*matmul(datom,dbi[2]) + dfd[1]*matmul(datom,dcross[2]) + dfd[2]*matmul(datom,dperp[2]) +
     442        3240 :               dfld[0]*dlbi[2] + dfld[1]*dlcross[2] + dfld[2]*dlperp[2];
     443        1620 :   rderiv[3] = dfld[0]*dlbi[3] + dfld[1]*dlcross[3] + dfld[2]*dlperp[3];
     444             : 
     445        1620 :   vir.zero();
     446        1620 :   vir-=Tensor( cpos,derivatives );
     447        8100 :   for(unsigned i=0; i<4; ++i) {
     448        6480 :     vir -= Tensor( getPosition(i), rderiv[i] );
     449             :   }
     450             : 
     451        1620 :   return tot;
     452             : }
     453             : 
     454             : }
     455             : }

Generated by: LCOV version 1.16