/* 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; inrot;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; inrot; 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; inrot;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; inrot; 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); }