/*
DFT++ is a density functional package developed by the research group
of Professor Tomas Arias
Copyright 1996-2003 Sohrab Ismail-Beigi
This file is part of DFT++.
DFT++ 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 2 of the License, or
(at your option) any later version.
DFT++ 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 DFT++; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Please see the file CREDITS for a list of authors.
For academic users, we request that publications using results obtained with
this software reference
"New algebraic formulation of density functional calculation," by Sohrab Ismail-Beigi
and T.A. Arias, Computer Physics Communications 128:1-2, 1-45 (June 2000).
and, if using the wavelet basis, further reference
"Multiresolution analysis of electronic structure: semicardinal and wavelet bases,"
T.A. Arias, Reviews of Modern Physics 71:1, 267-311 (January 1999).
and
"Robust ab initio calculation of condensed matter: transparent convergence through
semicardinal multiresolution analysis,'' I.P. Daykov, T.A. Arias, and
Torkel D. Engeness, Physical Review Letters, 90:21, 216402 (May 2003).
For your convenience, preprints of the above articles may be obtained from
http://arXiv.org/abs/cond-mat/9909130, 9805262, and 0204411, respectively.
*/
#include "header.h"
// Symmetrizes the grid 'in' w..r.t. the symmetries of the system
// As a beginning map the old wavelet symemtrizer as closely as
// possible: transform the symmetry matrices from 'Symmetries'
// to integer matrices that the wavelet code uses
//
// TODO: clean-up - change the wavelet code so that it uses
// the class 'Symmetries' directly
// THINK if it's necessary to call symmetrize_accum()
// in real space - probably any space will be alright
void symmetrize_n(WL_ComplexColumn &in, Symmetries *symm)
{
// return;
// Symmetrization always happens in COEFFSPACE
// go there if in REALSPACE
int inputspace = in.representation; // initial space (REAL/COEFFSPACE)
if(inputspace == REALSPACE)
apply_J(in, in);
Gridspec *gridspec;
switch(in.embedding){
case SPARSE:
gridspec = in.basis_spec->gridspec;
break;
case DENSE:
gridspec = in.basis_spec->gridspec_dense;
break;
default:
die("symmetrize_n: Unknown input embedding %d\n",in.embedding);
}
int i,j;
struct Ivec R; // symmetry center that the old wl code understands
// compute it from the Symemtry object
R.x=(int)(symm->Rsym.v[0]*gridspec[0].dim.x);
R.y=(int)(symm->Rsym.v[1]*gridspec[0].dim.y);
R.z=(int)(symm->Rsym.v[2]*gridspec[0].dim.z);
// these should be all integers
if( fmod(symm->Rsym.v[0]*gridspec[0].dim.x, 1) > MIN_SYMM_TOL ||
fmod(symm->Rsym.v[1]*gridspec[0].dim.y, 1) > MIN_SYMM_TOL ||
fmod(symm->Rsym.v[2]*gridspec[0].dim.x, 1) > MIN_SYMM_TOL )
die("WL_symm: wrong center of symemtry\n");
// symemtry matrices in the form that the old wl code likes
int *symgroup[48]; // pointers to the matrices (to loop over)
int symmetryop[48][9]; // the actual matrices
// translate the dft++ symmetries to old-wl language
for(i=0; i<48;i++)
for(j=0; j<9; j++)
symmetryop[i][j] = (int)*(&symm->sym[i].m[0][0] +j);
// set the pointers to the correct positions
for(i=0; i<symm->nrot;i++)
symgroup[i]=&symmetryop[i][0];
// Now create the grids that we'll symmetrize
Grid *n = mkgridnew(gridspec,NULL); //input
Grid *ns = mkgridnew(gridspec,NULL); //output
evalgrid(ns,NULLDVEC, zero);// initialize the output
// zero-out the coefficients, that do not have partners
// (perform the transforms inplace on the wl_column objects)
{
GetRe(n, in); // initialize the input grid
setsymzero(n);
PutRe(n,in);
// now we return back in real space
apply_I(in, in);
GetRe(n, in);
}
// ACCUMULATE S[i](n) on ns
for (int i=0; i<symm->nrot; i++)
symmetrize_accum(ns, n, symgroup[i], R);
// make sure the boundaries on the lower levels are consistent
adjustdown(ns);
// Rescale by the nymber of symemtry operators
// use the c style to save on memory
scalarmultnew(ns, 1./((double) symm->nrot), ns);
// zero-out the coefficients, that do not have partners
// (perform the transforms inplace on the wl_column objects)
{
// first go to COEFFSPACE
PutRe(ns,in);
apply_J(in,in);
//again zero-out the ones w/o a partner
GetRe(ns,in);
setsymzero(ns);
PutRe(ns,in);
}
// Return to REALSPACE if started there
if(inputspace == REALSPACE)
apply_I(in,in);
// Kill the grids we created!
killgridnew(n); killgridnew(ns);
}
int check_basis_symm_compatibility(Symmetries &symm, const WL_Basis &basis)
{
return 0;
}
//the dag of symmetrize_n()
// since the symmetrizewr is nonhermetian in the DFT gradient one must use
// the daggered version
void symmetrize_n_dag(WL_ComplexColumn &in, Symmetries *symm)
{
// return;
// Symmetrization always happens in COEFFSPACE
// go there if in REALSPACE
int inputspace = in.representation; // initial space (REAL/COEFFSPACE)
if(inputspace == REALSPACE)
apply_Idag(in, in);
Gridspec *gridspec;
switch(in.embedding){
case SPARSE:
gridspec = in.basis_spec->gridspec;
break;
case DENSE:
gridspec = in.basis_spec->gridspec_dense;
break;
default:
die("symmetrize_n: Unknown input embedding %d\n",in.embedding);
}
int i,j;
struct Ivec R; // symmetry center that the old wl code understands
// compute it from the Symemtry object
R.x=(int)(symm->Rsym.v[0]*gridspec[0].dim.x);
R.y=(int)(symm->Rsym.v[1]*gridspec[0].dim.y);
R.z=(int)(symm->Rsym.v[2]*gridspec[0].dim.z);
// these should be all integers
if( fmod(symm->Rsym.v[0]*gridspec[0].dim.x, 1) > MIN_SYMM_TOL ||
fmod(symm->Rsym.v[1]*gridspec[0].dim.y, 1) > MIN_SYMM_TOL ||
fmod(symm->Rsym.v[2]*gridspec[0].dim.x, 1) > MIN_SYMM_TOL )
die("WL_symm: wrong center of symemtry\n");
// symemtry matrices in the form that the old wl code likes
int *symgroup[48]; // pointers to the matrices (to loop over)
int symmetryop[48][9]; // the actual matrices
// translate the dft++ symmetries to old-wl language
for(i=0; i<48;i++)
for(j=0; j<9; j++)
symmetryop[i][j] = (int)*(&symm->sym[i].m[0][0] +j);
// set the pointers to the correct positions
for(i=0; i<symm->nrot;i++)
symgroup[i]=&symmetryop[i][0];
// Now create the grids that we'll symmetrize
Grid *n = mkgridnew(gridspec,NULL); //input
Grid *ns = mkgridnew(gridspec,NULL); //output
evalgrid(ns,NULLDVEC, zero);// initialize the output
// zero-out the coefficients, that do not have partners
// (perform the transforms inplace on the wl_column objects)
{
GetRe(n, in); // initialize the input grid
setsymzero(n);
PutRe(n,in);
// now we return back in real space
apply_Jdag(in, in);
GetRe(n, in);
}
// ACCUMULATE S[i](n) on ns
for (int i=0; i<symm->nrot; i++)
symmetrize_accum(ns, n, symgroup[i], R);
// make sure the boundaries on the lower levels are consistent
adjustdown(ns);
// Rescale by the nymber of symemtry operators
// use the c style to save on memory
scalarmultnew(ns, 1./((double) symm->nrot), ns);
// zero-out the coefficients, that do not have partners
// (perform the transforms inplace on the wl_column objects)
{
// first go to COEFFSPACE
PutRe(ns,in);
apply_Idag(in,in);
//again zero-out the ones w/o a partner
GetRe(ns,in);
setsymzero(ns);
PutRe(ns,in);
}
// Return to REALSPACE if started there
if(inputspace == REALSPACE)
apply_Jdag(in,in);
// Kill the grids we created!
killgridnew(n); killgridnew(ns);
}
syntax highlighted by Code2HTML, v. 0.9.1