Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2016-2021 The VES code team
3 : (see the PEOPLE-VES file at the root of this folder for a list of names)
4 :
5 : See http://www.ves-code.org for more information.
6 :
7 : This file is part of VES code module.
8 :
9 : The VES code module 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 : The VES code module 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 the VES code module. If not, see <http://www.gnu.org/licenses/>.
21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 :
23 : #include "TargetDistribution.h"
24 :
25 : #include "core/ActionRegister.h"
26 :
27 :
28 : namespace PLMD {
29 : namespace ves {
30 :
31 : //+PLUMEDOC VES_TARGETDIST TD_GENERALIZED_NORMAL
32 : /*
33 : Target distribution given by a sum of generalized normal distributions (static).
34 :
35 : Employ a target distribution that is given by a sum where each
36 : term is a product of one-dimensional
37 : [generalized normal distributions](https://en.wikipedia.org/wiki/Generalized_normal_distribution)
38 : (version 1, also know as an exponential power distribution), defined as
39 :
40 : $$
41 : p(\mathbf{s}) = \sum_{i} \, w_{i}
42 : \prod_{k}^{d}
43 : \frac{\beta_{k,i}}{2 \, \alpha_{k,i} \, \Gamma(1/\beta_{k,i})}
44 : \exp\left( -\left\vert \frac{s_{k}-\mu_{k,i}}{\alpha_{k,i}} \right\vert^{\beta_{k,i}} \right)
45 : $$
46 :
47 : where $(\mu_{1,i},\mu_{2,i},\ldots,\mu_{d,i})$
48 : are the centers of the distributions,
49 : $(\alpha_{1,i},\alpha_{2,i},\ldots,\alpha_{d,i})$ are the scale
50 : parameters of the distributions,
51 : $(\beta_{1,i},\beta_{2,i},\ldots,\beta_{d,i})$ are the shape
52 : parameters of the distributions, and $\Gamma(x)$ is the
53 : gamma function.
54 : The weights $w_{i}$ are normalized to 1, $\sum_{i}w_{i}=1$.
55 :
56 : Employing $\beta=2$ results in a
57 : Gaussian (normal) distributions with mean
58 : $\mu$ and variance $\alpha^2/2$,
59 : $\beta=1$ gives the Laplace distribution, and
60 : the limit $\beta \to \infty$ results in a
61 : uniform distribution on the interval $[\mu-\alpha,\mu+\alpha]$.
62 :
63 : The centers $(\mu_{1,i},\mu_{2,i},\ldots,\mu_{d,i})$
64 : are given using the numbered CENTER keywords, the scale
65 : parameters $(\alpha_{1,i},\alpha_{2,i},\ldots,\alpha_{d,i})$
66 : using the numbered SCALE keywords, and the shape parameters
67 : $(\beta_{1,i},\beta_{2,i},\ldots,\beta_{d,i})$ using the
68 : numbered SHAPE keywords.
69 : The weights are given using the WEIGHTS keywords, if no weights are
70 : given are all terms weighted equally.
71 :
72 : ## Examples
73 :
74 : A generalized normal distribution in one-dimensional
75 :
76 : ```plumed
77 : td1: TD_GENERALIZED_NORMAL CENTER1=+20.0 ALPHA1=5.0 BETA1=4.0
78 : ```
79 :
80 : A sum of two one-dimensional generalized normal distributions
81 :
82 : ```plumed
83 : TD_GENERALIZED_NORMAL ...
84 : CENTER1=+20.0 ALPHA1=5.0 BETA1=4.0
85 : CENTER2=-20.0 ALPHA2=5.0 BETA2=3.0
86 : LABEL=td1
87 : ... TD_GENERALIZED_NORMAL
88 : ```
89 :
90 : A sum of two two-dimensional generalized normal distributions
91 :
92 : ```plumed
93 : TD_GENERALIZED_NORMAL ...
94 : CENTER1=-20.0,-20.0 ALPHA1=5.0,3.0 BETA1=2.0,4.0
95 : CENTER2=-20.0,+20.0 ALPHA2=3.0,5.0 BETA2=4.0,2.0
96 : WEIGHTS=2.0,1.0
97 : LABEL=td1
98 : ... TD_GENERALIZED_NORMAL
99 : ```
100 :
101 : */
102 : //+ENDPLUMEDOC
103 :
104 : class TD_GeneralizedNormal: public TargetDistribution {
105 : std::vector< std::vector<double> > centers_;
106 : std::vector< std::vector<double> > alphas_;
107 : std::vector< std::vector<double> > betas_;
108 : std::vector< std::vector<double> > normalization_;
109 : std::vector<double> weights_;
110 : unsigned int ncenters_;
111 : double ExponentialPowerDiagonal(const std::vector<double>&, const std::vector<double>&, const std::vector<double>&, const std::vector<double>&, const std::vector<double>&) const;
112 : public:
113 : static void registerKeywords(Keywords&);
114 : explicit TD_GeneralizedNormal(const ActionOptions& ao);
115 : double getValue(const std::vector<double>&) const override;
116 : };
117 :
118 :
119 : PLUMED_REGISTER_ACTION(TD_GeneralizedNormal,"TD_GENERALIZED_NORMAL")
120 :
121 :
122 10 : void TD_GeneralizedNormal::registerKeywords(Keywords& keys) {
123 10 : TargetDistribution::registerKeywords(keys);
124 10 : keys.add("numbered","CENTER","The center of each generalized normal distribution.");
125 10 : keys.add("numbered","ALPHA","The alpha parameters for each generalized normal distribution.");
126 10 : keys.add("numbered","BETA","The beta parameters for each generalized normal distribution.");
127 10 : keys.add("optional","WEIGHTS","The weights of the generalized normal distribution. By default all are weighted equally.");
128 10 : keys.use("WELLTEMPERED_FACTOR");
129 10 : keys.use("SHIFT_TO_ZERO");
130 10 : keys.use("NORMALIZE");
131 10 : }
132 :
133 :
134 8 : TD_GeneralizedNormal::TD_GeneralizedNormal(const ActionOptions& ao):
135 : PLUMED_VES_TARGETDISTRIBUTION_INIT(ao),
136 16 : centers_(0),
137 8 : alphas_(0),
138 8 : betas_(0),
139 8 : normalization_(0),
140 8 : weights_(0),
141 16 : ncenters_(0) {
142 15 : for(unsigned int i=1;; i++) {
143 : std::vector<double> tmp_center;
144 46 : if(!parseNumberedVector("CENTER",i,tmp_center) ) {
145 : break;
146 : }
147 15 : centers_.push_back(tmp_center);
148 15 : }
149 15 : for(unsigned int i=1;; i++) {
150 : std::vector<double> tmp_alpha;
151 46 : if(!parseNumberedVector("ALPHA",i,tmp_alpha) ) {
152 : break;
153 : }
154 35 : for(unsigned int k=0; k<tmp_alpha.size(); k++) {
155 20 : if(tmp_alpha[k]<=0.0) {
156 0 : plumed_merror(getName()+": the values given in ALPHA should be positive");
157 : }
158 : }
159 15 : alphas_.push_back(tmp_alpha);
160 15 : }
161 15 : for(unsigned int i=1;; i++) {
162 : std::vector<double> tmp_beta;
163 46 : if(!parseNumberedVector("BETA",i,tmp_beta) ) {
164 : break;
165 : }
166 35 : for(unsigned int k=0; k<tmp_beta.size(); k++) {
167 20 : if(tmp_beta[k]<=0.0) {
168 0 : plumed_merror(getName()+": the values given in BETA should be positive");
169 : }
170 : }
171 15 : betas_.push_back(tmp_beta);
172 15 : }
173 : //
174 8 : if(centers_.size()==0) {
175 0 : plumed_merror(getName()+": CENTER keywords seem to be missing. Note that numbered keywords start at CENTER1.");
176 : }
177 : //
178 8 : if(centers_.size()!=alphas_.size() || centers_.size()!=betas_.size() ) {
179 0 : plumed_merror(getName()+": there has to be an equal amount of CENTER, ALPHA, and BETA keywords");
180 : }
181 : //
182 8 : setDimension(centers_[0].size());
183 8 : ncenters_ = centers_.size();
184 : //
185 : // check centers and sigmas
186 23 : for(unsigned int i=0; i<ncenters_; i++) {
187 15 : if(centers_[i].size()!=getDimension()) {
188 0 : plumed_merror(getName()+": one of the CENTER keyword does not match the given dimension");
189 : }
190 15 : if(alphas_[i].size()!=getDimension()) {
191 0 : plumed_merror(getName()+": one of the ALPHA keyword does not match the given dimension");
192 : }
193 15 : if(betas_[i].size()!=getDimension()) {
194 0 : plumed_merror(getName()+": one of the BETA keyword does not match the given dimension");
195 : }
196 : }
197 : //
198 16 : parseVector("WEIGHTS",weights_);
199 8 : if(weights_.size()==0) {
200 4 : weights_.assign(centers_.size(),1.0);
201 : }
202 8 : if(centers_.size()!=weights_.size()) {
203 0 : plumed_merror(getName()+": there has to be as many weights given in WEIGHTS as numbered CENTER keywords");
204 : }
205 : //
206 : double sum_weights=0.0;
207 23 : for(unsigned int i=0; i<weights_.size(); i++) {
208 15 : sum_weights+=weights_[i];
209 : }
210 23 : for(unsigned int i=0; i<weights_.size(); i++) {
211 15 : weights_[i]/=sum_weights;
212 : }
213 : //
214 8 : normalization_.resize(ncenters_);
215 23 : for(unsigned int i=0; i<ncenters_; i++) {
216 15 : normalization_[i].resize(getDimension());
217 35 : for(unsigned int k=0; k<getDimension(); k++) {
218 20 : normalization_[i][k] = 0.5*betas_[i][k]/(alphas_[i][k]*tgamma(1.0/betas_[i][k]));
219 : }
220 : }
221 8 : checkRead();
222 8 : }
223 :
224 :
225 21608 : double TD_GeneralizedNormal::getValue(const std::vector<double>& argument) const {
226 : double value=0.0;
227 74623 : for(unsigned int i=0; i<ncenters_; i++) {
228 53015 : value+=weights_[i]*ExponentialPowerDiagonal(argument,centers_[i],alphas_[i],betas_[i],normalization_[i]);
229 : }
230 21608 : return value;
231 : }
232 :
233 :
234 53015 : double TD_GeneralizedNormal::ExponentialPowerDiagonal(const std::vector<double>& argument, const std::vector<double>& center, const std::vector<double>& alpha, const std::vector<double>& beta, const std::vector<double>& normalization) const {
235 : double value = 1.0;
236 157035 : for(unsigned int k=0; k<argument.size(); k++) {
237 104020 : double arg=(std::abs(argument[k]-center[k]))/alpha[k];
238 104020 : arg = pow(arg,beta[k]);
239 104020 : value*=normalization[k]*exp(-arg);
240 : }
241 53015 : return value;
242 : }
243 :
244 :
245 :
246 : }
247 : }
|