JDFTx  1.2.0
Operators.h
Go to the documentation of this file.
1 /*-------------------------------------------------------------------
2 Copyright 2011 Ravishankar Sundararaman
3 
4 This file is part of JDFTx.
5 
6 JDFTx is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 JDFTx is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with JDFTx. If not, see <http://www.gnu.org/licenses/>.
18 -------------------------------------------------------------------*/
19 
20 #ifndef JDFTX_CORE_OPERATORS_H
21 #define JDFTX_CORE_OPERATORS_H
22 
25 
30 #include <core/ScalarField.h>
31 #include <core/BlasExtra.h>
32 #include <core/GridInfo.h>
33 #include <core/LoopMacros.h>
34 
35 //----------------- Real / complex conversion ------------------
41 complexScalarField Complex(const ScalarField& re, const ScalarField& im);
43 
44 //------------------------------ Linear Unary operators ------------------------------
45 
50 
51 //Transform operators:
52 // compat: force GPU transform output to be FFTW compatible (affects only how redundant Nyquist frequency components in the C->R transforms are handled)
53 // nThreads: maximum number of threads to use; use to prevent thread nesting when performing transforms of vector fields etc.
54 
55 ScalarField I(const ScalarFieldTilde&, bool compat=false, int nThreads=0);
56 ScalarField I(ScalarFieldTilde&&, bool compat=false, int nThreads=0);
57 complexScalarField I(const complexScalarFieldTilde&, int nThreads=0);
58 complexScalarField I(complexScalarFieldTilde&&, int nThreads=0);
59 
60 ScalarFieldTilde J(const ScalarField&, int nThreads=0);
61 complexScalarFieldTilde J(const complexScalarField&, int nThreads=0);
62 complexScalarFieldTilde J(complexScalarField&&, int nThreads=0);
63 
64 ScalarFieldTilde Idag(const ScalarField&, int nThreads=0);
65 complexScalarFieldTilde Idag(const complexScalarField&, int nThreads=0);
67 
68 ScalarField Jdag(const ScalarFieldTilde&, bool compat=false, int nThreads=0);
69 ScalarField Jdag(ScalarFieldTilde&&, bool compat=false, int nThreads=0);
70 complexScalarField Jdag(const complexScalarFieldTilde&, int nThreads=0);
72 
77 
82 
87 
88 void zeroNyquist(RealKernel& Gdata);
89 void zeroNyquist(ScalarFieldTilde& Gptr);
90 void zeroNyquist(ScalarField& Rptr);
91 
92 //------------------------------ Nonlinear Unary operators ------------------------------
93 
94 ScalarField exp(const ScalarField&);
96 
97 ScalarField log(const ScalarField&);
99 
100 ScalarField sqrt(const ScalarField&);
102 
103 ScalarField inv(const ScalarField&);
105 
106 ScalarField pow(const ScalarField&, double alpha);
107 ScalarField pow(ScalarField&&, double alpha);
108 
109 #define Tptr std::shared_ptr<T>
110 
111 template<class T> Tptr clone(const Tptr& X) { if(X) return X->clone(); else return 0; }
112 
113 //------------------------------ Multiplication operators ------------------------------
114 
115 template<class T> Tptr& operator*=(Tptr& in, double scaleFac) { if(in) in->scale *= scaleFac; return in; }
116 template<class T> Tptr operator*(const Tptr& in, double scaleFac) { Tptr out(in->clone()); return out *= scaleFac; }
117 template<class T> Tptr operator*(double scaleFac, const Tptr& in) { Tptr out(in->clone()); return out *= scaleFac; }
118 template<class T> Tptr operator*(Tptr&& in, double scaleFac) { return in *= scaleFac; }
119 template<class T> Tptr operator*(double scaleFac, Tptr&& in) { return in *= scaleFac; }
120 
122 template<class T> Tptr conj(Tptr&& in)
123 { callPref(eblas_dscal)(in->nElem, -1., ((double*)in->dataPref(false))+1, 2); //negate the imaginary parts
124  return in;
125 }
126 template<class T> Tptr conj(const Tptr& in) { return conj(clone(in)); }
127 
129 template<class T> Tptr& operator*=(Tptr& in, const Tptr& other)
130 { in->scale *= other->scale;
131  callPref(eblas_zmul)(in->nElem, other->dataPref(false), 1, in->dataPref(false), 1);
132  return in;
133 }
134 ScalarField& operator*=(ScalarField& in, const ScalarField& other);
135 template<class T> Tptr operator*(const Tptr& in1, const Tptr& in2) { Tptr out(in1->clone()); return out *= in2; }
136 template<class T> Tptr operator*(const Tptr& in1, Tptr&& in2) { return in2 *= in1; }
137 template<class T> Tptr operator*(Tptr&& in1, const Tptr& in2) { return in1 *= in2; }
138 template<class T> Tptr operator*(Tptr&& in1, Tptr&& in2) { return in1 *= in2; }
139 
140 //Extra operators in R-space alone for mixed complex-real elementwise multiplications:
146 
147 //Extra operators in G-space alone for real kernel multiplication:
153 
154 
155 //------------------------------ Linear combine operators ------------------------------
156 
158 template<typename T> void axpy(double alpha, const Tptr& X, Tptr& Y)
159 { if(X)
160  { if(Y)
161  { if(Y->scale == 0.0) { Y = X * alpha; }
162  else callPref(eblas_zaxpy)(X->nElem, alpha*X->scale/Y->scale, X->dataPref(false), 1, Y->dataPref(false), 1);
163  }
164  else Y = X * alpha;
165  }
166  //if X is null, nothing needs to be done, Y remains unchanged
167 }
168 void axpy(double alpha, const ScalarField& X, ScalarField& Y);
169 template<class T> Tptr& operator+=(Tptr& in, const Tptr& other) { axpy(+1.0, other, in); return in; }
170 template<class T> Tptr& operator-=(Tptr& in, const Tptr& other) { axpy(-1.0, other, in); return in; }
171 template<class T> Tptr operator+(const Tptr& in1, const Tptr& in2) { Tptr out(in1->clone()); return out += in2; }
172 template<class T> Tptr operator+(const Tptr& in1, Tptr&& in2) { return in2 += in1; }
173 template<class T> Tptr operator+(Tptr&& in1, const Tptr& in2) { return in1 += in2; }
174 template<class T> Tptr operator+(Tptr&& in1, Tptr&& in2) { return in1 += in2; }
175 template<class T> Tptr operator-(const Tptr& in1, const Tptr& in2) { Tptr out(in1->clone()); return out -= in2; }
176 template<class T> Tptr operator-(const Tptr& in1, Tptr&& in2) { return (in2 -= in1) *= -1.0; }
177 template<class T> Tptr operator-(Tptr&& in1, const Tptr& in2) { return in1 -= in2; }
178 template<class T> Tptr operator-(Tptr&& in1, Tptr&& in2) { return in1 -= in2; }
179 template<class T> Tptr operator-(const Tptr& in) { return (-1.0)*in; }
180 template<class T> Tptr operator-(Tptr&& in) { return in*=(-1.0); }
181 //Extra operators in R-space alone for scalar additions:
183 ScalarField operator+(double, const ScalarField&);
184 ScalarField operator+(const ScalarField&, double);
185 ScalarField operator+(double, ScalarField&&);
186 ScalarField operator+(ScalarField&&, double);
188 ScalarField operator-(double, const ScalarField&);
189 ScalarField operator-(const ScalarField&, double);
190 ScalarField operator-(double, ScalarField&&);
191 ScalarField operator-(ScalarField&&, double);
192 
193 
194 //------------------------------ Norms and dot products ------------------------------
195 
196 template<typename T> complex dot(const Tptr& X, const Tptr& Y)
197 { return callPref(eblas_zdotc)(X->nElem, X->dataPref(), 1, Y->dataPref(), 1);
198 }
199 template<typename T> double nrm2(const Tptr& X)
200 { return callPref(eblas_dznrm2)(X->nElem, X->dataPref(), 1);
201 }
202 template<typename T> complex sum(const Tptr& X)
203 { FieldData dataOne(X->gInfo, "complexScalarField", 1, 2, false); *((complex*)dataOne.data()) = 1.0;
204  return callPref(eblas_zdotc)(X->nElem, (complex*)dataOne.dataPref(), 0, X->dataPref(), 1);
205 }
206 //Special handling for real scalar fields:
207 double dot(const ScalarField&, const ScalarField&);
208 double dot(const ScalarFieldTilde&, const ScalarFieldTilde&);
209 double nrm2(const ScalarField&);
210 double nrm2(const ScalarFieldTilde&);
211 double sum(const ScalarField&);
212 double sum(const ScalarFieldTilde&);
213 
214 double integral(const ScalarField&);
215 double integral(const ScalarFieldTilde&);
218 
219 //------------------------------ Grid conversion utilities ------------------------------
220 ScalarFieldTilde changeGrid(const ScalarFieldTilde&, const GridInfo& gInfoNew); //Fourier up/down-sample to get to the new grid
221 ScalarField changeGrid(const ScalarField&, const GridInfo& gInfoNew); //Fourier up/down-sample to get to the new grid (real-space version)
222 complexScalarFieldTilde changeGrid(const complexScalarFieldTilde&, const GridInfo& gInfoNew); //Fourier up/down-sample to get to the new grid
223 complexScalarField changeGrid(const complexScalarField&, const GridInfo& gInfoNew); //Fourier up/down-sample to get to the new grid (real-space version)
224 
225 //------------------------------ Initialization utilities ------------------------------
226 
227 #include <string.h>
228 
229 template<typename T> void initZero(Tptr& X) { X->zero(); }
230 template<typename T> void initZero(Tptr& X, const GridInfo& gInfo) { if(X) X->zero(); else nullToZero(X, gInfo); }
231 template<typename T> void nullToZero(Tptr& X, const GridInfo& gInfo) { if(!X) { X=T::alloc(gInfo,isGpuEnabled()); initZero(X); } }
232 void initRandom(ScalarField&, double cap=0.0);
234 void initGaussianKernel(RealKernel&, double x0);
235 void initTranslation(ScalarFieldTilde&, const vector3<>& r);
236 ScalarFieldTilde gaussConvolve(const ScalarFieldTilde&, double sigma);
238 
240 template<typename Func, typename... Args> void applyFuncGsq(const GridInfo& gInfo, const Func& f, Args... args);
241 
243 template<typename Func, typename... Args> void applyFunc_r(const GridInfo& gInfo, const Func& f, Args... args);
244 
245 //------------------------------ Debug utilities ------------------------------
246 
247 void printStats(const ScalarField& X, const char* name, FILE* fp=stdout);
248 
249 
253 template<typename Callable, typename Vec> void checkSymmetry(Callable* func, const Vec& v1, const Vec& v2, const char* funcName)
254 { double dot1 = dot(v1, (*func)(v2));
255  double dot2 = dot(v2, (*func)(v1));
256  double dotDiff = fabs(dot1-dot2);
257  logPrintf("Relative error in symmetry of %s: %le\n", funcName, dotDiff/sqrt(fabs(dot1)*fabs(dot2)));
258 }
259 
261 
262 #undef Tptr
263 
265 
266 
267 template<typename Func, typename... Args>
268 void applyFuncGsq_sub(size_t iStart, size_t iStop, const vector3<int> S, const matrix3<> GGT, const Func* f, Args... args)
269 { THREAD_halfGspaceLoop( (*f)(i, GGT.metric_length_squared(iG), args...); )
270 }
271 template<typename Func, typename... Args> void applyFuncGsq(const GridInfo& gInfo, const Func& f, Args... args)
272 { threadLaunch(applyFuncGsq_sub<Func,Args...>, gInfo.nG, gInfo.S, gInfo.GGT, &f, args...);
273 }
274 
275 template<typename Func, typename... Args>
276 void applyFunc_r_sub(size_t iStart, size_t iStop, const vector3<int> S, const vector3<> h[3], const Func* f, Args... args)
277 { THREAD_rLoop
278  ( vector3<> ri = iv[0]*h[0] + iv[1]*h[1] + iv[2]*h[2];
279  (*f)(i, ri, args...);
280  )
281 }
282 template<typename Func, typename... Args> void applyFunc_r(const GridInfo& gInfo, const Func& f, Args... args)
283 { threadLaunch(applyFunc_r_sub<Func,Args...>, gInfo.nr, gInfo.S, gInfo.h, f, args...);
284 }
286 #endif //JDFTX_CORE_OPERATORS_H
ScalarFieldTilde Idag(const ScalarField &, int nThreads=0)
Forward transform transpose: Real space -> PW basis.
complex sum(const Tptr &X)
Definition: Operators.h:202
void checkSymmetry(Callable *func, const Vec &v1, const Vec &v2, const char *funcName)
Definition: Operators.h:253
ScalarField pow(const ScalarField &, double alpha)
Elementwise power (preserve input)
#define logPrintf(...)
printf() for log files
Definition: Util.h:110
ScalarField Imag(const complexScalarField &)
imaginary part of a complex scalar field (real-space)
void eblas_zmul(const int N, const complex *X, const int incX, complex *Y, const int incY)
Specialization of eblas_mul() for complex[] *= complex[].
Definition: BlasExtra.h:53
void eblas_zaxpy(int N, const complex &a, const complex *x, int incx, complex *y, int incy)
Scaled-accumulate on complex arrays: threaded wrapper to the cblas_zaxpy BLAS1 function.
void applyFunc_r(const GridInfo &gInfo, const Func &f, Args...args)
Evaluate a function f(i, r, args...) at each point in real space index by i.
Tptr operator*(const Tptr &in, double scaleFac)
Scalar multiply (preserve input)
Definition: Operators.h:116
ScalarField sqrt(const ScalarField &)
Elementwise square root (preserve input)
Simulation grid descriptor.
Definition: GridInfo.h:45
STL strings and streams with case insensitive comparison.
ScalarFieldTilde J(const ScalarField &, int nThreads=0)
Inverse transform: Real space -> PW basis.
void initRandom(ScalarField &, double cap=0.0)
initialize element-wise with a unit-normal random number (with a cap if cap>0)
Tptr conj(Tptr &&in)
Generic elementwise conjugate for complex data:
Definition: Operators.h:122
complex dot(const Tptr &X, const Tptr &Y)
Definition: Operators.h:196
ScalarField Jdag(const ScalarFieldTilde &, bool compat=false, int nThreads=0)
Inverse transform transpose: PW basis -> real space (preserve input)
#define callPref(functionName)
Select between functionName and functionName_gpu for the CPU and GPU executables respectively.
Definition: BlasExtra.h:269
double integral(const ScalarField &)
Integral in the unit cell (dV times sum())
void initRandomFlat(ScalarField &)
initialize element-wise with a unit-flat [0:1) random number
complexScalarField Complex(const ScalarField &)
convert real to complex scalar field with zero imaginary part (real-space)
std::shared_ptr< ScalarFieldTildeData > ScalarFieldTilde
A smart reference-counting pointer to ScalarFieldTildeData.
Definition: ScalarField.h:45
int nr
position space grid count = S[0]*S[1]*S[2]
Definition: GridInfo.h:99
vector3 h[3]
real space sample vectors
Definition: GridInfo.h:98
complex eblas_zdotc(int N, const complex *x, int incx, const complex *y, int incy)
Dot product of complex arrays: threaded wrapper to the cblas_zdotc BLAS1 function.
void * data(bool shouldAbsorbScale=true)
get a pointer to the actual data (after absorbing the scale factor, unless otherwise specified) ...
void threadLaunch(int nThreads, Callable *func, size_t nJobs, Args...args)
A simple utility for running muliple threads.
Tptr & operator-=(Tptr &in, const Tptr &other)
Decrement.
Definition: Operators.h:170
ScalarFieldTilde Linv(const ScalarFieldTilde &)
Inverse Laplacian.
void applyFuncGsq(const GridInfo &gInfo, const Func &f, Args...args)
Evaluate a function f(i, Gsq, args...) at each point in reciprocal space indexed by i...
void zeroNyquist(RealKernel &Gdata)
zeros out all the nyquist components of a real G-kernel
void nullToZero(Tptr &X, const GridInfo &gInfo)
If X is null, allocate and initialize to 0.
Definition: Operators.h:231
ScalarField Real(const complexScalarField &)
real part of a complex scalar field (real-space)
Real and complex scalar fields in real and reciprocal space.
int nG
reciprocal lattice count = S[0]*S[1]*(S[2]/2+1) [on account of using r2c and c2r ffts] ...
Definition: GridInfo.h:100
ScalarField I(const ScalarFieldTilde &, bool compat=false, int nThreads=0)
Forward transform: PW basis -> real space (preserve input)
void eblas_dscal(int N, double a, double *x, int incx)
Scale a real array: threaded wrapper to the cblas_dscal BLAS1 function.
std::shared_ptr< complexScalarFieldTildeData > complexScalarFieldTilde
A smart reference-counting pointer to complexScalarFieldTildeData.
Definition: ScalarField.h:47
Tptr clone(const Tptr &X)
Clone (NOTE: operator= is by reference for the ScalarField classes)
Definition: Operators.h:111
ScalarField log(const ScalarField &)
Elementwise logarithm (preserve input)
ScalarFieldTilde O(const ScalarFieldTilde &)
Inner product operator (diagonal in PW basis)
ScalarField JdagOJ(const ScalarField &)
Evaluate Jdag(O(J())), which avoids 2 fourier transforms in PW basis (preserve input) ...
vector3< int > S
sample points in each dimension (if 0, will be determined automatically based on Gmax) ...
Definition: GridInfo.h:85
Tptr operator+(const Tptr &in1, const Tptr &in2)
Add (preserve inputs)
Definition: Operators.h:171
ScalarFieldTilde L(const ScalarFieldTilde &)
Laplacian.
void printStats(const ScalarField &X, const char *name, FILE *fp=stdout)
Print mean and standard deviation of array with specified name (debug utility)
void initGaussianKernel(RealKernel &, double x0)
initialize to gaussian kernel exp(-(G x0/2)^2)
ScalarFieldTilde gaussConvolve(const ScalarFieldTilde &, double sigma)
convolve with a gaussian
Commonly used BLAS-like routines.
std::shared_ptr< complexScalarFieldData > complexScalarField
A smart reference-counting pointer to complexScalarFieldData.
Definition: ScalarField.h:46
ScalarField inv(const ScalarField &)
Elementwise reciprocal (preserve input)
ScalarField exp(const ScalarField &)
Elementwise exponential (preserve input)
Geometry of the simulation grid.
Tptr & operator*=(Tptr &in, double scaleFac)
Scale.
Definition: Operators.h:115
#define Tptr
shorthand for writing the template operators (undef&#39;d at end of header)
Definition: Operators.h:109
Base class for ScalarFieldData and ScalarFieldTildeData.
Definition: ScalarField.h:61
Special class for storing real reciprocal-space kernels encountered ever so often for convolutions...
Definition: ScalarField.h:180
std::shared_ptr< ScalarFieldData > ScalarField
A smart reference-counting pointer to ScalarFieldData.
Definition: ScalarField.h:41
Complex number (need to define our own because we need operators for gpu code as well) ...
Definition: scalar.h:49
void axpy(double alpha, const Tptr &X, Tptr &Y)
Generic axpy for complex data types (Note: null pointers are treated as zero)
Definition: Operators.h:158
void initTranslation(ScalarFieldTilde &, const vector3<> &r)
initialize to translation operator exp(-i G.r)
double eblas_dznrm2(int N, const complex *x, int incx)
2-norm of a complex array: threaded wrapper to the cblas_dznrm2 BLAS1 function
Tptr & operator+=(Tptr &in, const Tptr &other)
Increment.
Definition: Operators.h:169
Tptr operator-(const Tptr &in1, const Tptr &in2)
Subtract (preserve inputs)
Definition: Operators.h:175
double nrm2(const Tptr &X)
Definition: Operators.h:199