diff --git a/cpp/field.cpp b/cpp/field.cpp index a5779752ee4ca232f4883042c3171ec4c45ab18a..c4cb192a8a543733d015d43c793104c7b5969868 100644 --- a/cpp/field.cpp +++ b/cpp/field.cpp @@ -1266,23 +1266,17 @@ void field<rnumber, be, fc>::normalize() template <typename rnumber, field_backend be, field_components fc> -void field<rnumber, be, fc>::symmetrize() +void field<rnumber, be, fc>::Hermitian_reflect() { - TIMEZONE("field::symmetrize"); + TIMEZONE("field::Hermitian_reflect"); assert(!this->real_space_representation); - // for debugging, just use FFTW - //this->ift(); - //this->dft(); - //this->normalize(); - //return; typename fftw_interface<rnumber>::complex *cdata = this->get_cdata(); - // symmetrize kx = 0 plane, line by line, for ky != 0 + // reflect kx = 0 plane, line by line, for ky != 0 MPI_Status *mpistatus = new MPI_Status; // bufferp will hold data from "plus", i.e. iy // bufferm will hold data from "minus", i.e. ny - iy - typename fftw_interface<rnumber>::complex *bufferp = new typename fftw_interface<rnumber>::complex[ncomp(fc)*this->clayout->sizes[1]]; + typename fftw_interface<rnumber>::complex *bufferp = new typename fftw_interface<rnumber>::complex[ncomp(fc)*this->clayout->sizes[1]]; typename fftw_interface<rnumber>::complex *bufferm = new typename fftw_interface<rnumber>::complex[ncomp(fc)*this->clayout->sizes[1]]; - /*ptrdiff_t tindex;*/ int rankp, rankm; // for each ky slice except ky=0 for (ptrdiff_t iy = 1; iy < ptrdiff_t(this->clayout->sizes[0]/2); iy++) @@ -1360,15 +1354,15 @@ void field<rnumber, be, fc>::symmetrize() ptrdiff_t cindex = this->get_cindex(0, iyy, izz); for (int cc = 0; cc < int(ncomp(fc)); cc++) { - (*(cdata + ncomp(fc)*cindex + cc))[0] = ((*(bufferp + ncomp(fc)*iz+cc))[0] + (*(bufferm + ncomp(fc)*iz+cc))[0])/2; - (*(cdata + ncomp(fc)*cindex + cc))[1] = ((*(bufferp + ncomp(fc)*iz+cc))[1] - (*(bufferp + ncomp(fc)*iz+cc))[1])/2; + (*(cdata + ncomp(fc)*cindex + cc))[0] = (*(bufferm + ncomp(fc)*iz+cc))[0]; + (*(cdata + ncomp(fc)*cindex + cc))[1] = -(*(bufferm + ncomp(fc)*iz+cc))[1]; } } ptrdiff_t cindex = this->get_cindex(0, iyy, 0); for (int cc = 0; cc < int(ncomp(fc)); cc++) { - (*(cdata + cc + ncomp(fc)*cindex))[0] = ((*(bufferp + cc))[0] + (*(bufferm + cc))[0])/2; - (*(cdata + cc + ncomp(fc)*cindex))[1] = ((*(bufferp + cc))[1] - (*(bufferm + cc))[1])/2; + (*(cdata + cc + ncomp(fc)*cindex))[0] = (*(bufferm + cc))[0]; + (*(cdata + cc + ncomp(fc)*cindex))[1] = -(*(bufferm + cc))[1]; } } // if I my rank is either plus or minus, I should update my slice @@ -1381,15 +1375,15 @@ void field<rnumber, be, fc>::symmetrize() ptrdiff_t cindex = this->get_cindex(0, iyy, izz); for (int cc = 0; cc < int(ncomp(fc)); cc++) { - (*(cdata + ncomp(fc)*cindex + cc))[0] = ((*(bufferp + ncomp(fc)*iz+cc))[0] + (*(bufferm + ncomp(fc)*iz+cc))[0])/2; - (*(cdata + ncomp(fc)*cindex + cc))[1] = -((*(bufferp + ncomp(fc)*iz+cc))[1] - (*(bufferp + ncomp(fc)*iz+cc))[1])/2; + (*(cdata + ncomp(fc)*cindex + cc))[0] = (*(bufferp + ncomp(fc)*iz+cc))[0]; + (*(cdata + ncomp(fc)*cindex + cc))[1] = -(*(bufferp + ncomp(fc)*iz+cc))[1]; } } ptrdiff_t cindex = this->get_cindex(0, iyy, 0); for (int cc = 0; cc < int(ncomp(fc)); cc++) { - (*(cdata + cc + ncomp(fc)*cindex))[0] = ((*(bufferp + cc))[0] + (*(bufferm + cc))[0])/2; - (*(cdata + cc + ncomp(fc)*cindex))[1] = -((*(bufferp + cc))[1] - (*(bufferm + cc))[1])/2; + (*(cdata + cc + ncomp(fc)*cindex))[0] = (*(bufferp + cc))[0]; + (*(cdata + cc + ncomp(fc)*cindex))[1] = -(*(bufferp + cc))[1]; } } } @@ -1406,12 +1400,14 @@ void field<rnumber, be, fc>::symmetrize() ptrdiff_t cindex1 = this->get_cindex(0, 0, this->clayout->sizes[1] - iz); for (int cc = 0; cc < int(ncomp(fc)); cc++) { - double re = ((*(cdata + cc + ncomp(fc)*cindex0))[0] + (*(cdata + cc + ncomp(fc)*cindex1))[0])/2; - double im = ((*(cdata + cc + ncomp(fc)*cindex0))[1] - (*(cdata + cc + ncomp(fc)*cindex1))[1])/2; - (*(cdata + cc + ncomp(fc)*cindex0))[0] = re; - (*(cdata + cc + ncomp(fc)*cindex0))[1] = im; - (*(cdata + cc + ncomp(fc)*cindex1))[0] = re; - (*(cdata + cc + ncomp(fc)*cindex1))[1] = -im; + double rep = (*(cdata + cc + ncomp(fc)*cindex0))[0]; + double imp = (*(cdata + cc + ncomp(fc)*cindex0))[1]; + double rem = (*(cdata + cc + ncomp(fc)*cindex1))[0]; + double imm = (*(cdata + cc + ncomp(fc)*cindex1))[1]; + (*(cdata + cc + ncomp(fc)*cindex0))[0] = rem; + (*(cdata + cc + ncomp(fc)*cindex0))[1] = -imm; + (*(cdata + cc + ncomp(fc)*cindex1))[0] = rep; + (*(cdata + cc + ncomp(fc)*cindex1))[1] = -imp; } } } @@ -1456,6 +1452,200 @@ void field<rnumber, be, fc>::symmetrize() } } +template <typename rnumber, + field_backend be, + field_components fc> +void field<rnumber, be, fc>::symmetrize() +{ + TIMEZONE("field::symmetrize"); + assert(!this->real_space_representation); + typename fftw_interface<rnumber>::complex *cdata = this->get_cdata(); + + // make 0 mode real + if (this->myrank == this->clayout->rank[0][0]) + { + for (ptrdiff_t cc = 0; cc < ncomp(fc); cc++) + cdata[cc][1] = 0.0; + } + // put kx = nx/2 modes to 0 + for (ptrdiff_t iy = 0; iy < ptrdiff_t(this->clayout->subsizes[0]); iy++) + for (ptrdiff_t iz = 0; iz < ptrdiff_t(this->clayout->subsizes[1]); iz++) + { + ptrdiff_t cindex = this->get_cindex(this->clayout->sizes[2]-1, iy, iz); + for (int cc = 0; cc < int(ncomp(fc)); cc++) { + (*(cdata + cc + ncomp(fc)*cindex))[0] = 0.0; + (*(cdata + cc + ncomp(fc)*cindex))[1] = 0.0; + } + } + // put ky = ny/2 modes to 0 + if (this->clayout->myrank == this->clayout->rank[0][this->clayout->sizes[0]/2]) + { + for (ptrdiff_t iz = 0; iz < ptrdiff_t(this->clayout->subsizes[1]); iz++) + for (ptrdiff_t ix = 0; ix < ptrdiff_t(this->clayout->subsizes[2]); ix++) + { + ptrdiff_t cindex = this->get_cindex(ix, this->clayout->sizes[0]/2-this->clayout->starts[0], iz); + for (int cc = 0; cc < int(ncomp(fc)); cc++) { + (*(cdata + cc + ncomp(fc)*cindex))[0] = 0.0; + (*(cdata + cc + ncomp(fc)*cindex))[1] = 0.0; + } + } + } + // put kz = nz/2 modes to 0 + for (ptrdiff_t iy = 0; iy < ptrdiff_t(this->clayout->subsizes[0]); iy++) + for (ptrdiff_t ix = 0; ix < ptrdiff_t(this->clayout->subsizes[2]); ix++) + { + ptrdiff_t cindex = this->get_cindex(ix, iy, this->clayout->sizes[1]/2); + for (int cc = 0; cc < int(ncomp(fc)); cc++) { + (*(cdata + cc + ncomp(fc)*cindex))[0] = 0.0; + (*(cdata + cc + ncomp(fc)*cindex))[1] = 0.0; + } + } + + // for debugging, just use FFTW + this->ift(); + this->dft(); + this->normalize(); + return; + // symmetrize kx = 0 plane, line by line, for ky != 0 + MPI_Status *mpistatus = new MPI_Status; + // bufferp will hold data from "plus", i.e. iy + // bufferm will hold data from "minus", i.e. ny - iy + typename fftw_interface<rnumber>::complex *bufferp = new typename fftw_interface<rnumber>::complex[ncomp(fc)*this->clayout->sizes[1]]; + typename fftw_interface<rnumber>::complex *bufferm = new typename fftw_interface<rnumber>::complex[ncomp(fc)*this->clayout->sizes[1]]; + int rankp, rankm; + // for each ky slice except ky=0 + for (ptrdiff_t iy = 1; iy < ptrdiff_t(this->clayout->sizes[0]/2); iy++) + { + // read rank plus and rank minus + rankp = this->clayout->rank[0][iy]; + rankm = this->clayout->rank[0][this->clayout->sizes[0] - iy]; + // if my rank is rank plus, I should fill out the plus buffer + if (this->clayout->myrank == rankp) + { + ptrdiff_t iyy = iy - this->clayout->starts[0]; + for (ptrdiff_t iz = 0; iz < ptrdiff_t(this->clayout->sizes[1]); iz++) + { + ptrdiff_t cindex = this->get_cindex(0, iyy, iz); + for (int cc = 0; cc < int(ncomp(fc)); cc++) + for (int imag_comp=0; imag_comp<2; imag_comp++) + (*(bufferp + ncomp(fc)*iz+cc))[imag_comp] = + (*(cdata + ncomp(fc)*cindex + cc))[imag_comp]; + } + } + // if my rank is rank minus, I should fill out the minus buffer + if (this->clayout->myrank == rankm) + { + ptrdiff_t iyy = (this->clayout->sizes[0] - iy) - this->clayout->starts[0]; + for (ptrdiff_t iz = 0; iz < ptrdiff_t(this->clayout->sizes[1]); iz++) + { + ptrdiff_t cindex = this->get_cindex(0, iyy, iz); + for (int cc = 0; cc < int(ncomp(fc)); cc++) + for (int imag_comp=0; imag_comp<2; imag_comp++) + (*(bufferm + ncomp(fc)*iz+cc))[imag_comp] = + (*(cdata + ncomp(fc)*cindex + cc))[imag_comp]; + } + } + // if ranks are different, send and receive + if (rankp != rankm) + { + // if my rank is rank plus, send buffer plus, receive buffer minus + if (this->clayout->myrank == rankp) + { + MPI_Send((void*)bufferp, + ncomp(fc)*this->clayout->sizes[1], + mpi_real_type<rnumber>::complex(), + rankm, 2*iy+0, + this->clayout->comm); + MPI_Recv((void*)bufferm, + ncomp(fc)*this->clayout->sizes[1], + mpi_real_type<rnumber>::complex(), + rankm, 2*iy+1, + this->clayout->comm, + mpistatus); + } + // if my rank is rank minus, receive buffer plus, send buffer minus + if (this->clayout->myrank == rankm) + { + MPI_Recv((void*)bufferp, + ncomp(fc)*this->clayout->sizes[1], + mpi_real_type<rnumber>::complex(), + rankp, 2*iy+0, + this->clayout->comm, + mpistatus); + MPI_Send((void*)bufferm, + ncomp(fc)*this->clayout->sizes[1], + mpi_real_type<rnumber>::complex(), + rankp, 2*iy+1, + this->clayout->comm); + } + } + // if I my rank is either plus or minus, I should update my slice + if (this->clayout->myrank == rankp) + { + ptrdiff_t iyy = iy - this->clayout->starts[0]; + for (ptrdiff_t iz = 1; iz < ptrdiff_t(this->clayout->sizes[1]); iz++) + { + ptrdiff_t izz = (this->clayout->sizes[1] - iz); + ptrdiff_t cindex = this->get_cindex(0, iyy, izz); + for (int cc = 0; cc < int(ncomp(fc)); cc++) + { + (*(cdata + ncomp(fc)*cindex + cc))[0] = ((*(bufferp + ncomp(fc)*iz+cc))[0] + (*(bufferm + ncomp(fc)*iz+cc))[0])/2; + (*(cdata + ncomp(fc)*cindex + cc))[1] = ((*(bufferp + ncomp(fc)*iz+cc))[1] - (*(bufferm + ncomp(fc)*iz+cc))[1])/2; + } + } + ptrdiff_t cindex = this->get_cindex(0, iyy, 0); + for (int cc = 0; cc < int(ncomp(fc)); cc++) + { + (*(cdata + cc + ncomp(fc)*cindex))[0] = ((*(bufferp + cc))[0] + (*(bufferm + cc))[0])/2; + (*(cdata + cc + ncomp(fc)*cindex))[1] = ((*(bufferp + cc))[1] - (*(bufferm + cc))[1])/2; + } + } + // if I my rank is either plus or minus, I should update my slice + if (this->clayout->myrank == rankm) + { + ptrdiff_t iyy = (this->clayout->sizes[0] - iy) - this->clayout->starts[0]; + for (ptrdiff_t iz = 1; iz < ptrdiff_t(this->clayout->sizes[1]); iz++) + { + ptrdiff_t izz = (this->clayout->sizes[1] - iz); + ptrdiff_t cindex = this->get_cindex(0, iyy, izz); + for (int cc = 0; cc < int(ncomp(fc)); cc++) + { + (*(cdata + ncomp(fc)*cindex + cc))[0] = ((*(bufferp + ncomp(fc)*iz+cc))[0] + (*(bufferm + ncomp(fc)*iz+cc))[0])/2; + (*(cdata + ncomp(fc)*cindex + cc))[1] = -((*(bufferp + ncomp(fc)*iz+cc))[1] - (*(bufferm + ncomp(fc)*iz+cc))[1])/2; + } + } + ptrdiff_t cindex = this->get_cindex(0, iyy, 0); + for (int cc = 0; cc < int(ncomp(fc)); cc++) + { + (*(cdata + cc + ncomp(fc)*cindex))[0] = ((*(bufferp + cc))[0] + (*(bufferm + cc))[0])/2; + (*(cdata + cc + ncomp(fc)*cindex))[1] = -((*(bufferp + cc))[1] - (*(bufferm + cc))[1])/2; + } + } + } + //fftw_interface<rnumber>::free(buffer); + delete[] bufferp; + delete[] bufferm; + delete mpistatus; + // symmetrize kx = 0, ky = 0 line + if (this->clayout->myrank == this->clayout->rank[0][0]) + { + for (ptrdiff_t iz = 1; iz < ptrdiff_t(this->clayout->sizes[1]/2); iz++) + { + ptrdiff_t cindex0 = this->get_cindex(0, 0, iz); + ptrdiff_t cindex1 = this->get_cindex(0, 0, this->clayout->sizes[1] - iz); + for (int cc = 0; cc < int(ncomp(fc)); cc++) + { + double re = ((*(cdata + cc + ncomp(fc)*cindex0))[0] + (*(cdata + cc + ncomp(fc)*cindex1))[0])/2; + double im = ((*(cdata + cc + ncomp(fc)*cindex0))[1] - (*(cdata + cc + ncomp(fc)*cindex1))[1])/2; + (*(cdata + cc + ncomp(fc)*cindex0))[0] = re; + (*(cdata + cc + ncomp(fc)*cindex0))[1] = im; + (*(cdata + cc + ncomp(fc)*cindex1))[0] = re; + (*(cdata + cc + ncomp(fc)*cindex1))[1] = -im; + } + } + } +} + template <typename rnumber, field_backend be, field_components fc> diff --git a/cpp/field.hpp b/cpp/field.hpp index feb19c804766470197e37f66f8405d8b3bfb9c9f..cd7a06d74fd4bc670920121976bd28008b40003c 100644 --- a/cpp/field.hpp +++ b/cpp/field.hpp @@ -122,6 +122,7 @@ class field void ift(); void normalize(); void symmetrize(); + void Hermitian_reflect(); /* stats */ void compute_rspace_xincrement_stats(