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 2 : keys.add("atoms","ATOMS","atoms for which we calculate the shadow RMSD");
116 2 : keys.add("compulsory","UPDATE","stride for updating reference coordinates");
117 2 : keys.addFlag("REFERENCE",false,"this is the reference replica");
118 4 : keys.setValueDescription("scalar","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 : // list of atoms
125 : std::vector<AtomNumber> atoms;
126 0 : parseAtomList("ATOMS",atoms);
127 : // update stride
128 0 : parse("UPDATE",nupdate_);
129 :
130 : // is this the reference replica
131 0 : parseFlag("REFERENCE",isreference_);
132 :
133 : // periodic boundary conditions
134 0 : bool nopbc=!pbc_;
135 0 : parseFlag("NOPBC",nopbc);
136 0 : pbc_=!nopbc;
137 :
138 : // set intra-replica (openmp) parallel stuff
139 0 : size_ = comm.Get_size();
140 0 : rank_ = comm.Get_rank();
141 :
142 : // get number of (MPI) replicas
143 0 : int nrep = 0;
144 0 : int replica = 0;
145 : // only if openmp master
146 0 : if(rank_==0) {
147 0 : nrep = multi_sim_comm.Get_size();
148 0 : replica = multi_sim_comm.Get_rank();
149 : }
150 0 : comm.Sum(&nrep,1);
151 0 : comm.Sum(&replica,1);
152 : // check number of replicas
153 : //if(nrep<2) error("SHADOW must be used with at least two replicas");
154 :
155 0 : checkRead();
156 :
157 0 : log.printf(" atoms involved : ");
158 0 : for(unsigned i=0; i<atoms.size(); ++i) {
159 0 : log.printf("%d ",atoms[i].serial());
160 : }
161 0 : log.printf("\n");
162 0 : log.printf(" stride for updating reference coordinates : %d\n", nupdate_);
163 0 : log.printf(" number of replicas : %d\n", nrep);
164 0 : log.printf(" replica id : %d\n", replica);
165 0 : if(isreference_) {
166 0 : log.printf(" this is the reference replica\n");
167 : }
168 :
169 : // add value and set periodicity
170 0 : addValueWithDerivatives();
171 0 : setNotPeriodic();
172 :
173 : // request atoms
174 0 : requestAtoms(atoms);
175 0 : }
176 :
177 0 : void Shadow::update_reference() {
178 : // number of atoms
179 : unsigned natoms = getNumberOfAtoms();
180 : // initialize rmsd variables
181 0 : std::vector<double> align(natoms,1.0);
182 0 : std::vector<double> displace(natoms,1.0);
183 0 : std::vector<Vector> reference(natoms);
184 :
185 : // first get the reference coordinates
186 : // if master openmp task
187 0 : if(rank_==0) {
188 : // if reference replica
189 0 : if(isreference_) {
190 0 : reference = getPositions();
191 : }
192 : // share coordinates
193 0 : multi_sim_comm.Sum(&reference[0][0], 3*natoms);
194 : }
195 : // now intra replica (openmp) communication
196 0 : if(size_>1) {
197 0 : comm.Sum(&reference[0][0], 3*natoms);
198 : }
199 :
200 : // clear the rmsd object
201 0 : rmsd_.clear();
202 : // and initialize it
203 0 : rmsd_.set(align,displace,reference,"OPTIMAL");
204 0 : }
205 :
206 0 : void Shadow::calculate() {
207 : // make whole
208 0 : if(pbc_) {
209 0 : makeWhole();
210 : }
211 :
212 : // if it is time, update reference coordinates
213 0 : if(first_time_ || getStep()%nupdate_==0) {
214 0 : update_reference();
215 0 : first_time_ = false;
216 : }
217 :
218 : // calculate RMSD and derivatives
219 0 : std::vector<Vector> derivatives(getNumberOfAtoms());
220 0 : double rmsd = rmsd_.calculate(getPositions(), derivatives);
221 :
222 : // set RMSD value
223 0 : setValue(rmsd);
224 : // if this is not the reference replica, add derivatives
225 0 : if(!isreference_) {
226 0 : for(unsigned i=0; i<getNumberOfAtoms(); ++i) {
227 0 : setAtomsDerivatives(i, derivatives[i]);
228 : }
229 : }
230 : // set virial
231 0 : setBoxDerivativesNoPbc();
232 0 : }
233 :
234 : }
235 : }
|