1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 Copyright (c) 2011-2021 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 "Value.h"
23 #include "ActionWithValue.h"
24 #include "ActionAtomistic.h"
25 #include "ActionWithArguments.h"
26 #include "ActionWithVirtualAtom.h"
27 #include "tools/Exception.h"
28 #include "Atoms.h"
29 #include "PlumedMain.h"
30
31 namespace PLMD {
32
Value()33 Value::Value():
34 action(NULL),
35 value_set(false),
36 value(0.0),
37 inputForce(0.0),
38 hasForce(false),
39 hasDeriv(true),
40 periodicity(unset),
41 min(0.0),
42 max(0.0),
43 max_minus_min(0.0),
44 inv_max_minus_min(0.0)
45 {
46 }
47
Value(ActionWithValue * av,const std::string & name,const bool withderiv)48 Value::Value(ActionWithValue* av, const std::string& name, const bool withderiv):
49 action(av),
50 value_set(false),
51 value(0.0),
52 inputForce(0.0),
53 hasForce(false),
54 name(name),
55 hasDeriv(withderiv),
56 periodicity(unset),
57 min(0.0),
58 max(0.0),
59 max_minus_min(0.0),
60 inv_max_minus_min(0.0)
61 {
62 }
63
setupPeriodicity()64 void Value::setupPeriodicity() {
65 if( min==0 && max==0 ) {
66 periodicity=notperiodic;
67 } else {
68 periodicity=periodic;
69 max_minus_min=max-min;
70 plumed_massert(max_minus_min>0, "your function has a very strange domain?");
71 inv_max_minus_min=1.0/max_minus_min;
72 }
73 }
74
isPeriodic() const75 bool Value::isPeriodic()const {
76 plumed_massert(periodicity!=unset,"periodicity should be set");
77 return periodicity==periodic;
78 }
79
applyForce(std::vector<double> & forces) const80 bool Value::applyForce(std::vector<double>& forces ) const {
81 if( !hasForce ) return false;
82 plumed_dbg_massert( derivatives.size()==forces.size()," forces array has wrong size" );
83 const unsigned N=derivatives.size();
84 for(unsigned i=0; i<N; ++i) forces[i]=inputForce*derivatives[i];
85 return true;
86 }
87
setNotPeriodic()88 void Value::setNotPeriodic() {
89 min=0; max=0; periodicity=notperiodic;
90 }
91
setDomain(const std::string & pmin,const std::string & pmax)92 void Value::setDomain(const std::string& pmin,const std::string& pmax) {
93 str_min=pmin;
94 if( !Tools::convert(str_min,min) ) action->error("could not convert period string " + str_min + " to real");
95 str_max=pmax;
96 if( !Tools::convert(str_max,max) ) action->error("could not convert period string " + str_max + " to read");
97 setupPeriodicity();
98 }
99
getDomain(std::string & minout,std::string & maxout) const100 void Value::getDomain(std::string&minout,std::string&maxout) const {
101 plumed_massert(periodicity==periodic,"function should be periodic");
102 minout=str_min;
103 maxout=str_max;
104 }
105
getDomain(double & minout,double & maxout) const106 void Value::getDomain(double&minout,double&maxout) const {
107 plumed_massert(periodicity==periodic,"function should be periodic");
108 minout=min;
109 maxout=max;
110 }
111
setGradients()112 void Value::setGradients() {
113 // Can't do gradients if we don't have derivatives
114 if( !hasDeriv ) return;
115 gradients.clear();
116 ActionAtomistic*aa=dynamic_cast<ActionAtomistic*>(action);
117 ActionWithArguments*aw=dynamic_cast<ActionWithArguments*>(action);
118 if(aa) {
119 Atoms&atoms((aa->plumed).getAtoms());
120 for(unsigned j=0; j<aa->getNumberOfAtoms(); ++j) {
121 AtomNumber an=aa->getAbsoluteIndex(j);
122 if(atoms.isVirtualAtom(an)) {
123 const ActionWithVirtualAtom* a=atoms.getVirtualAtomsAction(an);
124 for(const auto & p : a->getGradients()) {
125 // controllare l'ordine del matmul:
126 gradients[p.first]+=matmul(Vector(derivatives[3*j],derivatives[3*j+1],derivatives[3*j+2]),p.second);
127 }
128 } else {
129 for(unsigned i=0; i<3; i++) gradients[an][i]+=derivatives[3*j+i];
130 }
131 }
132 } else if(aw) {
133 std::vector<Value*> values=aw->getArguments();
134 for(unsigned j=0; j<derivatives.size(); j++) {
135 for(const auto & p : values[j]->gradients) {
136 AtomNumber iatom=p.first;
137 gradients[iatom]+=p.second*derivatives[j];
138 }
139 }
140 } else plumed_error();
141 }
142
projection(const Value & v1,const Value & v2)143 double Value::projection(const Value& v1,const Value&v2) {
144 double proj=0.0;
145 const std::map<AtomNumber,Vector> & grad1(v1.gradients);
146 const std::map<AtomNumber,Vector> & grad2(v2.gradients);
147 for(const auto & p1 : grad1) {
148 AtomNumber a=p1.first;
149 const auto p2=grad2.find(a);
150 if(p2!=grad2.end()) {
151 proj+=dotProduct(p1.second,(*p2).second);
152 }
153 }
154 return proj;
155 }
156
getPntrToAction()157 ActionWithValue* Value::getPntrToAction() {
158 plumed_assert( action!=NULL );
159 return action;
160 }
161
copy(const Value & val1,Value & val2)162 void copy( const Value& val1, Value& val2 ) {
163 unsigned nder=val1.getNumberOfDerivatives();
164 if( nder!=val2.getNumberOfDerivatives() ) { val2.resizeDerivatives( nder ); }
165 val2.clearDerivatives();
166 for(unsigned i=0; i<val1.getNumberOfDerivatives(); ++i) val2.addDerivative( i, val1.getDerivative(i) );
167 val2.set( val1.get() );
168 }
169
copy(const Value & val1,Value * val2)170 void copy( const Value& val1, Value* val2 ) {
171 unsigned nder=val1.getNumberOfDerivatives();
172 if( nder!=val2->getNumberOfDerivatives() ) { val2->resizeDerivatives( nder ); }
173 val2->clearDerivatives();
174 for(unsigned i=0; i<val1.getNumberOfDerivatives(); ++i) val2->addDerivative( i, val1.getDerivative(i) );
175 val2->set( val1.get() );
176 }
177
add(const Value & val1,Value * val2)178 void add( const Value& val1, Value* val2 ) {
179 plumed_assert( val1.getNumberOfDerivatives()==val2->getNumberOfDerivatives() );
180 for(unsigned i=0; i<val1.getNumberOfDerivatives(); ++i) val2->addDerivative( i, val1.getDerivative(i) );
181 val2->set( val1.get() + val2->get() );
182 }
183
184 }
185