LCOV - code coverage report
Current view: top level - volumes - VolumeCavity.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 193 247 78.1 %
Date: 2025-04-08 21:11:17 Functions: 7 9 77.8 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2014-2020 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 "tools/Units.h"
      25             : #include "tools/Pbc.h"
      26             : #include "ActionVolume.h"
      27             : #include "VolumeShortcut.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             : This action can be used similarly to the way [AROUND](AROUND.md) is used.  Like [AROUND](AROUND.md) this action returns a vector
      34             : with elements that tell you whether an input atom is within a part of the box that is of particular interest or not. However, for this action
      35             : the elements of this vector are calculated using:
      36             : 
      37             : $$
      38             : 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
      39             :    K\left( \frac{u - u_i}{\sigma} \right)K\left( \frac{v - v_i}{\sigma} \right)K\left( \frac{w - w_i}{\sigma} \right)
      40             : $$
      41             : 
      42             : with $u_i,v_i,w_i$ being calculated from the positon of the $i$th atom, $(x_i,y_i,z_i)$, by performing the following transformation.
      43             : 
      44             : $$
      45             : \left(
      46             : \begin{matrix}
      47             :  u_i \\
      48             :  v_i \\
      49             :  w_i
      50             : \end{matrix}
      51             : \right) = R
      52             : \left(
      53             : \begin{matrix}
      54             :  x_i - x_o \\
      55             :  y_i - y_o \\
      56             :  z_i - z_o
      57             : \end{matrix}
      58             : \right)
      59             : $$
      60             : 
      61             : In this expression $R$ is a rotation matrix that is calculated by constructing a set of three orthonormal vectors from the
      62             : reference positions specified by the user. The first of these unit vectors points from the first reference atom to the second.
      63             : 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
      64             : these first two vectors.  $(x_o,y_o,z_o)$, meanwhile, specifies the position of the first reference atom.
      65             : 
      66             : In the first expression above $K$ is one of the kernel functions described in the documentation for the action [BETWEEN](BETWEEN.md)
      67             : and $\sigma$ is a bandwidth parameter.  Furthermore, The vector connecting atom 1 to atom 4 is used to define the extent of the box in
      68             : each of the $u$, $v$ and $w$ directions.  This vector connecting atom 1 to atom 4 is projected onto the three unit vectors
      69             : described above and the resulting projections determine the $u'$, $v'$ and $w'$ parameters in the above expression.
      70             : 
      71             : The following commands illustrate how this works in practise.  We are using PLUMED here to calculate the number of atoms from the group specified using the ATOMS keyword below are
      72             : in an ion channel in a protein.  The extent of the channel is calculated from the positions of atoms 1, 4, 5 and 11.
      73             : 
      74             : ```plumed
      75             : cav: CAVITY ATOMS=20-500 BOX=1,4,5,11 SIGMA=0.1
      76             : s: SUM ARG=cav PERIODIC=NO
      77             : PRINT ARG=s FILE=colvar
      78             : ```
      79             : 
      80             : By contrst the following command tells plumed to calculate the coordination numbers (with other water molecules) for the water
      81             : molecules in the protein channel described above. The average coordination number and the number of coordination
      82             : numbers more than 4 is then calculated for those molecules that are in the region of interest.
      83             : 
      84             : ```plumed
      85             : # Calculate the atoms that are in the cavity
      86             : cav: CAVITY ATOMS=20-500 BOX=1,4,5,11 SIGMA=0.1
      87             : # Calculate the coordination numbers of all the atoms
      88             : d1: COORDINATIONNUMBER SPECIES=20-500 SWITCH={RATIONAL R_0=0.1}
      89             : # Do atoms have a coordination number that is greater than 4
      90             : fd1: MORE_THAN ARG=d1 SWITCH={RATIONAL R_0=4}
      91             : # Calculate the mean coordination number in the channel
      92             : nnn: CUSTOM ARG=cav,d1 FUNC=x*y PERIODIC=NO
      93             : numer: SUM ARG=nnn PERIODIC=NO
      94             : denom: SUM ARG=cav PERIODIC=NO
      95             : mean: CUSTOM ARG=numer,denom FUNC=x/y PERIODIC=NO
      96             : # Calculate the number of atoms that are in the channel and that have a coordination number that is greater than 4
      97             : sss: CUSTOM ARG=fd1,cav FUNC=x*y PERIODIC=NO
      98             : mt: SUM ARG=sss PERIODIC=NO
      99             : # And print these two quantities to a file
     100             : PRINT ARG=mean,mt FILE=colvar
     101             : ```
     102             : 
     103             : As with [AROUND](AROUND.md) earlier version of PLUMED used a different syntax for doing these types of calculations, which can
     104             : still be used with this new version of the command.  However, we strongly recommend using the newer syntax.
     105             : 
     106             : */
     107             : //+ENDPLUMEDOC
     108             : 
     109             : //+PLUMEDOC MCOLVAR CAVITY_CALC
     110             : /*
     111             : Calculate a vector from the input positions with elements equal to one when the positions are in a particular part of the cell and elements equal to zero otherwise
     112             : 
     113             : \par Examples
     114             : 
     115             : */
     116             : //+ENDPLUMEDOC
     117             : 
     118             : namespace PLMD {
     119             : namespace volumes {
     120             : 
     121             : class VolumeCavity : public ActionVolume {
     122             : private:
     123             :   bool boxout;
     124             :   OFile boxfile;
     125             :   double lenunit;
     126             :   double jacob_det;
     127             :   double len_bi, len_cross, len_perp, sigma;
     128             :   Vector origin, bi, cross, perp;
     129             :   std::vector<Vector> dlbi, dlcross, dlperp;
     130             :   std::vector<Tensor> dbi, dcross, dperp;
     131             : public:
     132             :   static void registerKeywords( Keywords& keys );
     133             :   explicit VolumeCavity(const ActionOptions& ao);
     134             :   ~VolumeCavity();
     135             :   void setupRegions() override;
     136             :   void update() override;
     137             :   double calculateNumberInside( const Vector& cpos, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders ) const override;
     138             : };
     139             : 
     140             : PLUMED_REGISTER_ACTION(VolumeCavity,"CAVITY_CALC")
     141             : char glob_cavity[] = "CAVITY";
     142             : typedef VolumeShortcut<glob_cavity> VolumeCavityShortcut;
     143             : PLUMED_REGISTER_ACTION(VolumeCavityShortcut,"CAVITY")
     144             : 
     145           7 : void VolumeCavity::registerKeywords( Keywords& keys ) {
     146           7 :   ActionVolume::registerKeywords( keys );
     147          14 :   keys.setDisplayName("CAVITY");
     148           7 :   keys.add("atoms","BOX","the positions of four atoms that define spatial extent of the cavity");
     149           7 :   keys.addFlag("PRINT_BOX",false,"write out the positions of the corners of the box to an xyz file");
     150           7 :   keys.add("optional","FILE","the file on which to write out the box coordinates");
     151           7 :   keys.add("optional","UNITS","( default=nm ) the units in which to write out the corners of the box");
     152           7 : }
     153             : 
     154           1 : VolumeCavity::VolumeCavity(const ActionOptions& ao):
     155             :   Action(ao),
     156             :   ActionVolume(ao),
     157           1 :   boxout(false),
     158           1 :   lenunit(1.0),
     159           1 :   dlbi(4),
     160           1 :   dlcross(4),
     161           1 :   dlperp(4),
     162           1 :   dbi(3),
     163           1 :   dcross(3),
     164           2 :   dperp(3) {
     165             :   std::vector<AtomNumber> atoms;
     166           2 :   parseAtomList("BOX",atoms);
     167           1 :   if( atoms.size()!=4 ) {
     168           0 :     error("number of atoms in box should be equal to four");
     169             :   }
     170             : 
     171           1 :   log.printf("  boundaries for region are calculated based on positions of atoms : ");
     172           5 :   for(unsigned i=0; i<atoms.size(); ++i) {
     173           4 :     log.printf("%d ",atoms[i].serial() );
     174             :   }
     175           1 :   log.printf("\n");
     176           1 :   requestAtoms( atoms );
     177             : 
     178           1 :   boxout=false;
     179           1 :   parseFlag("PRINT_BOX",boxout);
     180           1 :   if(boxout) {
     181             :     std::string boxfname;
     182           0 :     parse("FILE",boxfname);
     183           0 :     if(boxfname.length()==0) {
     184           0 :       error("no name for box file specified");
     185             :     }
     186             :     std::string unitname;
     187           0 :     parse("UNITS",unitname);
     188           0 :     if ( unitname.length()>0 ) {
     189           0 :       Units u;
     190           0 :       u.setLength(unitname);
     191           0 :       lenunit=getUnits().getLength()/u.getLength();
     192           0 :     } else {
     193             :       unitname="nm";
     194             :     }
     195           0 :     boxfile.link(*this);
     196           0 :     boxfile.open( boxfname );
     197           0 :     log.printf("  printing box coordinates on file named %s in %s \n",boxfname.c_str(), unitname.c_str() );
     198             :   }
     199             : 
     200           1 :   checkRead();
     201           1 : }
     202             : 
     203           2 : VolumeCavity::~VolumeCavity() {
     204           2 : }
     205             : 
     206        1560 : void VolumeCavity::setupRegions() {
     207             :   // Make some space for things
     208        1560 :   Vector d1, d2, d3;
     209             : 
     210             :   // Retrieve the sigma value
     211        1560 :   sigma=getSigma();
     212             :   // Set the position of the origin
     213        1560 :   origin=getPosition(0);
     214             : 
     215             :   // Get two vectors
     216        1560 :   d1 = pbcDistance(origin,getPosition(1));
     217        1560 :   double d1l=d1.modulo();
     218        1560 :   d2 = pbcDistance(origin,getPosition(2));
     219             : 
     220             :   // Find the vector connecting the origin to the top corner of
     221             :   // the subregion
     222        1560 :   d3 = pbcDistance(origin,getPosition(3));
     223             : 
     224             :   // Create a set of unit vectors
     225        1560 :   bi = d1 / d1l;
     226        1560 :   len_bi=dotProduct( d3, bi );
     227        1560 :   cross = crossProduct( d1, d2 );
     228        1560 :   double crossmod=cross.modulo();
     229        1560 :   cross = cross / crossmod;
     230        1560 :   len_cross=dotProduct( d3, cross );
     231        1560 :   perp = crossProduct( cross, bi );
     232        1560 :   len_perp=dotProduct( d3, perp );
     233             : 
     234             :   // Calculate derivatives of box shape with respect to atoms
     235        1560 :   double d1l3=d1l*d1l*d1l;
     236        1560 :   dbi[0](0,0) = ( -(d1[1]*d1[1]+d1[2]*d1[2])/d1l3 );   // dx/dx
     237        1560 :   dbi[0](0,1) = (  d1[0]*d1[1]/d1l3 );                 // dx/dy
     238        1560 :   dbi[0](0,2) = (  d1[0]*d1[2]/d1l3 );                 // dx/dz
     239        1560 :   dbi[0](1,0) = (  d1[1]*d1[0]/d1l3 );                 // dy/dx
     240        1560 :   dbi[0](1,1) = ( -(d1[0]*d1[0]+d1[2]*d1[2])/d1l3 );   // dy/dy
     241        1560 :   dbi[0](1,2) = (  d1[1]*d1[2]/d1l3 );
     242        1560 :   dbi[0](2,0) = (  d1[2]*d1[0]/d1l3 );
     243        1560 :   dbi[0](2,1) = (  d1[2]*d1[1]/d1l3 );
     244        1560 :   dbi[0](2,2) = ( -(d1[1]*d1[1]+d1[0]*d1[0])/d1l3 );
     245             : 
     246        1560 :   dbi[1](0,0) = ( (d1[1]*d1[1]+d1[2]*d1[2])/d1l3 );
     247        1560 :   dbi[1](0,1) = ( -d1[0]*d1[1]/d1l3 );
     248        1560 :   dbi[1](0,2) = ( -d1[0]*d1[2]/d1l3 );
     249        1560 :   dbi[1](1,0) = ( -d1[1]*d1[0]/d1l3 );
     250        1560 :   dbi[1](1,1) = ( (d1[0]*d1[0]+d1[2]*d1[2])/d1l3 );
     251        1560 :   dbi[1](1,2) = ( -d1[1]*d1[2]/d1l3 );
     252        1560 :   dbi[1](2,0) = ( -d1[2]*d1[0]/d1l3 );
     253        1560 :   dbi[1](2,1) = ( -d1[2]*d1[1]/d1l3 );
     254        1560 :   dbi[1](2,2) = ( (d1[1]*d1[1]+d1[0]*d1[0])/d1l3 );
     255        1560 :   dbi[2].zero();
     256             : 
     257        1560 :   Tensor tcderiv;
     258        1560 :   double cmod3=crossmod*crossmod*crossmod;
     259        1560 :   Vector ucross=crossmod*cross;
     260        1560 :   tcderiv.setCol( 0, crossProduct( d1, Vector(-1.0,0.0,0.0) ) + crossProduct( Vector(-1.0,0.0,0.0), d2 ) );
     261        1560 :   tcderiv.setCol( 1, crossProduct( d1, Vector(0.0,-1.0,0.0) ) + crossProduct( Vector(0.0,-1.0,0.0), d2 ) );
     262        1560 :   tcderiv.setCol( 2, crossProduct( d1, Vector(0.0,0.0,-1.0) ) + crossProduct( Vector(0.0,0.0,-1.0), d2 ) );
     263        1560 :   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
     264        1560 :   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
     265        1560 :   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
     266        1560 :   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
     267        1560 :   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
     268        1560 :   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
     269        1560 :   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
     270        1560 :   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
     271        1560 :   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
     272             : 
     273        1560 :   tcderiv.setCol( 0, crossProduct( Vector(1.0,0.0,0.0), d2 ) );
     274        1560 :   tcderiv.setCol( 1, crossProduct( Vector(0.0,1.0,0.0), d2 ) );
     275        1560 :   tcderiv.setCol( 2, crossProduct( Vector(0.0,0.0,1.0), d2 ) );
     276        1560 :   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
     277        1560 :   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
     278        1560 :   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
     279        1560 :   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
     280        1560 :   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
     281        1560 :   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
     282        1560 :   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
     283        1560 :   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
     284        1560 :   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
     285             : 
     286        1560 :   tcderiv.setCol( 0, crossProduct( d1, Vector(1.0,0.0,0.0) ) );
     287        1560 :   tcderiv.setCol( 1, crossProduct( d1, Vector(0.0,1.0,0.0) ) );
     288        1560 :   tcderiv.setCol( 2, crossProduct( d1, Vector(0.0,0.0,1.0) ) );
     289        1560 :   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
     290        1560 :   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
     291        1560 :   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
     292        1560 :   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
     293        1560 :   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
     294        1560 :   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
     295        1560 :   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
     296        1560 :   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
     297        1560 :   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
     298             : 
     299        1560 :   dperp[0].setCol( 0, ( crossProduct( dcross[0].getCol(0), bi ) + crossProduct( cross, dbi[0].getCol(0) ) ) );
     300        1560 :   dperp[0].setCol( 1, ( crossProduct( dcross[0].getCol(1), bi ) + crossProduct( cross, dbi[0].getCol(1) ) ) );
     301        1560 :   dperp[0].setCol( 2, ( crossProduct( dcross[0].getCol(2), bi ) + crossProduct( cross, dbi[0].getCol(2) ) ) );
     302             : 
     303        1560 :   dperp[1].setCol( 0, ( crossProduct( dcross[1].getCol(0), bi ) + crossProduct( cross, dbi[1].getCol(0) ) ) );
     304        1560 :   dperp[1].setCol( 1, ( crossProduct( dcross[1].getCol(1), bi ) + crossProduct( cross, dbi[1].getCol(1) ) ) );
     305        1560 :   dperp[1].setCol( 2, ( crossProduct( dcross[1].getCol(2), bi ) + crossProduct( cross, dbi[1].getCol(2) ) ) );
     306             : 
     307        1560 :   dperp[2].setCol( 0, ( crossProduct( dcross[2].getCol(0), bi ) ) );
     308        1560 :   dperp[2].setCol( 1, ( crossProduct( dcross[2].getCol(1), bi ) ) );
     309        1560 :   dperp[2].setCol( 2, ( crossProduct( dcross[2].getCol(2), bi ) ) );
     310             : 
     311             :   // Ensure that all lengths are positive
     312        1560 :   if( len_bi<0 ) {
     313           0 :     bi=-bi;
     314           0 :     len_bi=-len_bi;
     315           0 :     for(unsigned i=0; i<3; ++i) {
     316           0 :       dbi[i]*=-1.0;
     317             :     }
     318             :   }
     319        1560 :   if( len_cross<0 ) {
     320           0 :     cross=-cross;
     321           0 :     len_cross=-len_cross;
     322           0 :     for(unsigned i=0; i<3; ++i) {
     323           0 :       dcross[i]*=-1.0;
     324             :     }
     325             :   }
     326        1560 :   if( len_perp<0 ) {
     327           0 :     perp=-perp;
     328           0 :     len_perp=-len_perp;
     329           0 :     for(unsigned i=0; i<3; ++i) {
     330           0 :       dperp[i]*=-1.0;
     331             :     }
     332             :   }
     333        1560 :   if( len_bi<=0 || len_cross<=0 || len_bi<=0 ) {
     334           0 :     plumed_merror("Invalid box coordinates");
     335             :   }
     336             : 
     337             :   // Now derivatives of lengths
     338        1560 :   Tensor dd3( Tensor::identity() );
     339        1560 :   dlbi[0] = matmul(d3,dbi[0]) - matmul(bi,dd3);
     340        1560 :   dlbi[1] = matmul(d3,dbi[1]);
     341        1560 :   dlbi[2] = matmul(d3,dbi[2]);
     342        1560 :   dlbi[3] = matmul(bi,dd3);
     343             : 
     344        1560 :   dlcross[0] = matmul(d3,dcross[0]) - matmul(cross,dd3);
     345        1560 :   dlcross[1] = matmul(d3,dcross[1]);
     346        1560 :   dlcross[2] = matmul(d3,dcross[2]);
     347        1560 :   dlcross[3] = matmul(cross,dd3);
     348             : 
     349        1560 :   dlperp[0] = matmul(d3,dperp[0]) - matmul(perp,dd3);
     350        1560 :   dlperp[1] = matmul(d3,dperp[1]);
     351        1560 :   dlperp[2] = matmul(d3,dperp[2]);
     352        1560 :   dlperp[3] = matmul(perp,dd3);
     353             : 
     354             :   // Need to calculate the jacobian
     355        1560 :   Tensor jacob;
     356        1560 :   jacob(0,0)=bi[0];
     357        1560 :   jacob(1,0)=bi[1];
     358        1560 :   jacob(2,0)=bi[2];
     359        1560 :   jacob(0,1)=cross[0];
     360        1560 :   jacob(1,1)=cross[1];
     361        1560 :   jacob(2,1)=cross[2];
     362        1560 :   jacob(0,2)=perp[0];
     363        1560 :   jacob(1,2)=perp[1];
     364        1560 :   jacob(2,2)=perp[2];
     365        1560 :   jacob_det = fabs( jacob.determinant() );
     366        1560 : }
     367             : 
     368          60 : void VolumeCavity::update() {
     369          60 :   if(boxout) {
     370           0 :     boxfile.printf("%d\n",8);
     371           0 :     const Tensor & t(getPbc().getBox());
     372           0 :     if(getPbc().isOrthorombic()) {
     373           0 :       boxfile.printf(" %f %f %f\n",lenunit*t(0,0),lenunit*t(1,1),lenunit*t(2,2));
     374             :     } else {
     375           0 :       boxfile.printf(" %f %f %f %f %f %f %f %f %f\n",
     376           0 :                      lenunit*t(0,0),lenunit*t(0,1),lenunit*t(0,2),
     377           0 :                      lenunit*t(1,0),lenunit*t(1,1),lenunit*t(1,2),
     378           0 :                      lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2)
     379             :                     );
     380             :     }
     381           0 :     boxfile.printf("AR %f %f %f \n",lenunit*origin[0],lenunit*origin[1],lenunit*origin[2]);
     382           0 :     Vector ut, vt, wt;
     383           0 :     ut = origin + len_bi*bi;
     384           0 :     vt = origin + len_cross*cross;
     385           0 :     wt = origin + len_perp*perp;
     386           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]), lenunit*(ut[1]), lenunit*(ut[2]) );
     387           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]), lenunit*(vt[1]), lenunit*(vt[2]) );
     388           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(wt[0]), lenunit*(wt[1]), lenunit*(wt[2]) );
     389           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_bi*bi[0]),
     390           0 :                    lenunit*(vt[1]+len_bi*bi[1]),
     391           0 :                    lenunit*(vt[2]+len_bi*bi[2]) );
     392           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]+len_perp*perp[0]),
     393           0 :                    lenunit*(ut[1]+len_perp*perp[1]),
     394           0 :                    lenunit*(ut[2]+len_perp*perp[2]) );
     395           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]),
     396           0 :                    lenunit*(vt[1]+len_perp*perp[1]),
     397           0 :                    lenunit*(vt[2]+len_perp*perp[2]) );
     398           0 :     boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]+len_bi*bi[0]),
     399           0 :                    lenunit*(vt[1]+len_perp*perp[1]+len_bi*bi[1]),
     400           0 :                    lenunit*(vt[2]+len_perp*perp[2]+len_bi*bi[2]) );
     401             :   }
     402          60 : }
     403             : 
     404        1560 : double VolumeCavity::calculateNumberInside( const Vector& cpos, Vector& derivatives, Tensor& vir, std::vector<Vector>& rderiv ) const {
     405             :   // Setup the histogram bead
     406        1560 :   HistogramBead bead;
     407             :   bead.isNotPeriodic();
     408        1560 :   bead.setKernelType( getKernelType() );
     409             : 
     410             :   // Calculate distance of atom from origin of new coordinate frame
     411        1560 :   Vector datom=pbcDistance( origin, cpos );
     412             :   double ucontr, uder, vcontr, vder, wcontr, wder;
     413             : 
     414             :   // Calculate contribution from integral along bi
     415        1560 :   bead.set( 0, len_bi, sigma );
     416        1560 :   double upos=dotProduct( datom, bi );
     417        1560 :   ucontr=bead.calculate( upos, uder );
     418        1560 :   double udlen=bead.uboundDerivative( upos );
     419        1560 :   double uder2 = bead.lboundDerivative( upos ) - udlen;
     420             : 
     421             :   // Calculate contribution from integral along cross
     422        1560 :   bead.set( 0, len_cross, sigma );
     423        1560 :   double vpos=dotProduct( datom, cross );
     424        1560 :   vcontr=bead.calculate( vpos, vder );
     425        1560 :   double vdlen=bead.uboundDerivative( vpos );
     426        1560 :   double vder2 = bead.lboundDerivative( vpos ) - vdlen;
     427             : 
     428             :   // Calculate contribution from integral along perp
     429        1560 :   bead.set( 0, len_perp, sigma );
     430        1560 :   double wpos=dotProduct( datom, perp );
     431        1560 :   wcontr=bead.calculate( wpos, wder );
     432        1560 :   double wdlen=bead.uboundDerivative( wpos );
     433        1560 :   double wder2 = bead.lboundDerivative( wpos ) - wdlen;
     434             : 
     435        1560 :   Vector dfd;
     436        1560 :   dfd[0]=uder*vcontr*wcontr;
     437        1560 :   dfd[1]=ucontr*vder*wcontr;
     438        1560 :   dfd[2]=ucontr*vcontr*wder;
     439        1560 :   derivatives[0] = (dfd[0]*bi[0]+dfd[1]*cross[0]+dfd[2]*perp[0]);
     440        1560 :   derivatives[1] = (dfd[0]*bi[1]+dfd[1]*cross[1]+dfd[2]*perp[1]);
     441        1560 :   derivatives[2] = (dfd[0]*bi[2]+dfd[1]*cross[2]+dfd[2]*perp[2]);
     442        1560 :   double tot = ucontr*vcontr*wcontr*jacob_det;
     443             : 
     444             :   // Add reference atom derivatives
     445        1560 :   dfd[0]=uder2*vcontr*wcontr;
     446        1560 :   dfd[1]=ucontr*vder2*wcontr;
     447        1560 :   dfd[2]=ucontr*vcontr*wder2;
     448        1560 :   Vector dfld;
     449        1560 :   dfld[0]=udlen*vcontr*wcontr;
     450        1560 :   dfld[1]=ucontr*vdlen*wcontr;
     451        1560 :   dfld[2]=ucontr*vcontr*wdlen;
     452        1560 :   rderiv[0] = dfd[0]*matmul(datom,dbi[0]) + dfd[1]*matmul(datom,dcross[0]) + dfd[2]*matmul(datom,dperp[0]) +
     453        3120 :               dfld[0]*dlbi[0] + dfld[1]*dlcross[0] + dfld[2]*dlperp[0] - derivatives;
     454        1560 :   rderiv[1] = dfd[0]*matmul(datom,dbi[1]) + dfd[1]*matmul(datom,dcross[1]) + dfd[2]*matmul(datom,dperp[1]) +
     455        3120 :               dfld[0]*dlbi[1] + dfld[1]*dlcross[1] + dfld[2]*dlperp[1];
     456        1560 :   rderiv[2] = dfd[0]*matmul(datom,dbi[2]) + dfd[1]*matmul(datom,dcross[2]) + dfd[2]*matmul(datom,dperp[2]) +
     457        3120 :               dfld[0]*dlbi[2] + dfld[1]*dlcross[2] + dfld[2]*dlperp[2];
     458        1560 :   rderiv[3] = dfld[0]*dlbi[3] + dfld[1]*dlcross[3] + dfld[2]*dlperp[3];
     459             : 
     460        1560 :   vir.zero();
     461        1560 :   vir-=Tensor( cpos,derivatives );
     462        7800 :   for(unsigned i=0; i<4; ++i) {
     463        6240 :     vir -= Tensor( getPosition(i), rderiv[i] );
     464             :   }
     465             : 
     466        1560 :   return tot;
     467             : }
     468             : 
     469             : }
     470             : }

Generated by: LCOV version 1.16