Ejemplo n.º 1
0
void removeUnitaryProductions(GrammarADT grammar) {
    ProductionsADT  productions = getProductions(grammar);
    int i,j,k, productionquant = getQuant(productions), unitaryquant = 0, lastunitaryquant = 0;
    /*auxiliar array for unitary productions*/
    char * unitaries = NULL;
    /*iterate over productions and determine first unitaries:
     * the productions that have only one non terminal symbol
     * on the right side */
    for (i=0; i< productionquant; i++) {
        char first = getProductionComponent(getProduction(productions,i),0);
        char sec = getProductionComponent(getProduction(productions,i),1);
        char third = getProductionComponent(getProduction(productions,i),2);
        if ( isNonTerminal(sec) && third == LAMDA ) {
            addPair(&unitaries,&unitaryquant,first, sec);
        } else if( isNonTerminal(third) && sec == LAMDA) {
            addPair(&unitaries,&unitaryquant,first, third);
        }
    }
    /*iterate over unitaries, adding the closure*/
    while(unitaryquant != lastunitaryquant) {
        lastunitaryquant = unitaryquant;
        for (i=0; i<unitaryquant ; i+=2) {
            char first1 = unitaries[i];
            char sec1 = unitaries[i+1];
            for (j=0; j<unitaryquant ; j+=2) {
                char first2 = unitaries[j];
                char sec2 = unitaries[j+1];
                /*(A,B)(B,C)-> (A,C)*/
                if (sec1 == first2 ) {
                    if (!containsPair(unitaries,unitaryquant,first1,sec2) &&
                            first1 != sec2 ) { /*no sense in adding (A,A) unitaries*/
                        addPair(&unitaries,&unitaryquant,first1,sec2);
                    }
                }
            }
        }
    }
    /*Debug*/
    //printByPairs(unitaries,unitaryquant);
    //printf("unitaries quant: %d\n\n", unitaryquant/2);
    /*create the new productions and remove the unitaries*/
    for(i=0; i<productionquant; i++) {
        ProductionADT p1 = getProduction(productions,i);
        if ( isUnitary(p1) ) {
            char first1 = getProductionComponent(p1,0);
            char sec1 = getProductionComponent(p1,1);
            char third1 = getProductionComponent(p1,2);
            for(j=0; j<unitaryquant; j+=2) {
                char uni1 = unitaries[j];
                char uni2 = unitaries[j+1];
                //A->B and (A,B) (unitary production is localized)
                if ((first1 == uni1) && (sec1 == uni2 || third1 == uni2 )) {
                    for(k=0; k<productionquant; k++ ) {
                        ProductionADT p2 = getProduction(productions,k);
                        char first2 = getProductionComponent(p2,0);
                        char sec2 = getProductionComponent(p2,1);
                        char third2 = getProductionComponent(p2,2);
                        if(!isUnitary(p2)) {
                            if(first2 == uni2 ) {
                                addProduction(productions,newProduction(first1,sec2,third2));
                            }
                        }
                    }
                }
            }
            removeParticularProduction(productions,p1);
            free(p1);
        }
    }
    /*remove non terminals and terminals that are no longer there */
    actualizeTerminals(grammar);
    actualizeNonTerminals(grammar);
    actualizeProductions(grammar);



}
Ejemplo n.º 2
0
void Phonon::setup(bool printDefaults)
{
	//Parse input to initialize unit cell:
	parse(input, e, printDefaults);
	logSuspend();
	parse(input, eSupTemplate); //silently create a copy by re-parsing input (Everything is not trivially copyable)
	logResume();
	
	//Ensure phonon command specified:
	if(!sup.length())
		die("phonon supercell must be specified using the phonon command.\n");
	if(!e.gInfo.S.length_squared())
		die("Manual fftbox setting required for phonon. If supercell grid\n"
			"initialization fails, specify slightly larger manual fftbox.\n");
	//Check kpoint and supercell compatibility:
	if(e.eInfo.qnums.size()>1 || e.eInfo.qnums[0].k.length_squared())
		die("phonon requires a Gamma-centered uniform kpoint mesh.\n");
	for(int j=0; j<3; j++)
	{	if(!sup[j] || e.eInfo.kfold[j] % sup[j])
		{	die("kpoint folding %d is not a multiple of supercell count %d for lattice direction %d.\n",
				e.eInfo.kfold[j], sup[j], j);
		}
		eSupTemplate.eInfo.kfold[j] = e.eInfo.kfold[j] / sup[j];
	}
	
	logPrintf("########### Unit cell calculation #############\n");
	SpeciesInfo::Constraint constraintFull;
	constraintFull.moveScale = 0;
	constraintFull.type = SpeciesInfo::Constraint::None;
	for(size_t sp=0; sp<e.iInfo.species.size(); sp++)
		e.iInfo.species[sp]->constraints.assign(e.iInfo.species[sp]->atpos.size(), constraintFull);
	e.setup();
	if(!e.coulombParams.supercell) e.updateSupercell(true); //force supercell generation

	nSpins = e.eInfo.spinType==SpinZ ? 2 : 1;
	nSpinor = e.eInfo.spinorLength();

	//Initialize state of unit cell:
	if(e.cntrl.dumpOnly)
	{	//Single energy calculation so that all dependent quantities have been initialized:
		logPrintf("\n----------- Energy evaluation at fixed state -------------\n"); logFlush();
		e.eVars.elecEnergyAndGrad(e.ener, 0, 0, true);
	}
	else elecFluidMinimize(e);
	logPrintf("# Energy components:\n"); e.ener.print(); logPrintf("\n");

	//Determine optimum number of bands for supercell calculation:
	nBandsOpt = 0;
	for(int q=e.eInfo.qStart; q<e.eInfo.qStop; q++)
	{	int nBands_q = std::upper_bound(e.eVars.F[q].begin(), e.eVars.F[q].end(), Fcut, std::greater<double>()) - e.eVars.F[q].begin();
		nBandsOpt = std::max(nBandsOpt, nBands_q);
	}
	mpiUtil->allReduce(nBandsOpt, MPIUtil::ReduceMax);
	logPrintf("Fcut=%lg reduced nBands from %d to %d per unit cell.\n", Fcut, e.eInfo.nBands, nBandsOpt);

	//Make unit cell state available on all processes 
	//(since MPI division of qSup and q are different and independent of the map)
	for(int q=0; q<e.eInfo.nStates; q++)
	{	//Allocate:
		if(!e.eInfo.isMine(q))
		{	e.eVars.C[q].init(e.eInfo.nBands, e.basis[q].nbasis * e.eInfo.spinorLength(), &e.basis[q], &e.eInfo.qnums[q]);
			e.eVars.F[q].resize(e.eInfo.nBands);
			e.eVars.Hsub_eigs[q].resize(e.eInfo.nBands);
			if(e.eInfo.fillingsUpdate==ElecInfo::FermiFillingsAux)
				e.eVars.B[q].init(e.eInfo.nBands, e.eInfo.nBands);
		}
		//Broadcast from owner:
		int qSrc = e.eInfo.whose(q);
		e.eVars.C[q].bcast(qSrc);
		e.eVars.F[q].bcast(qSrc);
		e.eVars.Hsub_eigs[q].bcast(qSrc);
		if(e.eInfo.fillingsUpdate==ElecInfo::FermiFillingsAux)
			e.eVars.B[q].bcast(qSrc);
	}

	logPrintf("\n------- Configuring supercell and perturbation modes -------\n");
	
	//Grid:
	eSupTemplate.gInfo.S = Diag(sup) * e.gInfo.S; //ensure exact supercell
	eSupTemplate.gInfo.R = e.gInfo.R * Diag(sup);
	prodSup = sup[0] * sup[1] * sup[2];
	
	//Replicate atoms (and related properties):
	for(size_t sp=0; sp<e.iInfo.species.size(); sp++)
	{	const SpeciesInfo& spIn = *(e.iInfo.species[sp]);
		SpeciesInfo& spOut = *(eSupTemplate.iInfo.species[sp]);
		spOut.atpos.clear();
		spOut.initialMagneticMoments.clear();
		matrix3<> invSup = inv(Diag(vector3<>(sup)));
		vector3<int> iR;
		for(iR[0]=0; iR[0]<sup[0]; iR[0]++)
		for(iR[1]=0; iR[1]<sup[1]; iR[1]++)
		for(iR[2]=0; iR[2]<sup[2]; iR[2]++)
		{	for(vector3<> pos: spIn.atpos)
				spOut.atpos.push_back(invSup * (pos + iR));
			for(vector3<> M: spIn.initialMagneticMoments)
				spOut.initialMagneticMoments.push_back(M); //needed only to determine supercell symmetries
		}
		spOut.constraints.assign(spOut.atpos.size(), constraintFull);
	}
	
	//Supercell symmetries:
	eSupTemplate.symm.setup(eSupTemplate);
	const std::vector< matrix3<int> >& symSup = eSupTemplate.symm.getMatrices();
	symSupCart.clear();
	eSupTemplate.gInfo.invR = inv(eSupTemplate.gInfo.R);
	for(const matrix3<int>& m: symSup)
		symSupCart.push_back(eSupTemplate.gInfo.R * m * eSupTemplate.gInfo.invR);
	
	//Pick maximally symmetric orthogonal basis:
	logPrintf("\nFinding maximally-symmetric orthogonal basis for displacements:\n");
	std::vector< vector3<> > dirBasis;
	{	std::multimap<int, vector3<> > dirList; //directions indexed by their stabilizer group cardinality
		vector3<int> iR;
		for(iR[0]=0; iR[0]<=+1; iR[0]++)
		for(iR[1]=-1; iR[1]<=+1; iR[1]++)
		for(iR[2]=-1; iR[2]<=+1; iR[2]++)
			if(iR.length_squared())
			{	//Try low-order lattice vector linear combination:
				vector3<> n = eSupTemplate.gInfo.R * iR; n *= (1./n.length());
				dirList.insert(std::make_pair(nStabilizer(n, symSupCart), n));
				//Try low-order reciprocal lattice vector linear combination:
				n = iR * eSupTemplate.gInfo.invR; n *= (1./n.length());
				dirList.insert(std::make_pair(nStabilizer(n, symSupCart), n));
			}
		dirBasis.push_back(dirList.rbegin()->second);
		//Pick second driection orthogonal to first:
		std::multimap<int, vector3<> > dirList2;
		for(auto entry: dirList)
		{	vector3<> n = entry.second;
			n -= dot(n, dirBasis[0]) * dirBasis[0];
			if(n.length_squared() < symmThresholdSq) continue;
			n *= (1./n.length());
			dirList2.insert(std::make_pair(nStabilizer(n, symSupCart), n));
		}
		dirBasis.push_back(dirList2.rbegin()->second);
		dirBasis.push_back(cross(dirBasis[0], dirBasis[1])); //third direction constrained by orthogonality
	}
	for(const vector3<>& n: dirBasis)
		logPrintf(" [ %+lf %+lf %+lf ] |Stabilizer|: %d\n", n[0], n[1], n[2], nStabilizer(n,symSupCart));
	
	//List all modes:
	modes.clear();
	for(size_t sp=0; sp<e.iInfo.species.size(); sp++)
		for(size_t at=0; at<e.iInfo.species[sp]->atpos.size(); at++) //only need to move atoms in first unit cell
			for(int iDir=0; iDir<3; iDir++)
			{	Mode mode;
				mode.sp = sp;
				mode.at = at;
				mode.dir[iDir] = 1.;
				modes.push_back(mode);
			}

	//Find irreducible modes:
	perturbations.clear();
	for(unsigned sp=0; sp<e.iInfo.species.size(); sp++)
	{	int nAtoms = e.iInfo.species[sp]->atpos.size();
		int nPert = nAtoms * dirBasis.size();
		//generate all perturbations first:
		std::vector<Perturbation> pertSp(nPert); //perturbations of this species
		std::vector<matrix> proj(nPert); //projection operator into subspace spanned by star of current perturbation
		matrix projTot;
		const auto& atomMap = eSupTemplate.symm.getAtomMap()[sp];
		for(int iPert=0; iPert<nPert; iPert++)
		{	pertSp[iPert].sp = sp;
			pertSp[iPert].at = iPert / dirBasis.size();
			pertSp[iPert].dir = dirBasis[iPert % dirBasis.size()];
			pertSp[iPert].weight = 1./symSupCart.size();
			for(unsigned iSym=0; iSym<symSupCart.size(); iSym++)
			{	int at = atomMap[pertSp[iPert].at][iSym] % nAtoms; //map back to first cell
				vector3<> dir = symSupCart[iSym] * pertSp[iPert].dir;
				matrix nHat = zeroes(nPert,1);
				for(int iDir=0; iDir<3; iDir++)
					nHat.set(at*3+iDir,0, dir[iDir]);
				proj[iPert] += pertSp[iPert].weight * nHat * dagger(nHat);
			}
			projTot += proj[iPert];
		}
		myassert(nrm2(projTot - eye(nPert)) < symmThreshold);
		//only select perturbations with distinct subspace projections:
		std::vector<bool> irred(nPert, true); //whether each perturbation is in irreducible set
		for(int iPert=0; iPert<nPert; iPert++)
		{	for(int jPert=0; jPert<iPert; jPert++)
				if(irred[jPert] && nrm2(proj[iPert]-proj[jPert])<symmThreshold)
				{	pertSp[jPert].weight += pertSp[iPert].weight; //send weight of current mode to its image in irreducible set
					irred[iPert] = false; //this mode will be accounted for upon symmetrization
					break;
				}
		}
		for(int iPert=0; iPert<nPert; iPert++)
			if(irred[iPert])
				perturbations.push_back(pertSp[iPert]);
	}
	logPrintf("\n%d perturbations of the unit cell reduced to %d under symmetries:\n", int(modes.size()), int(perturbations.size()));
	for(const Perturbation& pert: perturbations)
		logPrintf("%s %d  [ %+lf %+lf %+lf ] %lf\n", e.iInfo.species[pert.sp]->name.c_str(),
			pert.at, pert.dir[0], pert.dir[1], pert.dir[2], pert.weight*symSupCart.size());
	
	//Determine wavefunction unitary rotations:
	logPrintf("\nCalculating unitary rotations of unit cell states under symmetries:\n");
	stateRot.resize(nSpins);
	double unitarityErr = 0.;
	for(int iSpin=0; iSpin<nSpins; iSpin++)
	{	//Find states involved in the supercell Gamma-point:
		struct Kpoint : public Supercell::KmeshTransform
		{	vector3<> k; //also store k-point for convenience (KmeshTransform doesn't have it)
		};
		std::vector<Kpoint> kpoints; kpoints.reserve(prodSup);
		const Supercell& supercell = *(e.coulombParams.supercell);
		for(unsigned ik=0; ik<supercell.kmesh.size(); ik++)
		{	double kSupErr; round(matrix3<>(Diag(sup)) * supercell.kmesh[ik], &kSupErr);
			if(kSupErr < symmThreshold) //maps to Gamma point
			{	Kpoint kpoint;
				(Supercell::KmeshTransform&)kpoint = supercell.kmeshTransform[ik]; //copy base class
				kpoint.k = supercell.kmesh[ik];
				kpoint.iReduced += iSpin*(e.eInfo.nStates/nSpins); //point to source k-point with appropriate spin
				kpoints.push_back(kpoint);
			}
		}
		myassert(int(kpoints.size()) == prodSup);
		//Initialize basis and qnum for these states:
		std::vector<QuantumNumber> qnums(prodSup);
		std::vector<Basis> basis(prodSup);
		logSuspend();
		for(int ik=0; ik<prodSup; ik++)
		{	qnums[ik].k = kpoints[ik].k;
			qnums[ik].spin = (nSpins==1 ? 0 : (iSpin ? +1 : -1));
			qnums[ik].weight = 1./prodSup;
			basis[ik].setup(e.gInfo, e.iInfo, e.cntrl.Ecut, kpoints[ik].k);
		}
		logResume();
		//Get wavefunctions for all these k-points:
		#define whose_ik(ik) (((ik) * mpiUtil->nProcesses())/prodSup) //local MPI division
		std::vector<ColumnBundle> C(prodSup);
		std::vector<std::shared_ptr<ColumnBundleTransform::BasisWrapper> > basisWrapper(prodSup);
		auto sym = e.symm.getMatrices(); //unit cell symmetries
		for(int ik=0; ik<prodSup; ik++)
		{	C[ik].init(e.eInfo.nBands, basis[ik].nbasis*nSpinor, &basis[ik], &qnums[ik], isGpuEnabled());
			if(whose_ik(ik) == mpiUtil->iProcess())
			{	int q = kpoints[ik].iReduced;
				C[ik].zero();
				basisWrapper[ik] = std::make_shared<ColumnBundleTransform::BasisWrapper>(basis[ik]);
				ColumnBundleTransform(e.eInfo.qnums[q].k, e.basis[q], qnums[ik].k, *(basisWrapper[ik]),
					nSpinor, sym[kpoints[ik].iSym], kpoints[ik].invert).scatterAxpy(1., e.eVars.C[q], C[ik],0,1);
			}
		}
		for(int ik=0; ik<prodSup; ik++) C[ik].bcast(whose_ik(ik)); //make available on all processes
		//Determine max eigenvalue:
		int nBands = e.eInfo.nBands;
		double Emax = -INFINITY;
		for(int q=e.eInfo.qStart; q<e.eInfo.qStop; q++)
			Emax = std::max(Emax, e.eVars.Hsub_eigs[q].back());
		mpiUtil->allReduce(Emax, MPIUtil::MPIUtil::ReduceMax);
		double EmaxValid = +INFINITY;
		//Loop over supercell symmetry operations:
		PeriodicLookup<QuantumNumber> plook(qnums, e.gInfo.GGT);
		stateRot[iSpin].resize(symSupCart.size());
		for(size_t iSym=0; iSym<symSupCart.size(); iSym++)
		{	matrix3<> symUnitTmp = e.gInfo.invR * symSupCart[iSym] * e.gInfo.R; //in unit cell lattice coordinates
			#define SymmErrMsg \
				"Supercell symmetries do not map unit cell k-point mesh onto itself.\n" \
				"This implies that the supercell is more symmetric than the unit cell!\n" \
				"Please check to make sure that you have used the minimal unit cell.\n\n"
			matrix3<int> symUnit;
			for(int j1=0; j1<3; j1++)
				for(int j2=0; j2<3; j2++)
				{	symUnit(j1,j2) = round(symUnitTmp(j1,j2));
					if(fabs(symUnit(j1,j2) - symUnitTmp(j1,j2)) > symmThreshold)
						die(SymmErrMsg)
				}
			//Find image kpoints under rotation: (do this for all k-points so that all processes exit together if necessary)
			std::vector<int> ikRot(prodSup);
			for(int ik=0; ik<prodSup; ik++)
			{	size_t ikRotCur = plook.find(qnums[ik].k * symUnit);
				if(ikRotCur==string::npos) die(SymmErrMsg)
				ikRot[ik] = ikRotCur;
			}
			#undef SymmErrMsg
			//Calculate unitary transformation matrix:
			stateRot[iSpin][iSym].init(prodSup, nBands);
			for(int ik=0; ik<prodSup; ik++)
				if(whose_ik(ikRot[ik]) == mpiUtil->iProcess()) //MPI division by target k-point
				{	ColumnBundle Crot = C[ikRot[ik]].similar();
					Crot.zero();
					ColumnBundleTransform(qnums[ik].k, basis[ik], qnums[ikRot[ik]].k, *(basisWrapper[ikRot[ik]]),
						nSpinor, symUnit, +1).scatterAxpy(1., C[ik], Crot,0,1);
					matrix Urot = Crot ^ O(C[ikRot[ik]]); //will be unitary if Crot is a strict unitary rotation of C[ikRot[ik]]
					//Check maximal subspace that is unitary: (remiander must be incomplete degenerate subspace)
					int nBandsValid = nBands;
					while(nBandsValid && !isUnitary(Urot(0,nBandsValid, 0,nBandsValid)))
						nBandsValid--;
					if(nBandsValid<nBands)
					{	//Update energy range of validity:
						EmaxValid = std::min(EmaxValid, e.eVars.Hsub_eigs[kpoints[ik].iReduced][nBandsValid]);
						//Make valid subspace exactly unitary:
						matrix UrotSub = Urot(0,nBandsValid, 0,nBandsValid);
						matrix UrotOverlap = dagger(UrotSub) * UrotSub;
						UrotSub = UrotSub * invsqrt(UrotOverlap); //make exactly unitary
						unitarityErr += std::pow(nrm2(UrotOverlap - eye(nBandsValid)), 2);
						//Zero out invalid subspace:
						Urot.zero();
						Urot.set(0,nBandsValid, 0,nBandsValid, UrotSub);
					}
					stateRot[iSpin][iSym].set(ik, ikRot[ik], Urot);
				}
			stateRot[iSpin][iSym].allReduce();
		}
		#undef whose_ik
		mpiUtil->allReduce(EmaxValid, MPIUtil::ReduceMin);
		if(nSpins>1) logPrintf("\tSpin %+d: ", iSpin ? +1 : -1);  else logPrintf("\t");
		logPrintf("Matrix elements valid for ");
		if(std::isfinite(EmaxValid)) logPrintf("E < %+.6lf (Emax = %+.6lf) due to incomplete degenerate subspaces.\n", EmaxValid, Emax);
		else logPrintf("all available states (all degenerate subspaces are complete).\n");
	}
	mpiUtil->allReduce(unitarityErr, MPIUtil::ReduceSum);
	unitarityErr = sqrt(unitarityErr / (nSpins * prodSup * symSupCart.size()));
	logPrintf("\tRMS unitarity error in valid subspaces: %le\n", unitarityErr);
}