# ifndef WAVEPACKET_H
# define WAVEPACKET_H
# ifndef _USE_MATH_DEFINES
# define _USE_MATH_DEFINES
# endif
# include <cmath>
# include <complex>
# include <functional>
# include "cvector_3.h"
using namespace std;
const double MIN_EXP_ARG = -15.;
class WavePacket;
template<class Type>
struct eq_second : public binary_function <Type, Type, Type> {
Type operator()(const Type& _Left, const Type& _Right) const{
return _Right;
}
};
template<class Type>
struct eq_minus_second : public binary_function <Type, Type, Type> {
Type operator()(const Type& _Left, const Type& _Right) const{
return -_Right;
}
};
template< class CT >
int compare_compl(const CT &a, const CT& b, double tol=0.){
double dd=real(a)-real(b);
if(dd<-tol)
return -1;
if(dd>tol)
return 1;
dd=imag(a)-imag(b);
if(dd<-tol)
return -1;
if(dd>tol)
return 1;
return 0;
}
inline int compare_vec(const Vector_3 &a, const Vector_3& b, double tol=0.){
for(int i=0;i<3;i++){
double dd=a[i]-b[i];
if(dd<-tol)
return -1;
if(dd>tol)
return 1;
}
return 0;
}
class WavePacket{
friend WavePacket conj(const WavePacket &wp);
public:
cdouble a;
cVector_3 b;
cdouble lz;
WavePacket(const cdouble &sa=cdouble(1.,0.),const cVector_3 &sb=cVector_3(0.,0.), const cdouble &slz=0.): a(sa), b(sb), lz(slz){
}
WavePacket operator*(const WavePacket& other) const {
return WavePacket(a+other.a,b+other.b,lz+other.lz);
}
cdouble integral() const {
cdouble z = lz + b.norm2()/(4.*a);
if(real(z) < MIN_EXP_ARG) return 0.;
return pow(M_PI/a,3./2.)*exp(z);
}
void init(const double width=1., const Vector_3 &r=0., const Vector_3 &p=0., const double pw=0.){
a = (3./(2.*width) - cdouble(0.,1.)*pw)/(2.*width);
b = (2.*a)*r + cdouble(0.,1.)*p;
lz = log(3./(2.*M_PI*width*width))*(3./4.) + (-a*r.norm2() - cdouble(0.,1.)*(p*r));
}
void init(const cdouble &a_, const cVector_3 &b_){
a = a_;
b = b_;
Vector_3 r = get_r();
double r2 = r.norm2();
lz = cdouble( log( real(a)*(2./M_PI) )*(3./4.) - r2*real(a), r2*imag(a) - r*imag(b) );
}
cdouble operator()(const Vector_3 &x) const {
return exp(lz - a*x.norm2() + b*x);
}
WavePacket& normalize(){
Vector_3 r = get_r();
double r2 = r.norm2();
lz = cdouble( log( real(a)*(2./M_PI) )*(3./4.) - r2*real(a), r2*imag(a) - r*imag(b) );
return *this;
}
cdouble overlap(const WavePacket &other) const{
WavePacket wp=(*this)*other;
return wp.integral();
}
WavePacket translate(const Vector_3 &dr) const {
WavePacket wp(a,b,lz);
wp.b+=2*dr*a;
Vector_3 r=get_r();
double dr2=(r+dr).norm2()-r.norm2();
wp.lz+=-a*dr2-cdouble(0.,(get_p()*dr));
return wp;
}
double get_width() const{
return sqrt(3./4./real(a));
}
double get_pwidth() const{
return -imag(a)*sqrt(3./real(a));
}
pair<double,double> get_width_pars() const{
double c=sqrt(3./2./real(a));
return make_pair(c/2,-imag(a)*c);
}
Vector_3 get_r() const {
return real(b)/(2*real(a));
}
Vector_3 get_p() const {
return imag(b) - real(b)*(imag(a)/real(a));
}
template<template<class A> class operation, class d_it, class dfdx_it, class dfdp_it, class dfdw_it, class dfdpw_it>
void int2phys_der(d_it dfdi_,dfdx_it dfdx, dfdp_it dfdp, dfdw_it dfdw, dfdpw_it dfdpw, double h_p=h_plank) const {
operation<double> op;
double dfdi[8], dfn[8]; for(int i=0;i<8;i++)
dfdi[i]=*dfdi_++;
double w=get_width();
Vector_3 r=get_r();
double t=3/(2*w*w*w);
dfn[6]= -t*dfdi[0]-imag(a)*dfdi[1]/w; dfn[7]=-dfdi[1]/(2*w*h_p); for(int i=0;i<3;i++){
dfn[i]= 2*real(a)*dfdi[2+2*i]+2*imag(a)*dfdi[2+2*i+1];
dfn[3+i]= dfdi[2+2*i+1]*(1./h_p) ; dfn[7]+=-(r[i]*dfdi[2+2*i+1]/w)/h_p;
dfn[6]+=-2*r[i]*(t*dfdi[2+2*i]+imag(a)*dfdi[2+2*i+1]/w);
}
int i=0;
for(int k=0;k<3;k++)
*dfdx++=op(*dfdx,dfn[i++]);
for(int k=0;k<3;k++)
*dfdp++=op(*dfdp,dfn[i++]);
*dfdw=op(*dfdw,dfn[i++]);
*dfdpw=op(*dfdpw,dfn[i++]);
}
int compare(const WavePacket &other, double tol=0.) const {
int res=compare_compl(a,other.a, tol);
if(res)
return res;
for(int i=0;i<3;i++){
res=compare_compl(b[i],other.b[i]);
if(res)
return res;
}
return 0;
}
};
#if 0#endif
inline WavePacket conj(const WavePacket &wp){
return WavePacket(conj(wp.a),conj(wp.b),conj(wp.lz));
}
# endif