diff --git a/bfps/cpp/field.cpp b/bfps/cpp/field.cpp index a456b8a99b0989d4456f13907f91be0750b0f824..8a51ed5f830983cb7650ace4cf34971a6b2a03de 100644 --- a/bfps/cpp/field.cpp +++ b/bfps/cpp/field.cpp @@ -648,275 +648,6 @@ void field<rnumber, be, fc>::compute_stats( } } -template <field_backend be, - kspace_dealias_type dt> -template <field_components fc> -kspace<be, dt>::kspace( - const field_layout<fc> *source_layout, - const double DKX, - const double DKY, - const double DKZ) -{ - TIMEZONE("field::kspace"); - /* get layout */ - this->layout = new field_layout<ONE>( - source_layout->sizes, - source_layout->subsizes, - source_layout->starts, - source_layout->comm); - - /* store dk values */ - this->dkx = DKX; - this->dky = DKY; - this->dkz = DKZ; - - /* compute kx, ky, kz and compute kM values */ - switch(be) - { - case FFTW: - this->kx.resize(this->layout->sizes[2]); - this->ky.resize(this->layout->subsizes[0]); - this->kz.resize(this->layout->sizes[1]); - int i, ii; - for (i = 0; i<int(this->layout->sizes[2]); i++) - this->kx[i] = i*this->dkx; - for (i = 0; i<int(this->layout->subsizes[0]); i++) - { - ii = i + this->layout->starts[0]; - if (ii <= int(this->layout->sizes[1]/2)) - this->ky[i] = this->dky*ii; - else - this->ky[i] = this->dky*(ii - int(this->layout->sizes[1])); - } - for (i = 0; i<int(this->layout->sizes[1]); i++) - { - if (i <= int(this->layout->sizes[0]/2)) - this->kz[i] = this->dkz*i; - else - this->kz[i] = this->dkz*(i - int(this->layout->sizes[0])); - } - switch(dt) - { - case TWO_THIRDS: - this->kMx = this->dkx*(int(2*(int(this->layout->sizes[2])-1)/3)-1); - this->kMy = this->dky*(int(this->layout->sizes[0] / 3)-1); - this->kMz = this->dkz*(int(this->layout->sizes[1] / 3)-1); - break; - case SMOOTH: - this->kMx = this->dkx*(int(this->layout->sizes[2])-2); - this->kMy = this->dky*(int(this->layout->sizes[0] / 2)-1); - this->kMz = this->dkz*(int(this->layout->sizes[1] / 2)-1); - break; - } - break; - } - - /* get global kM and dk */ - this->kM = this->kMx; - if (this->kM < this->kMy) this->kM = this->kMy; - if (this->kM < this->kMz) this->kM = this->kMz; - this->kM2 = this->kM * this->kM; - this->dk = this->dkx; - if (this->dk > this->dky) this->dk = this->dky; - if (this->dk > this->dkz) this->dk = this->dkz; - this->dk2 = this->dk*this->dk; - - /* spectra stuff */ - this->nshells = int(this->kM / this->dk) + 2; - this->kshell.resize(this->nshells, 0); - this->nshell.resize(this->nshells, 0); - std::vector<double> kshell_local; - kshell_local.resize(this->nshells, 0); - std::vector<int64_t> nshell_local; - nshell_local.resize(this->nshells, 0); - this->CLOOP_K2_NXMODES( - [&](ptrdiff_t cindex, - ptrdiff_t xindex, - ptrdiff_t yindex, - ptrdiff_t zindex, - double k2, - int nxmodes){ - if (k2 < this->kM2) - { - double knorm = sqrt(k2); - nshell_local[int(knorm/this->dk)] += nxmodes; - kshell_local[int(knorm/this->dk)] += nxmodes*knorm; - } - if (dt == SMOOTH) - this->dealias_filter[int(round(k2 / this->dk2))] = \ - exp(-36.0 * pow(k2/this->kM2, 18.)); - }); - MPI_Allreduce( - &nshell_local.front(), - &this->nshell.front(), - this->nshells, - MPI_INT64_T, MPI_SUM, this->layout->comm); - MPI_Allreduce( - &kshell_local.front(), - &this->kshell.front(), - this->nshells, - MPI_DOUBLE, MPI_SUM, this->layout->comm); - for (int n=0; n<this->nshells; n++) - this->kshell[n] /= this->nshell[n]; -} - -template <field_backend be, - kspace_dealias_type dt> -kspace<be, dt>::~kspace() -{ - delete this->layout; -} - -template <field_backend be, - kspace_dealias_type dt> -template <typename rnumber, - field_components fc> -void kspace<be, dt>::low_pass(rnumber *__restrict__ a, const double kmax) -{ - const double km2 = kmax*kmax; - this->CLOOP_K2( - [&](ptrdiff_t cindex, - ptrdiff_t xindex, - ptrdiff_t yindex, - ptrdiff_t zindex, - double k2){ - if (k2 >= km2) - std::fill_n(a + 2*ncomp(fc)*cindex, 2*ncomp(fc), 0); - }); -} - -template <field_backend be, - kspace_dealias_type dt> -template <typename rnumber, - field_components fc> -void kspace<be, dt>::dealias(typename fftw_interface<rnumber>::complex *__restrict__ a) -{ - switch(dt) - { - case TWO_THIRDS: - this->low_pass<rnumber, fc>((rnumber*)a, this->kM); - break; - case SMOOTH: - this->CLOOP_K2( - [&](ptrdiff_t cindex, - ptrdiff_t xindex, - ptrdiff_t yindex, - ptrdiff_t zindex, - double k2){ - double tval = this->dealias_filter[int(round(k2 / this->dk2))]; - for (int tcounter=0; tcounter<2*ncomp(fc); tcounter++) - ((rnumber*)a)[2*ncomp(fc)*cindex + tcounter] *= tval; - }); - break; - } -} - -template <field_backend be, - kspace_dealias_type dt> -template <typename rnumber> -void kspace<be, dt>::force_divfree(typename fftw_interface<rnumber>::complex *__restrict__ a) -{ - TIMEZONE("kspace::force_divfree"); - typename fftw_interface<rnumber>::complex tval; - this->CLOOP_K2( - [&](ptrdiff_t cindex, - ptrdiff_t xindex, - ptrdiff_t yindex, - ptrdiff_t zindex, - double k2){ - if (k2 > 0) - { - tval[0] = (this->kx[xindex]*((*(a + cindex*3 ))[0]) + - this->ky[yindex]*((*(a + cindex*3+1))[0]) + - this->kz[zindex]*((*(a + cindex*3+2))[0]) ) / k2; - tval[1] = (this->kx[xindex]*((*(a + cindex*3 ))[1]) + - this->ky[yindex]*((*(a + cindex*3+1))[1]) + - this->kz[zindex]*((*(a + cindex*3+2))[1]) ) / k2; - for (int imag_part=0; imag_part<2; imag_part++) - { - a[cindex*3 ][imag_part] -= tval[imag_part]*this->kx[xindex]; - a[cindex*3+1][imag_part] -= tval[imag_part]*this->ky[yindex]; - a[cindex*3+2][imag_part] -= tval[imag_part]*this->kz[zindex]; - } - } - } - ); - if (this->layout->myrank == this->layout->rank[0][0]) - std::fill_n((rnumber*)(a), 6, 0.0); -} - -template <field_backend be, - kspace_dealias_type dt> -template <typename rnumber, - field_components fc> -void kspace<be, dt>::cospectrum( - const rnumber(* __restrict a)[2], - const rnumber(* __restrict b)[2], - const hid_t group, - const std::string dset_name, - const hsize_t toffset) -{ - TIMEZONE("field::cospectrum"); - std::vector<double> spec, spec_local; - spec.resize(this->nshells*ncomp(fc)*ncomp(fc), 0); - spec_local.resize(this->nshells*ncomp(fc)*ncomp(fc), 0); - this->CLOOP_K2_NXMODES( - [&](ptrdiff_t cindex, - ptrdiff_t xindex, - ptrdiff_t yindex, - ptrdiff_t zindex, - double k2, - int nxmodes){ - if (k2 <= this->kM2) - { - int tmp_int = int(sqrt(k2) / this->dk)*ncomp(fc)*ncomp(fc); - for (hsize_t i=0; i<ncomp(fc); i++) - for (hsize_t j=0; j<ncomp(fc); j++) - spec_local[tmp_int + i*ncomp(fc)+j] += nxmodes * ( - (a[ncomp(fc)*cindex + i][0] * b[ncomp(fc)*cindex + j][0]) + - (a[ncomp(fc)*cindex + i][1] * b[ncomp(fc)*cindex + j][1])); - } - }); - MPI_Allreduce( - &spec_local.front(), - &spec.front(), - spec.size(), - MPI_DOUBLE, MPI_SUM, this->layout->comm); - if (this->layout->myrank == 0) - { - hid_t dset, wspace, mspace; - hsize_t count[(ndim(fc)-2)*2], offset[(ndim(fc)-2)*2], dims[(ndim(fc)-2)*2]; - dset = H5Dopen(group, ("spectra/" + dset_name).c_str(), H5P_DEFAULT); - wspace = H5Dget_space(dset); - H5Sget_simple_extent_dims(wspace, dims, NULL); - switch (fc) - { - case THREExTHREE: - offset[4] = 0; - offset[5] = 0; - count[4] = ncomp(fc); - count[5] = ncomp(fc); - case THREE: - offset[2] = 0; - offset[3] = 0; - count[2] = ncomp(fc); - count[3] = ncomp(fc); - default: - offset[0] = toffset; - offset[1] = 0; - count[0] = 1; - count[1] = this->nshells; - } - mspace = H5Screate_simple((ndim(fc)-2)*2, count, NULL); - H5Sselect_hyperslab(wspace, H5S_SELECT_SET, offset, NULL, count, NULL); - H5Dwrite(dset, H5T_NATIVE_DOUBLE, mspace, wspace, H5P_DEFAULT, &spec.front()); - H5Sclose(wspace); - H5Sclose(mspace); - H5Dclose(dset); - } -} - - template <typename rnumber, field_backend be, field_components fc1, @@ -965,68 +696,6 @@ template class field<double, FFTW, ONE>; template class field<double, FFTW, THREE>; template class field<double, FFTW, THREExTHREE>; -template class kspace<FFTW, TWO_THIRDS>; -template class kspace<FFTW, SMOOTH>; - -template kspace<FFTW, TWO_THIRDS>::kspace<>( - const field_layout<ONE> *, - const double, const double, const double); -template kspace<FFTW, TWO_THIRDS>::kspace<>( - const field_layout<THREE> *, - const double, const double, const double); -template kspace<FFTW, TWO_THIRDS>::kspace<>( - const field_layout<THREExTHREE> *, - const double, const double, const double); - -template kspace<FFTW, SMOOTH>::kspace<>( - const field_layout<ONE> *, - const double, const double, const double); -template kspace<FFTW, SMOOTH>::kspace<>( - const field_layout<THREE> *, - const double, const double, const double); -template kspace<FFTW, SMOOTH>::kspace<>( - const field_layout<THREExTHREE> *, - const double, const double, const double); - -template void kspace<FFTW, SMOOTH>::low_pass<float, ONE>( - float *__restrict__ a, - const double kmax); -template void kspace<FFTW, SMOOTH>::low_pass<float, THREE>( - float *__restrict__ a, - const double kmax); -template void kspace<FFTW, SMOOTH>::low_pass<float, THREExTHREE>( - float *__restrict__ a, - const double kmax); - -template void kspace<FFTW, SMOOTH>::low_pass<double, ONE>( - double *__restrict__ a, - const double kmax); -template void kspace<FFTW, SMOOTH>::low_pass<double, THREE>( - double *__restrict__ a, - const double kmax); -template void kspace<FFTW, SMOOTH>::low_pass<double, THREExTHREE>( - double *__restrict__ a, - const double kmax); - -template void kspace<FFTW, SMOOTH>::dealias<float, ONE>( - typename fftw_interface<float>::complex *__restrict__ a); -template void kspace<FFTW, SMOOTH>::dealias<float, THREE>( - typename fftw_interface<float>::complex *__restrict__ a); -template void kspace<FFTW, SMOOTH>::dealias<float, THREExTHREE>( - typename fftw_interface<float>::complex *__restrict__ a); - -template void kspace<FFTW, SMOOTH>::dealias<double, ONE>( - typename fftw_interface<double>::complex *__restrict__ a); -template void kspace<FFTW, SMOOTH>::dealias<double, THREE>( - typename fftw_interface<double>::complex *__restrict__ a); -template void kspace<FFTW, SMOOTH>::dealias<double, THREExTHREE>( - typename fftw_interface<double>::complex *__restrict__ a); - -template void kspace<FFTW, SMOOTH>::force_divfree<float>( - typename fftw_interface<float>::complex *__restrict__ a); -template void kspace<FFTW, SMOOTH>::force_divfree<double>( - typename fftw_interface<double>::complex *__restrict__ a); - template void field<float, FFTW, ONE>::compute_stats<TWO_THIRDS>( kspace<FFTW, TWO_THIRDS> *, const hid_t, const std::string, const hsize_t, const double); diff --git a/bfps/cpp/field.hpp b/bfps/cpp/field.hpp index a1e38d03f766506ff3af980b3c8c0ec2f5781982..09b603d4f7ced58cd0b7ee06dc76c5bac6b491dd 100644 --- a/bfps/cpp/field.hpp +++ b/bfps/cpp/field.hpp @@ -28,116 +28,12 @@ #include <unordered_map> #include <vector> #include <string> -#include "fftw_interface.hpp" -#include "field_layout.hpp" +#include "kspace.hpp" #ifndef FIELD_HPP #define FIELD_HPP -enum field_backend {FFTW}; -enum kspace_dealias_type {TWO_THIRDS, SMOOTH}; - - -template <field_backend be, - kspace_dealias_type dt> -class kspace -{ - public: - /* relevant field layout */ - field_layout<ONE> *layout; - - /* physical parameters */ - double dkx, dky, dkz, dk, dk2; - - /* mode and dealiasing information */ - double kMx, kMy, kMz, kM, kM2; - std::vector<double> kx, ky, kz; - std::unordered_map<int, double> dealias_filter; - std::vector<double> kshell; - std::vector<int64_t> nshell; - int nshells; - - /* methods */ - template <field_components fc> - kspace( - const field_layout<fc> *source_layout, - const double DKX = 1.0, - const double DKY = 1.0, - const double DKZ = 1.0); - ~kspace(); - - template <typename rnumber, - field_components fc> - void low_pass(rnumber *__restrict__ a, const double kmax); - - template <typename rnumber, - field_components fc> - void dealias(typename fftw_interface<rnumber>::complex *__restrict__ a); - - template <typename rnumber, - field_components fc> - void cospectrum( - const rnumber(* __restrict__ a)[2], - const rnumber(* __restrict__ b)[2], - const hid_t group, - const std::string dset_name, - const hsize_t toffset); - template <class func_type> - void CLOOP(func_type expression) - { - ptrdiff_t cindex = 0; - for (hsize_t yindex = 0; yindex < this->layout->subsizes[0]; yindex++) - for (hsize_t zindex = 0; zindex < this->layout->subsizes[1]; zindex++) - for (hsize_t xindex = 0; xindex < this->layout->subsizes[2]; xindex++) - { - expression(cindex, xindex, yindex, zindex); - cindex++; - } - } - template <class func_type> - void CLOOP_K2(func_type expression) - { - double k2; - ptrdiff_t cindex = 0; - for (hsize_t yindex = 0; yindex < this->layout->subsizes[0]; yindex++) - for (hsize_t zindex = 0; zindex < this->layout->subsizes[1]; zindex++) - for (hsize_t xindex = 0; xindex < this->layout->subsizes[2]; xindex++) - { - k2 = (this->kx[xindex]*this->kx[xindex] + - this->ky[yindex]*this->ky[yindex] + - this->kz[zindex]*this->kz[zindex]); - expression(cindex, xindex, yindex, zindex, k2); - cindex++; - } - } - template <class func_type> - void CLOOP_K2_NXMODES(func_type expression) - { - ptrdiff_t cindex = 0; - for (hsize_t yindex = 0; yindex < this->layout->subsizes[0]; yindex++) - for (hsize_t zindex = 0; zindex < this->layout->subsizes[1]; zindex++) - { - hsize_t xindex = 0; - double k2 = ( - this->kx[xindex]*this->kx[xindex] + - this->ky[yindex]*this->ky[yindex] + - this->kz[zindex]*this->kz[zindex]); - expression(cindex, xindex, yindex, zindex, k2, 1); - cindex++; - for (xindex = 1; xindex < this->layout->subsizes[2]; xindex++) - { - k2 = (this->kx[xindex]*this->kx[xindex] + - this->ky[yindex]*this->ky[yindex] + - this->kz[zindex]*this->kz[zindex]); - expression(cindex, xindex, yindex, zindex, k2, 2); - cindex++; - } - } - } - template <typename rnumber> - void force_divfree(typename fftw_interface<rnumber>::complex *__restrict__ a); -}; template <typename rnumber, field_backend be, diff --git a/bfps/cpp/kspace.cpp b/bfps/cpp/kspace.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c0d957fa6e6bb030248e6477ec1bd0dc41961ef6 --- /dev/null +++ b/bfps/cpp/kspace.cpp @@ -0,0 +1,365 @@ +/********************************************************************** +* * +* Copyright 2015 Max Planck Institute * +* for Dynamics and Self-Organization * +* * +* This file is part of bfps. * +* * +* bfps is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published * +* by the Free Software Foundation, either version 3 of the License, * +* or (at your option) any later version. * +* * +* bfps is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with bfps. If not, see <http://www.gnu.org/licenses/> * +* * +* Contact: Cristian.Lalescu@ds.mpg.de * +* * +**********************************************************************/ + + +#include <cmath> +#include <cstdlib> +#include <algorithm> +#include <cassert> +#include "kspace.hpp" +#include "scope_timer.hpp" + + + +template <field_backend be, + kspace_dealias_type dt> +template <field_components fc> +kspace<be, dt>::kspace( + const field_layout<fc> *source_layout, + const double DKX, + const double DKY, + const double DKZ) +{ + TIMEZONE("field::kspace"); + /* get layout */ + this->layout = new field_layout<ONE>( + source_layout->sizes, + source_layout->subsizes, + source_layout->starts, + source_layout->comm); + + /* store dk values */ + this->dkx = DKX; + this->dky = DKY; + this->dkz = DKZ; + + /* compute kx, ky, kz and compute kM values */ + switch(be) + { + case FFTW: + this->kx.resize(this->layout->sizes[2]); + this->ky.resize(this->layout->subsizes[0]); + this->kz.resize(this->layout->sizes[1]); + int i, ii; + for (i = 0; i<int(this->layout->sizes[2]); i++) + this->kx[i] = i*this->dkx; + for (i = 0; i<int(this->layout->subsizes[0]); i++) + { + ii = i + this->layout->starts[0]; + if (ii <= int(this->layout->sizes[1]/2)) + this->ky[i] = this->dky*ii; + else + this->ky[i] = this->dky*(ii - int(this->layout->sizes[1])); + } + for (i = 0; i<int(this->layout->sizes[1]); i++) + { + if (i <= int(this->layout->sizes[0]/2)) + this->kz[i] = this->dkz*i; + else + this->kz[i] = this->dkz*(i - int(this->layout->sizes[0])); + } + switch(dt) + { + case TWO_THIRDS: + this->kMx = this->dkx*(int(2*(int(this->layout->sizes[2])-1)/3)-1); + this->kMy = this->dky*(int(this->layout->sizes[0] / 3)-1); + this->kMz = this->dkz*(int(this->layout->sizes[1] / 3)-1); + break; + case SMOOTH: + this->kMx = this->dkx*(int(this->layout->sizes[2])-2); + this->kMy = this->dky*(int(this->layout->sizes[0] / 2)-1); + this->kMz = this->dkz*(int(this->layout->sizes[1] / 2)-1); + break; + } + break; + } + + /* get global kM and dk */ + this->kM = this->kMx; + if (this->kM < this->kMy) this->kM = this->kMy; + if (this->kM < this->kMz) this->kM = this->kMz; + this->kM2 = this->kM * this->kM; + this->dk = this->dkx; + if (this->dk > this->dky) this->dk = this->dky; + if (this->dk > this->dkz) this->dk = this->dkz; + this->dk2 = this->dk*this->dk; + + /* spectra stuff */ + this->nshells = int(this->kM / this->dk) + 2; + this->kshell.resize(this->nshells, 0); + this->nshell.resize(this->nshells, 0); + std::vector<double> kshell_local; + kshell_local.resize(this->nshells, 0); + std::vector<int64_t> nshell_local; + nshell_local.resize(this->nshells, 0); + this->CLOOP_K2_NXMODES( + [&](ptrdiff_t cindex, + ptrdiff_t xindex, + ptrdiff_t yindex, + ptrdiff_t zindex, + double k2, + int nxmodes){ + if (k2 < this->kM2) + { + double knorm = sqrt(k2); + nshell_local[int(knorm/this->dk)] += nxmodes; + kshell_local[int(knorm/this->dk)] += nxmodes*knorm; + } + if (dt == SMOOTH) + this->dealias_filter[int(round(k2 / this->dk2))] = \ + exp(-36.0 * pow(k2/this->kM2, 18.)); + }); + MPI_Allreduce( + &nshell_local.front(), + &this->nshell.front(), + this->nshells, + MPI_INT64_T, MPI_SUM, this->layout->comm); + MPI_Allreduce( + &kshell_local.front(), + &this->kshell.front(), + this->nshells, + MPI_DOUBLE, MPI_SUM, this->layout->comm); + for (int n=0; n<this->nshells; n++) + this->kshell[n] /= this->nshell[n]; +} + +template <field_backend be, + kspace_dealias_type dt> +kspace<be, dt>::~kspace() +{ + delete this->layout; +} + +template <field_backend be, + kspace_dealias_type dt> +template <typename rnumber, + field_components fc> +void kspace<be, dt>::low_pass(rnumber *__restrict__ a, const double kmax) +{ + const double km2 = kmax*kmax; + this->CLOOP_K2( + [&](ptrdiff_t cindex, + ptrdiff_t xindex, + ptrdiff_t yindex, + ptrdiff_t zindex, + double k2){ + if (k2 >= km2) + std::fill_n(a + 2*ncomp(fc)*cindex, 2*ncomp(fc), 0); + }); +} + +template <field_backend be, + kspace_dealias_type dt> +template <typename rnumber, + field_components fc> +void kspace<be, dt>::dealias(typename fftw_interface<rnumber>::complex *__restrict__ a) +{ + switch(dt) + { + case TWO_THIRDS: + this->low_pass<rnumber, fc>((rnumber*)a, this->kM); + break; + case SMOOTH: + this->CLOOP_K2( + [&](ptrdiff_t cindex, + ptrdiff_t xindex, + ptrdiff_t yindex, + ptrdiff_t zindex, + double k2){ + double tval = this->dealias_filter[int(round(k2 / this->dk2))]; + for (int tcounter=0; tcounter<2*ncomp(fc); tcounter++) + ((rnumber*)a)[2*ncomp(fc)*cindex + tcounter] *= tval; + }); + break; + } +} + +template <field_backend be, + kspace_dealias_type dt> +template <typename rnumber> +void kspace<be, dt>::force_divfree(typename fftw_interface<rnumber>::complex *__restrict__ a) +{ + TIMEZONE("kspace::force_divfree"); + typename fftw_interface<rnumber>::complex tval; + this->CLOOP_K2( + [&](ptrdiff_t cindex, + ptrdiff_t xindex, + ptrdiff_t yindex, + ptrdiff_t zindex, + double k2){ + if (k2 > 0) + { + tval[0] = (this->kx[xindex]*((*(a + cindex*3 ))[0]) + + this->ky[yindex]*((*(a + cindex*3+1))[0]) + + this->kz[zindex]*((*(a + cindex*3+2))[0]) ) / k2; + tval[1] = (this->kx[xindex]*((*(a + cindex*3 ))[1]) + + this->ky[yindex]*((*(a + cindex*3+1))[1]) + + this->kz[zindex]*((*(a + cindex*3+2))[1]) ) / k2; + for (int imag_part=0; imag_part<2; imag_part++) + { + a[cindex*3 ][imag_part] -= tval[imag_part]*this->kx[xindex]; + a[cindex*3+1][imag_part] -= tval[imag_part]*this->ky[yindex]; + a[cindex*3+2][imag_part] -= tval[imag_part]*this->kz[zindex]; + } + } + } + ); + if (this->layout->myrank == this->layout->rank[0][0]) + std::fill_n((rnumber*)(a), 6, 0.0); +} + +template <field_backend be, + kspace_dealias_type dt> +template <typename rnumber, + field_components fc> +void kspace<be, dt>::cospectrum( + const rnumber(* __restrict a)[2], + const rnumber(* __restrict b)[2], + const hid_t group, + const std::string dset_name, + const hsize_t toffset) +{ + TIMEZONE("field::cospectrum"); + std::vector<double> spec, spec_local; + spec.resize(this->nshells*ncomp(fc)*ncomp(fc), 0); + spec_local.resize(this->nshells*ncomp(fc)*ncomp(fc), 0); + this->CLOOP_K2_NXMODES( + [&](ptrdiff_t cindex, + ptrdiff_t xindex, + ptrdiff_t yindex, + ptrdiff_t zindex, + double k2, + int nxmodes){ + if (k2 <= this->kM2) + { + int tmp_int = int(sqrt(k2) / this->dk)*ncomp(fc)*ncomp(fc); + for (hsize_t i=0; i<ncomp(fc); i++) + for (hsize_t j=0; j<ncomp(fc); j++) + spec_local[tmp_int + i*ncomp(fc)+j] += nxmodes * ( + (a[ncomp(fc)*cindex + i][0] * b[ncomp(fc)*cindex + j][0]) + + (a[ncomp(fc)*cindex + i][1] * b[ncomp(fc)*cindex + j][1])); + } + }); + MPI_Allreduce( + &spec_local.front(), + &spec.front(), + spec.size(), + MPI_DOUBLE, MPI_SUM, this->layout->comm); + if (this->layout->myrank == 0) + { + hid_t dset, wspace, mspace; + hsize_t count[(ndim(fc)-2)*2], offset[(ndim(fc)-2)*2], dims[(ndim(fc)-2)*2]; + dset = H5Dopen(group, ("spectra/" + dset_name).c_str(), H5P_DEFAULT); + wspace = H5Dget_space(dset); + H5Sget_simple_extent_dims(wspace, dims, NULL); + switch (fc) + { + case THREExTHREE: + offset[4] = 0; + offset[5] = 0; + count[4] = ncomp(fc); + count[5] = ncomp(fc); + case THREE: + offset[2] = 0; + offset[3] = 0; + count[2] = ncomp(fc); + count[3] = ncomp(fc); + default: + offset[0] = toffset; + offset[1] = 0; + count[0] = 1; + count[1] = this->nshells; + } + mspace = H5Screate_simple((ndim(fc)-2)*2, count, NULL); + H5Sselect_hyperslab(wspace, H5S_SELECT_SET, offset, NULL, count, NULL); + H5Dwrite(dset, H5T_NATIVE_DOUBLE, mspace, wspace, H5P_DEFAULT, &spec.front()); + H5Sclose(wspace); + H5Sclose(mspace); + H5Dclose(dset); + } +} + + +template class kspace<FFTW, TWO_THIRDS>; +template class kspace<FFTW, SMOOTH>; + +template kspace<FFTW, TWO_THIRDS>::kspace<>( + const field_layout<ONE> *, + const double, const double, const double); +template kspace<FFTW, TWO_THIRDS>::kspace<>( + const field_layout<THREE> *, + const double, const double, const double); +template kspace<FFTW, TWO_THIRDS>::kspace<>( + const field_layout<THREExTHREE> *, + const double, const double, const double); + +template kspace<FFTW, SMOOTH>::kspace<>( + const field_layout<ONE> *, + const double, const double, const double); +template kspace<FFTW, SMOOTH>::kspace<>( + const field_layout<THREE> *, + const double, const double, const double); +template kspace<FFTW, SMOOTH>::kspace<>( + const field_layout<THREExTHREE> *, + const double, const double, const double); + +template void kspace<FFTW, SMOOTH>::low_pass<float, ONE>( + float *__restrict__ a, + const double kmax); +template void kspace<FFTW, SMOOTH>::low_pass<float, THREE>( + float *__restrict__ a, + const double kmax); +template void kspace<FFTW, SMOOTH>::low_pass<float, THREExTHREE>( + float *__restrict__ a, + const double kmax); + +template void kspace<FFTW, SMOOTH>::low_pass<double, ONE>( + double *__restrict__ a, + const double kmax); +template void kspace<FFTW, SMOOTH>::low_pass<double, THREE>( + double *__restrict__ a, + const double kmax); +template void kspace<FFTW, SMOOTH>::low_pass<double, THREExTHREE>( + double *__restrict__ a, + const double kmax); + +template void kspace<FFTW, SMOOTH>::dealias<float, ONE>( + typename fftw_interface<float>::complex *__restrict__ a); +template void kspace<FFTW, SMOOTH>::dealias<float, THREE>( + typename fftw_interface<float>::complex *__restrict__ a); +template void kspace<FFTW, SMOOTH>::dealias<float, THREExTHREE>( + typename fftw_interface<float>::complex *__restrict__ a); + +template void kspace<FFTW, SMOOTH>::dealias<double, ONE>( + typename fftw_interface<double>::complex *__restrict__ a); +template void kspace<FFTW, SMOOTH>::dealias<double, THREE>( + typename fftw_interface<double>::complex *__restrict__ a); +template void kspace<FFTW, SMOOTH>::dealias<double, THREExTHREE>( + typename fftw_interface<double>::complex *__restrict__ a); + +template void kspace<FFTW, SMOOTH>::force_divfree<float>( + typename fftw_interface<float>::complex *__restrict__ a); +template void kspace<FFTW, SMOOTH>::force_divfree<double>( + typename fftw_interface<double>::complex *__restrict__ a); + diff --git a/bfps/cpp/kspace.hpp b/bfps/cpp/kspace.hpp new file mode 100644 index 0000000000000000000000000000000000000000..01d9a209b91119adcb2f6d28eb2bb6b637c790a1 --- /dev/null +++ b/bfps/cpp/kspace.hpp @@ -0,0 +1,143 @@ +/********************************************************************** +* * +* Copyright 2015 Max Planck Institute * +* for Dynamics and Self-Organization * +* * +* This file is part of bfps. * +* * +* bfps is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published * +* by the Free Software Foundation, either version 3 of the License, * +* or (at your option) any later version. * +* * +* bfps is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with bfps. If not, see <http://www.gnu.org/licenses/> * +* * +* Contact: Cristian.Lalescu@ds.mpg.de * +* * +**********************************************************************/ + + + +#include <hdf5.h> +#include <unordered_map> +#include <vector> +#include <string> +#include "fftw_interface.hpp" +#include "field_layout.hpp" + +#ifndef KSPACE_HPP + +#define KSPACE_HPP + +enum field_backend {FFTW}; +enum kspace_dealias_type {TWO_THIRDS, SMOOTH}; + + +template <field_backend be, + kspace_dealias_type dt> +class kspace +{ + public: + /* relevant field layout */ + field_layout<ONE> *layout; + + /* physical parameters */ + double dkx, dky, dkz, dk, dk2; + + /* mode and dealiasing information */ + double kMx, kMy, kMz, kM, kM2; + std::vector<double> kx, ky, kz; + std::unordered_map<int, double> dealias_filter; + std::vector<double> kshell; + std::vector<int64_t> nshell; + int nshells; + + /* methods */ + template <field_components fc> + kspace( + const field_layout<fc> *source_layout, + const double DKX = 1.0, + const double DKY = 1.0, + const double DKZ = 1.0); + ~kspace(); + + template <typename rnumber, + field_components fc> + void low_pass(rnumber *__restrict__ a, const double kmax); + + template <typename rnumber, + field_components fc> + void dealias(typename fftw_interface<rnumber>::complex *__restrict__ a); + + template <typename rnumber, + field_components fc> + void cospectrum( + const rnumber(* __restrict__ a)[2], + const rnumber(* __restrict__ b)[2], + const hid_t group, + const std::string dset_name, + const hsize_t toffset); + template <class func_type> + void CLOOP(func_type expression) + { + ptrdiff_t cindex = 0; + for (hsize_t yindex = 0; yindex < this->layout->subsizes[0]; yindex++) + for (hsize_t zindex = 0; zindex < this->layout->subsizes[1]; zindex++) + for (hsize_t xindex = 0; xindex < this->layout->subsizes[2]; xindex++) + { + expression(cindex, xindex, yindex, zindex); + cindex++; + } + } + template <class func_type> + void CLOOP_K2(func_type expression) + { + double k2; + ptrdiff_t cindex = 0; + for (hsize_t yindex = 0; yindex < this->layout->subsizes[0]; yindex++) + for (hsize_t zindex = 0; zindex < this->layout->subsizes[1]; zindex++) + for (hsize_t xindex = 0; xindex < this->layout->subsizes[2]; xindex++) + { + k2 = (this->kx[xindex]*this->kx[xindex] + + this->ky[yindex]*this->ky[yindex] + + this->kz[zindex]*this->kz[zindex]); + expression(cindex, xindex, yindex, zindex, k2); + cindex++; + } + } + template <class func_type> + void CLOOP_K2_NXMODES(func_type expression) + { + ptrdiff_t cindex = 0; + for (hsize_t yindex = 0; yindex < this->layout->subsizes[0]; yindex++) + for (hsize_t zindex = 0; zindex < this->layout->subsizes[1]; zindex++) + { + hsize_t xindex = 0; + double k2 = ( + this->kx[xindex]*this->kx[xindex] + + this->ky[yindex]*this->ky[yindex] + + this->kz[zindex]*this->kz[zindex]); + expression(cindex, xindex, yindex, zindex, k2, 1); + cindex++; + for (xindex = 1; xindex < this->layout->subsizes[2]; xindex++) + { + k2 = (this->kx[xindex]*this->kx[xindex] + + this->ky[yindex]*this->ky[yindex] + + this->kz[zindex]*this->kz[zindex]); + expression(cindex, xindex, yindex, zindex, k2, 2); + cindex++; + } + } + } + template <typename rnumber> + void force_divfree(typename fftw_interface<rnumber>::complex *__restrict__ a); +}; + +#endif//KSPACE_HPP + diff --git a/setup.py b/setup.py index 10ec94ee8f8762773db28e2d35723a6250ec7e64..8d4ae0f9dfb554229c6b7293e596646501a58bc7 100644 --- a/setup.py +++ b/setup.py @@ -90,6 +90,7 @@ print('This is bfps version ' + VERSION) ### lists of files and MANIFEST.in src_file_list = ['vorticity_equation', 'field', + 'kspace', 'field_layout', 'field_descriptor', 'rFFTW_distributed_particles',