Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2017-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 "ActionToPutData.h"
23 : #include "ActionRegister.h"
24 : #include "PlumedMain.h"
25 : #include "ActionSet.h"
26 :
27 : //+PLUMEDOC ANALYSIS PUT
28 : /*
29 : Pass data into PLUMED
30 :
31 : \par Examples
32 :
33 : */
34 : //+ENDPLUMEDOC
35 :
36 : namespace PLMD {
37 :
38 : PLUMED_REGISTER_ACTION(ActionToPutData,"PUT")
39 :
40 9332 : void ActionToPutData::registerKeywords(Keywords& keys) {
41 9332 : ActionForInterface::registerKeywords( keys );
42 18664 : keys.add("compulsory","SHAPE","0","the shape of the value that is being passed to PLUMED");
43 18664 : keys.add("compulsory","UNIT","the unit of the quantity that is being passed to PLUMED through this value. Can be either number, energy, time, length, mass or charge");
44 18664 : keys.add("compulsory","FORCE_UNIT","default","the units to use for the force");
45 18664 : keys.add("compulsory","PERIODIC","if the value being passed to plumed is periodic then you should specify the periodicity of the function. If the value "
46 : "is not periodic you must state this using PERIODIC=NO. Positions are passed with PERIODIC=NO even though special methods are used "
47 : "to deal with pbc");
48 18664 : keys.addFlag("CONSTANT",false,"does this quantity not depend on time");
49 18664 : keys.addFlag("FROM_DOMAINS",false,"is this quantity passed through the domain decomposition object");
50 18664 : keys.addFlag("MUTABLE",false,"can plumed change the value of the pointer that is passed from the MD code");
51 18664 : keys.addFlag("ROUND_TO_BASE_TEN",false,"is this quantity written by the user in base ten, as the timestep is. If the MD code "
52 : "passes floats, the extra digits that appear when converting them to double are removed");
53 9332 : keys.setValueDescription("the data that was passed from the MD code");
54 9332 : }
55 :
56 10869 : ActionToPutData::ActionToPutData(const ActionOptions&ao):
57 : Action(ao),
58 : ActionForInterface(ao),
59 10869 : noforce(false),
60 10869 : forces_added_elsewhere(false),
61 10869 : fixed(false),
62 10869 : from_domains(false),
63 10869 : resetable(false),
64 10869 : dataCanBeSet(true),
65 10869 : unit(n),
66 10869 : mydata(DataPassingObject::create(plumed.getRealPrecision())) {
67 10869 : if( getName()!="ENERGY" && getName()!="PBC" ) {
68 : std::vector<unsigned> shape;
69 18590 : parseVector("SHAPE",shape);
70 9295 : if( shape.size()==1 && shape[0]==0 ) {
71 1593 : shape.resize(0);
72 1593 : addValue( shape );
73 : } else {
74 7702 : addValue( shape );
75 : }
76 :
77 : std::string unitstr, funitstr;
78 9295 : parse("UNIT",unitstr);
79 9295 : parse("FORCE_UNIT",funitstr);
80 9295 : setUnit( unitstr, funitstr );
81 :
82 : // Now sort out period
83 : std::vector<std::string> period;
84 18590 : parseVector("PERIODIC",period);
85 9295 : if( period.size()==1 ) {
86 9293 : if( period[0]!="NO") {
87 0 : error("input to PERIODIC keyword does not make sense");
88 : }
89 9293 : setNotPeriodic();
90 2 : } else if( period.size()==2 ) {
91 2 : setPeriodic( period[0], period[1] );
92 : } else {
93 0 : error("input to PERIODIC keyword does not make sense");
94 : }
95 :
96 9295 : parseFlag("CONSTANT",fixed);
97 9295 : if( fixed ) {
98 4658 : noforce=true;
99 4658 : copyOutput(0)->setConstant();
100 : }
101 9295 : parseFlag("FROM_DOMAINS",from_domains);
102 9295 : parseFlag("MUTABLE",resetable);
103 9295 : bool round_to_base_ten=false;
104 18590 : parseFlag("ROUND_TO_BASE_TEN",round_to_base_ten);
105 : mydata->setRoundToBaseTen( round_to_base_ten );
106 9295 : }
107 10869 : }
108 :
109 10869 : void ActionToPutData::setUnit( const std::string& unitstr, const std::string& funitstr ) {
110 10869 : if( unitstr=="number" ) {
111 43 : unit=n;
112 10826 : } else if( unitstr=="energy" ) {
113 260 : unit=e;
114 10566 : } else if( unitstr=="length" ) {
115 6136 : unit=l;
116 4430 : } else if( unitstr=="mass" ) {
117 1534 : unit=m;
118 2896 : } else if( unitstr=="charge" ) {
119 1534 : unit=q;
120 1362 : } else if( unitstr=="time" ) {
121 1362 : unit=t;
122 : } else {
123 0 : error( unitstr + " is not a valid input unit");
124 : }
125 : // Set the force units
126 10869 : if( funitstr=="default" ) {
127 9335 : funit=d;
128 1534 : } else if( funitstr=="energy" ) {
129 1534 : funit=eng;
130 : } else {
131 0 : error( funitstr + " is not a valid input force unit");
132 : }
133 10869 : }
134 :
135 12647 : std::string ActionToPutData::getUnitName() const {
136 12647 : if( unit==e ) {
137 483 : return "energy";
138 : }
139 12164 : if( unit==l ) {
140 6272 : return "length";
141 : }
142 5892 : if( unit==m ) {
143 1568 : return "mass";
144 : }
145 4324 : if( unit==q ) {
146 1568 : return "charge";
147 : }
148 2756 : if( unit==t ) {
149 2756 : return "time";
150 : }
151 0 : plumed_error();
152 : }
153 :
154 818399 : void ActionToPutData::setStart( const std::string& name, const unsigned& sss) {
155 818399 : plumed_assert( name==getLabel() );
156 : mydata->setStart(sss);
157 818399 : }
158 :
159 818399 : void ActionToPutData::setStride( const std::string& name, const unsigned& sss ) {
160 818399 : plumed_assert( name==getLabel() );
161 : mydata->setStride(sss);
162 818399 : }
163 :
164 12679 : void ActionToPutData::updateUnits( DataPassingTools* passtools ) {
165 : // Don't need to do anythign if this is just a number
166 12679 : if( unit==n ) {
167 : return ;
168 : }
169 :
170 25294 : double vunits=passtools->getUnitConversion( getUnitName() );
171 : mydata->setUnit(vunits);
172 12647 : if( fixed && wasset ) {
173 3199 : mydata->share_data( 0, getPntrToValue()->getNumberOfValues(), getPntrToValue() );
174 : }
175 12647 : if( funit==eng ) {
176 1568 : mydata->setForceUnit( 1/passtools->getUnitConversion("energy"));
177 11079 : } else if( funit==d ) {
178 11079 : mydata->setForceUnit(1/passtools->getUnitConversion("energy")*vunits);
179 : }
180 : }
181 :
182 3028685 : bool ActionToPutData::setValuePointer( const std::string& name, const TypesafePtr & val ) {
183 3028685 : if( name!=getLabel() ) {
184 : return false;
185 : }
186 819987 : wasset=true;
187 819993 : plumed_massert( dataCanBeSet, "set " + getLabel() + " cannot be set at this time");
188 819984 : if( !from_domains ) {
189 188730 : if( !resetable && getPntrToComponent(0)->getRank()==0 ) {
190 5581 : mydata->saveValueAsDouble( val );
191 5581 : if( fixed ) {
192 1592 : mydata->share_data( 0, getPntrToValue()->getNumberOfValues(), getPntrToValue() );
193 : }
194 : } else {
195 183149 : mydata->setValuePointer(val,getPntrToComponent(0)->getShape(), !resetable);
196 : }
197 : } else {
198 1262508 : mydata->setValuePointer(val,std::vector<unsigned>(), !resetable);
199 : }
200 : return true;
201 : }
202 :
203 1671811 : bool ActionToPutData::setForcePointer( const std::string& name, const TypesafePtr & val ) {
204 1671811 : if( name!=getLabel() ) {
205 : return false;
206 : }
207 555645 : plumed_massert( dataCanBeSet, "force on " + getLabel() + " cannot be set at this time");
208 555645 : if( !from_domains ) {
209 133023 : mydata->setForcePointer(val,getPntrToComponent(0)->getShape());
210 : } else {
211 845244 : mydata->setForcePointer(val,std::vector<unsigned>());
212 : }
213 : return true;
214 : }
215 :
216 1350 : void ActionToPutData::getLocalValues( std::vector<double>& vals ) const {
217 1350 : mydata->share_data( vals );
218 1350 : }
219 :
220 186697 : void ActionToPutData::wait() {
221 186697 : dataCanBeSet=false;
222 186697 : if( fixed || !wasset ) {
223 : return;
224 : }
225 : plumed_assert( wasset );
226 185146 : mydata->share_data( 0, getPntrToValue()->getNumberOfValues(), getPntrToValue() );
227 : }
228 :
229 877402 : void ActionToPutData::apply() {
230 877402 : if( getPntrToValue()->forcesWereAdded() && !noforce && !forces_added_elsewhere ) {
231 451815 : if( getName()=="ENERGY" || getDependencies().size()==0 ) {
232 106968 : mydata->add_force( getPntrToValue() );
233 : }
234 : }
235 877402 : }
236 :
237 150 : unsigned ActionToPutData::getNumberOfForcesToRescale() const {
238 : // Values that are passed through the domain decomposition only store the atoms
239 : // that are local to this rank, so the number of forces held in the buffer of the
240 : // MD code is the number of local atoms and not the number of values
241 150 : if( !from_domains || getDependencies().size()!=1 ) {
242 0 : return copyOutput(0)->getNumberOfValues();
243 : }
244 150 : plumed_assert(getDependencies()[0]); // needed for following calls, see #1046
245 150 : ActionForInterface* ai = getDependencies()[0]->castToActionForInterface();
246 150 : if( !ai ) {
247 0 : return copyOutput(0)->getNumberOfValues();
248 : }
249 150 : return ai->getNumberOfForcesToRescale();
250 : }
251 :
252 200 : void ActionToPutData::rescaleForces( const double& alpha ) {
253 200 : if( noforce ) {
254 : return;
255 : }
256 150 : wasscaled=true;
257 150 : mydata->rescale_force( getNumberOfForcesToRescale(), alpha, getPntrToValue() );
258 :
259 : }
260 :
261 798 : void ActionToPutData::writeBinary(std::ostream&o) {
262 798 : if(!fixed) {
263 456 : getPntrToValue()->writeBinary(o);
264 : }
265 798 : }
266 :
267 798 : void ActionToPutData::readBinary(std::istream&i) {
268 798 : if(!fixed) {
269 456 : getPntrToValue()->readBinary(i);
270 : }
271 798 : }
272 :
273 : }
|