Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2017-2022 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 "colvar/Colvar.h"
23 : #include "core/ActionRegister.h"
24 : #include "core/PlumedMain.h"
25 : #include "tools/Communicator.h"
26 : #include "tools/Pbc.h"
27 : #include "tools/RMSD.h"
28 : #include <string>
29 :
30 : namespace PLMD {
31 : namespace isdb {
32 :
33 : //+PLUMEDOC ISDB_COLVAR SHADOW
34 : /*
35 : Communicate atoms positions among replicas and calculate the RMSD with respect to a mother (reference) simulation.
36 :
37 : The option \ref UPDATE allows to specify the stride for communication between mother and replica systems.
38 : The flag \ref REFERENCE needs to be specified in the input file of the mother replica.
39 : This action must be run in a multi-replica framework (such as the -multi option in GROMACS).
40 :
41 : \par Examples
42 :
43 : In this example, we perform a simulation of a RNA molecule using two replicas: a mother and a shadow replica.
44 : The mother simulation communicates the coordinates of the RNA backbone to the replica every 100 steps.
45 : The RMSD of the replica with respect to the mother is calculated on the RNA backbone atoms and an \ref UPPER_WALLS is applied at 0.2 nm.
46 : The mother replica contains also the \ref UPPER_WALLS action. However, the forces on the RNA atoms of the mother replica are automatically set to zero
47 : inside the \ref SHADOW action.
48 :
49 : The input file for the mother simulation looks as follows:
50 :
51 : \plumedfile
52 : # Reference PDB
53 : MOLINFO STRUCTURE=conf_emin_PLUMED.pdb WHOLE
54 : # Define RNA nucleic backbone
55 : rna: GROUP ATOMS=1,2,5,6,33,36,37,40,41,67,70,71,74,75,98,101,102,105,106,131,134,135,138,139,165,168,169,172,173,198,201,202,205,206,228,231,232,235,236,259,262,263,266,267,289,292,293,296,297,323,326,327,330,331,356,359,360,363,364,390,393,394,397,398,421,424,425,428,429,452,455,456,459,460,482,485,486,489,490,516,519,520,523,524,550,553,554,557,558,584,587,588,591,592,617,620,621,624,625,651,654,655,658,659,682,685,686,689,690,712,715,716,719,720,743,746,747,750,751,773,776,777,780,781,804,807,808,811,812,834,837,838,841,842,868,871,872,875,876,899,902,903,906,907
56 : # Reconstruct RNA PBC
57 : WHOLEMOLECULES ENTITY0=rna EMST STRIDE=1
58 :
59 : # Define shadow RMSD on RNA backbone
60 : rmsd: SHADOW ATOMS=rna NOPBC UPDATE=100 REFERENCE
61 : # Add upper wall - derivatives are set to zero inside SHADOW action
62 : uws: UPPER_WALLS ARG=rmsd AT=0.2 KAPPA=10000.0 STRIDE=1
63 :
64 : # Print useful info
65 : PRINT FILE=COLVAR STRIDE=500 ARG=rmsd,uws.bias
66 : \endplumedfile
67 :
68 : while the input file for a shadow replica looks like:
69 :
70 : \plumedfile
71 : # Reference PDB
72 : MOLINFO STRUCTURE=conf_emin_PLUMED.pdb WHOLE
73 : # Define RNA nucleic backbone
74 : rna: GROUP ATOMS=1,2,5,6,33,36,37,40,41,67,70,71,74,75,98,101,102,105,106,131,134,135,138,139,165,168,169,172,173,198,201,202,205,206,228,231,232,235,236,259,262,263,266,267,289,292,293,296,297,323,326,327,330,331,356,359,360,363,364,390,393,394,397,398,421,424,425,428,429,452,455,456,459,460,482,485,486,489,490,516,519,520,523,524,550,553,554,557,558,584,587,588,591,592,617,620,621,624,625,651,654,655,658,659,682,685,686,689,690,712,715,716,719,720,743,746,747,750,751,773,776,777,780,781,804,807,808,811,812,834,837,838,841,842,868,871,872,875,876,899,902,903,906,907
75 : # Reconstruct RNA PBC
76 : WHOLEMOLECULES ENTITY0=rna EMST STRIDE=1
77 :
78 : # Define shadow RMSD on RNA backbone
79 : rmsd: SHADOW ATOMS=rna NOPBC UPDATE=100
80 : # Add upper wall
81 : uws: UPPER_WALLS ARG=rmsd AT=0.2 KAPPA=10000.0 STRIDE=1
82 :
83 : # Print useful info
84 : PRINT FILE=COLVAR STRIDE=500 ARG=rmsd,uws.bias
85 : \endplumedfile
86 :
87 : */
88 : //+ENDPLUMEDOC
89 :
90 : class Shadow : public Colvar {
91 : // private stuff
92 : bool isreference_;
93 : unsigned nupdate_;
94 : bool pbc_;
95 : bool first_time_;
96 : // RMSD object
97 : PLMD::RMSD rmsd_;
98 : // parallel stuff
99 : unsigned size_;
100 : unsigned rank_;
101 : // update reference
102 : void update_reference();
103 :
104 : public:
105 : static void registerKeywords( Keywords& keys );
106 : explicit Shadow(const ActionOptions&);
107 : // active methods:
108 : void calculate() override;
109 : };
110 :
111 : PLUMED_REGISTER_ACTION(Shadow,"SHADOW")
112 :
113 2 : void Shadow::registerKeywords( Keywords& keys ) {
114 2 : Colvar::registerKeywords( keys );
115 4 : keys.add("atoms","ATOMS","atoms for which we calculate the shadow RMSD");
116 4 : keys.add("compulsory","UPDATE","stride for updating reference coordinates");
117 4 : keys.addFlag("REFERENCE",false,"this is the reference replica");
118 2 : keys.setValueDescription("the value of the shadow RMSD");
119 2 : }
120 :
121 0 : Shadow::Shadow(const ActionOptions&ao):
122 : PLUMED_COLVAR_INIT(ao),
123 0 : isreference_(false), nupdate_(1), pbc_(true), first_time_(true)
124 : {
125 : // list of atoms
126 : std::vector<AtomNumber> atoms;
127 0 : parseAtomList("ATOMS",atoms);
128 : // update stride
129 0 : parse("UPDATE",nupdate_);
130 :
131 : // is this the reference replica
132 0 : parseFlag("REFERENCE",isreference_);
133 :
134 : // periodic boundary conditions
135 0 : bool nopbc=!pbc_;
136 0 : parseFlag("NOPBC",nopbc);
137 0 : pbc_=!nopbc;
138 :
139 : // set intra-replica (openmp) parallel stuff
140 0 : size_ = comm.Get_size();
141 0 : rank_ = comm.Get_rank();
142 :
143 : // get number of (MPI) replicas
144 0 : int nrep = 0;
145 0 : int replica = 0;
146 : // only if openmp master
147 0 : if(rank_==0) {
148 0 : nrep = multi_sim_comm.Get_size();
149 0 : replica = multi_sim_comm.Get_rank();
150 : }
151 0 : comm.Sum(&nrep,1);
152 0 : comm.Sum(&replica,1);
153 : // check number of replicas
154 : //if(nrep<2) error("SHADOW must be used with at least two replicas");
155 :
156 0 : checkRead();
157 :
158 0 : log.printf(" atoms involved : ");
159 0 : for(unsigned i=0; i<atoms.size(); ++i) log.printf("%d ",atoms[i].serial());
160 0 : log.printf("\n");
161 0 : log.printf(" stride for updating reference coordinates : %d\n", nupdate_);
162 0 : log.printf(" number of replicas : %d\n", nrep);
163 0 : log.printf(" replica id : %d\n", replica);
164 0 : if(isreference_) log.printf(" this is the reference replica\n");
165 :
166 : // add value and set periodicity
167 0 : addValueWithDerivatives(); setNotPeriodic();
168 :
169 : // request atoms
170 0 : requestAtoms(atoms);
171 0 : }
172 :
173 0 : void Shadow::update_reference()
174 : {
175 : // number of atoms
176 : unsigned natoms = getNumberOfAtoms();
177 : // initialize rmsd variables
178 0 : std::vector<double> align(natoms,1.0);
179 0 : std::vector<double> displace(natoms,1.0);
180 0 : std::vector<Vector> reference(natoms);
181 :
182 : // first get the reference coordinates
183 : // if master openmp task
184 0 : if(rank_==0) {
185 : // if reference replica
186 0 : if(isreference_) reference = getPositions();
187 : // share coordinates
188 0 : multi_sim_comm.Sum(&reference[0][0], 3*natoms);
189 : }
190 : // now intra replica (openmp) communication
191 0 : if(size_>1) comm.Sum(&reference[0][0], 3*natoms);
192 :
193 : // clear the rmsd object
194 0 : rmsd_.clear();
195 : // and initialize it
196 0 : rmsd_.set(align,displace,reference,"OPTIMAL");
197 0 : }
198 :
199 0 : void Shadow::calculate()
200 : {
201 : // make whole
202 0 : if(pbc_) makeWhole();
203 :
204 : // if it is time, update reference coordinates
205 0 : if(first_time_ || getStep()%nupdate_==0) {
206 0 : update_reference();
207 0 : first_time_ = false;
208 : }
209 :
210 : // calculate RMSD and derivatives
211 0 : std::vector<Vector> derivatives(getNumberOfAtoms());
212 0 : double rmsd = rmsd_.calculate(getPositions(), derivatives);
213 :
214 : // set RMSD value
215 0 : setValue(rmsd);
216 : // if this is not the reference replica, add derivatives
217 0 : if(!isreference_) {
218 0 : for(unsigned i=0; i<getNumberOfAtoms(); ++i) setAtomsDerivatives(i, derivatives[i]);
219 : }
220 : // set virial
221 0 : setBoxDerivativesNoPbc();
222 0 : }
223 :
224 : }
225 : }
|