Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2012-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 "KernelFunctions.h"
23 : #include "IFile.h"
24 : #include <iostream>
25 : #include <cmath>
26 :
27 : namespace PLMD {
28 :
29 : //+PLUMEDOC INTERNAL kernelfunctions
30 : /*
31 : Functions that are used to construct histograms
32 :
33 : Constructing histograms is something you learned to do relatively early in life. You perform an experiment a number of times,
34 : count the number of times each result comes up and then draw a bar graph that describes how often each of the results came up.
35 : This only works when there are a finite number of possible results. If the result a number between 0 and 1 the bar chart is
36 : less easy to draw as there are as many possible results as there are numbers between zero and one - an infinite number.
37 : To resolve this problem we replace probability, \f$P\f$ with probability density, \f$\pi\f$, and write the probability of getting
38 : a number between \f$a\f$ and \f$b\f$ as:
39 :
40 : \f[
41 : P = \int_{a}^b \textrm{d}x \pi(x)
42 : \f]
43 :
44 : To calculate probability densities from a set of results we use a process called kernel density estimation.
45 : Histograms are accumulated by adding up kernel functions, \f$K\f$, with finite spatial extent, that integrate to one.
46 : These functions are centered on each of the \f$n\f$-dimensional data points, \f$\mathbf{x}_i\f$. The overall effect of this
47 : is that each result we obtain in our experiments contributes to the probability density in a finite sized region of the space.
48 :
49 : Expressing all this mathematically in kernel density estimation we write the probability density as:
50 :
51 : \f[
52 : \pi(\mathbf{x}) = \sum_i K\left[ (\mathbf{x} - \mathbf{x}_i)^T \Sigma (\mathbf{x} - \mathbf{x}_i) \right]
53 : \f]
54 :
55 : where \f$\Sigma\f$ is an \f$n \times n\f$ matrix called the bandwidth that controls the spatial extent of
56 : the kernel. Whenever we accumulate a histogram (e.g. in \ref HISTOGRAM or in \ref METAD) we use this
57 : technique.
58 :
59 : There is thus some flexibility in the particular function we use for \f$K[\mathbf{r}]\f$ in the above.
60 : The following variants are available.
61 :
62 : <table align=center frame=void width=95%% cellpadding=5%%>
63 : <tr>
64 : <td> TYPE </td> <td> FUNCTION </td>
65 : </tr> <tr>
66 : <td> gaussian </td> <td> \f$f(r) = \frac{1}{(2 \pi)^{n} \sqrt{|\Sigma^{-1}|}} \exp\left(-0.5 r^2 \right)\f$ </td>
67 : </tr> <tr>
68 : <td> truncated-gaussian </td> <td> \f$f(r) = \frac{1}{(2 \pi)^{n} \sqrt{|\Sigma^{-1}|} \left(\frac{\mathrm{erf}(-6.25/sqrt{2}) - \mathrm{erf}(-6.25/sqrt{2})}{2}\right)^n} \exp\left(-0.5 r^2 \right)\f$ </td>
69 : </tr> <tr>
70 : <td> triangular </td> <td> \f$f(r) = \frac{3}{V} ( 1 - | r | )H(1-|r|) \f$ </td>
71 : </tr> <tr>
72 : <td> uniform </td> <td> \f$f(r) = \frac{1}{V}H(1-|r|)\f$ </td>
73 : </tr>
74 : </table>
75 :
76 : In the above \f$H(y)\f$ is a function that is equal to one when \f$y>0\f$ and zero when \f$y \le 0\f$. \f$n\f$ is
77 : the dimensionality of the vector \f$\mathbf{x}\f$ and \f$V\f$ is the volume of an ellipse in an \f$n\f$ dimensional
78 : space which is given by:
79 :
80 : \f{eqnarray*}{
81 : V &=& | \Sigma^{-1} | \frac{ \pi^{\frac{n}{2}} }{\left( \frac{n}{2} \right)! } \qquad \textrm{for even} \quad n \\
82 : V &=& | \Sigma^{-1} | \frac{ 2^{\frac{n+1}{2}} \pi^{\frac{n-1}{2}} }{ n!! }
83 : \f}
84 :
85 : In \ref METAD the normalization constants are ignored so that the value of the function at \f$r=0\f$ is equal
86 : to one. In addition in \ref METAD we must be able to differentiate the bias in order to get forces. This limits
87 : the kernels we can use in this method. Notice also that Gaussian kernels should have infinite support. When used
88 : with grids, however, they are assumed to only be non-zero over a finite range. The difference between the
89 : truncated-gaussian and regular gaussian is that the truncated gaussian is scaled so that its integral over the grid
90 : is equal to one when it is normalized. The integral of a regular gaussian when it is evaluated on a grid will be
91 : slightly less that one because of the truncation of a function that should have infinite support.
92 : */
93 : //+ENDPLUMEDOC
94 :
95 12 : KernelFunctions::KernelFunctions( const std::string& input ) {
96 :
97 12 : if(!dp2cutoffNoStretch()) {
98 12 : stretchA=dp2cutoffA;
99 12 : stretchB=dp2cutoffB;
100 : }
101 :
102 12 : std::vector<std::string> data=Tools::getWords(input);
103 12 : std::string name=data[0];
104 : data.erase(data.begin());
105 :
106 : std::vector<double> at;
107 12 : bool foundc = Tools::parseVector(data,"CENTER",at);
108 12 : if(!foundc) {
109 0 : plumed_merror("failed to find center keyword in definition of kernel");
110 : }
111 : std::vector<double> sig;
112 12 : bool founds = Tools::parseVector(data,"SIGMA",sig);
113 12 : if(!founds) {
114 0 : plumed_merror("failed to find sigma keyword in definition of kernel");
115 : }
116 :
117 12 : bool multi=false;
118 12 : Tools::parseFlag(data,"MULTIVARIATE",multi);
119 12 : bool vonmises=false;
120 24 : Tools::parseFlag(data,"VON-MISSES",vonmises);
121 12 : if( center.size()==1 && multi ) {
122 0 : plumed_merror("one dimensional kernel cannot be multivariate");
123 : }
124 12 : if( center.size()==1 && vonmises ) {
125 0 : plumed_merror("one dimensional kernal cannot be von-misses");
126 : }
127 12 : if( center.size()==1 && sig.size()!=1 ) {
128 0 : plumed_merror("size mismatch between center size and sigma size");
129 : }
130 12 : if( multi && center.size()>1 && sig.size()!=0.5*center.size()*(center.size()-1) ) {
131 0 : plumed_merror("size mismatch between center size and sigma size");
132 : }
133 12 : if( !multi && center.size()>1 && sig.size()!=center.size() ) {
134 0 : plumed_merror("size mismatch between center size and sigma size");
135 : }
136 :
137 : double h;
138 12 : bool foundh = Tools::parse(data,"HEIGHT",h);
139 12 : if( !foundh) {
140 12 : h=1.0;
141 : }
142 :
143 12 : if( multi ) {
144 0 : setData( at, sig, name, "MULTIVARIATE", h );
145 12 : } else if( vonmises ) {
146 0 : setData( at, sig, name, "VON-MISSES", h );
147 : } else {
148 24 : setData( at, sig, name, "DIAGONAL", h );
149 : }
150 12 : }
151 :
152 30229 : KernelFunctions::KernelFunctions( const std::vector<double>& at, const std::vector<double>& sig, const std::string& type, const std::string& mtype, const double& w ) {
153 :
154 30229 : if(!dp2cutoffNoStretch()) {
155 30229 : stretchA=dp2cutoffA;
156 30229 : stretchB=dp2cutoffB;
157 : }
158 :
159 30229 : setData( at, sig, type, mtype, w );
160 30229 : }
161 :
162 0 : KernelFunctions::KernelFunctions( const KernelFunctions* in ):
163 0 : dtype(in->dtype),
164 0 : ktype(in->ktype),
165 0 : center(in->center),
166 0 : width(in->width),
167 0 : height(in->height) {
168 0 : if(!dp2cutoffNoStretch()) {
169 0 : stretchA=dp2cutoffA;
170 0 : stretchB=dp2cutoffB;
171 : }
172 0 : }
173 :
174 30241 : void KernelFunctions::setData( const std::vector<double>& at, const std::vector<double>& sig, const std::string& type, const std::string& mtype, const double& w ) {
175 :
176 30241 : height=w;
177 30241 : center.resize( at.size() );
178 114820 : for(unsigned i=0; i<at.size(); ++i) {
179 84579 : center[i]=at[i];
180 : }
181 30241 : width.resize( sig.size() );
182 119327 : for(unsigned i=0; i<sig.size(); ++i) {
183 89086 : width[i]=sig[i];
184 : }
185 30241 : if( mtype=="MULTIVARIATE" ) {
186 4412 : dtype=multi;
187 25829 : } else if( mtype=="VON-MISSES" ) {
188 9 : dtype=vonmises;
189 25820 : } else if( mtype=="DIAGONAL" ) {
190 25820 : dtype=diagonal;
191 : } else {
192 0 : plumed_merror(mtype + " is not a valid metric type");
193 : }
194 :
195 : // Setup the kernel type
196 60474 : if(type=="GAUSSIAN" || type=="gaussian" ) {
197 24674 : ktype=gaussian;
198 11134 : } else if(type=="STRETCHED-GAUSSIAN" || type=="stretched-gaussian" ) {
199 5563 : ktype=stretchedgaussian;
200 8 : } else if(type=="TRUNCATED-GAUSSIAN" || type=="truncated-gaussian" ) {
201 0 : ktype=truncatedgaussian;
202 8 : } else if(type=="UNIFORM" || type=="uniform") {
203 0 : ktype=uniform;
204 4 : } else if(type=="TRIANGULAR" || type=="triangular") {
205 4 : ktype=triangular;
206 : } else {
207 0 : plumed_merror(type+" is an invalid kernel type\n");
208 : }
209 30241 : }
210 :
211 24625 : void KernelFunctions::normalize( const std::vector<Value*>& myvals ) {
212 :
213 : double det=1.;
214 : unsigned ncv=ndim();
215 24625 : if(dtype==diagonal) {
216 97800 : for(unsigned i=0; i<width.size(); ++i) {
217 73228 : det*=width[i]*width[i];
218 : }
219 53 : } else if(dtype==multi) {
220 44 : Matrix<double> mymatrix( getMatrix() ), myinv( ncv, ncv );
221 44 : Invert(mymatrix,myinv);
222 : double logd;
223 44 : logdet( myinv, logd );
224 44 : det=std::exp(logd);
225 : }
226 24625 : if( dtype==diagonal || dtype==multi ) {
227 : double volume;
228 24616 : if( ktype==gaussian || ktype==stretchedgaussian ) {
229 24616 : volume=pow( 2*pi, 0.5*ncv ) * pow( det, 0.5 );
230 0 : } else if( ktype==truncatedgaussian ) {
231 : // This makes it so the gaussian integrates to one over the range over which it has support
232 : const double DP2CUTOFF=std::sqrt(6.25);
233 0 : volume=pow( 2*pi, 0.5*ncv ) * pow( det, 0.5 ) * pow( 0.5 * ( erf(DP2CUTOFF) - erf(-DP2CUTOFF) ), ncv);
234 0 : } else if( ktype==uniform || ktype==triangular ) {
235 0 : if( ncv%2==1 ) {
236 : double dfact=1;
237 0 : for(unsigned i=1; i<ncv; i+=2) {
238 0 : dfact*=static_cast<double>(i);
239 : }
240 0 : volume=( pow( pi, (ncv-1)/2 ) ) * ( pow( 2., (ncv+1)/2 ) ) / dfact;
241 : } else {
242 : double fact=1.;
243 0 : for(unsigned i=1; i<ncv/2; ++i) {
244 0 : fact*=static_cast<double>(i);
245 : }
246 0 : volume=pow( pi,ncv/2 ) / fact;
247 : }
248 0 : if(ktype==uniform) {
249 0 : volume*=det;
250 0 : } else if(ktype==triangular) {
251 0 : volume*=det / 3.;
252 : }
253 : } else {
254 0 : plumed_merror("not a valid kernel type");
255 : }
256 24616 : height /= volume;
257 24616 : return;
258 : }
259 9 : plumed_assert( dtype==vonmises && ktype==gaussian );
260 : // Now calculate determinant for aperiodic variables
261 : unsigned naper=0;
262 25 : for(unsigned i=0; i<ncv; ++i) {
263 16 : if( !myvals[i]->isPeriodic() ) {
264 2 : naper++;
265 : }
266 : }
267 : // Now construct sub matrix
268 : double volume=1;
269 9 : if( naper>0 ) {
270 : unsigned isub=0;
271 2 : Matrix<double> mymatrix( getMatrix() ), mysub( naper, naper );
272 4 : for(unsigned i=0; i<ncv; ++i) {
273 2 : if( myvals[i]->isPeriodic() ) {
274 : continue;
275 : }
276 : unsigned jsub=0;
277 4 : for(unsigned j=0; j<ncv; ++j) {
278 2 : if( myvals[j]->isPeriodic() ) {
279 0 : continue;
280 : }
281 2 : mysub( isub, jsub ) = mymatrix( i, j );
282 2 : jsub++;
283 : }
284 2 : isub++;
285 : }
286 : Matrix<double> myisub( naper, naper );
287 : double logd;
288 2 : Invert( mysub, myisub );
289 2 : logdet( myisub, logd );
290 2 : det=std::exp(logd);
291 2 : volume=pow( 2*pi, 0.5*ncv ) * pow( det, 0.5 );
292 : }
293 :
294 : // Calculate volume of periodic variables
295 : unsigned nper=0;
296 25 : for(unsigned i=0; i<ncv; ++i) {
297 16 : if( myvals[i]->isPeriodic() ) {
298 14 : nper++;
299 : }
300 : }
301 :
302 : // Now construct sub matrix
303 9 : if( nper>0 ) {
304 : unsigned isub=0;
305 7 : Matrix<double> mymatrix( getMatrix() ), mysub( nper, nper );
306 21 : for(unsigned i=0; i<ncv; ++i) {
307 14 : if( !myvals[i]->isPeriodic() ) {
308 : continue;
309 : }
310 : unsigned jsub=0;
311 42 : for(unsigned j=0; j<ncv; ++j) {
312 28 : if( !myvals[j]->isPeriodic() ) {
313 0 : continue;
314 : }
315 28 : mysub( isub, jsub ) = mymatrix( i, j );
316 28 : jsub++;
317 : }
318 14 : isub++;
319 : }
320 : Matrix<double> eigvec( nper, nper );
321 7 : std::vector<double> eigval( nper );
322 7 : diagMat( mysub, eigval, eigvec );
323 : unsigned iper=0;
324 : volume=1;
325 21 : for(unsigned i=0; i<ncv; ++i) {
326 14 : if( myvals[i]->isPeriodic() ) {
327 14 : volume *= myvals[i]->getMaxMinusMin()*Tools::bessel0(eigval[iper])*std::exp(-eigval[iper]);
328 14 : iper++;
329 : }
330 : }
331 : }
332 9 : height /= volume;
333 : }
334 :
335 10294 : double KernelFunctions::getCutoff( const double& width ) const {
336 : const double DP2CUTOFF=6.25;
337 10294 : if( ktype==gaussian || ktype==truncatedgaussian || ktype==stretchedgaussian ) {
338 10294 : return std::sqrt(2.0*DP2CUTOFF)*width;
339 0 : } else if(ktype==triangular ) {
340 0 : return width;
341 0 : } else if(ktype==uniform) {
342 0 : return width;
343 : } else {
344 0 : plumed_merror("No valid kernel type");
345 : }
346 : return 0.0;
347 : }
348 :
349 5141 : std::vector<double> KernelFunctions::getContinuousSupport( ) const {
350 : unsigned ncv=ndim();
351 5141 : std::vector<double> support( ncv );
352 5141 : if(dtype==diagonal) {
353 2152 : for(unsigned i=0; i<ncv; ++i) {
354 1423 : support[i]=getCutoff(width[i]);
355 : }
356 4412 : } else if(dtype==multi) {
357 4412 : Matrix<double> mymatrix( getMatrix() ), myinv( ncv,ncv );
358 4412 : Invert(mymatrix,myinv);
359 : Matrix<double> myautovec(ncv,ncv);
360 4412 : std::vector<double> myautoval(ncv);
361 4412 : diagMat(myinv,myautoval,myautovec);
362 : double maxautoval=0.;
363 : unsigned ind_maxautoval=0;
364 13280 : for (unsigned i=0; i<ncv; i++) {
365 8868 : if(myautoval[i]>maxautoval) {
366 : maxautoval=myautoval[i];
367 : ind_maxautoval=i;
368 : }
369 : }
370 13280 : for(unsigned i=0; i<ncv; ++i) {
371 8868 : double extent=std::fabs(std::sqrt(maxautoval)*myautovec(i,ind_maxautoval));
372 8868 : support[i]=getCutoff( extent );
373 : }
374 : } else {
375 0 : plumed_merror("cannot find support if metric is not multi or diagonal type");
376 : }
377 5141 : return support;
378 : }
379 :
380 3415 : std::vector<unsigned> KernelFunctions::getSupport( const std::vector<double>& dx ) const {
381 3415 : plumed_assert( ndim()==dx.size() );
382 3415 : std::vector<unsigned> support( dx.size() );
383 3415 : std::vector<double> vv=getContinuousSupport( );
384 10227 : for(unsigned i=0; i<dx.size(); ++i) {
385 6812 : support[i]=static_cast<unsigned>(ceil( vv[i]/dx[i] ));
386 : }
387 3415 : return support;
388 : }
389 :
390 23606894 : double KernelFunctions::evaluate( const std::vector<Value*>& pos, std::vector<double>& derivatives, bool usederiv, bool doInt, double lowI_, double uppI_) const {
391 : plumed_dbg_assert( pos.size()==ndim() && derivatives.size()==ndim() );
392 : #ifndef NDEBUG
393 : if( usederiv ) {
394 : plumed_massert( ktype!=uniform, "step function can not be differentiated" );
395 : }
396 : #endif
397 23606894 : if(doInt) {
398 : plumed_dbg_assert(center.size()==1);
399 0 : if(pos[0]->get()<lowI_) {
400 : pos[0]->set(lowI_);
401 : }
402 0 : if(pos[0]->get()>uppI_) {
403 : pos[0]->set(uppI_);
404 : }
405 : }
406 : double r2=0;
407 23606894 : if(dtype==diagonal) {
408 51709439 : for(unsigned i=0; i<ndim(); ++i) {
409 37730371 : derivatives[i]=-pos[i]->difference( center[i] ) / width[i];
410 37730371 : r2+=derivatives[i]*derivatives[i];
411 37730371 : derivatives[i] /= width[i];
412 : }
413 9627826 : } else if(dtype==multi) {
414 9627680 : Matrix<double> mymatrix( getMatrix() );
415 37540216 : for(unsigned i=0; i<mymatrix.nrows(); ++i) {
416 : double dp_i, dp_j;
417 27912536 : derivatives[i]=0;
418 27912536 : dp_i=-pos[i]->difference( center[i] );
419 109709136 : for(unsigned j=0; j<mymatrix.ncols(); ++j) {
420 81796600 : if(i==j) {
421 : dp_j=dp_i;
422 : } else {
423 53884064 : dp_j=-pos[j]->difference( center[j] );
424 : }
425 :
426 81796600 : derivatives[i]+=mymatrix(i,j)*dp_j;
427 81796600 : r2+=dp_i*dp_j*mymatrix(i,j);
428 : }
429 : }
430 146 : } else if(dtype==vonmises) {
431 146 : std::vector<double> costmp( ndim() ), sintmp( ndim() ), sinout( ndim(), 0.0 );
432 418 : for(unsigned i=0; i<ndim(); ++i) {
433 272 : if( pos[i]->isPeriodic() ) {
434 252 : sintmp[i]=std::sin( 2.*pi*(pos[i]->get() - center[i])/pos[i]->getMaxMinusMin() );
435 252 : costmp[i]=std::cos( 2.*pi*(pos[i]->get() - center[i])/pos[i]->getMaxMinusMin() );
436 : } else {
437 20 : sintmp[i]=pos[i]->get() - center[i];
438 20 : costmp[i]=1.0;
439 : }
440 : }
441 :
442 146 : Matrix<double> mymatrix( getMatrix() );
443 418 : for(unsigned i=0; i<mymatrix.nrows(); ++i) {
444 272 : derivatives[i]=0;
445 272 : if( pos[i]->isPeriodic() ) {
446 252 : r2+=2*( 1 - costmp[i] )*mymatrix(i,i);
447 : } else {
448 20 : r2+=sintmp[i]*sintmp[i]*mymatrix(i,i);
449 : }
450 796 : for(unsigned j=0; j<mymatrix.ncols(); ++j) {
451 524 : if( i!=j ) {
452 252 : sinout[i]+=mymatrix(i,j)*sintmp[j];
453 : }
454 : }
455 272 : derivatives[i] = mymatrix(i,i)*sintmp[i] + sinout[i]*costmp[i];
456 272 : if( pos[i]->isPeriodic() ) {
457 252 : derivatives[i] *= (2*pi/pos[i]->getMaxMinusMin());
458 : }
459 : }
460 418 : for(unsigned i=0; i<sinout.size(); ++i) {
461 272 : r2+=sintmp[i]*sinout[i];
462 : }
463 : }
464 : double kderiv, kval;
465 23606894 : if(ktype==gaussian || ktype==truncatedgaussian) {
466 22547753 : kval=height*std::exp(-0.5*r2);
467 22547753 : kderiv=-kval;
468 1059141 : } else if(ktype==stretchedgaussian) {
469 1024305 : auto dp=0.5*r2;
470 1024305 : if(dp<dp2cutoff) {
471 630478 : auto ee=std::exp(-0.5*r2);
472 630478 : kval=height*(stretchA*ee+stretchB);
473 630478 : kderiv=-height*stretchA*ee;
474 : } else {
475 : kval=0.0;
476 : kderiv=0.0;
477 : }
478 : } else {
479 34836 : double r=std::sqrt(r2);
480 34836 : if(ktype==triangular) {
481 34836 : if( r<1.0 ) {
482 : if(r==0) {
483 : kderiv=0;
484 : }
485 : kderiv=-1;
486 9753 : kval=height*( 1. - std::fabs(r) );
487 : } else {
488 : kval=0.;
489 : kderiv=0.;
490 : }
491 0 : } else if(ktype==uniform) {
492 : kderiv=0.;
493 0 : if(r<1.0) {
494 0 : kval=height;
495 : } else {
496 : kval=0;
497 : }
498 : } else {
499 0 : plumed_merror("Not a valid kernel type");
500 : }
501 34836 : kderiv*=height / r ;
502 : }
503 89250073 : for(unsigned i=0; i<ndim(); ++i) {
504 65643179 : derivatives[i]*=kderiv;
505 : }
506 23606894 : if(doInt) {
507 0 : if((pos[0]->get() <= lowI_ || pos[0]->get() >= uppI_) && usederiv )
508 0 : for(unsigned i=0; i<ndim(); ++i) {
509 0 : derivatives[i]=0;
510 : }
511 : }
512 23606894 : return kval;
513 : }
514 :
515 4530 : std::unique_ptr<KernelFunctions> KernelFunctions::read( IFile* ifile, const bool& cholesky, const std::vector<std::string>& valnames ) {
516 : double h;
517 9060 : if( !ifile->scanField("height",h) ) {
518 : return NULL;
519 : };
520 :
521 : std::string sss;
522 4524 : ifile->scanField("multivariate",sss);
523 4524 : std::string ktype="stretched-gaussian";
524 9048 : if( ifile->FieldExist("kerneltype") ) {
525 6864 : ifile->scanField("kerneltype",ktype);
526 : }
527 8954 : plumed_massert( sss=="false" || sss=="true" || sss=="von-misses", "multivariate flag must be either false, true or von-misses");
528 :
529 : // Read the position of the center
530 4524 : std::vector<double> cc( valnames.size() );
531 13613 : for(unsigned i=0; i<valnames.size(); ++i) {
532 9089 : ifile->scanField(valnames[i],cc[i]);
533 : }
534 :
535 : std::vector<double> sig;
536 4524 : if( sss=="false" ) {
537 103 : sig.resize( valnames.size() );
538 308 : for(unsigned i=0; i<valnames.size(); ++i) {
539 205 : ifile->scanField("sigma_"+valnames[i],sig[i]);
540 205 : if( !cholesky ) {
541 0 : sig[i]=std::sqrt(sig[i]);
542 : }
543 : }
544 103 : return Tools::make_unique<KernelFunctions>(cc, sig, ktype, "DIAGONAL", h);
545 : }
546 :
547 4421 : unsigned ncv=valnames.size();
548 4421 : sig.resize( (ncv*(ncv+1))/2 );
549 : Matrix<double> upper(ncv,ncv), lower(ncv,ncv), mymult( ncv, ncv ), invmatrix(ncv,ncv);
550 13305 : for(unsigned i=0; i<ncv; ++i) {
551 22275 : for(unsigned j=0; j<ncv-i; j++) {
552 26782 : ifile->scanField("sigma_" +valnames[j+i] + "_" + valnames[j], lower(j+i,j) );
553 13391 : upper(j,j+i)=lower(j+i,j);
554 13391 : mymult(j+i,j)=mymult(j,j+i)=lower(j+i,j);
555 : }
556 : }
557 4421 : if( cholesky ) {
558 4368 : mult(lower,upper,mymult);
559 : }
560 4421 : Invert( mymult, invmatrix );
561 : unsigned k=0;
562 13305 : for(unsigned i=0; i<ncv; i++) {
563 22275 : for(unsigned j=i; j<ncv; j++) {
564 13391 : sig[k]=invmatrix(i,j);
565 13391 : k++;
566 : }
567 : }
568 4421 : if( sss=="true" ) {
569 4412 : return Tools::make_unique<KernelFunctions>(cc, sig, ktype, "MULTIVARIATE", h);
570 : }
571 9 : return Tools::make_unique<KernelFunctions>( cc, sig, ktype, "VON-MISSES", h );
572 : }
573 :
574 : }
|