Commit 68e02e80 authored by Rossen Apostolov's avatar Rossen Apostolov
Browse files

Combined the Ewald and PME routines into a single one and added calculation of vdW interactions.

parent 351f6455
/* /*
* Reference implementation of PME reciprocal space interactions. * Reference implementation of PME reciprocal space interactions.
* *
* Copyright (c) 2009, Erik Lindahl, Rossen Apostolov, Szilard Pall * Copyright (c) 2009, Erik Lindahl, Rossen Apostolov, Szilard Pall
* All rights reserved. * All rights reserved.
* Contact: lindahl@cbr.su.se Stockholm University, Sweden. * Contact: lindahl@cbr.su.se Stockholm University, Sweden.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* Redistributions of source code must retain the above copyright notice, this * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer. Redistributions in binary * list of conditions and the following disclaimer. Redistributions in binary
* form must reproduce the above copyright notice, this list of conditions and * form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided * the following disclaimer in the documentation and/or other materials provided
* with the distribution. * with the distribution.
* Neither the name of the author/university nor the names of its contributors may * Neither the name of the author/university nor the names of its contributors may
* be used to endorse or promote products derived from this software without * be used to endorse or promote products derived from this software without
* specific prior written permission. * specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "pme.h" #include "PME.h"
#include "fftpack.h" #include "fftpack.h"
...@@ -48,29 +48,29 @@ struct pme ...@@ -48,29 +48,29 @@ struct pme
{ {
int natoms; int natoms;
RealOpenMM ewaldcoeff; RealOpenMM ewaldcoeff;
t_complex * grid; /* Memory for the grid we spread charges on. t_complex * grid; /* Memory for the grid we spread charges on.
* Element (i,j,k) is accessed as: * Element (i,j,k) is accessed as:
* grid[i*ngrid[1]*ngrid[2] + j*ngrid[2] + k] * grid[i*ngrid[1]*ngrid[2] + j*ngrid[2] + k]
*/ */
int ngrid[3]; /* Total grid dimensions (all data is complex!) */ int ngrid[3]; /* Total grid dimensions (all data is complex!) */
fftpack_t fftplan; /* Handle to fourier transform setup */ fftpack_t fftplan; /* Handle to fourier transform setup */
int order; /* PME interpolation order. Almost always 4 */ int order; /* PME interpolation order. Almost always 4 */
/* Data for bspline interpolation, see the Essman PME paper */ /* Data for bspline interpolation, see the Essman PME paper */
RealOpenMM * bsplines_moduli[3]; /* 3 pointers, to x/y/z bspline moduli, each of length ngrid[x/y/z] */ RealOpenMM * bsplines_moduli[3]; /* 3 pointers, to x/y/z bspline moduli, each of length ngrid[x/y/z] */
RealOpenMM * bsplines_theta[3]; /* each of x/y/z has length order*natoms */ RealOpenMM * bsplines_theta[3]; /* each of x/y/z has length order*natoms */
RealOpenMM * bsplines_dtheta[3]; /* each of x/y/z has length order*natoms */ RealOpenMM * bsplines_dtheta[3]; /* each of x/y/z has length order*natoms */
ivec * particleindex; /* Array of length natoms. Each element is ivec * particleindex; /* Array of length natoms. Each element is
* an ivec (3 ints) that specify the grid * an ivec (3 ints) that specify the grid
* indices for that particular atom. Updated every step! * indices for that particular atom. Updated every step!
*/ */
rvec * particlefraction; /* Array of length natoms. Fractional offset in the grid for rvec * particlefraction; /* Array of length natoms. Fractional offset in the grid for
* each atom in all three dimensions. * each atom in all three dimensions.
*/ */
/* Further explanation of index/fraction: /* Further explanation of index/fraction:
* *
* Assume we have a cell of size 10*10*10nm, and a total grid dimension of 100*100*100 cells. * Assume we have a cell of size 10*10*10nm, and a total grid dimension of 100*100*100 cells.
...@@ -86,9 +86,9 @@ struct pme ...@@ -86,9 +86,9 @@ struct pme
* In the current code version we might assume that a particle is not more than a whole box length away from * In the current code version we might assume that a particle is not more than a whole box length away from
* the central cell, i.e., in this case we would assume all coordinates fall in -10 nm < x,y,z < 20 nm. * the central cell, i.e., in this case we would assume all coordinates fall in -10 nm < x,y,z < 20 nm.
*/ */
RealOpenMM epsilon_r; /* Dielectric coefficient to use, typically 1.0 */ RealOpenMM epsilon_r; /* Dielectric coefficient to use, typically 1.0 */
}; };
/* Internal setup routines */ /* Internal setup routines */
...@@ -96,7 +96,7 @@ struct pme ...@@ -96,7 +96,7 @@ struct pme
/* Only called once from init_pme(), performance does not matter! */ /* Only called once from init_pme(), performance does not matter! */
static void static void
pme_calculate_bsplines_moduli(pme_t pme) pme_calculate_bsplines_moduli(pme_t pme)
{ {
int nmax; int nmax;
...@@ -115,18 +115,18 @@ pme_calculate_bsplines_moduli(pme_t pme) ...@@ -115,18 +115,18 @@ pme_calculate_bsplines_moduli(pme_t pme)
nmax = (pme->ngrid[d] > nmax) ? pme->ngrid[d] : nmax; nmax = (pme->ngrid[d] > nmax) ? pme->ngrid[d] : nmax;
pme->bsplines_moduli[d] = (RealOpenMM *) malloc(sizeof(RealOpenMM)*pme->ngrid[d]); pme->bsplines_moduli[d] = (RealOpenMM *) malloc(sizeof(RealOpenMM)*pme->ngrid[d]);
} }
order = pme->order; order = pme->order;
/* temp storage in this routine */ /* temp storage in this routine */
data = (RealOpenMM *) malloc(sizeof(RealOpenMM)*order); data = (RealOpenMM *) malloc(sizeof(RealOpenMM)*order);
ddata = (RealOpenMM *) malloc(sizeof(RealOpenMM)*order); ddata = (RealOpenMM *) malloc(sizeof(RealOpenMM)*order);
bsplines_data = (RealOpenMM *) malloc(sizeof(RealOpenMM)*nmax); bsplines_data = (RealOpenMM *) malloc(sizeof(RealOpenMM)*nmax);
data[order-1]=0; data[order-1]=0;
data[1]=0; data[1]=0;
data[0]=1; data[0]=1;
for(k=3;k<order;k++) for(k=3;k<order;k++)
{ {
div=1.0/(k-1.0); div=1.0/(k-1.0);
...@@ -137,23 +137,23 @@ pme_calculate_bsplines_moduli(pme_t pme) ...@@ -137,23 +137,23 @@ pme_calculate_bsplines_moduli(pme_t pme)
} }
data[0]=div*data[0]; data[0]=div*data[0];
} }
/* differentiate */ /* differentiate */
ddata[0]=-data[0]; ddata[0]=-data[0];
for(k=1;k<order;k++) for(k=1;k<order;k++)
{ {
ddata[k]=data[k-1]-data[k]; ddata[k]=data[k-1]-data[k];
} }
div=1.0/(order-1); div=1.0/(order-1);
data[order-1]=0; data[order-1]=0;
for(l=1;l<(order-1);l++) for(l=1;l<(order-1);l++)
{ {
data[order-l-1]=div*(l*data[order-l-2]+(order-l)*data[order-l-1]); data[order-l-1]=div*(l*data[order-l-2]+(order-l)*data[order-l-1]);
} }
data[0]=div*data[0]; data[0]=div*data[0];
for(i=0;i<nmax;i++) for(i=0;i<nmax;i++)
{ {
bsplines_data[i]=0; bsplines_data[i]=0;
...@@ -162,7 +162,7 @@ pme_calculate_bsplines_moduli(pme_t pme) ...@@ -162,7 +162,7 @@ pme_calculate_bsplines_moduli(pme_t pme)
{ {
bsplines_data[i]=data[i-1]; bsplines_data[i]=data[i-1];
} }
/* Evaluate the actual bspline moduli for X/Y/Z */ /* Evaluate the actual bspline moduli for X/Y/Z */
for(d=0;d<3;d++) for(d=0;d<3;d++)
{ {
...@@ -170,7 +170,7 @@ pme_calculate_bsplines_moduli(pme_t pme) ...@@ -170,7 +170,7 @@ pme_calculate_bsplines_moduli(pme_t pme)
for(i=0;i<ndata;i++) for(i=0;i<ndata;i++)
{ {
sc=ss=0; sc=ss=0;
for(j=0;j<ndata;j++) for(j=0;j<ndata;j++)
{ {
arg=(2.0*M_PI*i*j)/ndata; arg=(2.0*M_PI*i*j)/ndata;
sc+=bsplines_data[j]*cos(arg); sc+=bsplines_data[j]*cos(arg);
...@@ -185,7 +185,7 @@ pme_calculate_bsplines_moduli(pme_t pme) ...@@ -185,7 +185,7 @@ pme_calculate_bsplines_moduli(pme_t pme)
pme->bsplines_moduli[d][i]=(pme->bsplines_moduli[d][i-1]+pme->bsplines_moduli[d][i+1])*0.5; pme->bsplines_moduli[d][i]=(pme->bsplines_moduli[d][i-1]+pme->bsplines_moduli[d][i+1])*0.5;
} }
} }
} }
/* Release temp storage */ /* Release temp storage */
free(data); free(data);
...@@ -204,7 +204,7 @@ pme_update_grid_index_and_fraction(pme_t pme, ...@@ -204,7 +204,7 @@ pme_update_grid_index_and_fraction(pme_t pme,
int d; int d;
RealOpenMM t; RealOpenMM t;
int ti; int ti;
for(i=0;i<pme->natoms;i++) for(i=0;i<pme->natoms;i++)
{ {
for(d=0;d<3;d++) for(d=0;d<3;d++)
...@@ -216,7 +216,7 @@ pme_update_grid_index_and_fraction(pme_t pme, ...@@ -216,7 +216,7 @@ pme_update_grid_index_and_fraction(pme_t pme,
* *
* 1. First add the box size, to make sure this atom coordinate isnt -0.1 or something. * 1. First add the box size, to make sure this atom coordinate isnt -0.1 or something.
* After this we assume all fractional box positions are *positive*. * After this we assume all fractional box positions are *positive*.
* The reason for this is that we always want to round coordinates _down_ to get * The reason for this is that we always want to round coordinates _down_ to get
* their grid index, and when taking the integer part of -3.4 we would get -3, not -4 as we want. * their grid index, and when taking the integer part of -3.4 we would get -3, not -4 as we want.
* Since we anyway need the grid indices to fall in the central box, it is more convenient * Since we anyway need the grid indices to fall in the central box, it is more convenient
* to first manipulate the coordinates to be positive. * to first manipulate the coordinates to be positive.
...@@ -229,14 +229,14 @@ pme_update_grid_index_and_fraction(pme_t pme, ...@@ -229,14 +229,14 @@ pme_update_grid_index_and_fraction(pme_t pme,
* x[i][d]/box[d] becomes { 0.0543 , 0.6235 , -0.073 } * x[i][d]/box[d] becomes { 0.0543 , 0.6235 , -0.073 }
* (x[i][d]/box[d] + 1.0) becomes { 1.0543 , 1.6235 , 0.927 } * (x[i][d]/box[d] + 1.0) becomes { 1.0543 , 1.6235 , 0.927 }
* (x[i][d]/box[d] + 1.0)*ngrid[d] becomes { 105.43 , 162.35 , 92.7 } * (x[i][d]/box[d] + 1.0)*ngrid[d] becomes { 105.43 , 162.35 , 92.7 }
* *
* integer part is now { 105 , 162 , 92 } * integer part is now { 105 , 162 , 92 }
* *
* The fraction is calculates as t-ti, which becomes { 0.43 , 0.35 , 0.7 } * The fraction is calculates as t-ti, which becomes { 0.43 , 0.35 , 0.7 }
* *
* 3. Take the first integer index part (which can be larger than the grid) modulo the grid dimension * 3. Take the first integer index part (which can be larger than the grid) modulo the grid dimension
* *
* Now we get { 5 , 62 , 92 } * Now we get { 5 , 62 , 92 }
* *
* Voila, both index and fraction, entirely without conditionals. The one limitation here is that * Voila, both index and fraction, entirely without conditionals. The one limitation here is that
* we only add one box length, so if the particle had a coordinate <=-10.0, we would be screwed. * we only add one box length, so if the particle had a coordinate <=-10.0, we would be screwed.
...@@ -247,20 +247,20 @@ pme_update_grid_index_and_fraction(pme_t pme, ...@@ -247,20 +247,20 @@ pme_update_grid_index_and_fraction(pme_t pme,
*/ */
t = (atomCoordinates[i][d] / periodicBoxSize[d] + 1.0)*pme->ngrid[d]; t = (atomCoordinates[i][d] / periodicBoxSize[d] + 1.0)*pme->ngrid[d];
ti = t; ti = t;
pme->particlefraction[i][d] = t - ti; pme->particlefraction[i][d] = t - ti;
pme->particleindex[i][d] = ti % pme->ngrid[d]; pme->particleindex[i][d] = ti % pme->ngrid[d];
} }
} }
} }
/* Ugly bspline calculation taken from Tom Dardens reference equations. /* Ugly bspline calculation taken from Tom Dardens reference equations.
* This probably very sub-optimal in Cuda? Separate kernel? * This probably very sub-optimal in Cuda? Separate kernel?
* *
* In practice, it might help to require order=4 for the cuda port. * In practice, it might help to require order=4 for the cuda port.
*/ */
static void static void
pme_update_bsplines(pme_t pme) pme_update_bsplines(pme_t pme)
{ {
int i,j,k,l; int i,j,k,l;
...@@ -268,27 +268,27 @@ pme_update_bsplines(pme_t pme) ...@@ -268,27 +268,27 @@ pme_update_bsplines(pme_t pme)
RealOpenMM dr,div; RealOpenMM dr,div;
RealOpenMM * data; RealOpenMM * data;
RealOpenMM * ddata; RealOpenMM * ddata;
order = pme->order; order = pme->order;
for(i=0; (i<pme->natoms); i++) for(i=0; (i<pme->natoms); i++)
{ {
for(j=0; j<3; j++) for(j=0; j<3; j++)
{ {
/* dr is relative offset from lower cell limit */ /* dr is relative offset from lower cell limit */
dr = pme->particlefraction[i][j]; dr = pme->particlefraction[i][j];
data = &(pme->bsplines_theta[j][i*order]); data = &(pme->bsplines_theta[j][i*order]);
ddata = &(pme->bsplines_dtheta[j][i*order]); ddata = &(pme->bsplines_dtheta[j][i*order]);
data[order-1] = 0; data[order-1] = 0;
data[1] = dr; data[1] = dr;
data[0] = 1-dr; data[0] = 1-dr;
for(k=3; k<order; k++) for(k=3; k<order; k++)
{ {
div = 1.0/(k-1.0); div = 1.0/(k-1.0);
data[k-1] = div*dr*data[k-2]; data[k-1] = div*dr*data[k-2];
for(l=1; l<(k-1); l++) for(l=1; l<(k-1); l++)
{ {
data[k-l-1] = div*((dr+l)*data[k-l-2]+(k-l-dr)*data[k-l-1]); data[k-l-1] = div*((dr+l)*data[k-l-2]+(k-l-dr)*data[k-l-1]);
} }
...@@ -297,20 +297,20 @@ pme_update_bsplines(pme_t pme) ...@@ -297,20 +297,20 @@ pme_update_bsplines(pme_t pme)
/* differentiate */ /* differentiate */
ddata[0] = -data[0]; ddata[0] = -data[0];
for(k=1; k<order; k++) for(k=1; k<order; k++)
{ {
ddata[k] = data[k-1]-data[k]; ddata[k] = data[k-1]-data[k];
} }
div = 1.0/(order-1); div = 1.0/(order-1);
data[order-1] = div*dr*data[order-2]; data[order-1] = div*dr*data[order-2];
for(l=1; l<(order-1); l++) for(l=1; l<(order-1); l++)
{ {
data[order-l-1] = div*((dr+l)*data[order-l-2]+(order-l-dr)*data[order-l-1]); data[order-l-1] = div*((dr+l)*data[order-l-2]+(order-l-dr)*data[order-l-1]);
} }
data[0] = div*(1-dr)*data[0]; data[0] = div*(1-dr)*data[0];
} }
} }
} }
...@@ -331,64 +331,64 @@ pme_grid_spread_charge(pme_t pme, ...@@ -331,64 +331,64 @@ pme_grid_spread_charge(pme_t pme,
RealOpenMM * thetax; RealOpenMM * thetax;
RealOpenMM * thetay; RealOpenMM * thetay;
RealOpenMM * thetaz; RealOpenMM * thetaz;
order = pme->order; order = pme->order;
/* Reset the grid */ /* Reset the grid */
for(i=0;i<pme->ngrid[0]*pme->ngrid[1]*pme->ngrid[2];i++) for(i=0;i<pme->ngrid[0]*pme->ngrid[1]*pme->ngrid[2];i++)
{ {
pme->grid[i].re = pme->grid[i].im = 0; pme->grid[i].re = pme->grid[i].im = 0;
} }
for(i=0;i<pme->natoms;i++) for(i=0;i<pme->natoms;i++)
{ {
q = atomParameters[i][QIndex]; q = atomParameters[i][QIndex];
/* Grid index for the actual atom position */ /* Grid index for the actual atom position */
x0index = pme->particleindex[i][0]; x0index = pme->particleindex[i][0];
y0index = pme->particleindex[i][1]; y0index = pme->particleindex[i][1];
z0index = pme->particleindex[i][2]; z0index = pme->particleindex[i][2];
/* Bspline factors for this atom in each dimension , calculated from fractional coordinates */ /* Bspline factors for this atom in each dimension , calculated from fractional coordinates */
thetax = &(pme->bsplines_theta[0][i*order]); thetax = &(pme->bsplines_theta[0][i*order]);
thetay = &(pme->bsplines_theta[1][i*order]); thetay = &(pme->bsplines_theta[1][i*order]);
thetaz = &(pme->bsplines_theta[2][i*order]); thetaz = &(pme->bsplines_theta[2][i*order]);
/* Loop over norder*norder*norder (typically 4*4*4) neighbor cells. /* Loop over norder*norder*norder (typically 4*4*4) neighbor cells.
* *
* As a neat optimization, we only spread in the forward direction, but apply PBC! * As a neat optimization, we only spread in the forward direction, but apply PBC!
* *
* Since we are going to do an FFT on the grid, it doesnt matter where the data is, * Since we are going to do an FFT on the grid, it doesnt matter where the data is,
* in frequency space the result will be the same. * in frequency space the result will be the same.
* *
* So, the influence function (bsplines) will probably be something like (0.15,0.35,0.35,0.15), * So, the influence function (bsplines) will probably be something like (0.15,0.35,0.35,0.15),
* with largest weight 2-3 steps forward (you dont need to understand that for the implementation :-) * with largest weight 2-3 steps forward (you dont need to understand that for the implementation :-)
* Effectively, you can look at this as translating the entire grid. * Effectively, you can look at this as translating the entire grid.
* *
* Why do we do this stupid thing? * Why do we do this stupid thing?
* *
* 1) The loops get much simpler * 1) The loops get much simpler
* 2) Just looking forward will hopefully get us more cache hits * 2) Just looking forward will hopefully get us more cache hits
* 3) When we parallelize things, we only need to communicate in one direction instead of two! * 3) When we parallelize things, we only need to communicate in one direction instead of two!
*/ */
for(ix=0;ix<order;ix++) for(ix=0;ix<order;ix++)
{ {
/* Calculate index, apply PBC so we spread to index 0/1/2 when a particle is close to the upper limit of the grid */ /* Calculate index, apply PBC so we spread to index 0/1/2 when a particle is close to the upper limit of the grid */
xindex = (x0index + ix) % pme->ngrid[0]; xindex = (x0index + ix) % pme->ngrid[0];
for(iy=0;iy<order;iy++) for(iy=0;iy<order;iy++)
{ {
yindex = (y0index + iy) % pme->ngrid[1]; yindex = (y0index + iy) % pme->ngrid[1];
for(iz=0;iz<order;iz++) for(iz=0;iz<order;iz++)
{ {
/* Can be optimized, but we keep it simple here */ /* Can be optimized, but we keep it simple here */
zindex = (z0index + iz) % pme->ngrid[2]; zindex = (z0index + iz) % pme->ngrid[2];
/* Calculate index in the charge grid */ /* Calculate index in the charge grid */
index = xindex*pme->ngrid[1]*pme->ngrid[2] + yindex*pme->ngrid[2] + zindex; index = xindex*pme->ngrid[1]*pme->ngrid[2] + yindex*pme->ngrid[2] + zindex;
/* Add the charge times the bspline spread/interpolation factors to this grid position */ /* Add the charge times the bspline spread/interpolation factors to this grid position */
pme->grid[index].re += q*thetax[ix]*thetay[iy]*thetaz[iz]; pme->grid[index].re += q*thetax[ix]*thetay[iy]*thetaz[iz];
} }
} }
} }
...@@ -417,17 +417,17 @@ pme_reciprocal_convolution(pme_t pme, ...@@ -417,17 +417,17 @@ pme_reciprocal_convolution(pme_t pme,
RealOpenMM denom; RealOpenMM denom;
RealOpenMM boxfactor; RealOpenMM boxfactor;
RealOpenMM maxkx,maxky,maxkz; RealOpenMM maxkx,maxky,maxkz;
t_complex *ptr; t_complex *ptr;
nx = pme->ngrid[0]; nx = pme->ngrid[0];
ny = pme->ngrid[1]; ny = pme->ngrid[1];
nz = pme->ngrid[2]; nz = pme->ngrid[2];
one_4pi_eps=ONE_4PI_EPS0/pme->epsilon_r; one_4pi_eps=ONE_4PI_EPS0/pme->epsilon_r;
factor=M_PI*M_PI/(pme->ewaldcoeff*pme->ewaldcoeff); factor=M_PI*M_PI/(pme->ewaldcoeff*pme->ewaldcoeff);
boxfactor = M_PI*periodicBoxSize[0]*periodicBoxSize[1]*periodicBoxSize[2]; boxfactor = M_PI*periodicBoxSize[0]*periodicBoxSize[1]*periodicBoxSize[2];
esum = 0; esum = 0;
virxx = 0; virxx = 0;
virxy = 0; virxy = 0;
...@@ -435,7 +435,7 @@ pme_reciprocal_convolution(pme_t pme, ...@@ -435,7 +435,7 @@ pme_reciprocal_convolution(pme_t pme,
viryy = 0; viryy = 0;
viryz = 0; viryz = 0;
virzz = 0; virzz = 0;
maxkx = (nx+1)/2; maxkx = (nx+1)/2;
maxky = (ny+1)/2; maxky = (ny+1)/2;
maxkz = (nz+1)/2; maxkz = (nz+1)/2;
...@@ -453,7 +453,7 @@ pme_reciprocal_convolution(pme_t pme, ...@@ -453,7 +453,7 @@ pme_reciprocal_convolution(pme_t pme,
my = (ky<maxky) ? ky : (ky-ny); my = (ky<maxky) ? ky : (ky-ny);
mhy = my/periodicBoxSize[1]; mhy = my/periodicBoxSize[1];
by = pme->bsplines_moduli[1][ky]; by = pme->bsplines_moduli[1][ky];
for(kz=0;kz<nz;kz++) for(kz=0;kz<nz;kz++)
{ {
/* If the net charge of the system is 0.0, there will not be any DC (direct current, zero frequency) component. However, /* If the net charge of the system is 0.0, there will not be any DC (direct current, zero frequency) component. However,
...@@ -474,23 +474,23 @@ pme_reciprocal_convolution(pme_t pme, ...@@ -474,23 +474,23 @@ pme_reciprocal_convolution(pme_t pme,
mhz = mz/periodicBoxSize[2]; mhz = mz/periodicBoxSize[2];
/* Pointer to the grid cell in question */ /* Pointer to the grid cell in question */
ptr = pme->grid + kx*ny*nz + ky*nz + kz; ptr = pme->grid + kx*ny*nz + ky*nz + kz;
/* Get grid data for this frequency */ /* Get grid data for this frequency */
d1 = ptr->re; d1 = ptr->re;
d2 = ptr->im; d2 = ptr->im;
/* Calculate the convolution - see the Essman/Darden paper for the equation! */ /* Calculate the convolution - see the Essman/Darden paper for the equation! */
m2 = mhx*mhx+mhy*mhy+mhz*mhz; m2 = mhx*mhx+mhy*mhy+mhz*mhz;
bz = pme->bsplines_moduli[2][kz]; bz = pme->bsplines_moduli[2][kz];
denom = m2*bx*by*bz; denom = m2*bx*by*bz;
eterm = one_4pi_eps*exp(-factor*m2)/denom; eterm = one_4pi_eps*exp(-factor*m2)/denom;
/* write back convolution data to grid */ /* write back convolution data to grid */
ptr->re = d1*eterm; ptr->re = d1*eterm;
ptr->im = d2*eterm; ptr->im = d2*eterm;
struct2 = (d1*d1+d2*d2); struct2 = (d1*d1+d2*d2);
/* Long-range PME contribution to the energy for this frequency */ /* Long-range PME contribution to the energy for this frequency */
...@@ -504,7 +504,7 @@ pme_reciprocal_convolution(pme_t pme, ...@@ -504,7 +504,7 @@ pme_reciprocal_convolution(pme_t pme,
virxz += ets2*vfactor*mhx*mhz; virxz += ets2*vfactor*mhx*mhz;
viryy += ets2*(vfactor*mhy*mhy-1.0); viryy += ets2*(vfactor*mhy*mhy-1.0);
viryz += ets2*vfactor*mhy*mhz; viryz += ets2*vfactor*mhy*mhz;
virzz += ets2*(vfactor*mhz*mhz-1.0); virzz += ets2*(vfactor*mhz*mhz-1.0);
} }
} }
} }
...@@ -514,7 +514,7 @@ pme_reciprocal_convolution(pme_t pme, ...@@ -514,7 +514,7 @@ pme_reciprocal_convolution(pme_t pme,
pme_virial[0][1] = pme_virial[1][0] = 0.25*virxy; pme_virial[0][1] = pme_virial[1][0] = 0.25*virxy;
pme_virial[0][2] = pme_virial[2][0] = 0.25*virxz; pme_virial[0][2] = pme_virial[2][0] = 0.25*virxz;
pme_virial[1][2] = pme_virial[2][1] = 0.25*viryz; pme_virial[1][2] = pme_virial[2][1] = 0.25*viryz;
/* The factor 0.5 is nothing special, but it is better to have it here than inside the loop :-) */ /* The factor 0.5 is nothing special, but it is better to have it here than inside the loop :-) */
*energy = 0.5*esum; *energy = 0.5*esum;
} }
...@@ -545,26 +545,26 @@ pme_grid_interpolate_force(pme_t pme, ...@@ -545,26 +545,26 @@ pme_grid_interpolate_force(pme_t pme,
RealOpenMM fx,fy,fz; RealOpenMM fx,fy,fz;
RealOpenMM gridvalue; RealOpenMM gridvalue;
int nx,ny,nz; int nx,ny,nz;
nx = pme->ngrid[0]; nx = pme->ngrid[0];
ny = pme->ngrid[1]; ny = pme->ngrid[1];
nz = pme->ngrid[2]; nz = pme->ngrid[2];
order = pme->order; order = pme->order;
/* This is almost identical to the charge spreading routine! */ /* This is almost identical to the charge spreading routine! */
for(i=0;i<pme->natoms;i++) for(i=0;i<pme->natoms;i++)
{ {
fx = fy = fz = 0; fx = fy = fz = 0;
q = atomParameters[i][QIndex]; q = atomParameters[i][QIndex];
/* Grid index for the actual atom position */ /* Grid index for the actual atom position */
x0index = pme->particleindex[i][0]; x0index = pme->particleindex[i][0];
y0index = pme->particleindex[i][1]; y0index = pme->particleindex[i][1];
z0index = pme->particleindex[i][2]; z0index = pme->particleindex[i][2];
/* Bspline factors for this atom in each dimension , calculated from fractional coordinates */ /* Bspline factors for this atom in each dimension , calculated from fractional coordinates */
thetax = &(pme->bsplines_theta[0][i*order]); thetax = &(pme->bsplines_theta[0][i*order]);
thetay = &(pme->bsplines_theta[1][i*order]); thetay = &(pme->bsplines_theta[1][i*order]);
...@@ -574,7 +574,7 @@ pme_grid_interpolate_force(pme_t pme, ...@@ -574,7 +574,7 @@ pme_grid_interpolate_force(pme_t pme,
dthetaz = &(pme->bsplines_dtheta[2][i*order]); dthetaz = &(pme->bsplines_dtheta[2][i*order]);
/* See pme_grid_spread_charge() for comments about the order here, and only interpolation in one direction */ /* See pme_grid_spread_charge() for comments about the order here, and only interpolation in one direction */
/* Since we will add order^3 (typically 4*4*4=64) terms to the force on each particle, we use temporary fx/fy/fz /* Since we will add order^3 (typically 4*4*4=64) terms to the force on each particle, we use temporary fx/fy/fz
* variables, and only add it to memory forces[] at the end. * variables, and only add it to memory forces[] at the end.
*/ */
...@@ -584,14 +584,14 @@ pme_grid_interpolate_force(pme_t pme, ...@@ -584,14 +584,14 @@ pme_grid_interpolate_force(pme_t pme,
/* Get both the bspline factor and its derivative with respect to the x coordinate! */ /* Get both the bspline factor and its derivative with respect to the x coordinate! */
tx = thetax[ix]; tx = thetax[ix];
dtx = dthetax[ix]; dtx = dthetax[ix];
for(iy=0;iy<order;iy++) for(iy=0;iy<order;iy++)
{ {
yindex = (y0index + iy) % pme->ngrid[1]; yindex = (y0index + iy) % pme->ngrid[1];
/* bspline + derivative wrt y */ /* bspline + derivative wrt y */
ty = thetay[iy]; ty = thetay[iy];
dty = dthetay[iy]; dty = dthetay[iy];
for(iz=0;iz<order;iz++) for(iz=0;iz<order;iz++)
{ {
/* Can be optimized, but we keep it simple here */ /* Can be optimized, but we keep it simple here */
...@@ -600,7 +600,7 @@ pme_grid_interpolate_force(pme_t pme, ...@@ -600,7 +600,7 @@ pme_grid_interpolate_force(pme_t pme,
tz = thetaz[iz]; tz = thetaz[iz];
dtz = dthetaz[iz]; dtz = dthetaz[iz];
index = xindex*pme->ngrid[1]*pme->ngrid[2] + yindex*pme->ngrid[2] + zindex; index = xindex*pme->ngrid[1]*pme->ngrid[2] + yindex*pme->ngrid[2] + zindex;
/* Get the fft+convoluted+ifft:d data from the grid, which must be real by definition */ /* Get the fft+convoluted+ifft:d data from the grid, which must be real by definition */
/* Checking that the imaginary part is indeed zero might be a good check :-) */ /* Checking that the imaginary part is indeed zero might be a good check :-) */
gridvalue = pme->grid[index].re; gridvalue = pme->grid[index].re;
...@@ -623,7 +623,7 @@ pme_grid_interpolate_force(pme_t pme, ...@@ -623,7 +623,7 @@ pme_grid_interpolate_force(pme_t pme,
/* EXPORTED ROUTINES */ /* EXPORTED ROUTINES */
int int
pme_init(pme_t * ppme, pme_init(pme_t * ppme,
RealOpenMM ewaldcoeff, RealOpenMM ewaldcoeff,
int natoms, int natoms,
...@@ -633,14 +633,14 @@ pme_init(pme_t * ppme, ...@@ -633,14 +633,14 @@ pme_init(pme_t * ppme,
{ {
pme_t pme; pme_t pme;
int d; int d;
pme = (pme_t) malloc(sizeof(struct pme)); pme = (pme_t) malloc(sizeof(struct pme));
pme->order = pme_order; pme->order = pme_order;
pme->epsilon_r = epsilon_r; pme->epsilon_r = epsilon_r;
pme->ewaldcoeff = ewaldcoeff; pme->ewaldcoeff = ewaldcoeff;
pme->natoms = natoms; pme->natoms = natoms;
for(d=0;d<3;d++) for(d=0;d<3;d++)
{ {
pme->ngrid[d] = ngrid[d]; pme->ngrid[d] = ngrid[d];
...@@ -650,17 +650,17 @@ pme_init(pme_t * ppme, ...@@ -650,17 +650,17 @@ pme_init(pme_t * ppme,
pme->particlefraction = (rvec *)malloc(sizeof(rvec)*natoms); pme->particlefraction = (rvec *)malloc(sizeof(rvec)*natoms);
pme->particleindex = (ivec *)malloc(sizeof(ivec)*natoms); pme->particleindex = (ivec *)malloc(sizeof(ivec)*natoms);
/* Allocate charge grid storage */ /* Allocate charge grid storage */
pme->grid = (t_complex *)malloc(sizeof(t_complex)*ngrid[0]*ngrid[1]*ngrid[2]); pme->grid = (t_complex *)malloc(sizeof(t_complex)*ngrid[0]*ngrid[1]*ngrid[2]);
fftpack_init_3d(&pme->fftplan,ngrid[0],ngrid[1],ngrid[2]); fftpack_init_3d(&pme->fftplan,ngrid[0],ngrid[1],ngrid[2]);
/* Setup bspline moduli (see Essman paper) */ /* Setup bspline moduli (see Essman paper) */
pme_calculate_bsplines_moduli(pme); pme_calculate_bsplines_moduli(pme);
*ppme = pme; *ppme = pme;
return 0; return 0;
} }
...@@ -677,32 +677,32 @@ int pme_exec(pme_t pme, ...@@ -677,32 +677,32 @@ int pme_exec(pme_t pme,
RealOpenMM pme_virial[3][3]) RealOpenMM pme_virial[3][3])
{ {
/* Routine is called with coordinates in x, a box, and charges in q */ /* Routine is called with coordinates in x, a box, and charges in q */
/* Before we can do the actual interpolation, we need to recalculate and update /* Before we can do the actual interpolation, we need to recalculate and update
* the indices for each particle in the charge grid (initialized in pme_init()), * the indices for each particle in the charge grid (initialized in pme_init()),
* and what its fractional offset in this grid cell is. * and what its fractional offset in this grid cell is.
*/ */
/* Update charge grid indices and fractional offsets for each atom. /* Update charge grid indices and fractional offsets for each atom.
* The indices/fractions are stored internally in the pme datatype * The indices/fractions are stored internally in the pme datatype
*/ */
pme_update_grid_index_and_fraction(pme,atomCoordinates,periodicBoxSize); pme_update_grid_index_and_fraction(pme,atomCoordinates,periodicBoxSize);
/* Calculate bsplines (and their differentials) from current fractional coordinates, store in pme structure */ /* Calculate bsplines (and their differentials) from current fractional coordinates, store in pme structure */
pme_update_bsplines(pme); pme_update_bsplines(pme);
/* Spread the charges on grid (using newly calculated bsplines in the pme structure) */ /* Spread the charges on grid (using newly calculated bsplines in the pme structure) */
pme_grid_spread_charge(pme,atomParameters); pme_grid_spread_charge(pme,atomParameters);
/* do 3d-fft */ /* do 3d-fft */
fftpack_exec_3d(pme->fftplan,FFTPACK_FORWARD,pme->grid,pme->grid); fftpack_exec_3d(pme->fftplan,FFTPACK_FORWARD,pme->grid,pme->grid);
/* solve in k-space */ /* solve in k-space */
pme_reciprocal_convolution(pme,periodicBoxSize,energy,pme_virial); pme_reciprocal_convolution(pme,periodicBoxSize,energy,pme_virial);
/* do 3d-invfft */ /* do 3d-invfft */
fftpack_exec_3d(pme->fftplan,FFTPACK_BACKWARD,pme->grid,pme->grid); fftpack_exec_3d(pme->fftplan,FFTPACK_BACKWARD,pme->grid,pme->grid);
/* Get the particle forces from the grid and bsplines in the pme structure */ /* Get the particle forces from the grid and bsplines in the pme structure */
pme_grid_interpolate_force(pme,periodicBoxSize,atomParameters,forces); pme_grid_interpolate_force(pme,periodicBoxSize,atomParameters,forces);
...@@ -715,23 +715,23 @@ int ...@@ -715,23 +715,23 @@ int
pme_destroy(pme_t pme) pme_destroy(pme_t pme)
{ {
int d; int d;
free(pme->grid); free(pme->grid);
for(d=0;d<3;d++) for(d=0;d<3;d++)
{ {
free(pme->bsplines_moduli[d]); free(pme->bsplines_moduli[d]);
free(pme->bsplines_theta[d]); free(pme->bsplines_theta[d]);
free(pme->bsplines_dtheta[d]); free(pme->bsplines_dtheta[d]);
} }
free(pme->particlefraction); free(pme->particlefraction);
free(pme->particleindex); free(pme->particleindex);
fftpack_destroy(pme->fftplan); fftpack_destroy(pme->fftplan);
/* destroy structure itself */ /* destroy structure itself */
free(pme); free(pme);
return 0; return 0;
} }
...@@ -31,8 +31,7 @@ ...@@ -31,8 +31,7 @@
#include "../SimTKUtilities/SimTKOpenMMUtilities.h" #include "../SimTKUtilities/SimTKOpenMMUtilities.h"
#include "ReferenceLJCoulombIxn.h" #include "ReferenceLJCoulombIxn.h"
#include "ReferenceForce.h" #include "ReferenceForce.h"
#include "PME.h"
#include "pme.h"
// In case we're using some primitive version of Visual Studio this will // In case we're using some primitive version of Visual Studio this will
// make sure that erf() and erfc() are defined. // make sure that erf() and erfc() are defined.
...@@ -85,13 +84,13 @@ ReferenceLJCoulombIxn::~ReferenceLJCoulombIxn( ){ ...@@ -85,13 +84,13 @@ ReferenceLJCoulombIxn::~ReferenceLJCoulombIxn( ){
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
int ReferenceLJCoulombIxn::setUseCutoff( RealOpenMM distance, const OpenMM::NeighborList& neighbors, RealOpenMM solventDielectric ) { int ReferenceLJCoulombIxn::setUseCutoff( RealOpenMM distance, const OpenMM::NeighborList& neighbors, RealOpenMM solventDielectric ) {
cutoff = true; cutoff = true;
cutoffDistance = distance; cutoffDistance = distance;
neighborList = &neighbors; neighborList = &neighbors;
krf = pow(cutoffDistance, -3.0f)*(solventDielectric-1.0f)/(2.0f*solventDielectric+1.0f); krf = pow(cutoffDistance, -3.0f)*(solventDielectric-1.0f)/(2.0f*solventDielectric+1.0f);
crf = (1.0f/cutoffDistance)*(3.0f*solventDielectric)/(2.0f*solventDielectric+1.0f); crf = (1.0f/cutoffDistance)*(3.0f*solventDielectric)/(2.0f*solventDielectric+1.0f);
return ReferenceForce::DefaultReturn; return ReferenceForce::DefaultReturn;
} }
...@@ -193,9 +192,9 @@ int ReferenceLJCoulombIxn::getDerivedParameters( RealOpenMM c6, RealOpenMM c12, ...@@ -193,9 +192,9 @@ int ReferenceLJCoulombIxn::getDerivedParameters( RealOpenMM c6, RealOpenMM c12,
parameters[SigIndex] = half; parameters[SigIndex] = half;
} else { } else {
parameters[EpsIndex] = c6*SQRT( one/c12 ); parameters[EpsIndex] = c6*SQRT( one/c12 );
parameters[SigIndex] = POW( (c12/c6), oneSixth ); parameters[SigIndex] = POW( (c12/c6), oneSixth );
parameters[SigIndex] *= half; parameters[SigIndex] *= half;
} }
...@@ -222,9 +221,9 @@ int ReferenceLJCoulombIxn::getDerivedParameters( RealOpenMM c6, RealOpenMM c12, ...@@ -222,9 +221,9 @@ int ReferenceLJCoulombIxn::getDerivedParameters( RealOpenMM c6, RealOpenMM c12,
@param totalEnergy total energy @param totalEnergy total energy
@return ReferenceForce::DefaultReturn @return ReferenceForce::DefaultReturn
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
int ReferenceLJCoulombIxn::calculateEwaldIxn( int numberOfAtoms, RealOpenMM** atomCoordinates, int ReferenceLJCoulombIxn::calculateEwaldIxn( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** atomParameters, int** exclusions, RealOpenMM** atomParameters, int** exclusions,
RealOpenMM* fixedParameters, RealOpenMM** forces, RealOpenMM* fixedParameters, RealOpenMM** forces,
...@@ -233,40 +232,80 @@ int ReferenceLJCoulombIxn::calculateEwaldIxn( int numberOfAtoms, RealOpenMM** at ...@@ -233,40 +232,80 @@ int ReferenceLJCoulombIxn::calculateEwaldIxn( int numberOfAtoms, RealOpenMM** at
#include "../SimTKUtilities/RealTypeSimTk.h" #include "../SimTKUtilities/RealTypeSimTk.h"
typedef std::complex<RealOpenMM> d_complex; typedef std::complex<RealOpenMM> d_complex;
int kmax = std::max(numRx, std::max(numRy,numRz));
RealOpenMM factorEwald = -1 / (4*alphaEwald*alphaEwald);
RealOpenMM SQRT_PI = sqrt(PI);
RealOpenMM TWO_PI = 2.0 * PI;
static const RealOpenMM epsilon = 1.0; static const RealOpenMM epsilon = 1.0;
static const RealOpenMM one = 1.0; static const RealOpenMM one = 1.0;
static const RealOpenMM six = 6.0;
static const RealOpenMM twelve = 12.0;
RealOpenMM recipCoeff = (RealOpenMM)(4*PI/(periodicBoxSize[0] * periodicBoxSize[1] * periodicBoxSize[2]) /epsilon); int kmax = std::max(numRx, std::max(numRy,numRz));
RealOpenMM factorEwald = -1 / (4*alphaEwald*alphaEwald);
RealOpenMM SQRT_PI = sqrt(PI);
RealOpenMM TWO_PI = 2.0 * PI;
RealOpenMM recipCoeff = (RealOpenMM)(4*PI/(periodicBoxSize[0] * periodicBoxSize[1] * periodicBoxSize[2]) /epsilon);
RealOpenMM selfEwaldEnergy = 0.0; RealOpenMM selfEwaldEnergy = 0.0;
RealOpenMM realSpaceEwaldEnergy = 0.0; RealOpenMM realSpaceEwaldEnergy = 0.0;
RealOpenMM recipEnergy = 0.0; RealOpenMM recipEnergy = 0.0;
RealOpenMM vdwEnergy = 0.0;
// ************************************************************************************** // **************************************************************************************
// SELF ENERGY // SELF ENERGY
// ************************************************************************************** // **************************************************************************************
for( int atomID = 0; atomID < numberOfAtoms; atomID++ ){ for( int atomID = 0; atomID < numberOfAtoms; atomID++ ){
selfEwaldEnergy = selfEwaldEnergy + atomParameters[atomID][QIndex]*atomParameters[atomID][QIndex]; selfEwaldEnergy = atomParameters[atomID][QIndex]*atomParameters[atomID][QIndex] * alphaEwald/SQRT_PI;
if( totalEnergy )
*totalEnergy -= selfEwaldEnergy;
if( energyByAtom ){
energyByAtom[atomID] -= selfEwaldEnergy;
}
} }
selfEwaldEnergy = selfEwaldEnergy * alphaEwald/SQRT_PI ;
// ************************************************************************************** // **************************************************************************************
// RECIPROCAL SPACE EWALD ENERGY AND FORCES // RECIPROCAL SPACE EWALD ENERGY AND FORCES
// ************************************************************************************** // **************************************************************************************
// setup reciprocal box // PME
if (pme) {
pme_t pmedata; /* abstract handle for PME data */
int ngrid[3];
RealOpenMM virial[3][3];
/* PME grid dimensions.
* We typically want to set this as the spacing rather than absolute dimensions, but
* to be able to reproduce results from other programs (e.g. Gromacs) we need to be
* able to set exact grid dimenisions occasionally.
*/
ngrid[0] = 16;
ngrid[1] = 16;
ngrid[2] = 16;
pme_init(&pmedata,alphaEwald,numberOfAtoms,ngrid,4,1);
pme_exec(pmedata,atomCoordinates,forces,atomParameters,periodicBoxSize,&recipEnergy,virial);
if( totalEnergy )
*totalEnergy += recipEnergy;
if( energyByAtom )
for(int n = 0; n < numberOfAtoms; n++)
energyByAtom[n] += recipEnergy;
}
// Ewald method
else if (ewald) {
// setup reciprocal box
RealOpenMM recipBoxSize[3] = { TWO_PI / periodicBoxSize[0], TWO_PI / periodicBoxSize[1], TWO_PI / periodicBoxSize[2]}; RealOpenMM recipBoxSize[3] = { TWO_PI / periodicBoxSize[0], TWO_PI / periodicBoxSize[1], TWO_PI / periodicBoxSize[2]};
// setup K-vectors // setup K-vectors
#define EIR(x, y, z) eir[(x)*numberOfAtoms*3+(y)*3+z] #define EIR(x, y, z) eir[(x)*numberOfAtoms*3+(y)*3+z]
vector<d_complex> eir(kmax*numberOfAtoms*3); vector<d_complex> eir(kmax*numberOfAtoms*3);
...@@ -292,7 +331,8 @@ int ReferenceLJCoulombIxn::calculateEwaldIxn( int numberOfAtoms, RealOpenMM** at ...@@ -292,7 +331,8 @@ int ReferenceLJCoulombIxn::calculateEwaldIxn( int numberOfAtoms, RealOpenMM** at
EIR(j, i, m) = EIR(j-1, i, m) * EIR(1, i, m); EIR(j, i, m) = EIR(j-1, i, m) * EIR(1, i, m);
} }
// calculate reciprocal space energy and forces // calculate reciprocal space energy and forces
int lowry = 0; int lowry = 0;
int lowrz = 1; int lowrz = 1;
...@@ -335,231 +375,92 @@ int ReferenceLJCoulombIxn::calculateEwaldIxn( int numberOfAtoms, RealOpenMM** at ...@@ -335,231 +375,92 @@ int ReferenceLJCoulombIxn::calculateEwaldIxn( int numberOfAtoms, RealOpenMM** at
ss += tab_qxyz[n].imag(); ss += tab_qxyz[n].imag();
} }
RealOpenMM kz = rz * recipBoxSize[2]; RealOpenMM kz = rz * recipBoxSize[2];
RealOpenMM k2 = kx * kx + ky * ky + kz * kz; RealOpenMM k2 = kx * kx + ky * ky + kz * kz;
RealOpenMM ak = exp(k2*factorEwald) / k2; RealOpenMM ak = exp(k2*factorEwald) / k2;
recipEnergy += ak * ( cs * cs + ss * ss);
for(int n = 0; n < numberOfAtoms; n++) { for(int n = 0; n < numberOfAtoms; n++) {
RealOpenMM force = ak * (cs * tab_qxyz[n].imag() - ss * tab_qxyz[n].real()); RealOpenMM force = ak * (cs * tab_qxyz[n].imag() - ss * tab_qxyz[n].real());
forces[n][0] += 2 * recipCoeff * force * kx ; forces[n][0] += 2 * recipCoeff * force * kx ;
forces[n][1] += 2 * recipCoeff * force * ky ; forces[n][1] += 2 * recipCoeff * force * ky ;
forces[n][2] += 2 * recipCoeff * force * kz ; forces[n][2] += 2 * recipCoeff * force * kz ;
} }
recipEnergy = recipCoeff * ak * ( cs * cs + ss * ss);
if( totalEnergy )
*totalEnergy += recipEnergy;
if( energyByAtom )
for(int n = 0; n < numberOfAtoms; n++)
energyByAtom[n] += recipEnergy;
lowrz = 1 - numRz; lowrz = 1 - numRz;
} }
lowry = 1 - numRy; lowry = 1 - numRy;
} }
} }
}
recipEnergy *= recipCoeff; else {
std::stringstream message;
message << " Wrong method for Ewald summation, Aborting" << std::endl;
SimTKOpenMMLog::printError( message );
}
// ************************************************************************************** // **************************************************************************************
// SHORT-RANGE ENERGY AND FORCES // SHORT-RANGE ENERGY AND FORCES
// ************************************************************************************** // **************************************************************************************
RealOpenMM deltaR[2][ReferenceForce::LastDeltaRIndex]; for (int i = 0; i < (int) neighborList->size(); i++) {
OpenMM::AtomPair pair = (*neighborList)[i];
for( int atomID1 = 0; atomID1 < numberOfAtoms; atomID1++ ){ int ii = pair.first;
for( int atomID2 = atomID1 + 1; atomID2 < numberOfAtoms; atomID2++ ){ int jj = pair.second;
ReferenceForce::getDeltaRPeriodic( atomCoordinates[atomID2], atomCoordinates[atomID1], periodicBoxSize, deltaR[0] );
RealOpenMM r = deltaR[0][ReferenceForce::RIndex];
RealOpenMM r2 = deltaR[0][ReferenceForce::R2Index];
RealOpenMM inverseR = one/(deltaR[0][ReferenceForce::RIndex]);
realSpaceEwaldEnergy = RealOpenMM deltaR[2][ReferenceForce::LastDeltaRIndex];
(RealOpenMM)(realSpaceEwaldEnergy + atomParameters[atomID1][QIndex]*atomParameters[atomID2][QIndex]*inverseR*erfc(alphaEwald*r)); ReferenceForce::getDeltaRPeriodic( atomCoordinates[jj], atomCoordinates[ii], periodicBoxSize, deltaR[0] );
}
}
// allocate and initialize exclusion array
vector<int> exclusionIndices(numberOfAtoms);
for( int ii = 0; ii < numberOfAtoms; ii++ ){
exclusionIndices[ii] = -1;
}
for( int ii = 0; ii < numberOfAtoms; ii++ ){
// set exclusions
for( int jj = 1; jj <= exclusions[ii][0]; jj++ ){
exclusionIndices[exclusions[ii][jj]] = ii;
}
// loop over atom pairs
for( int jj = ii+1; jj < numberOfAtoms; jj++ ){
if( exclusionIndices[jj] != ii ){
ReferenceForce::getDeltaRPeriodic( atomCoordinates[jj], atomCoordinates[ii], periodicBoxSize, deltaR[0] );
RealOpenMM r = deltaR[0][ReferenceForce::RIndex]; RealOpenMM r = deltaR[0][ReferenceForce::RIndex];
RealOpenMM r2 = deltaR[0][ReferenceForce::R2Index]; RealOpenMM r2 = deltaR[0][ReferenceForce::R2Index];
RealOpenMM inverseR = one/(deltaR[0][ReferenceForce::RIndex]); RealOpenMM inverseR = one/(deltaR[0][ReferenceForce::RIndex]);
RealOpenMM alphaR = alphaEwald * r; RealOpenMM alphaR = alphaEwald * r;
realSpaceEwaldEnergy =
(RealOpenMM)(realSpaceEwaldEnergy + atomParameters[ii][QIndex]*atomParameters[jj][QIndex]*inverseR*erfc(alphaR));
RealOpenMM dEdR = atomParameters[ii][QIndex] * atomParameters[jj][QIndex] * inverseR * inverseR * inverseR;
dEdR = (RealOpenMM)(dEdR * (erfc(alphaR) + 2 * alphaR * exp ( - alphaR * alphaR) / SQRT_PI ));
for( int kk = 0; kk < 3; kk++ ){
RealOpenMM force = dEdR*deltaR[0][kk];
forces[ii][kk] += force;
forces[jj][kk] -= force;
}
}
}
}
// ***********************************************************************
if( totalEnergy ) {
*totalEnergy += recipEnergy + realSpaceEwaldEnergy - selfEwaldEnergy;
}
return ReferenceForce::DefaultReturn;
}
/**---------------------------------------------------------------------------------------
Calculate PME ixn
@param numberOfAtoms number of atoms
@param atomCoordinates atom coordinates
@param atomParameters atom parameters atomParameters[atomIndex][paramterIndex]
@param exclusions atom exclusion indices exclusions[atomIndex][atomToExcludeIndex]
exclusions[atomIndex][0] = number of exclusions
exclusions[atomIndex][1-no.] = atom indices of atoms to excluded from
interacting w/ atom atomIndex
@param fixedParameters non atom parameters (not currently used)
@param forces force array (forces added)
@param energyByAtom atom energy
@param totalEnergy total energy
@return ReferenceForce::DefaultReturn
--------------------------------------------------------------------------------------- */
int ReferenceLJCoulombIxn::calculatePMEIxn( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** atomParameters, int** exclusions,
RealOpenMM* fixedParameters, RealOpenMM** forces,
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy) const {
RealOpenMM SQRT_PI = sqrt(PI);
static const RealOpenMM one = 1.0;
RealOpenMM selfEwaldEnergy = 0.0;
RealOpenMM realSpaceEwaldEnergy = 0.0;
RealOpenMM recipEnergy = 0.0;
// **************************************************************************************
// SELF ENERGY
// **************************************************************************************
for( int atomID = 0; atomID < numberOfAtoms; atomID++ ){
selfEwaldEnergy = selfEwaldEnergy + atomParameters[atomID][QIndex]*atomParameters[atomID][QIndex];
}
selfEwaldEnergy = selfEwaldEnergy * alphaEwald/SQRT_PI ;
// **************************************************************************************
// RECIPROCAL SPACE EWALD ENERGY AND FORCES
// **************************************************************************************
pme_t pmedata; /* abstract handle for PME data */
int ngrid[3];
RealOpenMM virial[3][3];
/* PME grid dimensions.
* We typically want to set this as the spacing rather than absolute dimensions, but
* to be able to reproduce results from other programs (e.g. Gromacs) we need to be
* able to set exact grid dimenisions occasionally.
*/
ngrid[0] = 16;
ngrid[1] = 16;
ngrid[2] = 16;
pme_init(&pmedata,alphaEwald,numberOfAtoms,ngrid,4,1);
pme_exec(pmedata,atomCoordinates,forces,atomParameters,periodicBoxSize,&recipEnergy,virial);
// **************************************************************************************
// SHORT-RANGE ENERGY AND FORCES
// **************************************************************************************
RealOpenMM deltaR[2][ReferenceForce::LastDeltaRIndex];
for( int atomID1 = 0; atomID1 < numberOfAtoms; atomID1++ ){ RealOpenMM dEdR = atomParameters[ii][QIndex] * atomParameters[jj][QIndex] * inverseR * inverseR * inverseR;
for( int atomID2 = atomID1 + 1; atomID2 < numberOfAtoms; atomID2++ ){ dEdR = (RealOpenMM)(dEdR * (erfc(alphaR) + 2 * alphaR * exp ( - alphaR * alphaR) / SQRT_PI ));
ReferenceForce::getDeltaRPeriodic( atomCoordinates[atomID2], atomCoordinates[atomID1], periodicBoxSize, deltaR[0] ); RealOpenMM sig = atomParameters[ii][SigIndex] + atomParameters[jj][SigIndex];
RealOpenMM r = deltaR[0][ReferenceForce::RIndex]; RealOpenMM sig2 = inverseR*sig;
RealOpenMM r2 = deltaR[0][ReferenceForce::R2Index]; sig2 *= sig2;
RealOpenMM inverseR = one/(deltaR[0][ReferenceForce::RIndex]); RealOpenMM sig6 = sig2*sig2*sig2;
RealOpenMM eps = atomParameters[ii][EpsIndex]*atomParameters[jj][EpsIndex];
realSpaceEwaldEnergy = dEdR += eps*( twelve*sig6 - six )*sig6;
(RealOpenMM)(realSpaceEwaldEnergy + atomParameters[atomID1][QIndex]*atomParameters[atomID2][QIndex]*inverseR*erfc(alphaEwald*r));
}
}
// allocate and initialize exclusion array // accumulate forces
vector<int> exclusionIndices(numberOfAtoms); for( int kk = 0; kk < 3; kk++ ){
for( int ii = 0; ii < numberOfAtoms; ii++ ){ RealOpenMM force = dEdR*deltaR[0][kk];
exclusionIndices[ii] = -1; forces[ii][kk] += force;
forces[jj][kk] -= force;
} }
for( int ii = 0; ii < numberOfAtoms; ii++ ){ // accumulate energies
// set exclusions realSpaceEwaldEnergy = atomParameters[ii][QIndex]*atomParameters[jj][QIndex]*inverseR*erfc(alphaR);
vdwEnergy = eps*(sig6-one)*sig6;
for( int jj = 1; jj <= exclusions[ii][0]; jj++ ){ if( totalEnergy )
exclusionIndices[exclusions[ii][jj]] = ii; *totalEnergy += realSpaceEwaldEnergy + vdwEnergy;
}
// loop over atom pairs
for( int jj = ii+1; jj < numberOfAtoms; jj++ ){
if( exclusionIndices[jj] != ii ){ if( energyByAtom ){
energyByAtom[ii] += realSpaceEwaldEnergy + vdwEnergy;
energyByAtom[jj] += realSpaceEwaldEnergy + vdwEnergy;
}
ReferenceForce::getDeltaRPeriodic( atomCoordinates[jj], atomCoordinates[ii], periodicBoxSize, deltaR[0] ); }
RealOpenMM r = deltaR[0][ReferenceForce::RIndex];
RealOpenMM r2 = deltaR[0][ReferenceForce::R2Index];
RealOpenMM inverseR = one/(deltaR[0][ReferenceForce::RIndex]);
RealOpenMM alphaR = alphaEwald * r;
realSpaceEwaldEnergy =
(RealOpenMM)(realSpaceEwaldEnergy + atomParameters[ii][QIndex]*atomParameters[jj][QIndex]*inverseR*erfc(alphaR));
RealOpenMM dEdR = atomParameters[ii][QIndex] * atomParameters[jj][QIndex] * inverseR * inverseR * inverseR;
dEdR = (RealOpenMM)(dEdR * (erfc(alphaR) + 2 * alphaR * exp ( - alphaR * alphaR) / SQRT_PI ));
for( int kk = 0; kk < 3; kk++ ){
RealOpenMM force = dEdR*deltaR[0][kk];
forces[ii][kk] += force;
forces[jj][kk] -= force;
}
}
}
}
// *********************************************************************** // ***********************************************************************
if( totalEnergy ) {
*totalEnergy += recipEnergy + realSpaceEwaldEnergy - selfEwaldEnergy;
}
return ReferenceForce::DefaultReturn; return ReferenceForce::DefaultReturn;
} }
...@@ -582,18 +483,16 @@ int ReferenceLJCoulombIxn::calculatePMEIxn( int numberOfAtoms, RealOpenMM** atom ...@@ -582,18 +483,16 @@ int ReferenceLJCoulombIxn::calculatePMEIxn( int numberOfAtoms, RealOpenMM** atom
@param totalEnergy total energy @param totalEnergy total energy
@return ReferenceForce::DefaultReturn @return ReferenceForce::DefaultReturn
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
int ReferenceLJCoulombIxn::calculatePairIxn( int numberOfAtoms, RealOpenMM** atomCoordinates, int ReferenceLJCoulombIxn::calculatePairIxn( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** atomParameters, int** exclusions, RealOpenMM** atomParameters, int** exclusions,
RealOpenMM* fixedParameters, RealOpenMM** forces, RealOpenMM* fixedParameters, RealOpenMM** forces,
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy ) const { RealOpenMM* energyByAtom, RealOpenMM* totalEnergy ) const {
if (ewald) if (ewald || pme)
return calculateEwaldIxn(numberOfAtoms, atomCoordinates, atomParameters, exclusions, fixedParameters, forces, energyByAtom, totalEnergy); return calculateEwaldIxn(numberOfAtoms, atomCoordinates, atomParameters, exclusions, fixedParameters, forces, energyByAtom, totalEnergy);
if (pme)
return calculatePMEIxn(numberOfAtoms, atomCoordinates, atomParameters, exclusions, fixedParameters, forces, energyByAtom, totalEnergy);
if (cutoff) { if (cutoff) {
for (int i = 0; i < (int) neighborList->size(); i++) { for (int i = 0; i < (int) neighborList->size(); i++) {
OpenMM::AtomPair pair = (*neighborList)[i]; OpenMM::AtomPair pair = (*neighborList)[i];
...@@ -681,9 +580,9 @@ int ReferenceLJCoulombIxn::calculateOneIxn( int ii, int jj, RealOpenMM** atomCoo ...@@ -681,9 +580,9 @@ int ReferenceLJCoulombIxn::calculateOneIxn( int ii, int jj, RealOpenMM** atomCoo
// get deltaR, R2, and R between 2 atoms // get deltaR, R2, and R between 2 atoms
if (periodic) if (periodic)
ReferenceForce::getDeltaRPeriodic( atomCoordinates[jj], atomCoordinates[ii], periodicBoxSize, deltaR[0] ); ReferenceForce::getDeltaRPeriodic( atomCoordinates[jj], atomCoordinates[ii], periodicBoxSize, deltaR[0] );
else else
ReferenceForce::getDeltaR( atomCoordinates[jj], atomCoordinates[ii], deltaR[0] ); ReferenceForce::getDeltaR( atomCoordinates[jj], atomCoordinates[ii], deltaR[0] );
RealOpenMM r2 = deltaR[0][ReferenceForce::R2Index]; RealOpenMM r2 = deltaR[0][ReferenceForce::R2Index];
RealOpenMM inverseR = one/(deltaR[0][ReferenceForce::RIndex]); RealOpenMM inverseR = one/(deltaR[0][ReferenceForce::RIndex]);
...@@ -699,7 +598,7 @@ int ReferenceLJCoulombIxn::calculateOneIxn( int ii, int jj, RealOpenMM** atomCoo ...@@ -699,7 +598,7 @@ int ReferenceLJCoulombIxn::calculateOneIxn( int ii, int jj, RealOpenMM** atomCoo
else else
dEdR += atomParameters[ii][QIndex]*atomParameters[jj][QIndex]*inverseR; dEdR += atomParameters[ii][QIndex]*atomParameters[jj][QIndex]*inverseR;
dEdR *= inverseR*inverseR; dEdR *= inverseR*inverseR;
// accumulate forces // accumulate forces
for( int kk = 0; kk < 3; kk++ ){ for( int kk = 0; kk < 3; kk++ ){
...@@ -726,7 +625,7 @@ int ReferenceLJCoulombIxn::calculateOneIxn( int ii, int jj, RealOpenMM** atomCoo ...@@ -726,7 +625,7 @@ int ReferenceLJCoulombIxn::calculateOneIxn( int ii, int jj, RealOpenMM** atomCoo
} }
} }
// debug // debug
if( debug == ii ){ if( debug == ii ){
static bool printHeader = false; static bool printHeader = false;
...@@ -734,11 +633,11 @@ int ReferenceLJCoulombIxn::calculateOneIxn( int ii, int jj, RealOpenMM** atomCoo ...@@ -734,11 +633,11 @@ int ReferenceLJCoulombIxn::calculateOneIxn( int ii, int jj, RealOpenMM** atomCoo
message << methodName; message << methodName;
message << std::endl; message << std::endl;
int pairArray[2] = { ii, jj }; int pairArray[2] = { ii, jj };
if( !printHeader ){ if( !printHeader ){
printHeader = true; printHeader = true;
message << std::endl; message << std::endl;
message << methodName.c_str() << " a0 k [c q p s] r1 r2 angle dt rp p[] dot cosine angle dEdR*r F[]" << std::endl; message << methodName.c_str() << " a0 k [c q p s] r1 r2 angle dt rp p[] dot cosine angle dEdR*r F[]" << std::endl;
} }
message << std::endl; message << std::endl;
for( int kk = 0; kk < 2; kk++ ){ for( int kk = 0; kk < 2; kk++ ){
......
...@@ -49,6 +49,41 @@ using namespace std; ...@@ -49,6 +49,41 @@ using namespace std;
const double TOL = 1e-5; const double TOL = 1e-5;
void testLargeSystem() {
ReferencePlatform platform;
System system;
for (int i = 0; i < 500; i++)
system.addParticle(22.99);
for (int i = 0; i < 500; i++)
system.addParticle(35.45);
VerletIntegrator integrator(0.01);
NonbondedForce* nonbonded = new NonbondedForce();
for (int i = 0; i < 500; i++)
nonbonded->addParticle(1.0, 1.0,0.0);
// nonbonded->addParticle(1.0, 0.33284,0.0115897);
for (int i = 0; i < 500; i++)
nonbonded->addParticle(-1.0, 1.0,0.0);
// nonbonded->addParticle(-1.0, 0.440104,0.4184);
nonbonded->setNonbondedMethod(NonbondedForce::PME);
const double cutoff = 1.0;
nonbonded->setCutoffDistance(cutoff);
nonbonded->setPeriodicBoxVectors(Vec3(2.82, 0, 0), Vec3(0, 2.82, 0), Vec3(0, 0, 2.82));
nonbonded->setEwaldErrorTolerance(TOL);
system.addForce(nonbonded);
Context context(system, integrator, platform);
vector<Vec3> positions(1000);
#include "nacl_crystal.dat"
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
// cout << "force 0: " << forces[0] << endl;
// cout << "force 1: " << forces[1] << endl;
cout << "PotentialEnergy: " << state.getPotentialEnergy() << endl;
ASSERT_EQUAL_TOL(-430355, state.getPotentialEnergy(), 100*TOL);
// ASSERT_EQUAL_VEC(Vec3(-123.711, 64.1877, -302.716), forces[0], 10*TOL);
// ASSERT_EQUAL_VEC(Vec3(123.711, -64.1877, 302.716), forces[1], 10*TOL);
}
void testEwald() { void testEwald() {
ReferencePlatform platform; ReferencePlatform platform;
System system; System system;
...@@ -58,6 +93,9 @@ void testEwald() { ...@@ -58,6 +93,9 @@ void testEwald() {
NonbondedForce* nonbonded = new NonbondedForce(); NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->addParticle(1.0, 1, 0); nonbonded->addParticle(1.0, 1, 0);
nonbonded->addParticle(-1.0, 1, 0); nonbonded->addParticle(-1.0, 1, 0);
// Sodium Chloride
// nonbonded->addParticle(1.0, 0.33284,0.0115897);
// nonbonded->addParticle(-1.0, 0.440104,0.4184);
nonbonded->setNonbondedMethod(NonbondedForce::Ewald); nonbonded->setNonbondedMethod(NonbondedForce::Ewald);
const double cutoff = 2.0; const double cutoff = 2.0;
nonbonded->setCutoffDistance(cutoff); nonbonded->setCutoffDistance(cutoff);
...@@ -71,9 +109,9 @@ void testEwald() { ...@@ -71,9 +109,9 @@ void testEwald() {
context.setPositions(positions); context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy); State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces(); const vector<Vec3>& forces = state.getForces();
cout << "force 0: " << forces[0] << endl; // cout << "force 0: " << forces[0] << endl;
cout << "force 1: " << forces[1] << endl; // cout << "force 1: " << forces[1] << endl;
cout << "PotentialEnergy: " << state.getPotentialEnergy() << endl; // cout << "PotentialEnergy: " << state.getPotentialEnergy() << endl;
ASSERT_EQUAL_VEC(Vec3(-123.711, 64.1877, -302.716), forces[0], 10*TOL); ASSERT_EQUAL_VEC(Vec3(-123.711, 64.1877, -302.716), forces[0], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(123.711, -64.1877, 302.716), forces[1], 10*TOL); ASSERT_EQUAL_VEC(Vec3(123.711, -64.1877, 302.716), forces[1], 10*TOL);
} }
...@@ -101,48 +139,7 @@ void testPME() { ...@@ -101,48 +139,7 @@ void testPME() {
system.addForce(nonbonded); system.addForce(nonbonded);
Context context(system, integrator, platform); Context context(system, integrator, platform);
vector<Vec3> positions(42); vector<Vec3> positions(42);
positions[0] = Vec3( 0.23,0.628,0.113); #include "water.dat"
positions[1] = Vec3(0.137,0.626, 0.15);
positions[2] = Vec3(0.231,0.589,0.021);
positions[3] = Vec3(-0.307,-0.351,0.703);
positions[4] = Vec3(-0.364,-0.367,0.784);
positions[5] = Vec3(-0.366,-0.341,0.623);
positions[6] = Vec3(-0.569,-0.634,-0.439);
positions[7] = Vec3(-0.532,-0.707,-0.497);
positions[8] = Vec3(-0.517,-0.629,-0.354);
positions[9] = Vec3(-0.871, 0.41,-0.62);
positions[10] = Vec3(-0.948,0.444,-0.566);
positions[11] = Vec3(-0.905,0.359,-0.699);
positions[12] = Vec3(0.249,-0.077,-0.621);
positions[13] = Vec3(0.306,-0.142,-0.571);
positions[14] = Vec3(0.233,-0.11,-0.714);
positions[15] = Vec3(0.561,0.222,-0.715);
positions[16] = Vec3(0.599,0.138,-0.678);
positions[17] = Vec3(0.473,0.241,-0.671);
positions[18] = Vec3(-0.515,-0.803,-0.628);
positions[19] = Vec3(-0.491,-0.866,-0.702);
positions[20] = Vec3(-0.605,-0.763,-0.646);
positions[21] = Vec3(-0.021,0.175,-0.899);
positions[22] = Vec3(0.018, 0.09,-0.935);
positions[23] = Vec3(-0.119,0.177,-0.918);
positions[24] = Vec3(-0.422,0.856,-0.464);
positions[25] = Vec3(-0.479,0.908,-0.527);
positions[26] = Vec3(-0.326,0.868,-0.488);
positions[27] = Vec3(-0.369,-0.095,-0.903);
positions[28] = Vec3(-0.336,-0.031,-0.972);
positions[29] = Vec3(-0.303,-0.101,-0.828);
positions[30] = Vec3(0.594,0.745,0.652);
positions[31] = Vec3(0.644, 0.83,0.633);
positions[32] = Vec3(0.506,0.747,0.604);
positions[33] = Vec3(-0.157,-0.375,-0.758);
positions[34] = Vec3(-0.25, -0.4,-0.785);
positions[35] = Vec3(-0.131,-0.425,-0.676);
positions[36] = Vec3(0.618,-0.295,-0.578);
positions[37] = Vec3(0.613,-0.213,-0.521);
positions[38] = Vec3(0.707,-0.298,-0.623);
positions[39] = Vec3(0.039,-0.785, 0.3);
positions[40] = Vec3(0.138,-0.796,0.291);
positions[41] = Vec3(-0.001,-0.871,0.332);
context.setPositions(positions); context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy); State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces(); const vector<Vec3>& forces = state.getForces();
...@@ -156,8 +153,9 @@ positions[41] = Vec3(-0.001,-0.871,0.332); ...@@ -156,8 +153,9 @@ positions[41] = Vec3(-0.001,-0.871,0.332);
int main() { int main() {
try { try {
testEwald(); testLargeSystem();
testPME(); testEwald();
testPME();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
positions[0] = Vec3(0.141000,0.141000,0.141000);
positions[1] = Vec3(0.141000,0.141000,0.705000);
positions[2] = Vec3(0.141000,0.141000,1.269000);
positions[3] = Vec3(0.141000,0.141000,1.833000);
positions[4] = Vec3(0.141000,0.141000,2.397000);
positions[5] = Vec3(0.141000,0.423000,0.423000);
positions[6] = Vec3(0.141000,0.423000,0.987000);
positions[7] = Vec3(0.141000,0.423000,1.551000);
positions[8] = Vec3(0.141000,0.423000,2.115000);
positions[9] = Vec3(0.141000,0.423000,2.679000);
positions[10] = Vec3(0.141000,0.705000,0.141000);
positions[11] = Vec3(0.141000,0.705000,0.705000);
positions[12] = Vec3(0.141000,0.705000,1.269000);
positions[13] = Vec3(0.141000,0.705000,1.833000);
positions[14] = Vec3(0.141000,0.705000,2.397000);
positions[15] = Vec3(0.141000,0.987000,0.423000);
positions[16] = Vec3(0.141000,0.987000,0.987000);
positions[17] = Vec3(0.141000,0.987000,1.551000);
positions[18] = Vec3(0.141000,0.987000,2.115000);
positions[19] = Vec3(0.141000,0.987000,2.679000);
positions[20] = Vec3(0.141000,1.269000,0.141000);
positions[21] = Vec3(0.141000,1.269000,0.705000);
positions[22] = Vec3(0.141000,1.269000,1.269000);
positions[23] = Vec3(0.141000,1.269000,1.833000);
positions[24] = Vec3(0.141000,1.269000,2.397000);
positions[25] = Vec3(0.141000,1.551000,0.423000);
positions[26] = Vec3(0.141000,1.551000,0.987000);
positions[27] = Vec3(0.141000,1.551000,1.551000);
positions[28] = Vec3(0.141000,1.551000,2.115000);
positions[29] = Vec3(0.141000,1.551000,2.679000);
positions[30] = Vec3(0.141000,1.833000,0.141000);
positions[31] = Vec3(0.141000,1.833000,0.705000);
positions[32] = Vec3(0.141000,1.833000,1.269000);
positions[33] = Vec3(0.141000,1.833000,1.833000);
positions[34] = Vec3(0.141000,1.833000,2.397000);
positions[35] = Vec3(0.141000,2.115000,0.423000);
positions[36] = Vec3(0.141000,2.115000,0.987000);
positions[37] = Vec3(0.141000,2.115000,1.551000);
positions[38] = Vec3(0.141000,2.115000,2.115000);
positions[39] = Vec3(0.141000,2.115000,2.679000);
positions[40] = Vec3(0.141000,2.397000,0.141000);
positions[41] = Vec3(0.141000,2.397000,0.705000);
positions[42] = Vec3(0.141000,2.397000,1.269000);
positions[43] = Vec3(0.141000,2.397000,1.833000);
positions[44] = Vec3(0.141000,2.397000,2.397000);
positions[45] = Vec3(0.141000,2.679000,0.423000);
positions[46] = Vec3(0.141000,2.679000,0.987000);
positions[47] = Vec3(0.141000,2.679000,1.551000);
positions[48] = Vec3(0.141000,2.679000,2.115000);
positions[49] = Vec3(0.141000,2.679000,2.679000);
positions[50] = Vec3(0.423000,0.141000,0.423000);
positions[51] = Vec3(0.423000,0.141000,0.987000);
positions[52] = Vec3(0.423000,0.141000,1.551000);
positions[53] = Vec3(0.423000,0.141000,2.115000);
positions[54] = Vec3(0.423000,0.141000,2.679000);
positions[55] = Vec3(0.423000,0.423000,0.141000);
positions[56] = Vec3(0.423000,0.423000,0.705000);
positions[57] = Vec3(0.423000,0.423000,1.269000);
positions[58] = Vec3(0.423000,0.423000,1.833000);
positions[59] = Vec3(0.423000,0.423000,2.397000);
positions[60] = Vec3(0.423000,0.705000,0.423000);
positions[61] = Vec3(0.423000,0.705000,0.987000);
positions[62] = Vec3(0.423000,0.705000,1.551000);
positions[63] = Vec3(0.423000,0.705000,2.115000);
positions[64] = Vec3(0.423000,0.705000,2.679000);
positions[65] = Vec3(0.423000,0.987000,0.141000);
positions[66] = Vec3(0.423000,0.987000,0.705000);
positions[67] = Vec3(0.423000,0.987000,1.269000);
positions[68] = Vec3(0.423000,0.987000,1.833000);
positions[69] = Vec3(0.423000,0.987000,2.397000);
positions[70] = Vec3(0.423000,1.269000,0.423000);
positions[71] = Vec3(0.423000,1.269000,0.987000);
positions[72] = Vec3(0.423000,1.269000,1.551000);
positions[73] = Vec3(0.423000,1.269000,2.115000);
positions[74] = Vec3(0.423000,1.269000,2.679000);
positions[75] = Vec3(0.423000,1.551000,0.141000);
positions[76] = Vec3(0.423000,1.551000,0.705000);
positions[77] = Vec3(0.423000,1.551000,1.269000);
positions[78] = Vec3(0.423000,1.551000,1.833000);
positions[79] = Vec3(0.423000,1.551000,2.397000);
positions[80] = Vec3(0.423000,1.833000,0.423000);
positions[81] = Vec3(0.423000,1.833000,0.987000);
positions[82] = Vec3(0.423000,1.833000,1.551000);
positions[83] = Vec3(0.423000,1.833000,2.115000);
positions[84] = Vec3(0.423000,1.833000,2.679000);
positions[85] = Vec3(0.423000,2.115000,0.141000);
positions[86] = Vec3(0.423000,2.115000,0.705000);
positions[87] = Vec3(0.423000,2.115000,1.269000);
positions[88] = Vec3(0.423000,2.115000,1.833000);
positions[89] = Vec3(0.423000,2.115000,2.397000);
positions[90] = Vec3(0.423000,2.397000,0.423000);
positions[91] = Vec3(0.423000,2.397000,0.987000);
positions[92] = Vec3(0.423000,2.397000,1.551000);
positions[93] = Vec3(0.423000,2.397000,2.115000);
positions[94] = Vec3(0.423000,2.397000,2.679000);
positions[95] = Vec3(0.423000,2.679000,0.141000);
positions[96] = Vec3(0.423000,2.679000,0.705000);
positions[97] = Vec3(0.423000,2.679000,1.269000);
positions[98] = Vec3(0.423000,2.679000,1.833000);
positions[99] = Vec3(0.423000,2.679000,2.397000);
positions[100] = Vec3(0.705000,0.141000,0.141000);
positions[101] = Vec3(0.705000,0.141000,0.705000);
positions[102] = Vec3(0.705000,0.141000,1.269000);
positions[103] = Vec3(0.705000,0.141000,1.833000);
positions[104] = Vec3(0.705000,0.141000,2.397000);
positions[105] = Vec3(0.705000,0.423000,0.423000);
positions[106] = Vec3(0.705000,0.423000,0.987000);
positions[107] = Vec3(0.705000,0.423000,1.551000);
positions[108] = Vec3(0.705000,0.423000,2.115000);
positions[109] = Vec3(0.705000,0.423000,2.679000);
positions[110] = Vec3(0.705000,0.705000,0.141000);
positions[111] = Vec3(0.705000,0.705000,0.705000);
positions[112] = Vec3(0.705000,0.705000,1.269000);
positions[113] = Vec3(0.705000,0.705000,1.833000);
positions[114] = Vec3(0.705000,0.705000,2.397000);
positions[115] = Vec3(0.705000,0.987000,0.423000);
positions[116] = Vec3(0.705000,0.987000,0.987000);
positions[117] = Vec3(0.705000,0.987000,1.551000);
positions[118] = Vec3(0.705000,0.987000,2.115000);
positions[119] = Vec3(0.705000,0.987000,2.679000);
positions[120] = Vec3(0.705000,1.269000,0.141000);
positions[121] = Vec3(0.705000,1.269000,0.705000);
positions[122] = Vec3(0.705000,1.269000,1.269000);
positions[123] = Vec3(0.705000,1.269000,1.833000);
positions[124] = Vec3(0.705000,1.269000,2.397000);
positions[125] = Vec3(0.705000,1.551000,0.423000);
positions[126] = Vec3(0.705000,1.551000,0.987000);
positions[127] = Vec3(0.705000,1.551000,1.551000);
positions[128] = Vec3(0.705000,1.551000,2.115000);
positions[129] = Vec3(0.705000,1.551000,2.679000);
positions[130] = Vec3(0.705000,1.833000,0.141000);
positions[131] = Vec3(0.705000,1.833000,0.705000);
positions[132] = Vec3(0.705000,1.833000,1.269000);
positions[133] = Vec3(0.705000,1.833000,1.833000);
positions[134] = Vec3(0.705000,1.833000,2.397000);
positions[135] = Vec3(0.705000,2.115000,0.423000);
positions[136] = Vec3(0.705000,2.115000,0.987000);
positions[137] = Vec3(0.705000,2.115000,1.551000);
positions[138] = Vec3(0.705000,2.115000,2.115000);
positions[139] = Vec3(0.705000,2.115000,2.679000);
positions[140] = Vec3(0.705000,2.397000,0.141000);
positions[141] = Vec3(0.705000,2.397000,0.705000);
positions[142] = Vec3(0.705000,2.397000,1.269000);
positions[143] = Vec3(0.705000,2.397000,1.833000);
positions[144] = Vec3(0.705000,2.397000,2.397000);
positions[145] = Vec3(0.705000,2.679000,0.423000);
positions[146] = Vec3(0.705000,2.679000,0.987000);
positions[147] = Vec3(0.705000,2.679000,1.551000);
positions[148] = Vec3(0.705000,2.679000,2.115000);
positions[149] = Vec3(0.705000,2.679000,2.679000);
positions[150] = Vec3(0.987000,0.141000,0.423000);
positions[151] = Vec3(0.987000,0.141000,0.987000);
positions[152] = Vec3(0.987000,0.141000,1.551000);
positions[153] = Vec3(0.987000,0.141000,2.115000);
positions[154] = Vec3(0.987000,0.141000,2.679000);
positions[155] = Vec3(0.987000,0.423000,0.141000);
positions[156] = Vec3(0.987000,0.423000,0.705000);
positions[157] = Vec3(0.987000,0.423000,1.269000);
positions[158] = Vec3(0.987000,0.423000,1.833000);
positions[159] = Vec3(0.987000,0.423000,2.397000);
positions[160] = Vec3(0.987000,0.705000,0.423000);
positions[161] = Vec3(0.987000,0.705000,0.987000);
positions[162] = Vec3(0.987000,0.705000,1.551000);
positions[163] = Vec3(0.987000,0.705000,2.115000);
positions[164] = Vec3(0.987000,0.705000,2.679000);
positions[165] = Vec3(0.987000,0.987000,0.141000);
positions[166] = Vec3(0.987000,0.987000,0.705000);
positions[167] = Vec3(0.987000,0.987000,1.269000);
positions[168] = Vec3(0.987000,0.987000,1.833000);
positions[169] = Vec3(0.987000,0.987000,2.397000);
positions[170] = Vec3(0.987000,1.269000,0.423000);
positions[171] = Vec3(0.987000,1.269000,0.987000);
positions[172] = Vec3(0.987000,1.269000,1.551000);
positions[173] = Vec3(0.987000,1.269000,2.115000);
positions[174] = Vec3(0.987000,1.269000,2.679000);
positions[175] = Vec3(0.987000,1.551000,0.141000);
positions[176] = Vec3(0.987000,1.551000,0.705000);
positions[177] = Vec3(0.987000,1.551000,1.269000);
positions[178] = Vec3(0.987000,1.551000,1.833000);
positions[179] = Vec3(0.987000,1.551000,2.397000);
positions[180] = Vec3(0.987000,1.833000,0.423000);
positions[181] = Vec3(0.987000,1.833000,0.987000);
positions[182] = Vec3(0.987000,1.833000,1.551000);
positions[183] = Vec3(0.987000,1.833000,2.115000);
positions[184] = Vec3(0.987000,1.833000,2.679000);
positions[185] = Vec3(0.987000,2.115000,0.141000);
positions[186] = Vec3(0.987000,2.115000,0.705000);
positions[187] = Vec3(0.987000,2.115000,1.269000);
positions[188] = Vec3(0.987000,2.115000,1.833000);
positions[189] = Vec3(0.987000,2.115000,2.397000);
positions[190] = Vec3(0.987000,2.397000,0.423000);
positions[191] = Vec3(0.987000,2.397000,0.987000);
positions[192] = Vec3(0.987000,2.397000,1.551000);
positions[193] = Vec3(0.987000,2.397000,2.115000);
positions[194] = Vec3(0.987000,2.397000,2.679000);
positions[195] = Vec3(0.987000,2.679000,0.141000);
positions[196] = Vec3(0.987000,2.679000,0.705000);
positions[197] = Vec3(0.987000,2.679000,1.269000);
positions[198] = Vec3(0.987000,2.679000,1.833000);
positions[199] = Vec3(0.987000,2.679000,2.397000);
positions[200] = Vec3(1.269000,0.141000,0.141000);
positions[201] = Vec3(1.269000,0.141000,0.705000);
positions[202] = Vec3(1.269000,0.141000,1.269000);
positions[203] = Vec3(1.269000,0.141000,1.833000);
positions[204] = Vec3(1.269000,0.141000,2.397000);
positions[205] = Vec3(1.269000,0.423000,0.423000);
positions[206] = Vec3(1.269000,0.423000,0.987000);
positions[207] = Vec3(1.269000,0.423000,1.551000);
positions[208] = Vec3(1.269000,0.423000,2.115000);
positions[209] = Vec3(1.269000,0.423000,2.679000);
positions[210] = Vec3(1.269000,0.705000,0.141000);
positions[211] = Vec3(1.269000,0.705000,0.705000);
positions[212] = Vec3(1.269000,0.705000,1.269000);
positions[213] = Vec3(1.269000,0.705000,1.833000);
positions[214] = Vec3(1.269000,0.705000,2.397000);
positions[215] = Vec3(1.269000,0.987000,0.423000);
positions[216] = Vec3(1.269000,0.987000,0.987000);
positions[217] = Vec3(1.269000,0.987000,1.551000);
positions[218] = Vec3(1.269000,0.987000,2.115000);
positions[219] = Vec3(1.269000,0.987000,2.679000);
positions[220] = Vec3(1.269000,1.269000,0.141000);
positions[221] = Vec3(1.269000,1.269000,0.705000);
positions[222] = Vec3(1.269000,1.269000,1.269000);
positions[223] = Vec3(1.269000,1.269000,1.833000);
positions[224] = Vec3(1.269000,1.269000,2.397000);
positions[225] = Vec3(1.269000,1.551000,0.423000);
positions[226] = Vec3(1.269000,1.551000,0.987000);
positions[227] = Vec3(1.269000,1.551000,1.551000);
positions[228] = Vec3(1.269000,1.551000,2.115000);
positions[229] = Vec3(1.269000,1.551000,2.679000);
positions[230] = Vec3(1.269000,1.833000,0.141000);
positions[231] = Vec3(1.269000,1.833000,0.705000);
positions[232] = Vec3(1.269000,1.833000,1.269000);
positions[233] = Vec3(1.269000,1.833000,1.833000);
positions[234] = Vec3(1.269000,1.833000,2.397000);
positions[235] = Vec3(1.269000,2.115000,0.423000);
positions[236] = Vec3(1.269000,2.115000,0.987000);
positions[237] = Vec3(1.269000,2.115000,1.551000);
positions[238] = Vec3(1.269000,2.115000,2.115000);
positions[239] = Vec3(1.269000,2.115000,2.679000);
positions[240] = Vec3(1.269000,2.397000,0.141000);
positions[241] = Vec3(1.269000,2.397000,0.705000);
positions[242] = Vec3(1.269000,2.397000,1.269000);
positions[243] = Vec3(1.269000,2.397000,1.833000);
positions[244] = Vec3(1.269000,2.397000,2.397000);
positions[245] = Vec3(1.269000,2.679000,0.423000);
positions[246] = Vec3(1.269000,2.679000,0.987000);
positions[247] = Vec3(1.269000,2.679000,1.551000);
positions[248] = Vec3(1.269000,2.679000,2.115000);
positions[249] = Vec3(1.269000,2.679000,2.679000);
positions[250] = Vec3(1.551000,0.141000,0.423000);
positions[251] = Vec3(1.551000,0.141000,0.987000);
positions[252] = Vec3(1.551000,0.141000,1.551000);
positions[253] = Vec3(1.551000,0.141000,2.115000);
positions[254] = Vec3(1.551000,0.141000,2.679000);
positions[255] = Vec3(1.551000,0.423000,0.141000);
positions[256] = Vec3(1.551000,0.423000,0.705000);
positions[257] = Vec3(1.551000,0.423000,1.269000);
positions[258] = Vec3(1.551000,0.423000,1.833000);
positions[259] = Vec3(1.551000,0.423000,2.397000);
positions[260] = Vec3(1.551000,0.705000,0.423000);
positions[261] = Vec3(1.551000,0.705000,0.987000);
positions[262] = Vec3(1.551000,0.705000,1.551000);
positions[263] = Vec3(1.551000,0.705000,2.115000);
positions[264] = Vec3(1.551000,0.705000,2.679000);
positions[265] = Vec3(1.551000,0.987000,0.141000);
positions[266] = Vec3(1.551000,0.987000,0.705000);
positions[267] = Vec3(1.551000,0.987000,1.269000);
positions[268] = Vec3(1.551000,0.987000,1.833000);
positions[269] = Vec3(1.551000,0.987000,2.397000);
positions[270] = Vec3(1.551000,1.269000,0.423000);
positions[271] = Vec3(1.551000,1.269000,0.987000);
positions[272] = Vec3(1.551000,1.269000,1.551000);
positions[273] = Vec3(1.551000,1.269000,2.115000);
positions[274] = Vec3(1.551000,1.269000,2.679000);
positions[275] = Vec3(1.551000,1.551000,0.141000);
positions[276] = Vec3(1.551000,1.551000,0.705000);
positions[277] = Vec3(1.551000,1.551000,1.269000);
positions[278] = Vec3(1.551000,1.551000,1.833000);
positions[279] = Vec3(1.551000,1.551000,2.397000);
positions[280] = Vec3(1.551000,1.833000,0.423000);
positions[281] = Vec3(1.551000,1.833000,0.987000);
positions[282] = Vec3(1.551000,1.833000,1.551000);
positions[283] = Vec3(1.551000,1.833000,2.115000);
positions[284] = Vec3(1.551000,1.833000,2.679000);
positions[285] = Vec3(1.551000,2.115000,0.141000);
positions[286] = Vec3(1.551000,2.115000,0.705000);
positions[287] = Vec3(1.551000,2.115000,1.269000);
positions[288] = Vec3(1.551000,2.115000,1.833000);
positions[289] = Vec3(1.551000,2.115000,2.397000);
positions[290] = Vec3(1.551000,2.397000,0.423000);
positions[291] = Vec3(1.551000,2.397000,0.987000);
positions[292] = Vec3(1.551000,2.397000,1.551000);
positions[293] = Vec3(1.551000,2.397000,2.115000);
positions[294] = Vec3(1.551000,2.397000,2.679000);
positions[295] = Vec3(1.551000,2.679000,0.141000);
positions[296] = Vec3(1.551000,2.679000,0.705000);
positions[297] = Vec3(1.551000,2.679000,1.269000);
positions[298] = Vec3(1.551000,2.679000,1.833000);
positions[299] = Vec3(1.551000,2.679000,2.397000);
positions[300] = Vec3(1.833000,0.141000,0.141000);
positions[301] = Vec3(1.833000,0.141000,0.705000);
positions[302] = Vec3(1.833000,0.141000,1.269000);
positions[303] = Vec3(1.833000,0.141000,1.833000);
positions[304] = Vec3(1.833000,0.141000,2.397000);
positions[305] = Vec3(1.833000,0.423000,0.423000);
positions[306] = Vec3(1.833000,0.423000,0.987000);
positions[307] = Vec3(1.833000,0.423000,1.551000);
positions[308] = Vec3(1.833000,0.423000,2.115000);
positions[309] = Vec3(1.833000,0.423000,2.679000);
positions[310] = Vec3(1.833000,0.705000,0.141000);
positions[311] = Vec3(1.833000,0.705000,0.705000);
positions[312] = Vec3(1.833000,0.705000,1.269000);
positions[313] = Vec3(1.833000,0.705000,1.833000);
positions[314] = Vec3(1.833000,0.705000,2.397000);
positions[315] = Vec3(1.833000,0.987000,0.423000);
positions[316] = Vec3(1.833000,0.987000,0.987000);
positions[317] = Vec3(1.833000,0.987000,1.551000);
positions[318] = Vec3(1.833000,0.987000,2.115000);
positions[319] = Vec3(1.833000,0.987000,2.679000);
positions[320] = Vec3(1.833000,1.269000,0.141000);
positions[321] = Vec3(1.833000,1.269000,0.705000);
positions[322] = Vec3(1.833000,1.269000,1.269000);
positions[323] = Vec3(1.833000,1.269000,1.833000);
positions[324] = Vec3(1.833000,1.269000,2.397000);
positions[325] = Vec3(1.833000,1.551000,0.423000);
positions[326] = Vec3(1.833000,1.551000,0.987000);
positions[327] = Vec3(1.833000,1.551000,1.551000);
positions[328] = Vec3(1.833000,1.551000,2.115000);
positions[329] = Vec3(1.833000,1.551000,2.679000);
positions[330] = Vec3(1.833000,1.833000,0.141000);
positions[331] = Vec3(1.833000,1.833000,0.705000);
positions[332] = Vec3(1.833000,1.833000,1.269000);
positions[333] = Vec3(1.833000,1.833000,1.833000);
positions[334] = Vec3(1.833000,1.833000,2.397000);
positions[335] = Vec3(1.833000,2.115000,0.423000);
positions[336] = Vec3(1.833000,2.115000,0.987000);
positions[337] = Vec3(1.833000,2.115000,1.551000);
positions[338] = Vec3(1.833000,2.115000,2.115000);
positions[339] = Vec3(1.833000,2.115000,2.679000);
positions[340] = Vec3(1.833000,2.397000,0.141000);
positions[341] = Vec3(1.833000,2.397000,0.705000);
positions[342] = Vec3(1.833000,2.397000,1.269000);
positions[343] = Vec3(1.833000,2.397000,1.833000);
positions[344] = Vec3(1.833000,2.397000,2.397000);
positions[345] = Vec3(1.833000,2.679000,0.423000);
positions[346] = Vec3(1.833000,2.679000,0.987000);
positions[347] = Vec3(1.833000,2.679000,1.551000);
positions[348] = Vec3(1.833000,2.679000,2.115000);
positions[349] = Vec3(1.833000,2.679000,2.679000);
positions[350] = Vec3(2.115000,0.141000,0.423000);
positions[351] = Vec3(2.115000,0.141000,0.987000);
positions[352] = Vec3(2.115000,0.141000,1.551000);
positions[353] = Vec3(2.115000,0.141000,2.115000);
positions[354] = Vec3(2.115000,0.141000,2.679000);
positions[355] = Vec3(2.115000,0.423000,0.141000);
positions[356] = Vec3(2.115000,0.423000,0.705000);
positions[357] = Vec3(2.115000,0.423000,1.269000);
positions[358] = Vec3(2.115000,0.423000,1.833000);
positions[359] = Vec3(2.115000,0.423000,2.397000);
positions[360] = Vec3(2.115000,0.705000,0.423000);
positions[361] = Vec3(2.115000,0.705000,0.987000);
positions[362] = Vec3(2.115000,0.705000,1.551000);
positions[363] = Vec3(2.115000,0.705000,2.115000);
positions[364] = Vec3(2.115000,0.705000,2.679000);
positions[365] = Vec3(2.115000,0.987000,0.141000);
positions[366] = Vec3(2.115000,0.987000,0.705000);
positions[367] = Vec3(2.115000,0.987000,1.269000);
positions[368] = Vec3(2.115000,0.987000,1.833000);
positions[369] = Vec3(2.115000,0.987000,2.397000);
positions[370] = Vec3(2.115000,1.269000,0.423000);
positions[371] = Vec3(2.115000,1.269000,0.987000);
positions[372] = Vec3(2.115000,1.269000,1.551000);
positions[373] = Vec3(2.115000,1.269000,2.115000);
positions[374] = Vec3(2.115000,1.269000,2.679000);
positions[375] = Vec3(2.115000,1.551000,0.141000);
positions[376] = Vec3(2.115000,1.551000,0.705000);
positions[377] = Vec3(2.115000,1.551000,1.269000);
positions[378] = Vec3(2.115000,1.551000,1.833000);
positions[379] = Vec3(2.115000,1.551000,2.397000);
positions[380] = Vec3(2.115000,1.833000,0.423000);
positions[381] = Vec3(2.115000,1.833000,0.987000);
positions[382] = Vec3(2.115000,1.833000,1.551000);
positions[383] = Vec3(2.115000,1.833000,2.115000);
positions[384] = Vec3(2.115000,1.833000,2.679000);
positions[385] = Vec3(2.115000,2.115000,0.141000);
positions[386] = Vec3(2.115000,2.115000,0.705000);
positions[387] = Vec3(2.115000,2.115000,1.269000);
positions[388] = Vec3(2.115000,2.115000,1.833000);
positions[389] = Vec3(2.115000,2.115000,2.397000);
positions[390] = Vec3(2.115000,2.397000,0.423000);
positions[391] = Vec3(2.115000,2.397000,0.987000);
positions[392] = Vec3(2.115000,2.397000,1.551000);
positions[393] = Vec3(2.115000,2.397000,2.115000);
positions[394] = Vec3(2.115000,2.397000,2.679000);
positions[395] = Vec3(2.115000,2.679000,0.141000);
positions[396] = Vec3(2.115000,2.679000,0.705000);
positions[397] = Vec3(2.115000,2.679000,1.269000);
positions[398] = Vec3(2.115000,2.679000,1.833000);
positions[399] = Vec3(2.115000,2.679000,2.397000);
positions[400] = Vec3(2.397000,0.141000,0.141000);
positions[401] = Vec3(2.397000,0.141000,0.705000);
positions[402] = Vec3(2.397000,0.141000,1.269000);
positions[403] = Vec3(2.397000,0.141000,1.833000);
positions[404] = Vec3(2.397000,0.141000,2.397000);
positions[405] = Vec3(2.397000,0.423000,0.423000);
positions[406] = Vec3(2.397000,0.423000,0.987000);
positions[407] = Vec3(2.397000,0.423000,1.551000);
positions[408] = Vec3(2.397000,0.423000,2.115000);
positions[409] = Vec3(2.397000,0.423000,2.679000);
positions[410] = Vec3(2.397000,0.705000,0.141000);
positions[411] = Vec3(2.397000,0.705000,0.705000);
positions[412] = Vec3(2.397000,0.705000,1.269000);
positions[413] = Vec3(2.397000,0.705000,1.833000);
positions[414] = Vec3(2.397000,0.705000,2.397000);
positions[415] = Vec3(2.397000,0.987000,0.423000);
positions[416] = Vec3(2.397000,0.987000,0.987000);
positions[417] = Vec3(2.397000,0.987000,1.551000);
positions[418] = Vec3(2.397000,0.987000,2.115000);
positions[419] = Vec3(2.397000,0.987000,2.679000);
positions[420] = Vec3(2.397000,1.269000,0.141000);
positions[421] = Vec3(2.397000,1.269000,0.705000);
positions[422] = Vec3(2.397000,1.269000,1.269000);
positions[423] = Vec3(2.397000,1.269000,1.833000);
positions[424] = Vec3(2.397000,1.269000,2.397000);
positions[425] = Vec3(2.397000,1.551000,0.423000);
positions[426] = Vec3(2.397000,1.551000,0.987000);
positions[427] = Vec3(2.397000,1.551000,1.551000);
positions[428] = Vec3(2.397000,1.551000,2.115000);
positions[429] = Vec3(2.397000,1.551000,2.679000);
positions[430] = Vec3(2.397000,1.833000,0.141000);
positions[431] = Vec3(2.397000,1.833000,0.705000);
positions[432] = Vec3(2.397000,1.833000,1.269000);
positions[433] = Vec3(2.397000,1.833000,1.833000);
positions[434] = Vec3(2.397000,1.833000,2.397000);
positions[435] = Vec3(2.397000,2.115000,0.423000);
positions[436] = Vec3(2.397000,2.115000,0.987000);
positions[437] = Vec3(2.397000,2.115000,1.551000);
positions[438] = Vec3(2.397000,2.115000,2.115000);
positions[439] = Vec3(2.397000,2.115000,2.679000);
positions[440] = Vec3(2.397000,2.397000,0.141000);
positions[441] = Vec3(2.397000,2.397000,0.705000);
positions[442] = Vec3(2.397000,2.397000,1.269000);
positions[443] = Vec3(2.397000,2.397000,1.833000);
positions[444] = Vec3(2.397000,2.397000,2.397000);
positions[445] = Vec3(2.397000,2.679000,0.423000);
positions[446] = Vec3(2.397000,2.679000,0.987000);
positions[447] = Vec3(2.397000,2.679000,1.551000);
positions[448] = Vec3(2.397000,2.679000,2.115000);
positions[449] = Vec3(2.397000,2.679000,2.679000);
positions[450] = Vec3(2.679000,0.141000,0.423000);
positions[451] = Vec3(2.679000,0.141000,0.987000);
positions[452] = Vec3(2.679000,0.141000,1.551000);
positions[453] = Vec3(2.679000,0.141000,2.115000);
positions[454] = Vec3(2.679000,0.141000,2.679000);
positions[455] = Vec3(2.679000,0.423000,0.141000);
positions[456] = Vec3(2.679000,0.423000,0.705000);
positions[457] = Vec3(2.679000,0.423000,1.269000);
positions[458] = Vec3(2.679000,0.423000,1.833000);
positions[459] = Vec3(2.679000,0.423000,2.397000);
positions[460] = Vec3(2.679000,0.705000,0.423000);
positions[461] = Vec3(2.679000,0.705000,0.987000);
positions[462] = Vec3(2.679000,0.705000,1.551000);
positions[463] = Vec3(2.679000,0.705000,2.115000);
positions[464] = Vec3(2.679000,0.705000,2.679000);
positions[465] = Vec3(2.679000,0.987000,0.141000);
positions[466] = Vec3(2.679000,0.987000,0.705000);
positions[467] = Vec3(2.679000,0.987000,1.269000);
positions[468] = Vec3(2.679000,0.987000,1.833000);
positions[469] = Vec3(2.679000,0.987000,2.397000);
positions[470] = Vec3(2.679000,1.269000,0.423000);
positions[471] = Vec3(2.679000,1.269000,0.987000);
positions[472] = Vec3(2.679000,1.269000,1.551000);
positions[473] = Vec3(2.679000,1.269000,2.115000);
positions[474] = Vec3(2.679000,1.269000,2.679000);
positions[475] = Vec3(2.679000,1.551000,0.141000);
positions[476] = Vec3(2.679000,1.551000,0.705000);
positions[477] = Vec3(2.679000,1.551000,1.269000);
positions[478] = Vec3(2.679000,1.551000,1.833000);
positions[479] = Vec3(2.679000,1.551000,2.397000);
positions[480] = Vec3(2.679000,1.833000,0.423000);
positions[481] = Vec3(2.679000,1.833000,0.987000);
positions[482] = Vec3(2.679000,1.833000,1.551000);
positions[483] = Vec3(2.679000,1.833000,2.115000);
positions[484] = Vec3(2.679000,1.833000,2.679000);
positions[485] = Vec3(2.679000,2.115000,0.141000);
positions[486] = Vec3(2.679000,2.115000,0.705000);
positions[487] = Vec3(2.679000,2.115000,1.269000);
positions[488] = Vec3(2.679000,2.115000,1.833000);
positions[489] = Vec3(2.679000,2.115000,2.397000);
positions[490] = Vec3(2.679000,2.397000,0.423000);
positions[491] = Vec3(2.679000,2.397000,0.987000);
positions[492] = Vec3(2.679000,2.397000,1.551000);
positions[493] = Vec3(2.679000,2.397000,2.115000);
positions[494] = Vec3(2.679000,2.397000,2.679000);
positions[495] = Vec3(2.679000,2.679000,0.141000);
positions[496] = Vec3(2.679000,2.679000,0.705000);
positions[497] = Vec3(2.679000,2.679000,1.269000);
positions[498] = Vec3(2.679000,2.679000,1.833000);
positions[499] = Vec3(2.679000,2.679000,2.397000);
positions[500] = Vec3(0.141000,0.141000,0.423000);
positions[501] = Vec3(0.141000,0.141000,0.987000);
positions[502] = Vec3(0.141000,0.141000,1.551000);
positions[503] = Vec3(0.141000,0.141000,2.115000);
positions[504] = Vec3(0.141000,0.141000,2.679000);
positions[505] = Vec3(0.141000,0.423000,0.141000);
positions[506] = Vec3(0.141000,0.423000,0.705000);
positions[507] = Vec3(0.141000,0.423000,1.269000);
positions[508] = Vec3(0.141000,0.423000,1.833000);
positions[509] = Vec3(0.141000,0.423000,2.397000);
positions[510] = Vec3(0.141000,0.705000,0.423000);
positions[511] = Vec3(0.141000,0.705000,0.987000);
positions[512] = Vec3(0.141000,0.705000,1.551000);
positions[513] = Vec3(0.141000,0.705000,2.115000);
positions[514] = Vec3(0.141000,0.705000,2.679000);
positions[515] = Vec3(0.141000,0.987000,0.141000);
positions[516] = Vec3(0.141000,0.987000,0.705000);
positions[517] = Vec3(0.141000,0.987000,1.269000);
positions[518] = Vec3(0.141000,0.987000,1.833000);
positions[519] = Vec3(0.141000,0.987000,2.397000);
positions[520] = Vec3(0.141000,1.269000,0.423000);
positions[521] = Vec3(0.141000,1.269000,0.987000);
positions[522] = Vec3(0.141000,1.269000,1.551000);
positions[523] = Vec3(0.141000,1.269000,2.115000);
positions[524] = Vec3(0.141000,1.269000,2.679000);
positions[525] = Vec3(0.141000,1.551000,0.141000);
positions[526] = Vec3(0.141000,1.551000,0.705000);
positions[527] = Vec3(0.141000,1.551000,1.269000);
positions[528] = Vec3(0.141000,1.551000,1.833000);
positions[529] = Vec3(0.141000,1.551000,2.397000);
positions[530] = Vec3(0.141000,1.833000,0.423000);
positions[531] = Vec3(0.141000,1.833000,0.987000);
positions[532] = Vec3(0.141000,1.833000,1.551000);
positions[533] = Vec3(0.141000,1.833000,2.115000);
positions[534] = Vec3(0.141000,1.833000,2.679000);
positions[535] = Vec3(0.141000,2.115000,0.141000);
positions[536] = Vec3(0.141000,2.115000,0.705000);
positions[537] = Vec3(0.141000,2.115000,1.269000);
positions[538] = Vec3(0.141000,2.115000,1.833000);
positions[539] = Vec3(0.141000,2.115000,2.397000);
positions[540] = Vec3(0.141000,2.397000,0.423000);
positions[541] = Vec3(0.141000,2.397000,0.987000);
positions[542] = Vec3(0.141000,2.397000,1.551000);
positions[543] = Vec3(0.141000,2.397000,2.115000);
positions[544] = Vec3(0.141000,2.397000,2.679000);
positions[545] = Vec3(0.141000,2.679000,0.141000);
positions[546] = Vec3(0.141000,2.679000,0.705000);
positions[547] = Vec3(0.141000,2.679000,1.269000);
positions[548] = Vec3(0.141000,2.679000,1.833000);
positions[549] = Vec3(0.141000,2.679000,2.397000);
positions[550] = Vec3(0.423000,0.141000,0.141000);
positions[551] = Vec3(0.423000,0.141000,0.705000);
positions[552] = Vec3(0.423000,0.141000,1.269000);
positions[553] = Vec3(0.423000,0.141000,1.833000);
positions[554] = Vec3(0.423000,0.141000,2.397000);
positions[555] = Vec3(0.423000,0.423000,0.423000);
positions[556] = Vec3(0.423000,0.423000,0.987000);
positions[557] = Vec3(0.423000,0.423000,1.551000);
positions[558] = Vec3(0.423000,0.423000,2.115000);
positions[559] = Vec3(0.423000,0.423000,2.679000);
positions[560] = Vec3(0.423000,0.705000,0.141000);
positions[561] = Vec3(0.423000,0.705000,0.705000);
positions[562] = Vec3(0.423000,0.705000,1.269000);
positions[563] = Vec3(0.423000,0.705000,1.833000);
positions[564] = Vec3(0.423000,0.705000,2.397000);
positions[565] = Vec3(0.423000,0.987000,0.423000);
positions[566] = Vec3(0.423000,0.987000,0.987000);
positions[567] = Vec3(0.423000,0.987000,1.551000);
positions[568] = Vec3(0.423000,0.987000,2.115000);
positions[569] = Vec3(0.423000,0.987000,2.679000);
positions[570] = Vec3(0.423000,1.269000,0.141000);
positions[571] = Vec3(0.423000,1.269000,0.705000);
positions[572] = Vec3(0.423000,1.269000,1.269000);
positions[573] = Vec3(0.423000,1.269000,1.833000);
positions[574] = Vec3(0.423000,1.269000,2.397000);
positions[575] = Vec3(0.423000,1.551000,0.423000);
positions[576] = Vec3(0.423000,1.551000,0.987000);
positions[577] = Vec3(0.423000,1.551000,1.551000);
positions[578] = Vec3(0.423000,1.551000,2.115000);
positions[579] = Vec3(0.423000,1.551000,2.679000);
positions[580] = Vec3(0.423000,1.833000,0.141000);
positions[581] = Vec3(0.423000,1.833000,0.705000);
positions[582] = Vec3(0.423000,1.833000,1.269000);
positions[583] = Vec3(0.423000,1.833000,1.833000);
positions[584] = Vec3(0.423000,1.833000,2.397000);
positions[585] = Vec3(0.423000,2.115000,0.423000);
positions[586] = Vec3(0.423000,2.115000,0.987000);
positions[587] = Vec3(0.423000,2.115000,1.551000);
positions[588] = Vec3(0.423000,2.115000,2.115000);
positions[589] = Vec3(0.423000,2.115000,2.679000);
positions[590] = Vec3(0.423000,2.397000,0.141000);
positions[591] = Vec3(0.423000,2.397000,0.705000);
positions[592] = Vec3(0.423000,2.397000,1.269000);
positions[593] = Vec3(0.423000,2.397000,1.833000);
positions[594] = Vec3(0.423000,2.397000,2.397000);
positions[595] = Vec3(0.423000,2.679000,0.423000);
positions[596] = Vec3(0.423000,2.679000,0.987000);
positions[597] = Vec3(0.423000,2.679000,1.551000);
positions[598] = Vec3(0.423000,2.679000,2.115000);
positions[599] = Vec3(0.423000,2.679000,2.679000);
positions[600] = Vec3(0.705000,0.141000,0.423000);
positions[601] = Vec3(0.705000,0.141000,0.987000);
positions[602] = Vec3(0.705000,0.141000,1.551000);
positions[603] = Vec3(0.705000,0.141000,2.115000);
positions[604] = Vec3(0.705000,0.141000,2.679000);
positions[605] = Vec3(0.705000,0.423000,0.141000);
positions[606] = Vec3(0.705000,0.423000,0.705000);
positions[607] = Vec3(0.705000,0.423000,1.269000);
positions[608] = Vec3(0.705000,0.423000,1.833000);
positions[609] = Vec3(0.705000,0.423000,2.397000);
positions[610] = Vec3(0.705000,0.705000,0.423000);
positions[611] = Vec3(0.705000,0.705000,0.987000);
positions[612] = Vec3(0.705000,0.705000,1.551000);
positions[613] = Vec3(0.705000,0.705000,2.115000);
positions[614] = Vec3(0.705000,0.705000,2.679000);
positions[615] = Vec3(0.705000,0.987000,0.141000);
positions[616] = Vec3(0.705000,0.987000,0.705000);
positions[617] = Vec3(0.705000,0.987000,1.269000);
positions[618] = Vec3(0.705000,0.987000,1.833000);
positions[619] = Vec3(0.705000,0.987000,2.397000);
positions[620] = Vec3(0.705000,1.269000,0.423000);
positions[621] = Vec3(0.705000,1.269000,0.987000);
positions[622] = Vec3(0.705000,1.269000,1.551000);
positions[623] = Vec3(0.705000,1.269000,2.115000);
positions[624] = Vec3(0.705000,1.269000,2.679000);
positions[625] = Vec3(0.705000,1.551000,0.141000);
positions[626] = Vec3(0.705000,1.551000,0.705000);
positions[627] = Vec3(0.705000,1.551000,1.269000);
positions[628] = Vec3(0.705000,1.551000,1.833000);
positions[629] = Vec3(0.705000,1.551000,2.397000);
positions[630] = Vec3(0.705000,1.833000,0.423000);
positions[631] = Vec3(0.705000,1.833000,0.987000);
positions[632] = Vec3(0.705000,1.833000,1.551000);
positions[633] = Vec3(0.705000,1.833000,2.115000);
positions[634] = Vec3(0.705000,1.833000,2.679000);
positions[635] = Vec3(0.705000,2.115000,0.141000);
positions[636] = Vec3(0.705000,2.115000,0.705000);
positions[637] = Vec3(0.705000,2.115000,1.269000);
positions[638] = Vec3(0.705000,2.115000,1.833000);
positions[639] = Vec3(0.705000,2.115000,2.397000);
positions[640] = Vec3(0.705000,2.397000,0.423000);
positions[641] = Vec3(0.705000,2.397000,0.987000);
positions[642] = Vec3(0.705000,2.397000,1.551000);
positions[643] = Vec3(0.705000,2.397000,2.115000);
positions[644] = Vec3(0.705000,2.397000,2.679000);
positions[645] = Vec3(0.705000,2.679000,0.141000);
positions[646] = Vec3(0.705000,2.679000,0.705000);
positions[647] = Vec3(0.705000,2.679000,1.269000);
positions[648] = Vec3(0.705000,2.679000,1.833000);
positions[649] = Vec3(0.705000,2.679000,2.397000);
positions[650] = Vec3(0.987000,0.141000,0.141000);
positions[651] = Vec3(0.987000,0.141000,0.705000);
positions[652] = Vec3(0.987000,0.141000,1.269000);
positions[653] = Vec3(0.987000,0.141000,1.833000);
positions[654] = Vec3(0.987000,0.141000,2.397000);
positions[655] = Vec3(0.987000,0.423000,0.423000);
positions[656] = Vec3(0.987000,0.423000,0.987000);
positions[657] = Vec3(0.987000,0.423000,1.551000);
positions[658] = Vec3(0.987000,0.423000,2.115000);
positions[659] = Vec3(0.987000,0.423000,2.679000);
positions[660] = Vec3(0.987000,0.705000,0.141000);
positions[661] = Vec3(0.987000,0.705000,0.705000);
positions[662] = Vec3(0.987000,0.705000,1.269000);
positions[663] = Vec3(0.987000,0.705000,1.833000);
positions[664] = Vec3(0.987000,0.705000,2.397000);
positions[665] = Vec3(0.987000,0.987000,0.423000);
positions[666] = Vec3(0.987000,0.987000,0.987000);
positions[667] = Vec3(0.987000,0.987000,1.551000);
positions[668] = Vec3(0.987000,0.987000,2.115000);
positions[669] = Vec3(0.987000,0.987000,2.679000);
positions[670] = Vec3(0.987000,1.269000,0.141000);
positions[671] = Vec3(0.987000,1.269000,0.705000);
positions[672] = Vec3(0.987000,1.269000,1.269000);
positions[673] = Vec3(0.987000,1.269000,1.833000);
positions[674] = Vec3(0.987000,1.269000,2.397000);
positions[675] = Vec3(0.987000,1.551000,0.423000);
positions[676] = Vec3(0.987000,1.551000,0.987000);
positions[677] = Vec3(0.987000,1.551000,1.551000);
positions[678] = Vec3(0.987000,1.551000,2.115000);
positions[679] = Vec3(0.987000,1.551000,2.679000);
positions[680] = Vec3(0.987000,1.833000,0.141000);
positions[681] = Vec3(0.987000,1.833000,0.705000);
positions[682] = Vec3(0.987000,1.833000,1.269000);
positions[683] = Vec3(0.987000,1.833000,1.833000);
positions[684] = Vec3(0.987000,1.833000,2.397000);
positions[685] = Vec3(0.987000,2.115000,0.423000);
positions[686] = Vec3(0.987000,2.115000,0.987000);
positions[687] = Vec3(0.987000,2.115000,1.551000);
positions[688] = Vec3(0.987000,2.115000,2.115000);
positions[689] = Vec3(0.987000,2.115000,2.679000);
positions[690] = Vec3(0.987000,2.397000,0.141000);
positions[691] = Vec3(0.987000,2.397000,0.705000);
positions[692] = Vec3(0.987000,2.397000,1.269000);
positions[693] = Vec3(0.987000,2.397000,1.833000);
positions[694] = Vec3(0.987000,2.397000,2.397000);
positions[695] = Vec3(0.987000,2.679000,0.423000);
positions[696] = Vec3(0.987000,2.679000,0.987000);
positions[697] = Vec3(0.987000,2.679000,1.551000);
positions[698] = Vec3(0.987000,2.679000,2.115000);
positions[699] = Vec3(0.987000,2.679000,2.679000);
positions[700] = Vec3(1.269000,0.141000,0.423000);
positions[701] = Vec3(1.269000,0.141000,0.987000);
positions[702] = Vec3(1.269000,0.141000,1.551000);
positions[703] = Vec3(1.269000,0.141000,2.115000);
positions[704] = Vec3(1.269000,0.141000,2.679000);
positions[705] = Vec3(1.269000,0.423000,0.141000);
positions[706] = Vec3(1.269000,0.423000,0.705000);
positions[707] = Vec3(1.269000,0.423000,1.269000);
positions[708] = Vec3(1.269000,0.423000,1.833000);
positions[709] = Vec3(1.269000,0.423000,2.397000);
positions[710] = Vec3(1.269000,0.705000,0.423000);
positions[711] = Vec3(1.269000,0.705000,0.987000);
positions[712] = Vec3(1.269000,0.705000,1.551000);
positions[713] = Vec3(1.269000,0.705000,2.115000);
positions[714] = Vec3(1.269000,0.705000,2.679000);
positions[715] = Vec3(1.269000,0.987000,0.141000);
positions[716] = Vec3(1.269000,0.987000,0.705000);
positions[717] = Vec3(1.269000,0.987000,1.269000);
positions[718] = Vec3(1.269000,0.987000,1.833000);
positions[719] = Vec3(1.269000,0.987000,2.397000);
positions[720] = Vec3(1.269000,1.269000,0.423000);
positions[721] = Vec3(1.269000,1.269000,0.987000);
positions[722] = Vec3(1.269000,1.269000,1.551000);
positions[723] = Vec3(1.269000,1.269000,2.115000);
positions[724] = Vec3(1.269000,1.269000,2.679000);
positions[725] = Vec3(1.269000,1.551000,0.141000);
positions[726] = Vec3(1.269000,1.551000,0.705000);
positions[727] = Vec3(1.269000,1.551000,1.269000);
positions[728] = Vec3(1.269000,1.551000,1.833000);
positions[729] = Vec3(1.269000,1.551000,2.397000);
positions[730] = Vec3(1.269000,1.833000,0.423000);
positions[731] = Vec3(1.269000,1.833000,0.987000);
positions[732] = Vec3(1.269000,1.833000,1.551000);
positions[733] = Vec3(1.269000,1.833000,2.115000);
positions[734] = Vec3(1.269000,1.833000,2.679000);
positions[735] = Vec3(1.269000,2.115000,0.141000);
positions[736] = Vec3(1.269000,2.115000,0.705000);
positions[737] = Vec3(1.269000,2.115000,1.269000);
positions[738] = Vec3(1.269000,2.115000,1.833000);
positions[739] = Vec3(1.269000,2.115000,2.397000);
positions[740] = Vec3(1.269000,2.397000,0.423000);
positions[741] = Vec3(1.269000,2.397000,0.987000);
positions[742] = Vec3(1.269000,2.397000,1.551000);
positions[743] = Vec3(1.269000,2.397000,2.115000);
positions[744] = Vec3(1.269000,2.397000,2.679000);
positions[745] = Vec3(1.269000,2.679000,0.141000);
positions[746] = Vec3(1.269000,2.679000,0.705000);
positions[747] = Vec3(1.269000,2.679000,1.269000);
positions[748] = Vec3(1.269000,2.679000,1.833000);
positions[749] = Vec3(1.269000,2.679000,2.397000);
positions[750] = Vec3(1.551000,0.141000,0.141000);
positions[751] = Vec3(1.551000,0.141000,0.705000);
positions[752] = Vec3(1.551000,0.141000,1.269000);
positions[753] = Vec3(1.551000,0.141000,1.833000);
positions[754] = Vec3(1.551000,0.141000,2.397000);
positions[755] = Vec3(1.551000,0.423000,0.423000);
positions[756] = Vec3(1.551000,0.423000,0.987000);
positions[757] = Vec3(1.551000,0.423000,1.551000);
positions[758] = Vec3(1.551000,0.423000,2.115000);
positions[759] = Vec3(1.551000,0.423000,2.679000);
positions[760] = Vec3(1.551000,0.705000,0.141000);
positions[761] = Vec3(1.551000,0.705000,0.705000);
positions[762] = Vec3(1.551000,0.705000,1.269000);
positions[763] = Vec3(1.551000,0.705000,1.833000);
positions[764] = Vec3(1.551000,0.705000,2.397000);
positions[765] = Vec3(1.551000,0.987000,0.423000);
positions[766] = Vec3(1.551000,0.987000,0.987000);
positions[767] = Vec3(1.551000,0.987000,1.551000);
positions[768] = Vec3(1.551000,0.987000,2.115000);
positions[769] = Vec3(1.551000,0.987000,2.679000);
positions[770] = Vec3(1.551000,1.269000,0.141000);
positions[771] = Vec3(1.551000,1.269000,0.705000);
positions[772] = Vec3(1.551000,1.269000,1.269000);
positions[773] = Vec3(1.551000,1.269000,1.833000);
positions[774] = Vec3(1.551000,1.269000,2.397000);
positions[775] = Vec3(1.551000,1.551000,0.423000);
positions[776] = Vec3(1.551000,1.551000,0.987000);
positions[777] = Vec3(1.551000,1.551000,1.551000);
positions[778] = Vec3(1.551000,1.551000,2.115000);
positions[779] = Vec3(1.551000,1.551000,2.679000);
positions[780] = Vec3(1.551000,1.833000,0.141000);
positions[781] = Vec3(1.551000,1.833000,0.705000);
positions[782] = Vec3(1.551000,1.833000,1.269000);
positions[783] = Vec3(1.551000,1.833000,1.833000);
positions[784] = Vec3(1.551000,1.833000,2.397000);
positions[785] = Vec3(1.551000,2.115000,0.423000);
positions[786] = Vec3(1.551000,2.115000,0.987000);
positions[787] = Vec3(1.551000,2.115000,1.551000);
positions[788] = Vec3(1.551000,2.115000,2.115000);
positions[789] = Vec3(1.551000,2.115000,2.679000);
positions[790] = Vec3(1.551000,2.397000,0.141000);
positions[791] = Vec3(1.551000,2.397000,0.705000);
positions[792] = Vec3(1.551000,2.397000,1.269000);
positions[793] = Vec3(1.551000,2.397000,1.833000);
positions[794] = Vec3(1.551000,2.397000,2.397000);
positions[795] = Vec3(1.551000,2.679000,0.423000);
positions[796] = Vec3(1.551000,2.679000,0.987000);
positions[797] = Vec3(1.551000,2.679000,1.551000);
positions[798] = Vec3(1.551000,2.679000,2.115000);
positions[799] = Vec3(1.551000,2.679000,2.679000);
positions[800] = Vec3(1.833000,0.141000,0.423000);
positions[801] = Vec3(1.833000,0.141000,0.987000);
positions[802] = Vec3(1.833000,0.141000,1.551000);
positions[803] = Vec3(1.833000,0.141000,2.115000);
positions[804] = Vec3(1.833000,0.141000,2.679000);
positions[805] = Vec3(1.833000,0.423000,0.141000);
positions[806] = Vec3(1.833000,0.423000,0.705000);
positions[807] = Vec3(1.833000,0.423000,1.269000);
positions[808] = Vec3(1.833000,0.423000,1.833000);
positions[809] = Vec3(1.833000,0.423000,2.397000);
positions[810] = Vec3(1.833000,0.705000,0.423000);
positions[811] = Vec3(1.833000,0.705000,0.987000);
positions[812] = Vec3(1.833000,0.705000,1.551000);
positions[813] = Vec3(1.833000,0.705000,2.115000);
positions[814] = Vec3(1.833000,0.705000,2.679000);
positions[815] = Vec3(1.833000,0.987000,0.141000);
positions[816] = Vec3(1.833000,0.987000,0.705000);
positions[817] = Vec3(1.833000,0.987000,1.269000);
positions[818] = Vec3(1.833000,0.987000,1.833000);
positions[819] = Vec3(1.833000,0.987000,2.397000);
positions[820] = Vec3(1.833000,1.269000,0.423000);
positions[821] = Vec3(1.833000,1.269000,0.987000);
positions[822] = Vec3(1.833000,1.269000,1.551000);
positions[823] = Vec3(1.833000,1.269000,2.115000);
positions[824] = Vec3(1.833000,1.269000,2.679000);
positions[825] = Vec3(1.833000,1.551000,0.141000);
positions[826] = Vec3(1.833000,1.551000,0.705000);
positions[827] = Vec3(1.833000,1.551000,1.269000);
positions[828] = Vec3(1.833000,1.551000,1.833000);
positions[829] = Vec3(1.833000,1.551000,2.397000);
positions[830] = Vec3(1.833000,1.833000,0.423000);
positions[831] = Vec3(1.833000,1.833000,0.987000);
positions[832] = Vec3(1.833000,1.833000,1.551000);
positions[833] = Vec3(1.833000,1.833000,2.115000);
positions[834] = Vec3(1.833000,1.833000,2.679000);
positions[835] = Vec3(1.833000,2.115000,0.141000);
positions[836] = Vec3(1.833000,2.115000,0.705000);
positions[837] = Vec3(1.833000,2.115000,1.269000);
positions[838] = Vec3(1.833000,2.115000,1.833000);
positions[839] = Vec3(1.833000,2.115000,2.397000);
positions[840] = Vec3(1.833000,2.397000,0.423000);
positions[841] = Vec3(1.833000,2.397000,0.987000);
positions[842] = Vec3(1.833000,2.397000,1.551000);
positions[843] = Vec3(1.833000,2.397000,2.115000);
positions[844] = Vec3(1.833000,2.397000,2.679000);
positions[845] = Vec3(1.833000,2.679000,0.141000);
positions[846] = Vec3(1.833000,2.679000,0.705000);
positions[847] = Vec3(1.833000,2.679000,1.269000);
positions[848] = Vec3(1.833000,2.679000,1.833000);
positions[849] = Vec3(1.833000,2.679000,2.397000);
positions[850] = Vec3(2.115000,0.141000,0.141000);
positions[851] = Vec3(2.115000,0.141000,0.705000);
positions[852] = Vec3(2.115000,0.141000,1.269000);
positions[853] = Vec3(2.115000,0.141000,1.833000);
positions[854] = Vec3(2.115000,0.141000,2.397000);
positions[855] = Vec3(2.115000,0.423000,0.423000);
positions[856] = Vec3(2.115000,0.423000,0.987000);
positions[857] = Vec3(2.115000,0.423000,1.551000);
positions[858] = Vec3(2.115000,0.423000,2.115000);
positions[859] = Vec3(2.115000,0.423000,2.679000);
positions[860] = Vec3(2.115000,0.705000,0.141000);
positions[861] = Vec3(2.115000,0.705000,0.705000);
positions[862] = Vec3(2.115000,0.705000,1.269000);
positions[863] = Vec3(2.115000,0.705000,1.833000);
positions[864] = Vec3(2.115000,0.705000,2.397000);
positions[865] = Vec3(2.115000,0.987000,0.423000);
positions[866] = Vec3(2.115000,0.987000,0.987000);
positions[867] = Vec3(2.115000,0.987000,1.551000);
positions[868] = Vec3(2.115000,0.987000,2.115000);
positions[869] = Vec3(2.115000,0.987000,2.679000);
positions[870] = Vec3(2.115000,1.269000,0.141000);
positions[871] = Vec3(2.115000,1.269000,0.705000);
positions[872] = Vec3(2.115000,1.269000,1.269000);
positions[873] = Vec3(2.115000,1.269000,1.833000);
positions[874] = Vec3(2.115000,1.269000,2.397000);
positions[875] = Vec3(2.115000,1.551000,0.423000);
positions[876] = Vec3(2.115000,1.551000,0.987000);
positions[877] = Vec3(2.115000,1.551000,1.551000);
positions[878] = Vec3(2.115000,1.551000,2.115000);
positions[879] = Vec3(2.115000,1.551000,2.679000);
positions[880] = Vec3(2.115000,1.833000,0.141000);
positions[881] = Vec3(2.115000,1.833000,0.705000);
positions[882] = Vec3(2.115000,1.833000,1.269000);
positions[883] = Vec3(2.115000,1.833000,1.833000);
positions[884] = Vec3(2.115000,1.833000,2.397000);
positions[885] = Vec3(2.115000,2.115000,0.423000);
positions[886] = Vec3(2.115000,2.115000,0.987000);
positions[887] = Vec3(2.115000,2.115000,1.551000);
positions[888] = Vec3(2.115000,2.115000,2.115000);
positions[889] = Vec3(2.115000,2.115000,2.679000);
positions[890] = Vec3(2.115000,2.397000,0.141000);
positions[891] = Vec3(2.115000,2.397000,0.705000);
positions[892] = Vec3(2.115000,2.397000,1.269000);
positions[893] = Vec3(2.115000,2.397000,1.833000);
positions[894] = Vec3(2.115000,2.397000,2.397000);
positions[895] = Vec3(2.115000,2.679000,0.423000);
positions[896] = Vec3(2.115000,2.679000,0.987000);
positions[897] = Vec3(2.115000,2.679000,1.551000);
positions[898] = Vec3(2.115000,2.679000,2.115000);
positions[899] = Vec3(2.115000,2.679000,2.679000);
positions[900] = Vec3(2.397000,0.141000,0.423000);
positions[901] = Vec3(2.397000,0.141000,0.987000);
positions[902] = Vec3(2.397000,0.141000,1.551000);
positions[903] = Vec3(2.397000,0.141000,2.115000);
positions[904] = Vec3(2.397000,0.141000,2.679000);
positions[905] = Vec3(2.397000,0.423000,0.141000);
positions[906] = Vec3(2.397000,0.423000,0.705000);
positions[907] = Vec3(2.397000,0.423000,1.269000);
positions[908] = Vec3(2.397000,0.423000,1.833000);
positions[909] = Vec3(2.397000,0.423000,2.397000);
positions[910] = Vec3(2.397000,0.705000,0.423000);
positions[911] = Vec3(2.397000,0.705000,0.987000);
positions[912] = Vec3(2.397000,0.705000,1.551000);
positions[913] = Vec3(2.397000,0.705000,2.115000);
positions[914] = Vec3(2.397000,0.705000,2.679000);
positions[915] = Vec3(2.397000,0.987000,0.141000);
positions[916] = Vec3(2.397000,0.987000,0.705000);
positions[917] = Vec3(2.397000,0.987000,1.269000);
positions[918] = Vec3(2.397000,0.987000,1.833000);
positions[919] = Vec3(2.397000,0.987000,2.397000);
positions[920] = Vec3(2.397000,1.269000,0.423000);
positions[921] = Vec3(2.397000,1.269000,0.987000);
positions[922] = Vec3(2.397000,1.269000,1.551000);
positions[923] = Vec3(2.397000,1.269000,2.115000);
positions[924] = Vec3(2.397000,1.269000,2.679000);
positions[925] = Vec3(2.397000,1.551000,0.141000);
positions[926] = Vec3(2.397000,1.551000,0.705000);
positions[927] = Vec3(2.397000,1.551000,1.269000);
positions[928] = Vec3(2.397000,1.551000,1.833000);
positions[929] = Vec3(2.397000,1.551000,2.397000);
positions[930] = Vec3(2.397000,1.833000,0.423000);
positions[931] = Vec3(2.397000,1.833000,0.987000);
positions[932] = Vec3(2.397000,1.833000,1.551000);
positions[933] = Vec3(2.397000,1.833000,2.115000);
positions[934] = Vec3(2.397000,1.833000,2.679000);
positions[935] = Vec3(2.397000,2.115000,0.141000);
positions[936] = Vec3(2.397000,2.115000,0.705000);
positions[937] = Vec3(2.397000,2.115000,1.269000);
positions[938] = Vec3(2.397000,2.115000,1.833000);
positions[939] = Vec3(2.397000,2.115000,2.397000);
positions[940] = Vec3(2.397000,2.397000,0.423000);
positions[941] = Vec3(2.397000,2.397000,0.987000);
positions[942] = Vec3(2.397000,2.397000,1.551000);
positions[943] = Vec3(2.397000,2.397000,2.115000);
positions[944] = Vec3(2.397000,2.397000,2.679000);
positions[945] = Vec3(2.397000,2.679000,0.141000);
positions[946] = Vec3(2.397000,2.679000,0.705000);
positions[947] = Vec3(2.397000,2.679000,1.269000);
positions[948] = Vec3(2.397000,2.679000,1.833000);
positions[949] = Vec3(2.397000,2.679000,2.397000);
positions[950] = Vec3(2.679000,0.141000,0.141000);
positions[951] = Vec3(2.679000,0.141000,0.705000);
positions[952] = Vec3(2.679000,0.141000,1.269000);
positions[953] = Vec3(2.679000,0.141000,1.833000);
positions[954] = Vec3(2.679000,0.141000,2.397000);
positions[955] = Vec3(2.679000,0.423000,0.423000);
positions[956] = Vec3(2.679000,0.423000,0.987000);
positions[957] = Vec3(2.679000,0.423000,1.551000);
positions[958] = Vec3(2.679000,0.423000,2.115000);
positions[959] = Vec3(2.679000,0.423000,2.679000);
positions[960] = Vec3(2.679000,0.705000,0.141000);
positions[961] = Vec3(2.679000,0.705000,0.705000);
positions[962] = Vec3(2.679000,0.705000,1.269000);
positions[963] = Vec3(2.679000,0.705000,1.833000);
positions[964] = Vec3(2.679000,0.705000,2.397000);
positions[965] = Vec3(2.679000,0.987000,0.423000);
positions[966] = Vec3(2.679000,0.987000,0.987000);
positions[967] = Vec3(2.679000,0.987000,1.551000);
positions[968] = Vec3(2.679000,0.987000,2.115000);
positions[969] = Vec3(2.679000,0.987000,2.679000);
positions[970] = Vec3(2.679000,1.269000,0.141000);
positions[971] = Vec3(2.679000,1.269000,0.705000);
positions[972] = Vec3(2.679000,1.269000,1.269000);
positions[973] = Vec3(2.679000,1.269000,1.833000);
positions[974] = Vec3(2.679000,1.269000,2.397000);
positions[975] = Vec3(2.679000,1.551000,0.423000);
positions[976] = Vec3(2.679000,1.551000,0.987000);
positions[977] = Vec3(2.679000,1.551000,1.551000);
positions[978] = Vec3(2.679000,1.551000,2.115000);
positions[979] = Vec3(2.679000,1.551000,2.679000);
positions[980] = Vec3(2.679000,1.833000,0.141000);
positions[981] = Vec3(2.679000,1.833000,0.705000);
positions[982] = Vec3(2.679000,1.833000,1.269000);
positions[983] = Vec3(2.679000,1.833000,1.833000);
positions[984] = Vec3(2.679000,1.833000,2.397000);
positions[985] = Vec3(2.679000,2.115000,0.423000);
positions[986] = Vec3(2.679000,2.115000,0.987000);
positions[987] = Vec3(2.679000,2.115000,1.551000);
positions[988] = Vec3(2.679000,2.115000,2.115000);
positions[989] = Vec3(2.679000,2.115000,2.679000);
positions[990] = Vec3(2.679000,2.397000,0.141000);
positions[991] = Vec3(2.679000,2.397000,0.705000);
positions[992] = Vec3(2.679000,2.397000,1.269000);
positions[993] = Vec3(2.679000,2.397000,1.833000);
positions[994] = Vec3(2.679000,2.397000,2.397000);
positions[995] = Vec3(2.679000,2.679000,0.423000);
positions[996] = Vec3(2.679000,2.679000,0.987000);
positions[997] = Vec3(2.679000,2.679000,1.551000);
positions[998] = Vec3(2.679000,2.679000,2.115000);
positions[999] = Vec3(2.679000,2.679000,2.679000);
positions[0] = Vec3( 0.23,0.628,0.113);
positions[1] = Vec3(0.137,0.626, 0.15);
positions[2] = Vec3(0.231,0.589,0.021);
positions[3] = Vec3(-0.307,-0.351,0.703);
positions[4] = Vec3(-0.364,-0.367,0.784);
positions[5] = Vec3(-0.366,-0.341,0.623);
positions[6] = Vec3(-0.569,-0.634,-0.439);
positions[7] = Vec3(-0.532,-0.707,-0.497);
positions[8] = Vec3(-0.517,-0.629,-0.354);
positions[9] = Vec3(-0.871, 0.41,-0.62);
positions[10] = Vec3(-0.948,0.444,-0.566);
positions[11] = Vec3(-0.905,0.359,-0.699);
positions[12] = Vec3(0.249,-0.077,-0.621);
positions[13] = Vec3(0.306,-0.142,-0.571);
positions[14] = Vec3(0.233,-0.11,-0.714);
positions[15] = Vec3(0.561,0.222,-0.715);
positions[16] = Vec3(0.599,0.138,-0.678);
positions[17] = Vec3(0.473,0.241,-0.671);
positions[18] = Vec3(-0.515,-0.803,-0.628);
positions[19] = Vec3(-0.491,-0.866,-0.702);
positions[20] = Vec3(-0.605,-0.763,-0.646);
positions[21] = Vec3(-0.021,0.175,-0.899);
positions[22] = Vec3(0.018, 0.09,-0.935);
positions[23] = Vec3(-0.119,0.177,-0.918);
positions[24] = Vec3(-0.422,0.856,-0.464);
positions[25] = Vec3(-0.479,0.908,-0.527);
positions[26] = Vec3(-0.326,0.868,-0.488);
positions[27] = Vec3(-0.369,-0.095,-0.903);
positions[28] = Vec3(-0.336,-0.031,-0.972);
positions[29] = Vec3(-0.303,-0.101,-0.828);
positions[30] = Vec3(0.594,0.745,0.652);
positions[31] = Vec3(0.644, 0.83,0.633);
positions[32] = Vec3(0.506,0.747,0.604);
positions[33] = Vec3(-0.157,-0.375,-0.758);
positions[34] = Vec3(-0.25, -0.4,-0.785);
positions[35] = Vec3(-0.131,-0.425,-0.676);
positions[36] = Vec3(0.618,-0.295,-0.578);
positions[37] = Vec3(0.613,-0.213,-0.521);
positions[38] = Vec3(0.707,-0.298,-0.623);
positions[39] = Vec3(0.039,-0.785, 0.3);
positions[40] = Vec3(0.138,-0.796,0.291);
positions[41] = Vec3(-0.001,-0.871,0.332);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment