Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2015-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 "KDE.h"
23 : #include "KDEGridTools.h"
24 : #include "SphericalKDEGridTools.h"
25 : #include "core/AccelerableShortcut.h"
26 : #include "core/ActionShortcut.h"
27 : #include "core/ActionRegister.h"
28 :
29 : //+PLUMEDOC ANALYSIS KDE
30 : /*
31 : Create a histogram from the input scalar/vector/matrix using KDE
32 :
33 : This action can be used to construct instantaneous distributions for quantities by using [kernel density esstimation](https://en.wikipedia.org/wiki/Kernel_density_estimation).
34 : The input arguments must all have the same rank and size but you can use a scalar, vector or matrix in input. The distribution
35 : of this quantity on a grid is then computed using kernel density estimation.
36 :
37 : The following example demonstrates how this action can be used with a scalar as input:
38 :
39 : ```plumed
40 : d1: DISTANCE ATOMS=1,2
41 : kde: KDE ARG=d1 GRID_MIN=0.0 GRID_MAX=1.0 GRID_BIN=100 BANDWIDTH=0.2
42 : DUMPGRID ARG=kde STRIDE=1 FILE=kde.grid
43 : ```
44 :
45 : This input outputs a different file on every time step. These files contain a function stored on a grid. The function output in this case
46 : consists of a single Gaussian with $\sigma=0.2$ that is centered on the instantaneous value of the distance between atoms 1 and 2. Obviously,
47 : you are unlikely to use an input like the one above. The more usual thing to do would be to accumulate the histogram over the course of a
48 : few trajectory frames using the [ACCUMULATE](ACCUMULATE.md) command as has been done in the input below, which estimates a histogram as a function
49 : of two collective variables:
50 :
51 : ```plumed
52 : d1: DISTANCE ATOMS=1,2
53 : d2: DISTANCE ATOMS=1,2
54 : kde: KDE ARG=d1,d2 GRID_MIN=0.0,0.0 GRID_MAX=1.0,1.0 GRID_BIN=100,100 BANDWIDTH=0.2,0.2
55 : histo: ACCUMULATE ARG=kde STRIDE=1
56 : DUMPGRID ARG=histo FILE=histo.grid STRIDE=10000
57 : ```
58 :
59 : Notice, that you can also achieve something similar by using the [HISTOGRAM](HISTOGRAM.md) shortcut.
60 :
61 : ## Controlloing the grid
62 :
63 : If you prefer to specify the grid spacing rather than the number of bins you can do so using the GRID_SPACING keyword as shown below:
64 :
65 : ```plumed
66 : d1: DISTANCE ATOMS=1,2
67 : kde: KDE ARG=d1 GRID_MIN=0.0 GRID_MAX=1.0 GRID_SPACING=0.01 BANDWIDTH=0.2
68 : DUMPGRID ARG=kde STRIDE=1 FILE=kde.grid
69 : ```
70 :
71 : If $x$ is one of the input arguments to the KDE action and $x<g_{min}$ or $x>g_{max}$, where $g_{min}$ and $g_{max}$ are the minimum
72 : and maximum values on the grid for that argument that were specified using GRID_MIN and GRID_MAX, then by PLUMED will crash.
73 :
74 : ## Constructing the density
75 :
76 : If you are performing a simulation in the NVT ensemble and wish to look at the density as a function of position in the cell you can use an input like the one shown below:
77 :
78 : ```plumed
79 : a: FIXEDATOM AT=0,0,0
80 : dens: DISTANCES ATOMS=1-100 ORIGIN=a COMPONENTS
81 : kde: KDE ARG=dens.x,dens.y,dens.z GRID_BIN=100,100,100 BANDWIDTH=0.05,0.05,0.05
82 : DUMPGRID ARG=kde STRIDE=1 FILE=density
83 : ```
84 :
85 : Notice that you do not need to specify GRID_MIN and GRID_MAX values with this input. In this case PLUMED gets the extent of the grid from the cell vectors during the first
86 : step of the simulation.
87 :
88 : ## Specifying a non diagonal bandwidth
89 :
90 : If for any reason you want to use a bandwidth that is not diagonal when doing kensity density estimation you can do by using an input similar to the one shown below:
91 :
92 : ```plumed
93 : d1: DISTANCE ATOMS=1,2
94 : d2: DISTANCE ATOMS=1,2
95 : kde: KDE ...
96 : ARG=d1,d2 GRID_MIN=0.0,0.0
97 : GRID_MAX=1.0,1.0 GRID_BIN=100,100
98 : BANDWIDTH=0.2,0.1,0.1,0.2 HEIGHTS=1
99 : ...
100 : histo: ACCUMULATE ARG=kde STRIDE=1
101 : DUMPGRID ARG=histo FILE=histo.grid STRIDE=10000
102 : ```
103 :
104 : As there are two arguments for this KDE action the four numbers passed in the bandwdith parameter are interepretted as a $2\times 2$ matrix.
105 : Notice that you can also pass the information for the bandwidth in from another argument as has been done here:
106 :
107 : ```plumed
108 : m: CONSTANT VALUES=0.2,0.1,0.1,0.2 NROWS=2 NCOLS=2
109 :
110 : d1: DISTANCE ATOMS=1,2
111 : d2: DISTANCE ATOMS=1,2
112 : kde: KDE ...
113 : ARG=d1,d2 GRID_MIN=0.0,0.0
114 : GRID_MAX=1.0,1.0 GRID_BIN=100,100
115 : BANDWIDTH=m HEIGHTS=1
116 : ...
117 : histo: ACCUMULATE ARG=kde STRIDE=1
118 : DUMPGRID ARG=histo FILE=histo.grid STRIDE=10000
119 : ```
120 :
121 : In this case the input is equivalent to the first input above and the bandwidth is a constant. You could, however, also use a non-constant value as input to the BANDWIDTH keyword.
122 :
123 : ## Working with vectors and scalars
124 :
125 : If the input to your KDE action is a set of scalars it appears odd to separate the process of computing the KDE from the process of accumulating the histogram. However, if
126 : you are using vectors as in the example below, this division can be helpful.
127 :
128 : ```plumed
129 : d1: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8 ATOMS5=9,10
130 : kde: KDE ARG=d1 GRID_MIN=0.0 GRID_MAX=1.0 GRID_BIN=100 BANDWIDTH=0.2
131 : ```
132 :
133 : In the papea cited in the bibliography below, the [KL_ENTROPY](KL_ENTROPY.md) between the instantaneous distribution of CVs and a reference distribution was introduced
134 : as a collective variable. As is detailed in the documentation for that action, the ability to calculate the instantaneous histogram from an input vector is essential to
135 : reproducing these calculations.
136 :
137 : Notice that you can also use a one or multiple matrices in the input for a KDE object. The example below uses the angles between the z axis and set of bonds aroud two
138 : atoms:
139 :
140 : ```plumed
141 : d1: DISTANCE_MATRIX GROUPA=1,2 GROUPB=3-10 COMPONENTS
142 : phi: CUSTOM ARG=d1.z,d1.w FUNC=acos(x/y) PERIODIC=NO
143 : kde: KDE ARG=phi GRID_MIN=0 GRID_MAX=pi GRID_BIN=200 BANDWIDTH=0.1
144 : ```
145 :
146 : ## Using different weights
147 :
148 : In all the inputs above the kernels that are added to the grid on each step are Gaussians with that are normalised so that their integral over all space is one. If you want your
149 : Gaussians to have a particular height you can use the HEIGHT keyword as illustrated below:
150 :
151 : ```plumed
152 : d1: CONTACT_MATRIX GROUPA=1,2 GROUPB=3-10 SWITCH={RATIONAL R_0=0.1} COMPONENTS
153 : mag: CUSTOM ARG=d1.x,d1.y,d1.z FUNC=x*x+y*y+z*z PERIODIC=NO
154 : phi: CUSTOM ARG=d1.z,mag FUNC=acos(x/sqrt(y)) PERIODIC=NO
155 : kde: KDE ARG=phi GRID_MIN=0 GRID_MAX=pi HEIGHTS=d1.w GRID_BIN=200 BANDWIDTH=0.1
156 : ```
157 :
158 : As indicated above, the HEIGHTS keyword should be passed a Value that has the same rank and size as the arguments that are passed using the ARG keyword. Each of the Gaussian kernels
159 : that are added to the grid in this case have a value equal to the weight at the maximum of the function.
160 :
161 : Notice that you can also use the VOLUMES keyword in a similar way as shown below:
162 :
163 : ```plumed
164 : d1: CONTACT_MATRIX GROUPA=1,2 GROUPB=3-10 SWITCH={RATIONAL R_0=0.1} COMPONENTS
165 : mag: CUSTOM ARG=d1.x,d1.y,d1.z FUNC=x*x+y*y+z*z PERIODIC=NO
166 : phi: CUSTOM ARG=d1.z,mag FUNC=acos(x/sqrt(y)) PERIODIC=NO
167 : kde: KDE ARG=phi GRID_MIN=0 GRID_MAX=pi VOLUMES=d1.w GRID_BIN=200 BANDWIDTH=0.1
168 : ```
169 :
170 : Now, however, the integral of the Gaussians over all space are equal to the elements of d1.w.
171 :
172 : ## Setting the kernel
173 :
174 : When you run molecular dynamics and calculate $d$ collective variables using PLUMED you generate a time series of $d$ dimensional vectors $\mathbf{x}_t$. The Kernel Density Estimation
175 : method that is implemented in this action allows you to calculate an estimate of the probabilty density for the $d$ collective variables, which is a function with $d$ arguments.
176 : This estimate is calculated using:
177 :
178 : $$
179 : f(\mathbf{x}) = \sum_{t=1}^n h_t K\left[ \sqrt{(\mathbf{x}-\mathbf{x}_t)^T \mathbf{H}^{-1} (\mathbf{x}-\mathbf{x}_t)} \right]
180 : $$
181 :
182 : This expression assumes that you are calculating the density from $n$ trajectory frames. $\mathbf{H}$ is bandwidths matrix and $h_t$ is the height that you want to use for the $t$th of your observations.
183 : $K$ is then a non-negative function called the kernel. This function acts upon the [Mahalanobis distance](https://en.wikipedia.org/wiki/Mahalanobis_distance) between $\mathbf{x}$ and $\mathbf{x}_t$.
184 :
185 : To provide users with flexibility, the functional form for the kernel is specified using a syntax similar to the one described in the documentation for the [LESS_THAN](LESS_THAN.md)
186 : action. The only difference from the instructions for swtiching functions in [LESS_THAN](LESS_THAN.md) is that PLUMED automatically
187 : sets the $r_0$ parameter of your switching function to one for you. __You should thus not include R_0 when you set the parameters of your kernel function.__
188 :
189 : By default PLUMED uses a Gaussian kernel function as illustrated in the input below:
190 :
191 : ```plumed
192 : d1: DISTANCE ATOMS=1,2
193 : kde: KDE ARG=d1 GRID_MIN=0.0 GRID_MAX=1.0 GRID_BIN=100 BANDWIDTH=0.2 KERNEL={GAUSSIAN D_MAX=3.5355}
194 : DUMPGRID ARG=kde STRIDE=1 FILE=kde.grid
195 : ```
196 :
197 : Notice that a stretching and scaling is performed on the gaussian kernel that is employed here so the function is guaranteed to be equal to zero if
198 : $\sqrt{(\mathbf{x}-\mathbf{x}_t)^T \mathbf{H}^{-1} (\mathbf{x}-\mathbf{x}_t)}>3.5355$. One consequence of this is that the integral of the $d$ dimensional
199 : Gaussian will be slightly less than $(2\pi)^{d/2}\det(H)^{1/2}$. This can be a problem if you are assuming that the integral of your Gaussians is equal to this value when
200 : normalising them. You can partially avoid this problem by using the NOSTRETCH option as shown below:
201 :
202 : ```plumed
203 : d1: DISTANCE ATOMS=1,2
204 : kde: KDE ARG=d1 GRID_MIN=0.0 GRID_MAX=1.0 GRID_BIN=100 BANDWIDTH=0.2 KERNEL={GAUSSIAN NOSTRETCH D_MAX=3.5355}
205 : DUMPGRID ARG=kde STRIDE=1 FILE=kde.grid
206 : ```
207 :
208 : This, however, introduces a discontinuity in the kernel at $d_{max}$.
209 :
210 : __We strongly recommend setting a D_MAX parameter for your kernels__.
211 : If you do not set a D_MAX value for your KERNEL then a cutoff of $d_{max}=\sqrt{2*6.25}\approx 3.5355$ is used. If you are calculating a 1D histogram and D_MAX is unset PLUMED
212 : then you evaluate a kernel at centered at $a$ on the gridpoint at $b$ if $\frac{|a-b|}{s}<=\left\lceil \frac{d_{max}\sigma}{s}\right\rceil$, where $s$ is the spacing between
213 : grid points and $\sigma$ is the bandwidth. The ceiling on the right hand side of this inequality obviously makes this s necessary but not sufficient condition for ensuring that
214 : $\sqrt{(\mathbf{x}-\mathbf{x}_t)^T \mathbf{H}^{-1} (\mathbf{x}-\mathbf{x}_t)}<d_{max}$. In higher dimensions this becomes even more severe. In 2D to
215 : determine if we need to evaluate a kernel centered at $(a,b)$ for the grid point $(c,d)$ we first determine if $\frac{|a-c|}{s}<=\left\lceil \frac{d_{max}\sigma}{s}\right\rceil$ and
216 : if $\frac{|b-d|}{s}<=\left\lceil \frac{d_{max}\sigma}{s}\right\rceil$. With these tests there are many more points that satisfy these two criteria but that do not satisfy
217 : $\sqrt{(\mathbf{x}-\mathbf{x}_t)^T \mathbf{H}^{-1} (\mathbf{x}-\mathbf{x}_t)}<d_{max}$. The key thing to recognise is that when D_MAX is set PLUMED sets the value of the kernel equal to zero if
218 : $\sqrt{(\mathbf{x}-\mathbf{x}_t)^T \mathbf{H}^{-1} (\mathbf{x}-\mathbf{x}_t)}>d_{max}$ even when the NOSTRETCH option is employed. If D_MAX is not set this check is not performed and
219 : kernels can thus contribute density to grid points that are more than $\sqrt(2*6.25)$ from the center of the kernel.
220 :
221 : Kernel density estimation is a method for estimating a histogram but it is probably not the first method that you learned for estimating histograms. Instead you probably learned to assume that the
222 : the density is constant between grid points. In 1D we thus express the density between grid point $x_k$ and $x_{k+1}$ using:
223 :
224 : $$
225 : F(x_{k+1}) - F(x_k) = \int_{x_k}^{x_{k+1}} f(x) \textrm{d}x = \int_{x_k}^{x_{k+1}} \sum_{t=1}^n h_t K\left[ \frac{|x - x_t|}{\sigma} \right] \textrm{d}x
226 : $$
227 :
228 : In the typical method for calculating histograms $\sigma=x_{k+1}-x_k$ and $K$ is then:
229 :
230 : $$
231 : K(x) = \begin{cases}
232 : 1 & \textrm{if} x<1 \\
233 : 0 & \textrm{otherwise}
234 : \end{cases}
235 : $$
236 :
237 : This is the method used for estimating the histogram when you use KERNEL=DISCRETE. Other (continuous) choices for $K$ are possible and are described in the documentation for [BETWEEN](BETWEEN.md).
238 : For example, in the following input $K$ is is a Gaussian:
239 :
240 : ```
241 : d1: DISTANCE ATOMS=1,2
242 : kde: KDE ARG=d1 GRID_MIN=0.0 GRID_MAX=1.0 GRID_BIN=100 BANDWIDTH=0.2 KERNEL=gaussian-bin
243 : DUMPGRID ARG=kde STRIDE=1 FILE=kde.grid
244 : ```
245 :
246 : Multidimensional analogues of this approach can also be used. For example, in a 2D analogue the density in the square with corners at $(x_k,y_j)$, $(x_{k+1},y_j)$, $(x_k,y_{j+1})$ and $(x_{k+1},y_{j+1})$ is computed using:
247 :
248 : $$
249 : [ F(x_{k+1}) - F(x_k) ][ F(y_{j+1} - F(y_j) ] = \int_{x_k}^{x_{k+1}} f(x) \textrm{d}x = \sum_{t=1}^n h_t \int_{x_k}^{x_{k+1}} K\left[ \frac{|x - x_t|}{\sigma} \right] \textrm{d}x \int_{y_j}^{y_{j+1}} K\left[ \frac{|y - y_t|}{\sigma} \right] \textrm{d}y
250 : $$
251 :
252 : */
253 : //+ENDPLUMEDOC
254 :
255 : //+PLUMEDOC ANALYSIS SPHERICAL_KDE
256 : /*
257 : Create a histogram from the input scalar/vector/matrix using SPHERICAL_KDE
258 :
259 : This action operates similarly to [KDE](KDE.md) but it is designed to be used for investigating [directional statistics]().
260 : It is particularly useful if you are looking at the distribution of bond vectors as illustrated in the input below:
261 :
262 : ```plumed
263 : # Calculate all the bond vectors
264 : d1: CONTACT_MATRIX GROUP=1-100 SWITCH={RATIONAL R_0=0.1} COMPONENTS
265 : # Normalise the bond vectors
266 : mag: CUSTOM ARG=d1.x,d1.y,d1.z FUNC=sqrt(x*x+y*y+z*z) PERIODIC=NO
267 : d1x: CUSTOM ARG=d1.x,mag FUNC=x/y PERIODIC=NO
268 : d1y: CUSTOM ARG=d1.y,mag FUNC=x/y PERIODIC=NO
269 : d1z: CUSTOM ARG=d1.z,mag FUNC=x/y PERIODIC=NO
270 : # And construct the KDE
271 : kde: SPHERICAL_KDE ARG=d1x,d1y,d1z HEIGHTS=d1.w CONCENTRATION=100 GRID_BIN=144
272 : ```
273 :
274 : Each bond vector here contributes a [Fisher von-Mises kernel](https://en.wikipedia.org/wiki/Von_Mises–Fisher_distribution) to the spherical grid. This spherical grid is constructed
275 : using a [Fibonnacci sphere algorithm](https://stackoverflow.com/questions/9600801/evenly-distributing-n-points-on-a-sphere) so the number of specified using the GRID_BIN keyword must be a Fibonacci number.
276 :
277 : */
278 : //+ENDPLUMEDOC
279 :
280 : namespace PLMD {
281 : namespace gridtools {
282 :
283 : typedef KDE<DiagonalKernelParams,DiscreteKernel,KDEGridTools<DiagonalKernelParams,DiscreteKernel>> discretekde;
284 : PLUMED_REGISTER_ACTION(discretekde,"KDE_DISCRETE")
285 : typedef KDE<DiagonalKernelParams,HistogramBeadKernel,KDEGridTools<DiagonalKernelParams,HistogramBeadKernel>> beadkde;
286 : PLUMED_REGISTER_ACTION(beadkde,"KDE_BEADS")
287 : typedef KDE<DiagonalKernelParams,RegularKernel<DiagonalKernelParams>,KDEGridTools<DiagonalKernelParams,RegularKernel<DiagonalKernelParams>>> flatkde;
288 : PLUMED_REGISTER_ACTION(flatkde,"KDE_KERNELS")
289 : typedef KDE<VonMissesKernelParams,UniversalVonMisses,SphericalKDEGridTools> sphericalkde;
290 : PLUMED_REGISTER_ACTION(sphericalkde,"SPHERICAL_KDE_CPU")
291 : typedef AccelerableShortcut<sphericalkde> sphshortcut;
292 : PLUMED_REGISTER_ACTION(sphshortcut,"SPHERICAL_KDE")
293 : typedef KDE<NonDiagonalKernelParams,RegularKernel<NonDiagonalKernelParams>,KDEGridTools<NonDiagonalKernelParams,RegularKernel<NonDiagonalKernelParams>>> flatfkde;
294 : PLUMED_REGISTER_ACTION(flatfkde,"KDE_FULLCOVAR")
295 :
296 :
297 : class KDEShortcut : public ActionShortcut {
298 : public:
299 : static void registerKeywords(Keywords& keys);
300 : explicit KDEShortcut(const ActionOptions&);
301 : };
302 :
303 : PLUMED_REGISTER_ACTION(KDEShortcut,"KDE")
304 :
305 181 : void KDEShortcut::registerKeywords(Keywords& keys) {
306 181 : KDE<DiagonalKernelParams,RegularKernel<DiagonalKernelParams>,KDEGridTools<DiagonalKernelParams,RegularKernel<DiagonalKernelParams>>>::registerKeywords( keys );
307 181 : keys.addActionNameSuffix("_DISCRETE");
308 181 : keys.addActionNameSuffix("_KERNELS");
309 181 : keys.addActionNameSuffix("_BEADS");
310 181 : keys.addActionNameSuffix("_FULLCOVAR");
311 181 : keys.addActionNameSuffix("_DISCRETEACC");
312 181 : keys.addActionNameSuffix("_KERNELSACC");
313 181 : keys.addActionNameSuffix("_BEADSACC");
314 181 : keys.addActionNameSuffix("_FULLCOVARACC");
315 181 : }
316 :
317 100 : KDEShortcut::KDEShortcut(const ActionOptions&ao):
318 : Action(ao),
319 100 : ActionShortcut(ao) {
320 100 : bool usegpuFLAG=false;
321 200 : parseFlag("USEGPU",usegpuFLAG);
322 : std::string kerneltype;
323 100 : parse("KERNEL",kerneltype);
324 100 : if( kerneltype=="DISCRETE" ) {
325 62 : readInputLine( getShortcutLabel() + ": KDE_DISCRETE" + (usegpuFLAG ? "ACC ":" ") + convertInputLineToString() );
326 : return;
327 : }
328 85 : std::vector<std::string> args;
329 85 : parseVector("ARG", args );
330 85 : std::vector<Value*> argvals;
331 85 : ActionWithArguments::interpretArgumentList( args, plumed.getActionSet(), this, argvals );
332 85 : if( argvals.empty() ) {
333 2 : error("no arguments were specified with ARG");
334 : }
335 85 : std::string argstr = " ARG=" + argvals[0]->getName();
336 118 : for(unsigned i=1; i<argvals.size(); ++i) {
337 68 : argstr += "," + argvals[i]->getName();
338 : }
339 85 : std::vector<std::string> bw;
340 170 : parseVector("BANDWIDTH",bw);
341 85 : if( bw.empty() ) {
342 1 : error("BANDWIDTH is required unless KERNEL=DISCRETE");
343 : }
344 84 : std::string bwstr = " BANDWIDTH=" + bw[0];
345 119 : for(unsigned i=1; i<bw.size(); ++i) {
346 70 : bwstr += "," + bw[i];
347 : }
348 84 : if( bw.size() == 1 && argvals.size()>1 ) {
349 0 : std::vector<Value*> bwargs;
350 0 : ActionWithArguments::interpretArgumentList( bw, plumed.getActionSet(), this, bwargs );
351 0 : if( bwargs.size()!=1 ) {
352 0 : error("invalid input for bandwidth parameter");
353 0 : } else if( bwargs[0]->getRank()<=1 ) {
354 0 : if( kerneltype.find("bin")==std::string::npos ) {
355 0 : readInputLine( getShortcutLabel() + ": KDE_KERNELS" + (usegpuFLAG ? "ACC ":" ") + argstr + " " + bwstr + " KERNEL={" + kerneltype + "} " + convertInputLineToString() );
356 : } else {
357 0 : std::size_t dd = kerneltype.find("-bin");
358 0 : readInputLine( getShortcutLabel() + ": KDE_BEADS" + (usegpuFLAG ? "ACC ":" ") + argstr + " " + bwstr + " KERNEL=" + kerneltype.substr(0,dd) + " " + convertInputLineToString() );
359 : }
360 0 : } else if( bwargs[0]->getRank()==2 ) {
361 0 : readInputLine( getShortcutLabel() + ": KDE_FULLCOVAR" + (usegpuFLAG ? "ACC ":" ") + argstr + " " + bwstr + " KERNEL={" + kerneltype + "} " + convertInputLineToString() );
362 : } else {
363 0 : error("found strange rank for bandwidth parameter");
364 : }
365 84 : } else if( bw.size()==argvals.size() ) {
366 83 : if( kerneltype.find("bin")==std::string::npos ) {
367 455 : readInputLine( getShortcutLabel() + ": KDE_KERNELS" + (usegpuFLAG ? "ACC ":" ") + argstr + " " + bwstr + " KERNEL={" + kerneltype + "} " + convertInputLineToString() );
368 : } else {
369 18 : std::size_t dd = kerneltype.find("-bin");
370 126 : readInputLine( getShortcutLabel() + ": KDE_BEADS" + (usegpuFLAG ? "ACC ":" ") + argstr + " " + bwstr + " KERNEL=" + kerneltype.substr(0,dd) + " " + convertInputLineToString() );
371 : }
372 1 : } else if( bw.size()==argvals.size()*argvals.size() ) {
373 7 : readInputLine( getShortcutLabel() + ": KDE_FULLCOVAR" + (usegpuFLAG ? "ACC ":" ")+ argstr + " " + bwstr + " KERNEL={" + kerneltype + "} " + convertInputLineToString() );
374 : } else {
375 1 : error("invalid input for bandwidth");
376 : }
377 174 : }
378 :
379 : }
380 : }
|