LCOV - code coverage report
Current view: top level - generic - ResetCell.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 52 54 96.3 %
Date: 2026-11-05 10:19:04 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2015-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/ActionAtomistic.h"
      23             : #include "core/ActionPilot.h"
      24             : #include "core/ActionRegister.h"
      25             : #include "core/PlumedMain.h"
      26             : #include "core/ActionSet.h"
      27             : #include "tools/Vector.h"
      28             : #include "tools/Matrix.h"
      29             : #include "tools/AtomNumber.h"
      30             : #include "tools/Tools.h"
      31             : #include "core/PbcAction.h"
      32             : #include "tools/Pbc.h"
      33             : 
      34             : namespace PLMD {
      35             : namespace generic {
      36             : 
      37             : //+PLUMEDOC GENERIC RESET_CELL
      38             : /*
      39             : This action is used to rotate the full cell
      40             : 
      41             : Rotating the full cell is useful if you want to modify the periodic box. Notice that
      42             : this is done at fixed scaled coordinates,
      43             : so that also atomic coordinates for the entire system are affected.
      44             : To see what effect try using [DUMPATOMS](DUMPATOMS.md) directive to output the atomic positions.
      45             : 
      46             : Also notice that PLUMED propagate forces correctly so that you can add a bias on a CV computed
      47             : after rotation. You can read the documentation for [FIT_TO_TEMPLATE](FIT_TO_TEMPLATE.md) for more
      48             : detail.
      49             : 
      50             : Currently, only TYPE=TRIANGULAR is implemented, which allows one to reset
      51             : the cell to a lower triangular one. This command finds a proper rotation
      52             : rotates the box so that the first lattice vector is in the form (ax,0,0),
      53             : the second lattice vector is in the form (bx,by,0), and the third lattice vector is
      54             : arbitrary.
      55             : 
      56             : !!! caution ""
      57             : 
      58             :     The implementation of this action is available but should be considered in testing phase. Please report any
      59             :     strange behavior.
      60             : 
      61             : !!! caution ""
      62             : 
      63             :     This directive modifies the stored position at the precise moment
      64             :     it is executed. This means that only collective variables
      65             :     which are below it in the input script will see the corrected positions.
      66             :     Unless you
      67             :     know exactly what you are doing, leave the default stride (1), so that
      68             :     this action is performed at every MD step.
      69             : 
      70             : ## Examples
      71             : 
      72             : Reset cell to be triangular after a rototranslational fit
      73             : 
      74             : ```plumed
      75             : #SETTINGS INPUTFILES=regtest/basic/rt63/align.pdb
      76             : DUMPATOMS FILE=dump-original.xyz ATOMS=1-20
      77             : FIT_TO_TEMPLATE STRIDE=1 REFERENCE=regtest/basic/rt63/align.pdb TYPE=OPTIMAL
      78             : DUMPATOMS FILE=dump-fit.xyz ATOMS=1-20
      79             : RESET_CELL TYPE=TRIANGULAR STRIDE=1
      80             : DUMPATOMS FILE=dump-reset.xyz ATOMS=1-20
      81             : ```
      82             : 
      83             : */
      84             : //+ENDPLUMEDOC
      85             : 
      86             : 
      87             : class ResetCell:
      88             :   public ActionPilot,
      89             :   public ActionAtomistic {
      90             :   std::string type;
      91             :   Tensor rotation,newbox;
      92             :   Value* boxValue;
      93             :   PbcAction* pbc_action;
      94             : public:
      95             :   explicit ResetCell(const ActionOptions&ao);
      96             :   static void registerKeywords( Keywords& keys );
      97             :   void calculate() override;
      98             :   void apply() override;
      99             : };
     100             : 
     101             : PLUMED_REGISTER_ACTION(ResetCell,"RESET_CELL")
     102             : 
     103           6 : void ResetCell::registerKeywords( Keywords& keys ) {
     104           6 :   Action::registerKeywords( keys );
     105           6 :   ActionAtomistic::registerKeywords( keys );
     106           6 :   keys.add("compulsory","STRIDE","1","the frequency with which molecules are reassembled.  Unless you are completely certain about what you are doing leave this set equal to 1!");
     107           6 :   keys.add("compulsory","TYPE","TRIANGULAR","the manner in which the cell is reset");
     108           6 : }
     109             : 
     110           2 : ResetCell::ResetCell(const ActionOptions&ao):
     111             :   Action(ao),
     112             :   ActionPilot(ao),
     113           2 :   ActionAtomistic(ao) {
     114           2 :   type.assign("TRIANGULAR");
     115           2 :   parse("TYPE",type);
     116             : 
     117           2 :   log<<"  type: "<<type<<"\n";
     118           2 :   if(type!="TRIANGULAR") {
     119           0 :     error("undefined type "+type);
     120             :   }
     121             : 
     122           2 :   pbc_action=plumed.getActionSet().selectWithLabel<PbcAction*>("Box");
     123           2 :   if( !pbc_action ) {
     124           0 :     error("cannot reset cell if box has not been set");
     125             :   }
     126           2 :   boxValue=pbc_action->copyOutput(0);
     127           2 : }
     128             : 
     129             : 
     130          17 : void ResetCell::calculate() {
     131          17 :   Tensor box=pbc_action->getPbc().getBox();
     132             : 
     133             : // moduli of lattice vectors
     134          17 :   double a=modulo(box.getRow(0));
     135          17 :   double b=modulo(box.getRow(1));
     136          17 :   double c=modulo(box.getRow(2));
     137             : // cos-angle between lattice vectors
     138          17 :   double ab=dotProduct(box.getRow(0),box.getRow(1))/(a*b);
     139          17 :   double ac=dotProduct(box.getRow(0),box.getRow(2))/(a*c);
     140          17 :   double bc=dotProduct(box.getRow(1),box.getRow(2))/(b*c);
     141             : 
     142             : // generate a new set of lattice vectors as a lower triangular matrix
     143          17 :   newbox[0][0]=a;
     144          17 :   newbox[1][0]=b*ab;
     145          17 :   newbox[1][1]=std::sqrt(b*b-newbox[1][0]*newbox[1][0]);
     146          17 :   newbox[2][0]=c*ac;
     147          17 :   newbox[2][1]=c*(bc-ac*ab)/std::sqrt(1-ab*ab);
     148          17 :   newbox[2][2]=std::sqrt(c*c-newbox[2][0]*newbox[2][0]-newbox[2][1]*newbox[2][1]);
     149             : 
     150          17 :   if(determinant(newbox)*determinant(box)<0) {
     151           1 :     newbox[2][2]=-newbox[2][2];
     152             :   }
     153             : 
     154             : // rotation matrix from old to new coordinates
     155          17 :   rotation=transpose(matmul(inverse(box),newbox));
     156             : 
     157             : // rotate all coordinates
     158          17 :   rotateAllGlobalPositions(rotation);
     159             : // rotate box
     160          17 :   pbc_action->getPbc().setBox(newbox);
     161          17 : }
     162             : 
     163          17 : void ResetCell::apply() {
     164             : // rotate back forces
     165          17 :   const Tensor rotationT=transpose(rotation);
     166          17 :   rotateForcesOnAllAtoms(rotationT);
     167             : 
     168             : // I have no mathematical derivation for this.
     169             : // The reasoning is the following.
     170             : // virial= h^T * dU/dh, where h is the box matrix and dU/dh its derivatives.
     171             : // The final virial should be rotationally invariant, that is symmetric.
     172             : // in the rotated frame, dU/dh elements [0][1], [0][2], and [1][2] should
     173             : // be changed so as to enforce rotational invariance. Thus we here have to
     174             : // make the virial matrix symmetric.
     175             : // Since h^T is upper triangular, it can be shown that any change in these elements
     176             : // will only affect the corresponding elements of the virial matrix.
     177             : // Thus, the only possibility is to set the corresponding elements
     178             : // of the virial matrix equal to their symmetric ones.
     179             : // GB
     180          17 :   Tensor virial;
     181          68 :   for(unsigned i=0; i<3; ++i)
     182         204 :     for(unsigned j=0; j<3; ++j) {
     183         153 :       virial[i][j]=boxValue->getForce( 3*i+j );
     184             :     }
     185          17 :   virial[0][1]=virial[1][0];
     186          17 :   virial[0][2]=virial[2][0];
     187          17 :   virial[1][2]=virial[2][1];
     188             : // rotate back virial
     189          17 :   virial=matmul(rotationT,matmul(virial,rotation));
     190          17 :   boxValue->clearInputForce();
     191          68 :   for(unsigned i=0; i<3; ++i)
     192         204 :     for(unsigned j=0; j<3; ++j) {
     193         153 :       boxValue->addForce( 3*i+j, virial(i,j) );
     194             :     }
     195             : 
     196             : 
     197          17 : }
     198             : 
     199             : }
     200             : }

Generated by: LCOV version 1.16