Unverified Commit 1dac981a authored by Peter Eastman's avatar Peter Eastman Committed by GitHub
Browse files

Use PocketFFT (#3667)

* Use PocketFFT instead of FFTW

* Minor cleanup

* Use PocketFFT instead of fftpack for reference platform

* Remove FFTW as a dependency

* Converted a test case to use PocketFFT

* Fixed an incorrect comment
parent 583471a6
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2011-2016 Stanford University and the Authors. *
* Portions copyright (c) 2011-2022 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -30,7 +30,7 @@
* -------------------------------------------------------------------------- */
/**
* This tests the OpenCL implementation of sorting.
* This tests the OpenCL implementation of FFT.
*/
#include "openmm/internal/AssertionUtilities.h"
......@@ -38,12 +38,16 @@
#include "OpenCLContext.h"
#include "OpenCLFFT3D.h"
#include "OpenCLSort.h"
#include "fftpack.h"
#include "sfmt/SFMT.h"
#include "openmm/System.h"
#include <complex>
#include <iostream>
#include <cmath>
#include <set>
#ifdef _MSC_VER
#define POCKETFFT_NO_VECTORS
#endif
#include "pocketfft_hdronly.h"
using namespace OpenMM;
using namespace std;
......@@ -60,17 +64,17 @@ void testTransform(bool realToComplex, int xsize, int ysize, int zsize) {
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<Real2> original(xsize*ysize*zsize);
vector<t_complex> reference(original.size());
vector<complex<double> > reference(original.size());
for (int i = 0; i < (int) original.size(); i++) {
Real2 value = Real2((cl_float) genrand_real2(sfmt), (cl_float) genrand_real2(sfmt));
original[i] = value;
reference[i] = t_complex(value.x, value.y);
reference[i] = complex<double>(value.x, value.y);
}
for (int i = 0; i < (int) reference.size(); i++) {
if (realToComplex)
reference[i] = t_complex(i%2 == 0 ? original[i/2].x : original[i/2].y, 0);
reference[i] = complex<double>(i%2 == 0 ? original[i/2].x : original[i/2].y, 0);
else
reference[i] = t_complex(original[i].x, original[i].y);
reference[i] = complex<double>(original[i].x, original[i].y);
}
OpenCLArray grid1(context, original.size(), sizeof(Real2), "grid1");
OpenCLArray grid2(context, original.size(), sizeof(Real2), "grid2");
......@@ -82,19 +86,21 @@ void testTransform(bool realToComplex, int xsize, int ysize, int zsize) {
fft.execFFT(grid1, grid2, true);
vector<Real2> result;
grid2.download(result);
fftpack_t plan;
fftpack_init_3d(&plan, xsize, ysize, zsize);
fftpack_exec_3d(plan, FFTPACK_FORWARD, &reference[0], &reference[0]);
vector<size_t> shape = {(size_t) xsize, (size_t) ysize, (size_t) zsize};
vector<size_t> axes = {0, 1, 2};
vector<ptrdiff_t> stride = {(ptrdiff_t) (ysize*zsize*sizeof(complex<double>)),
(ptrdiff_t) (zsize*sizeof(complex<double>)),
(ptrdiff_t) sizeof(complex<double>)};
pocketfft::c2c(shape, stride, stride, axes, true, reference.data(), reference.data(), 1.0);
int outputZSize = (realToComplex ? zsize/2+1 : zsize);
for (int x = 0; x < xsize; x++)
for (int y = 0; y < ysize; y++)
for (int z = 0; z < outputZSize; z++) {
int index1 = x*ysize*zsize + y*zsize + z;
int index2 = x*ysize*outputZSize + y*outputZSize + z;
ASSERT_EQUAL_TOL(reference[index1].re, result[index2].x, 1e-3);
ASSERT_EQUAL_TOL(reference[index1].im, result[index2].y, 1e-3);
ASSERT_EQUAL_TOL(reference[index1].real(), result[index2].x, 1e-3);
ASSERT_EQUAL_TOL(reference[index1].imag(), result[index2].y, 1e-3);
}
fftpack_destroy(plan);
// Perform a backward transform and see if we get the original values.
......
/*
* This file contains a Fortran to C translation of the 1D transformations
* based on the original FFTPACK, written by paul n swarztrauber
* at the national center for atmospheric research and available
* at www.netlib.org. FFTPACK is in the public domain.
*
* Higher-dimension transforms written by Erik Lindahl, 2008-2009.
* Just as FFTPACK, this file may be redistributed freely, and can be
* considered to be in the public domain.
*
* Any errors in this (threadsafe, but not threaded) C version
* are probably due to the f2c translator, or hacks by Erik Lindahl,
* rather than FFTPACK. If you find a bug, it would be great if you could
* drop a line to lindahl@cbr.su.se and let me know about it!
*/
#ifndef _FFTPACK_H_
#define _FFTPACK_H_
#include <stdio.h>
#include "openmm/internal/windowsExport.h"
#ifdef __cplusplus
extern "C" {
#endif
#if 0
} /* fixes auto-indentation problems */
#endif
class t_complex {
public:
double re;
double im;
t_complex() : re(0.0), im(0.0) {
}
t_complex(double re, double im) : re(re), im(im) {
}
t_complex(const t_complex& c) : re(c.re), im(c.im) {
}
t_complex operator*(double r) {
return t_complex(re*r, im*r);
}
t_complex operator+(const t_complex& c) const {
return t_complex(re+c.re, im+c.im);
}
t_complex operator-(const t_complex& c) const {
return t_complex(re-c.re, im-c.im);
}
t_complex& operator+=(const t_complex& c) {
re += c.re;
im += c.im;
return *this;
}
t_complex& operator-=(const t_complex& c) {
re -= c.re;
im -= c.im;
return *this;
}
};
/*! \brief Datatype for FFT setup
*
* The fftpack_t type contains all the setup information, e.g. twiddle
* factors, necessary to perform an FFT. Internally it is mapped to
* whatever FFT library we are using, or the built-in FFTPACK if no fast
* external library is available.
*/
typedef struct fftpack *
fftpack_t;
/*! \brief Specifier for FFT direction.
*
* The definition of the 1D forward transform from input x[] to output y[] is
* \f[
* y_{k} = \sum_{j=0}^{N-1} x_{j} \exp{-i 2 \pi j k /N}
* \f]
*
* while the corresponding backward transform is
*
* \f[
* y_{k} = \sum_{j=0}^{N-1} x_{j} \exp{i 2 \pi j k /N}
* \f]
*
* A forward-backward transform pair will this result in data scaled by N.
*
*/
typedef enum fftpack_direction
{
FFTPACK_FORWARD, /*!< Forward complex-to-complex transform */
FFTPACK_BACKWARD, /*!< Backward complex-to-complex transform */
} fftpack_direction;
/*! \brief Setup a 1-dimensional complex-to-complex transform
*
* \param fft Pointer to opaque Gromacs FFT datatype
* \param nx Length of transform
*
* \return status - 0 or a standard error message.
*/
int
OPENMM_EXPORT
fftpack_init_1d (fftpack_t * fft,
int nx);
/*! \brief Setup a 2-dimensional complex-to-complex transform
*
* \param fft Pointer to opaque Gromacs FFT datatype
* \param nx Length of transform in first dimension
* \param ny Length of transform in second dimension
*
* \return status - 0 or a standard error message.
*
*/
int
OPENMM_EXPORT
fftpack_init_2d (fftpack_t * fft,
int nx,
int ny);
/*! \brief Setup a 3-dimensional complex-to-complex transform
*
* \param fft Pointer to opaque Gromacs FFT datatype
* \param nx Length of transform in first dimension
* \param ny Length of transform in second dimension
* \param nz Length of transform in third dimension
*
* \return status - 0 or a standard error message.
*
*/
int
OPENMM_EXPORT
fftpack_init_3d (fftpack_t * fft,
int nx,
int ny,
int nz);
/*! \brief Perform a 1-dimensional complex-to-complex transform
*
* Performs an instance of a transform previously initiated.
*
* \param setup Setup returned from fftpack_init_1d()
* \param dir Forward or Backward
* \param in_data Input grid data.
* \param out_data Output grid data.
* You can provide the same pointer for in_data and out_data
* to perform an in-place transform.
*
* \return 0 on success, or an error code.
*
* \note Data pointers are declared as void, to avoid casting pointers
* depending on your grid type.
*/
int
OPENMM_EXPORT
fftpack_exec_1d (fftpack_t setup,
enum fftpack_direction dir,
t_complex * in_data,
t_complex * out_data);
/*! \brief Perform a 2-dimensional complex-to-complex transform
*
* Performs an instance of a transform previously initiated.
*
* \param setup Setup returned from fftpack_init_1d()
* \param dir Forward or Backward
* \param in_data Input grid data.
* \param out_data Output grid data.
* You can provide the same pointer for in_data and out_data
* to perform an in-place transform.
*
* \return 0 on success, or an error code.
*
* \note Data pointers are declared as void, to avoid casting pointers
* depending on your grid type.
*/
int
OPENMM_EXPORT
fftpack_exec_2d (fftpack_t setup,
enum fftpack_direction dir,
t_complex * in_data,
t_complex * out_data);
/*! \brief Perform a 3-dimensional complex-to-complex transform
*
* Performs an instance of a transform previously initiated.
*
* \param setup Setup returned from fftpack_init_1d()
* \param dir Forward or Backward
* \param in_data Input grid data.
* \param out_data Output grid data.
* You can provide the same pointer for in_data and out_data
* to perform an in-place transform.
*
* \return 0 on success, or an error code.
*
* \note Data pointers are declared as void, to avoid casting pointers
* depending on your grid type.
*/
int
OPENMM_EXPORT
fftpack_exec_3d (fftpack_t setup,
enum fftpack_direction dir,
t_complex * in_data,
t_complex * out_data);
/*! \brief Release an FFT setup structure
*
* Destroy setup and release all allocated memory.
*
* \param setup Setup returned from fftpack_init_1d(), or one
* of the other initializers.
*
*/
void
OPENMM_EXPORT
fftpack_destroy (fftpack_t setup);
#ifdef __cplusplus
}
#endif
#endif /* _FFTPACK_H_ */
/*
* Reference implementation of PME reciprocal space interactions.
*
* Copyright (c) 2009, Erik Lindahl, Rossen Apostolov, Szilard Pall
* Copyright (c) 2009-2022, Erik Lindahl, Rossen Apostolov, Szilard Pall, Peter Eastman
* All rights reserved.
* Contact: lindahl@cbr.su.se Stockholm University, Sweden.
*
......@@ -32,12 +32,17 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <complex>
#include "ReferencePME.h"
#include "fftpack.h"
#include "SimTKOpenMMRealType.h"
using std::vector;
#ifdef _MSC_VER
#define POCKETFFT_NO_VECTORS
#endif
#include "pocketfft_hdronly.h"
using namespace std;
typedef int ivec[3];
......@@ -48,12 +53,11 @@ struct pme
int natoms;
double ewaldcoeff;
t_complex * grid; /* Memory for the grid we spread charges on.
complex<double>* grid; /* Memory for the grid we spread charges on.
* Element (i,j,k) is accessed as:
* grid[i*ngrid[1]*ngrid[2] + j*ngrid[2] + k]
*/
int ngrid[3]; /* Total grid dimensions (all data is complex!) */
fftpack_t fftplan; /* Handle to fourier transform setup */
int order; /* PME interpolation order. Almost always 4 */
......@@ -346,7 +350,7 @@ pme_grid_spread_charge(pme_t pme, const vector<double>& charges)
/* Reset the grid */
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] = complex<double>(0, 0);
}
for (i=0;i<pme->natoms;i++)
......@@ -397,7 +401,7 @@ pme_grid_spread_charge(pme_t pme, const vector<double>& charges)
/* Calculate index in the charge grid */
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 */
pme->grid[index].re += q*thetax[ix]*thetay[iy]*thetaz[iz];
pme->grid[index] += q*thetax[ix]*thetay[iy]*thetaz[iz];
}
}
}
......@@ -427,7 +431,7 @@ pme_reciprocal_convolution(pme_t pme,
double boxfactor;
double maxkx,maxky,maxkz;
t_complex *ptr;
complex<double> *ptr;
nx = pme->ngrid[0];
ny = pme->ngrid[1];
......@@ -486,8 +490,8 @@ pme_reciprocal_convolution(pme_t pme,
ptr = pme->grid + kx*ny*nz + ky*nz + kz;
/* Get grid data for this frequency */
d1 = ptr->re;
d2 = ptr->im;
d1 = ptr->real();
d2 = ptr->imag();
/* Calculate the convolution - see the Essman/Darden paper for the equation! */
m2 = mhx*mhx+mhy*mhy+mhz*mhz;
......@@ -497,8 +501,8 @@ pme_reciprocal_convolution(pme_t pme,
eterm = one_4pi_eps*exp(-factor*m2)/denom;
/* write back convolution data to grid */
ptr->re = d1*eterm;
ptr->im = d2*eterm;
ptr->real(d1*eterm);
ptr->imag(d2*eterm);
struct2 = (d1*d1+d2*d2);
......@@ -532,7 +536,7 @@ dpme_reciprocal_convolution(pme_t pme,
double boxfactor;
double maxkx,maxky,maxkz;
t_complex *ptr;
complex<double> *ptr;
nx = pme->ngrid[0];
ny = pme->ngrid[1];
......@@ -580,8 +584,8 @@ dpme_reciprocal_convolution(pme_t pme,
ptr = pme->grid + kx*ny*nz + ky*nz + kz;
/* Get grid data for this frequency */
d1 = ptr->re;
d2 = ptr->im;
d1 = ptr->real();
d2 = ptr->imag();
/* Calculate the convolution - see the Essman/Darden paper for the equation! */
m2 = mhx*mhx+mhy*mhy+mhz*mhz;
......@@ -598,8 +602,8 @@ dpme_reciprocal_convolution(pme_t pme,
eterm = (fac1*erfcterm*m3 + expterm*(fac2 + fac3*m2)) * denom;
/* write back convolution data to grid */
ptr->re = d1*eterm;
ptr->im = d2*eterm;
ptr->real(d1*eterm);
ptr->imag(d2*eterm);
struct2 = (d1*d1+d2*d2);
......@@ -696,7 +700,7 @@ pme_grid_interpolate_force(pme_t pme,
/* 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 :-) */
gridvalue = pme->grid[index].re;
gridvalue = pme->grid[index].real();
/* The d component of the force is calculated by taking the derived bspline in dimension d, normal bsplines in the other two */
fx += dtx*ty*tz*gridvalue;
......@@ -745,9 +749,7 @@ pme_init(pme_t * ppme,
pme->particleindex = (ivec *)malloc(sizeof(ivec)*natoms);
/* Allocate charge grid storage */
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]);
pme->grid = (complex<double> *)malloc(sizeof(complex<double>)*ngrid[0]*ngrid[1]*ngrid[2]);
/* Setup bspline moduli (see Essman paper) */
pme_calculate_bsplines_moduli(pme);
......@@ -790,13 +792,18 @@ int pme_exec(pme_t pme,
pme_grid_spread_charge(pme, charges);
/* do 3d-fft */
fftpack_exec_3d(pme->fftplan,FFTPACK_FORWARD,pme->grid,pme->grid);
vector<size_t> shape = {(size_t) pme->ngrid[0], (size_t) pme->ngrid[1], (size_t) pme->ngrid[2]};
vector<size_t> axes = {0, 1, 2};
vector<ptrdiff_t> stride = {(ptrdiff_t) (pme->ngrid[1]*pme->ngrid[2]*sizeof(complex<double>)),
(ptrdiff_t) (pme->ngrid[2]*sizeof(complex<double>)),
(ptrdiff_t) sizeof(complex<double>)};
pocketfft::c2c(shape, stride, stride, axes, true, pme->grid, pme->grid, 1.0, 0);
/* solve in k-space */
pme_reciprocal_convolution(pme,periodicBoxVectors,recipBoxVectors,energy);
/* do 3d-invfft */
fftpack_exec_3d(pme->fftplan,FFTPACK_BACKWARD,pme->grid,pme->grid);
pocketfft::c2c(shape, stride, stride, axes, false, pme->grid, pme->grid, 1.0, 0);
/* Get the particle forces from the grid and bsplines in the pme structure */
pme_grid_interpolate_force(pme,recipBoxVectors,charges,forces);
......@@ -834,13 +841,18 @@ int pme_exec_dpme(pme_t pme,
pme_grid_spread_charge(pme, c6s);
/* do 3d-fft */
fftpack_exec_3d(pme->fftplan,FFTPACK_FORWARD,pme->grid,pme->grid);
vector<size_t> shape = {(size_t) pme->ngrid[0], (size_t) pme->ngrid[1], (size_t) pme->ngrid[2]};
vector<size_t> axes = {0, 1, 2};
vector<ptrdiff_t> stride = {(ptrdiff_t) (pme->ngrid[1]*pme->ngrid[2]*sizeof(complex<double>)),
(ptrdiff_t) (pme->ngrid[2]*sizeof(complex<double>)),
(ptrdiff_t) sizeof(complex<double>)};
pocketfft::c2c(shape, stride, stride, axes, true, pme->grid, pme->grid, 1.0, 0);
/* solve in k-space */
dpme_reciprocal_convolution(pme,periodicBoxVectors,recipBoxVectors,energy);
/* do 3d-invfft */
fftpack_exec_3d(pme->fftplan,FFTPACK_BACKWARD,pme->grid,pme->grid);
pocketfft::c2c(shape, stride, stride, axes, false, pme->grid, pme->grid, 1.0, 0);
/* Get the particle forces from the grid and bsplines in the pme structure */
pme_grid_interpolate_force(pme,recipBoxVectors,c6s,forces);
......@@ -866,8 +878,6 @@ pme_destroy(pme_t pme)
free(pme->particlefraction);
free(pme->particleindex);
fftpack_destroy(pme->fftplan);
/* destroy structure itself */
free(pme);
......
This diff is collapsed.
/* Portions copyright (c) 2006-2019 Stanford University and Simbios.
/* Portions copyright (c) 2006-2022 Stanford University and Simbios.
* Contributors: Pande Group
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -30,6 +30,10 @@
#include "SimTKOpenMMRealType.h"
#include "jama_svd.h"
#include <algorithm>
#ifdef _MSC_VER
#define POCKETFFT_NO_VECTORS
#endif
#include "pocketfft_hdronly.h"
// In case we're using some primitive version of Visual Studio this will
// make sure that erf() and erfc() are defined.
......@@ -1396,7 +1400,6 @@ const double AmoebaReferencePmeHippoNonbondedForce::SQRT_PI = sqrt(M_PI);
AmoebaReferencePmeHippoNonbondedForce::AmoebaReferencePmeHippoNonbondedForce(const HippoNonbondedForce& force, const System& system) :
AmoebaReferenceHippoNonbondedForce(force) {
_fftplan = NULL;
force.getPMEParameters(_alphaEwald, _pmeGridDimensions[0], _pmeGridDimensions[1], _pmeGridDimensions[2]);
force.getDPMEParameters(_dalphaEwald, _dpmeGridDimensions[0], _dpmeGridDimensions[1], _dpmeGridDimensions[2]);
if (_alphaEwald == 0.0 || _dalphaEwald == 0.0) {
......@@ -1408,15 +1411,9 @@ AmoebaReferencePmeHippoNonbondedForce::AmoebaReferencePmeHippoNonbondedForce(con
if (_dalphaEwald == 0.0)
NonbondedForceImpl::calcPMEParameters(system, nb, _dalphaEwald, _dpmeGridDimensions[0], _dpmeGridDimensions[1], _dpmeGridDimensions[2], true);
}
fftpack_init_3d(&_fftplan, _pmeGridDimensions[0], _pmeGridDimensions[1], _pmeGridDimensions[2]);
initializeBSplineModuli();
}
AmoebaReferencePmeHippoNonbondedForce::~AmoebaReferencePmeHippoNonbondedForce() {
if (_fftplan != NULL)
fftpack_destroy(_fftplan);
};
double AmoebaReferencePmeHippoNonbondedForce::getCutoffDistance() const {
return _cutoffDistance;
};
......@@ -1451,11 +1448,6 @@ void AmoebaReferencePmeHippoNonbondedForce::setPmeGridDimensions(vector<int>& pm
(pmeGridDimensions[2] == _pmeGridDimensions[2]))
return;
if (_fftplan) {
fftpack_destroy(_fftplan);
}
fftpack_init_3d(&_fftplan,pmeGridDimensions[0], pmeGridDimensions[1], pmeGridDimensions[2]);
_pmeGridDimensions[0] = pmeGridDimensions[0];
_pmeGridDimensions[1] = pmeGridDimensions[1];
_pmeGridDimensions[2] = pmeGridDimensions[2];
......@@ -1469,11 +1461,6 @@ void AmoebaReferencePmeHippoNonbondedForce::setDispersionPmeGridDimensions(vecto
(pmeGridDimensions[2] == _dpmeGridDimensions[2]))
return;
if (_fftplan) {
fftpack_destroy(_fftplan);
}
fftpack_init_3d(&_fftplan,pmeGridDimensions[0], pmeGridDimensions[1], pmeGridDimensions[2]);
_dpmeGridDimensions[0] = pmeGridDimensions[0];
_dpmeGridDimensions[1] = pmeGridDimensions[1];
_dpmeGridDimensions[2] = pmeGridDimensions[2];
......@@ -1516,7 +1503,7 @@ void AmoebaReferencePmeHippoNonbondedForce::resizePmeArrays() {
void AmoebaReferencePmeHippoNonbondedForce::initializePmeGrid() {
for (int jj = 0; jj < _pmeGrid.size(); jj++)
_pmeGrid[jj].re = _pmeGrid[jj].im = 0.0;
_pmeGrid[jj] = complex<double>(0, 0);
}
void AmoebaReferencePmeHippoNonbondedForce::getPeriodicDelta(Vec3& deltaR) const {
......@@ -1674,9 +1661,14 @@ void AmoebaReferencePmeHippoNonbondedForce::calculateFixedMultipoleField() {
computeAmoebaBsplines(particleData);
initializePmeGrid();
spreadFixedMultipolesOntoGrid(particleData);
fftpack_exec_3d(_fftplan, FFTPACK_FORWARD, _pmeGrid.data(), _pmeGrid.data());
vector<size_t> shape = {(size_t) _pmeGridDimensions[0], (size_t) _pmeGridDimensions[1], (size_t) _pmeGridDimensions[2]};
vector<size_t> axes = {0, 1, 2};
vector<ptrdiff_t> stride = {(ptrdiff_t) (_pmeGridDimensions[1]*_pmeGridDimensions[2]*sizeof(complex<double>)),
(ptrdiff_t) (_pmeGridDimensions[2]*sizeof(complex<double>)),
(ptrdiff_t) sizeof(complex<double>)};
pocketfft::c2c(shape, stride, stride, axes, true, _pmeGrid.data(), _pmeGrid.data(), 1.0, 0);
performAmoebaReciprocalConvolution();
fftpack_exec_3d(_fftplan, FFTPACK_BACKWARD, _pmeGrid.data(), _pmeGrid.data());
pocketfft::c2c(shape, stride, stride, axes, false, _pmeGrid.data(), _pmeGrid.data(), 1.0, 0);
computeFixedPotentialFromGrid();
recordFixedMultipoleField();
......@@ -1875,7 +1867,7 @@ void AmoebaReferencePmeHippoNonbondedForce::spreadFixedMultipolesOntoGrid(const
// Clear the grid.
for (int gridIndex = 0; gridIndex < _pmeGrid.size(); gridIndex++)
_pmeGrid[gridIndex] = t_complex(0, 0);
_pmeGrid[gridIndex] = complex<double>(0, 0);
// Loop over atoms and spread them on the grid.
......@@ -1904,8 +1896,8 @@ void AmoebaReferencePmeHippoNonbondedForce::spreadFixedMultipolesOntoGrid(const
for (int iz = 0; iz < AMOEBA_PME_ORDER; iz++) {
int z = (gridPoint[2]+iz) % _pmeGridDimensions[2];
HippoDouble4 v = _thetai[2][atomIndex*AMOEBA_PME_ORDER+iz];
t_complex& gridValue = _pmeGrid[x*_pmeGridDimensions[1]*_pmeGridDimensions[2]+y*_pmeGridDimensions[2]+z];
gridValue.re += term0*v[0] + term1*v[1] + term2*v[2];
complex<double>& gridValue = _pmeGrid[x*_pmeGridDimensions[1]*_pmeGridDimensions[2]+y*_pmeGridDimensions[2]+z];
gridValue += term0*v[0] + term1*v[1] + term2*v[2];
}
}
}
......@@ -1923,7 +1915,7 @@ void AmoebaReferencePmeHippoNonbondedForce::performAmoebaReciprocalConvolution()
int kz = remainder-ky*_pmeGridDimensions[2];
if (kx == 0 && ky == 0 && kz == 0) {
_pmeGrid[index].re = _pmeGrid[index].im = 0.0;
_pmeGrid[index] = complex<double>(0, 0);
continue;
}
......@@ -1943,8 +1935,7 @@ void AmoebaReferencePmeHippoNonbondedForce::performAmoebaReciprocalConvolution()
double denom = m2*bx*by*bz;
double eterm = scaleFactor*exp(-expFactor*m2)/denom;
_pmeGrid[index].re *= eterm;
_pmeGrid[index].im *= eterm;
_pmeGrid[index] *= eterm;
}
}
......@@ -1993,7 +1984,7 @@ void AmoebaReferencePmeHippoNonbondedForce::computeFixedPotentialFromGrid() {
for (int ix = 0; ix < AMOEBA_PME_ORDER; ix++) {
int i = gridPoint[0]+ix-(gridPoint[0]+ix >= _pmeGridDimensions[0] ? _pmeGridDimensions[0] : 0);
int gridIndex = i*_pmeGridDimensions[1]*_pmeGridDimensions[2] + j*_pmeGridDimensions[2] + k;
double tq = _pmeGrid[gridIndex].re;
double tq = _pmeGrid[gridIndex].real();
HippoDouble4 tadd = _thetai[0][m*AMOEBA_PME_ORDER+ix];
t[0] += tq*tadd[0];
t[1] += tq*tadd[1];
......@@ -2066,7 +2057,7 @@ void AmoebaReferencePmeHippoNonbondedForce::spreadInducedDipolesOnGrid(const vec
// Clear the grid.
for (int gridIndex = 0; gridIndex < _pmeGrid.size(); gridIndex++)
_pmeGrid[gridIndex] = t_complex(0, 0);
_pmeGrid[gridIndex] = complex<double>(0, 0);
// Loop over atoms and spread them on the grid.
......@@ -2086,8 +2077,8 @@ void AmoebaReferencePmeHippoNonbondedForce::spreadInducedDipolesOnGrid(const vec
for (int iz = 0; iz < AMOEBA_PME_ORDER; iz++) {
int z = (gridPoint[2]+iz) % _pmeGridDimensions[2];
HippoDouble4 v = _thetai[2][atomIndex*AMOEBA_PME_ORDER+iz];
t_complex& gridValue = _pmeGrid[x*_pmeGridDimensions[1]*_pmeGridDimensions[2]+y*_pmeGridDimensions[2]+z];
gridValue.re += term01*v[0] + term11*v[1];
complex<double>& gridValue = _pmeGrid[x*_pmeGridDimensions[1]*_pmeGridDimensions[2]+y*_pmeGridDimensions[2]+z];
gridValue += term01*v[0] + term11*v[1];
}
}
}
......@@ -2142,12 +2133,12 @@ void AmoebaReferencePmeHippoNonbondedForce::computeInducedPotentialFromGrid() {
for (int ix = 0; ix < AMOEBA_PME_ORDER; ix++) {
int i = gridPoint[0]+ix-(gridPoint[0]+ix >= _pmeGridDimensions[0] ? _pmeGridDimensions[0] : 0);
int gridIndex = i*_pmeGridDimensions[1]*_pmeGridDimensions[2] + j*_pmeGridDimensions[2] + k;
t_complex tq = _pmeGrid[gridIndex];
complex<double> tq = _pmeGrid[gridIndex];
HippoDouble4 tadd = _thetai[0][m*AMOEBA_PME_ORDER+ix];
t0 += tq.re*tadd[0];
t1 += tq.re*tadd[1];
t2 += tq.re*tadd[2];
t3 += tq.re*tadd[3];
t0 += tq.real()*tadd[0];
t1 += tq.real()*tadd[1];
t2 += tq.real()*tadd[2];
t3 += tq.real()*tadd[3];
}
tu00 += t0*u[0];
tu10 += t1*u[0];
......@@ -2412,9 +2403,14 @@ void AmoebaReferencePmeHippoNonbondedForce::calculateReciprocalSpaceInducedDipol
initializePmeGrid();
spreadInducedDipolesOnGrid(_inducedDipole);
fftpack_exec_3d(_fftplan, FFTPACK_FORWARD, _pmeGrid.data(), _pmeGrid.data());
vector<size_t> shape = {(size_t) _pmeGridDimensions[0], (size_t) _pmeGridDimensions[1], (size_t) _pmeGridDimensions[2]};
vector<size_t> axes = {0, 1, 2};
vector<ptrdiff_t> stride = {(ptrdiff_t) (_pmeGridDimensions[1]*_pmeGridDimensions[2]*sizeof(complex<double>)),
(ptrdiff_t) (_pmeGridDimensions[2]*sizeof(complex<double>)),
(ptrdiff_t) sizeof(complex<double>)};
pocketfft::c2c(shape, stride, stride, axes, true, _pmeGrid.data(), _pmeGrid.data(), 1.0, 0);
performAmoebaReciprocalConvolution();
fftpack_exec_3d(_fftplan, FFTPACK_BACKWARD, _pmeGrid.data(), _pmeGrid.data());
pocketfft::c2c(shape, stride, stride, axes, false, _pmeGrid.data(), _pmeGrid.data(), 1.0, 0);
computeInducedPotentialFromGrid();
recordInducedDipoleField(_inducedDipoleField);
}
......
/* Portions copyright (c) 2006-2019 Stanford University and Simbios.
/* Portions copyright (c) 2006-2022 Stanford University and Simbios.
* Contributors: Pande Group
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -31,7 +31,6 @@
#include <map>
#include <utility>
#include <vector>
#include "fftpack.h"
#include <complex>
namespace OpenMM {
......@@ -110,12 +109,6 @@ public:
*/
AmoebaReferenceHippoNonbondedForce(const HippoNonbondedForce& force);
/**
* Destructor
*
*/
virtual ~AmoebaReferenceHippoNonbondedForce() {};
/**
* Get nonbonded method.
*
......@@ -655,9 +648,7 @@ private:
int _pmeGridDimensions[3];
int _dpmeGridDimensions[3];
fftpack_t _fftplan;
std::vector<t_complex> _pmeGrid;
std::vector<std::complex<double> > _pmeGrid;
std::vector<double> _pmeBsplineModuli[3];
std::vector<HippoDouble4> _thetai[3];
......
/* Portions copyright (c) 2006-2015 Stanford University and Simbios.
/* Portions copyright (c) 2006-222 Stanford University and Simbios.
* Contributors: Pande Group
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -26,6 +26,10 @@
#include "SimTKOpenMMRealType.h"
#include "jama_svd.h"
#include <algorithm>
#ifdef _MSC_VER
#define POCKETFFT_NO_VECTORS
#endif
#include "pocketfft_hdronly.h"
// In case we're using some primitive version of Visual Studio this will
// make sure that erf() and erfc() are defined.
......@@ -4809,16 +4813,12 @@ AmoebaReferencePmeMultipoleForce::AmoebaReferencePmeMultipoleForce() :
_pmeGridSize(0), _totalGridSize(0), _alphaEwald(0.0)
{
_fftplan = NULL;
_pmeGrid = NULL;
_pmeGridDimensions = IntVec(-1, -1, -1);
}
AmoebaReferencePmeMultipoleForce::~AmoebaReferencePmeMultipoleForce()
{
if (_fftplan) {
fftpack_destroy(_fftplan);
}
if (_pmeGrid) {
delete[] _pmeGrid;
}
......@@ -4863,11 +4863,6 @@ void AmoebaReferencePmeMultipoleForce::setPmeGridDimensions(vector<int>& pmeGrid
(pmeGridDimensions[2] == _pmeGridDimensions[2]))
return;
if (_fftplan) {
fftpack_destroy(_fftplan);
}
fftpack_init_3d(&_fftplan,pmeGridDimensions[0], pmeGridDimensions[1], pmeGridDimensions[2]);
_pmeGridDimensions[0] = pmeGridDimensions[0];
_pmeGridDimensions[1] = pmeGridDimensions[1];
_pmeGridDimensions[2] = pmeGridDimensions[2];
......@@ -4908,7 +4903,7 @@ void AmoebaReferencePmeMultipoleForce::resizePmeArrays()
if (_pmeGrid) {
delete[] _pmeGrid;
}
_pmeGrid = new t_complex[_totalGridSize];
_pmeGrid = new complex<double>[_totalGridSize];
_pmeGridSize = _totalGridSize;
}
......@@ -4930,7 +4925,7 @@ void AmoebaReferencePmeMultipoleForce::initializePmeGrid()
return;
for (int jj = 0; jj < _totalGridSize; jj++)
_pmeGrid[jj].re = _pmeGrid[jj].im = 0.0;
_pmeGrid[jj] = complex<double>(0, 0);
}
void AmoebaReferencePmeMultipoleForce::getPeriodicDelta(Vec3& deltaR) const
......@@ -5175,9 +5170,14 @@ void AmoebaReferencePmeMultipoleForce::calculateFixedMultipoleField(const vector
computeAmoebaBsplines(particleData);
initializePmeGrid();
spreadFixedMultipolesOntoGrid(particleData);
fftpack_exec_3d(_fftplan, FFTPACK_FORWARD, _pmeGrid, _pmeGrid);
vector<size_t> shape = {(size_t) _pmeGridDimensions[0], (size_t) _pmeGridDimensions[1], (size_t) _pmeGridDimensions[2]};
vector<size_t> axes = {0, 1, 2};
vector<ptrdiff_t> stride = {(ptrdiff_t) (_pmeGridDimensions[1]*_pmeGridDimensions[2]*sizeof(complex<double>)),
(ptrdiff_t) (_pmeGridDimensions[2]*sizeof(complex<double>)),
(ptrdiff_t) sizeof(complex<double>)};
pocketfft::c2c(shape, stride, stride, axes, true, _pmeGrid, _pmeGrid, 1.0, 0);
performAmoebaReciprocalConvolution();
fftpack_exec_3d(_fftplan, FFTPACK_BACKWARD, _pmeGrid, _pmeGrid);
pocketfft::c2c(shape, stride, stride, axes, false, _pmeGrid, _pmeGrid, 1.0, 0);
computeFixedPotentialFromGrid();
recordFixedMultipoleField();
......@@ -5385,7 +5385,7 @@ void AmoebaReferencePmeMultipoleForce::spreadFixedMultipolesOntoGrid(const vecto
// Clear the grid.
for (int gridIndex = 0; gridIndex < _totalGridSize; gridIndex++)
_pmeGrid[gridIndex] = t_complex(0, 0);
_pmeGrid[gridIndex] = complex<double>(0, 0);
// Loop over atoms and spread them on the grid.
......@@ -5414,8 +5414,8 @@ void AmoebaReferencePmeMultipoleForce::spreadFixedMultipolesOntoGrid(const vecto
for (int iz = 0; iz < AMOEBA_PME_ORDER; iz++) {
int z = (gridPoint[2]+iz) % _pmeGridDimensions[2];
double4 v = _thetai[2][atomIndex*AMOEBA_PME_ORDER+iz];
t_complex& gridValue = _pmeGrid[x*_pmeGridDimensions[1]*_pmeGridDimensions[2]+y*_pmeGridDimensions[2]+z];
gridValue.re += term0*v[0] + term1*v[1] + term2*v[2];
complex<double>& gridValue = _pmeGrid[x*_pmeGridDimensions[1]*_pmeGridDimensions[2]+y*_pmeGridDimensions[2]+z];
gridValue += term0*v[0] + term1*v[1] + term2*v[2];
}
}
}
......@@ -5436,7 +5436,7 @@ void AmoebaReferencePmeMultipoleForce::performAmoebaReciprocalConvolution()
int kz = remainder-ky*_pmeGridDimensions[2];
if (kx == 0 && ky == 0 && kz == 0) {
_pmeGrid[index].re = _pmeGrid[index].im = 0.0;
_pmeGrid[index] = complex<double>(0, 0);
continue;
}
......@@ -5456,8 +5456,7 @@ void AmoebaReferencePmeMultipoleForce::performAmoebaReciprocalConvolution()
double denom = m2*bx*by*bz;
double eterm = scaleFactor*exp(-expFactor*m2)/denom;
_pmeGrid[index].re *= eterm;
_pmeGrid[index].im *= eterm;
_pmeGrid[index] *= eterm;
}
}
......@@ -5507,7 +5506,7 @@ void AmoebaReferencePmeMultipoleForce::computeFixedPotentialFromGrid()
for (int ix = 0; ix < AMOEBA_PME_ORDER; ix++) {
int i = gridPoint[0]+ix-(gridPoint[0]+ix >= _pmeGridDimensions[0] ? _pmeGridDimensions[0] : 0);
int gridIndex = i*_pmeGridDimensions[1]*_pmeGridDimensions[2] + j*_pmeGridDimensions[2] + k;
double tq = _pmeGrid[gridIndex].re;
double tq = _pmeGrid[gridIndex].real();
double4 tadd = _thetai[0][m*AMOEBA_PME_ORDER+ix];
t[0] += tq*tadd[0];
t[1] += tq*tadd[1];
......@@ -5581,7 +5580,7 @@ void AmoebaReferencePmeMultipoleForce::spreadInducedDipolesOnGrid(const vector<V
// Clear the grid.
for (int gridIndex = 0; gridIndex < _totalGridSize; gridIndex++)
_pmeGrid[gridIndex] = t_complex(0, 0);
_pmeGrid[gridIndex] = complex<double>(0, 0);
// Loop over atoms and spread them on the grid.
......@@ -5606,9 +5605,8 @@ void AmoebaReferencePmeMultipoleForce::spreadInducedDipolesOnGrid(const vector<V
for (int iz = 0; iz < AMOEBA_PME_ORDER; iz++) {
int z = (gridPoint[2]+iz) % _pmeGridDimensions[2];
double4 v = _thetai[2][atomIndex*AMOEBA_PME_ORDER+iz];
t_complex& gridValue = _pmeGrid[x*_pmeGridDimensions[1]*_pmeGridDimensions[2]+y*_pmeGridDimensions[2]+z];
gridValue.re += term01*v[0] + term11*v[1];
gridValue.im += term02*v[0] + term12*v[1];
complex<double>& gridValue = _pmeGrid[x*_pmeGridDimensions[1]*_pmeGridDimensions[2]+y*_pmeGridDimensions[2]+z];
gridValue += complex<double>(term01*v[0] + term11*v[1], term02*v[0] + term12*v[1]);
}
}
}
......@@ -5697,15 +5695,15 @@ void AmoebaReferencePmeMultipoleForce::computeInducedPotentialFromGrid()
for (int ix = 0; ix < AMOEBA_PME_ORDER; ix++) {
int i = gridPoint[0]+ix-(gridPoint[0]+ix >= _pmeGridDimensions[0] ? _pmeGridDimensions[0] : 0);
int gridIndex = i*_pmeGridDimensions[1]*_pmeGridDimensions[2] + j*_pmeGridDimensions[2] + k;
t_complex tq = _pmeGrid[gridIndex];
complex<double> tq = _pmeGrid[gridIndex];
double4 tadd = _thetai[0][m*AMOEBA_PME_ORDER+ix];
t0_1 += tq.re*tadd[0];
t1_1 += tq.re*tadd[1];
t2_1 += tq.re*tadd[2];
t0_2 += tq.im*tadd[0];
t1_2 += tq.im*tadd[1];
t2_2 += tq.im*tadd[2];
t3 += (tq.re+tq.im)*tadd[3];
t0_1 += tq.real()*tadd[0];
t1_1 += tq.real()*tadd[1];
t2_1 += tq.real()*tadd[2];
t0_2 += tq.imag()*tadd[0];
t1_2 += tq.imag()*tadd[1];
t2_2 += tq.imag()*tadd[2];
t3 += (tq.real()+tq.imag())*tadd[3];
}
tu00_1 += t0_1*u[0];
tu10_1 += t1_1*u[0];
......@@ -6049,9 +6047,14 @@ void AmoebaReferencePmeMultipoleForce::calculateReciprocalSpaceInducedDipoleFiel
initializePmeGrid();
spreadInducedDipolesOnGrid(*updateInducedDipoleFields[0].inducedDipoles, *updateInducedDipoleFields[1].inducedDipoles);
fftpack_exec_3d(_fftplan, FFTPACK_FORWARD, _pmeGrid, _pmeGrid);
vector<size_t> shape = {(size_t) _pmeGridDimensions[0], (size_t) _pmeGridDimensions[1], (size_t) _pmeGridDimensions[2]};
vector<size_t> axes = {0, 1, 2};
vector<ptrdiff_t> stride = {(ptrdiff_t) (_pmeGridDimensions[1]*_pmeGridDimensions[2]*sizeof(complex<double>)),
(ptrdiff_t) (_pmeGridDimensions[2]*sizeof(complex<double>)),
(ptrdiff_t) sizeof(complex<double>)};
pocketfft::c2c(shape, stride, stride, axes, true, _pmeGrid, _pmeGrid, 1.0, 0);
performAmoebaReciprocalConvolution();
fftpack_exec_3d(_fftplan, FFTPACK_BACKWARD, _pmeGrid, _pmeGrid);
pocketfft::c2c(shape, stride, stride, axes, false, _pmeGrid, _pmeGrid, 1.0, 0);
computeInducedPotentialFromGrid();
recordInducedDipoleField(updateInducedDipoleFields[0].inducedDipoleField, updateInducedDipoleFields[1].inducedDipoleField);
}
......
/* Portions copyright (c) 2006-2015 Stanford University and Simbios.
/* Portions copyright (c) 2006-2022 Stanford University and Simbios.
* Contributors: Pande Group
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -28,7 +28,6 @@
#include "openmm/Vec3.h"
#include "AmoebaReferenceGeneralizedKirkwoodForce.h"
#include <map>
#include "fftpack.h"
#include <complex>
namespace OpenMM {
......@@ -1474,10 +1473,8 @@ private:
int _totalGridSize;
IntVec _pmeGridDimensions;
fftpack_t _fftplan;
unsigned int _pmeGridSize;
t_complex* _pmeGrid;
std::complex<double>* _pmeGrid;
std::vector<double> _pmeBsplineModuli[3];
std::vector<double4> _thetai[3];
......
......@@ -64,17 +64,14 @@ IF(NOT MSVC)
ENDIF()
ENDIF()
# Include FFTW related files.
INCLUDE_DIRECTORIES(${FFTW_INCLUDES})
# Include PocketFFT.
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/libraries/include/pocketfft")
# Build the shared plugin library.
IF (OPENMM_BUILD_SHARED_LIB)
ADD_LIBRARY(${SHARED_TARGET} SHARED ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${API_INCLUDE_FILES})
TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${OPENMM_LIBRARY_NAME} ${PTHREADS_LIB} ${FFTW_LIBRARY})
IF (FFTW_THREADS_LIBRARY)
TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${FFTW_THREADS_LIBRARY})
ENDIF (FFTW_THREADS_LIBRARY)
TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${OPENMM_LIBRARY_NAME} ${PTHREADS_LIB})
SET_TARGET_PROPERTIES(${SHARED_TARGET} PROPERTIES LINK_FLAGS "${EXTRA_LINK_FLAGS}" COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_PME_BUILDING_SHARED_LIBRARY")
INSTALL_TARGETS(/lib/plugins RUNTIME_DIRECTORY /lib/plugins ${SHARED_TARGET})
......@@ -84,10 +81,7 @@ ENDIF (OPENMM_BUILD_SHARED_LIB)
IF(OPENMM_BUILD_STATIC_LIB)
ADD_LIBRARY(${STATIC_TARGET} STATIC ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${API_INCLUDE_FILES})
TARGET_LINK_LIBRARIES(${STATIC_TARGET} ${OPENMM_LIBRARY_NAME}_static ${PTHREADS_LIB} ${FFTW_LIBRARY})
IF (FFTW_THREADS_LIBRARY)
TARGET_LINK_LIBRARIES(${STATIC_TARGET} ${FFTW_THREADS_LIBRARY})
ENDIF (FFTW_THREADS_LIBRARY)
TARGET_LINK_LIBRARIES(${STATIC_TARGET} ${OPENMM_LIBRARY_NAME}_static ${PTHREADS_LIB})
SET_TARGET_PROPERTIES(${STATIC_TARGET} PROPERTIES LINK_FLAGS "${EXTRA_LINK_FLAGS}" COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_PME_BUILDING_STATIC_LIBRARY")
INSTALL_TARGETS(/lib/plugins RUNTIME_DIRECTORY /lib/plugins ${STATIC_TARGET})
......
This diff is collapsed.
......@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2013-2018 Stanford University and the Authors. *
* Portions copyright (c) 2013-2022 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -38,7 +38,7 @@
#include "openmm/Vec3.h"
#include "openmm/internal/ThreadPool.h"
#include <atomic>
#include <fftw3.h>
#include <complex>
#include <pthread.h>
#include <vector>
......@@ -46,13 +46,13 @@ namespace OpenMM {
/**
* This is an optimized CPU implementation of CalcPmeReciprocalForceKernel. It is both
* vectorized (requiring SSE 4.1) and multithreaded. It uses FFTW to perform the FFTs.
* vectorized (requiring SSE 4.1) and multithreaded. It uses PocketFFT to perform the FFTs.
*/
class OPENMM_EXPORT_PME CpuCalcPmeReciprocalForceKernel : public CalcPmeReciprocalForceKernel {
public:
CpuCalcPmeReciprocalForceKernel(const std::string& name, const Platform& platform) : CalcPmeReciprocalForceKernel(name, platform),
hasCreatedPlan(false), isDeleted(false), realGrid(NULL), complexGrid(NULL) {
isDeleted(false) {
}
/**
* Initialize the kernel.
......@@ -104,24 +104,24 @@ public:
void getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const;
private:
/**
* Select a size for one grid dimension that FFTW can handle efficiently.
* Select a size for one grid dimension that PocketFFT can handle efficiently.
*/
int findFFTDimension(int minimum, bool isZ);
int findFFTDimension(int minimum);
static bool hasInitializedThreads;
static int numThreads;
int gridx, gridy, gridz, numParticles;
double alpha;
bool deterministic;
bool hasCreatedPlan, isFinished, isDeleted;
bool isFinished, isDeleted;
std::vector<float> force;
std::vector<float> bsplineModuli[3];
std::vector<float> recipEterm;
Vec3 lastBoxVectors[3];
std::vector<float> threadEnergy;
std::vector<float*> tempGrid;
float* realGrid;
fftwf_complex* complexGrid;
fftwf_plan forwardFFT, backwardFFT;
std::vector<std::vector<float> > realGrids;
std::vector<std::complex<float> > complexGrid;
std::vector<std::size_t> gridShape, fftAxes;
std::vector<std::ptrdiff_t> realGridStride, complexGridStride;
int waitCount;
pthread_cond_t startCondition, endCondition;
pthread_mutex_t lock;
......@@ -139,13 +139,13 @@ private:
/**
* This is an optimized CPU implementation of CalcDispersionPmeReciprocalForceKernel. It is both
* vectorized (requiring SSE 4.1) and multithreaded. It uses FFTW to perform the FFTs.
* vectorized (requiring SSE 4.1) and multithreaded. It uses PocketFFT to perform the FFTs.
*/
class OPENMM_EXPORT_PME CpuCalcDispersionPmeReciprocalForceKernel : public CalcDispersionPmeReciprocalForceKernel {
public:
CpuCalcDispersionPmeReciprocalForceKernel(const std::string& name, const Platform& platform) : CalcDispersionPmeReciprocalForceKernel(name, platform),
hasCreatedPlan(false), isDeleted(false), realGrid(NULL), complexGrid(NULL) {
isDeleted(false) {
}
/**
* Initialize the kernel.
......@@ -198,24 +198,24 @@ public:
private:
class ComputeTask;
/**
* Select a size for one grid dimension that FFTW can handle efficiently.
* Select a size for one grid dimension that PocketFFT can handle efficiently.
*/
int findFFTDimension(int minimum, bool isZ);
int findFFTDimension(int minimum);
static bool hasInitializedThreads;
static int numThreads;
int gridx, gridy, gridz, numParticles;
double alpha;
bool deterministic;
bool hasCreatedPlan, isFinished, isDeleted;
bool isFinished, isDeleted;
std::vector<float> force;
std::vector<float> bsplineModuli[3];
std::vector<float> recipEterm;
Vec3 lastBoxVectors[3];
std::vector<float> threadEnergy;
std::vector<float*> tempGrid;
float* realGrid;
fftwf_complex* complexGrid;
fftwf_plan forwardFFT, backwardFFT;
std::vector<std::vector<float> > realGrids;
std::vector<std::complex<float> > complexGrid;
std::vector<std::size_t> gridShape, fftAxes;
std::vector<std::ptrdiff_t> realGridStride, complexGridStride;
int waitCount;
pthread_cond_t startCondition, endCondition;
pthread_mutex_t lock;
......
......@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2011-2013 Stanford University and the Authors. *
* Portions copyright (c) 2011-2022 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -35,7 +35,6 @@
#include "ReferencePlatform.h"
#include "openmm/RpmdKernels.h"
#include "openmm/Vec3.h"
#include "fftpack.h"
namespace OpenMM {
......@@ -46,9 +45,8 @@ namespace OpenMM {
class ReferenceIntegrateRPMDStepKernel : public IntegrateRPMDStepKernel {
public:
ReferenceIntegrateRPMDStepKernel(const std::string& name, const Platform& platform) :
IntegrateRPMDStepKernel(name, platform), fft(NULL) {
IntegrateRPMDStepKernel(name, platform) {
}
~ReferenceIntegrateRPMDStepKernel();
/**
* Initialize the kernel.
*
......@@ -93,8 +91,6 @@ private:
std::vector<std::vector<Vec3> > contractedForces;
std::map<int, int> groupsByCopies;
int groupsNotContracted;
fftpack* fft;
std::map<int, fftpack*> contractionFFT;
};
} // namespace OpenMM
......
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