Skip to content

Commit 4be3395

Browse files
Merge branch 'master' into onthefly-flare-cluster
2 parents 677e3d8 + 70c3060 commit 4be3395

22 files changed

Lines changed: 5992 additions & 6 deletions

Modules/Classify.py

Lines changed: 784 additions & 0 deletions
Large diffs are not rendered by default.

Modules/Ensemble.py

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import numpy as np
77
import time
88
#from scipy.special import tanh, sinh, cosh
9+
10+
import sscha.Classify as Classify
11+
import sscha.qClassify as qClassify
912
try:
1013
from typing import Union
1114
from flare.bffs.gp import GaussianProcess
@@ -3841,7 +3844,274 @@ def get_free_energy_hessian(self, include_v4 = False, get_full_hessian = True, v
38413844
return dyn_hessian, d3* 2.0 # Ha to Ry
38423845
return dyn_hessian
38433846

3847+
def get_free_energy_hessian_dev(self, include_v4 = False, do_scf = True, eps = 1e-6, alpha_mix=0.3, get_full_hessian = True, verbose = False):
3848+
"""
3849+
Dev function.
3850+
3851+
GET THE FREE ENERGY ODD CORRECTION DEV
3852+
======================================
3853+
3854+
This function computes the third and fourth order corrections classifying the
3855+
polarization vector by wave-vector q. We rewrote the hessian from Bianco's paper
3856+
into smaller objects. The expression will be soon uploaded.
3857+
3858+
To reduce the required RAM, only the symmetry independent third and fourth order
3859+
force constants are saved in memory, computing the rest on the fly.
3860+
3861+
Parameters
3862+
----------
3863+
include_v4 : bool
3864+
If True we include the fourth order force constant matrix.
3865+
This requires a lot of memory
3866+
do_scf : bool
3867+
If True, the W matrix is self-consitently converged. Otherwise, just the first
3868+
correction of the fourth-order is considered (False often enough in practice).
3869+
eps : float
3870+
Precision to reach for the max value of |W|. It is later weighted by alpha-mix
3871+
in practice to ensure convergence. Defaults to 1e-6.
3872+
alpha_mix : float
3873+
Mixing parameter used in the scf loop of W, where
3874+
W(n+1)=W(n)(1-alpha_mix)+alpha_mix*W(n+1). Default to 0.3.
3875+
get_full_hessian : bool
3876+
If True the full hessian matrix is returned, if false, only the correction to
3877+
the SSCHA dynamical matrix is returned.
3878+
verbose : bool
3879+
If true, the third order force constant tensor is written in output [Ha/bohr^3 units].
3880+
This can be used to interpolate the result on a bigger mesh with cellconstructor.
3881+
3882+
Returns
3883+
-------
3884+
phi_sc : Phonons()
3885+
The dynamical matrix of the free energy hessian in (Ry/bohr^2)
3886+
"""
3887+
3888+
self.convert_units(UNITS_HARTREE)
3889+
super_structure = self.current_dyn.structure.generate_supercell(self.supercell)
3890+
dyn_supercell = self.current_dyn.GenerateSupercellDyn(self.supercell)
3891+
nr = np.prod(self.supercell)
3892+
3893+
nat_sc = dyn_supercell.structure.N_atoms
3894+
n_modes = nat_sc*3
3895+
3896+
mapping, rot_cart, map_uc, map_tr, T_list, T_list_frac = Classify.map_singlet(self.current_dyn, verbose = verbose)
3897+
3898+
orbit2a, orbit2s, norbit, indep_elem, n_indep_elem, tensor = Classify.recognize_doublet(self.current_dyn, mapping, map_uc, verbose = verbose)
3899+
3900+
orbit3a, orbit3s, norbit3, indep_3fc_elem, n_indep_3fc_elem, kernel_3fc, rot_3fc, mapping_triplet = Classify.recognize_triplet(self.current_dyn, mapping, map_uc, verbose=verbose)
3901+
3902+
nref2 = orbit2a.shape[0]
3903+
indep_fc = np.zeros((nref2, max(n_indep_elem)), dtype=np.float64)
3904+
3905+
super_structure = self.current_dyn.structure.generate_supercell(self.supercell)
3906+
w, pols = self.current_dyn.DiagonalizeSupercell()
3907+
3908+
n_modes = len(w)
3909+
nat_sc = int(np.shape(pols)[0] / 3)
3910+
nat = self.dyn_0.structure.N_atoms
3911+
3912+
a = np.zeros( (nat_sc * 3), dtype = np.double)
3913+
new_pol = np.zeros( (nat_sc, nat_sc * 3, 3), dtype = np.double)
3914+
# If the element is sym:
3915+
ur = np.zeros( (self.N, nat_sc * 3))
3916+
upsilon = np.zeros( (nat_sc*3, nat_sc * 3))
3917+
# Symmetry data for sym 3FC:
3918+
s_cart = np.zeros( (3, 3, 48) , dtype = np.float64, order = "F")
3919+
s_inv_cart = np.zeros( (3, 3, 48) , dtype = np.float64, order = "F")
3920+
irt = np.zeros( (48, nat_sc), dtype = np.intc, order = "F")
3921+
translations_irt = np.zeros( (nat_sc, np.prod(self.supercell)), dtype = np.intc, order = "F")
3922+
3923+
# Get the translational modes
3924+
if not self.ignore_small_w:
3925+
trans = CC.Methods.get_translations(pols, super_structure.get_masses_array())
3926+
else:
3927+
trans = np.abs(w) < CC.Phonons.__EPSILON_W__
3928+
38443929

3930+
# Get the atomic types
3931+
ityp = super_structure.get_ityp() + 1 #Py to Fortran indexing
3932+
n_typ = len(self.current_dyn.structure.masses)
3933+
3934+
amass = np.zeros(n_typ, dtype = np.double)
3935+
3936+
for at_type in self.current_dyn.structure.masses:
3937+
index = ityp[self.current_dyn.structure.atoms.index(at_type)] - 1
3938+
amass[index] = self.current_dyn.structure.masses[at_type]
3939+
3940+
# Get the forces and conver in the correct units
3941+
f = (self.forces - self.sscha_forces)# * Bohr
3942+
u = self.u_disps.reshape((self.N, nat_sc, 3), order = "C") #/ Bohr
3943+
3944+
log_err = "err_yesrho"
3945+
a = SCHAModules.thermodynamic.w_to_a(w, self.current_T)
3946+
# Get the polarization vectors in the correct format
3947+
for i in range(nat_sc):
3948+
for j in range(n_modes):
3949+
new_pol[i, j, :] = pols[3*i : 3*(i+1), j]
3950+
3951+
#Calculating rotated displacements and upsilon matrix"
3952+
ur, upsilon = SCHAModules.get_ur_upsilon_matrices(a, new_pol, trans, amass, ityp, u)
3953+
#Obtaining symmetry data
3954+
qe_sym = CC.symmetries.QE_Symmetry(super_structure)
3955+
qe_sym.SetupFromSPGLIB()
3956+
3957+
# SpaceGroup symmetries data
3958+
s_cart, s_inv_cart, irt = qe_sym.QE_s_cart, qe_sym.QE_s_inv_cart, qe_sym.QE_irt
3959+
s_cart = np.asfortranarray(s_cart)
3960+
s_inv_cart = np.asfortranarray(s_inv_cart)
3961+
3962+
#Translations
3963+
translations_irt = qe_sym.QE_translations_irt
3964+
#self.prepare_sym_third_fc = False
3965+
3966+
wq = np.empty(nat*3, dtype=np.float64)
3967+
tmp_pol_vecs = np.empty([nat*3, nat*3], dtype=np.complex128)
3968+
norm_pol_vecs = np.empty([nat*3, nat*3], dtype=np.complex128)
3969+
pol_vecs = np.empty([self.supercell[0]*self.supercell[1]*self.supercell[2], nat*3, nat_sc*3], dtype=np.complex128)
3970+
l = np.empty([self.supercell[0]*self.supercell[1]*self.supercell[2], nat*3, nat_sc*3], dtype=np.complex128)
3971+
wq = np.empty([l.shape[0], l.shape[1]], dtype=np.float64)
3972+
aq = np.empty([l.shape[0], l.shape[1]], dtype=np.float64)
3973+
3974+
rcell = CC.Methods.get_reciprocal_vectors(self.current_dyn.structure.unit_cell)
3975+
q_list = np.empty([l.shape[0], 3], dtype=np.float64)
3976+
q_list_cart = np.empty([l.shape[0], 3], dtype=np.float64)
3977+
qi=0
3978+
for qstar in self.current_dyn.q_stars:
3979+
for q in qstar:
3980+
q_cryst = np.round(CC.Methods.cart_to_cryst(rcell, q)/__A_TO_BOHR__,6)
3981+
wq[qi], tmp_pol_vecs = self.current_dyn.DyagDinQ(iq=qi)
3982+
tmp_pol_vecs = np.transpose(tmp_pol_vecs) # First index mode. Second incex atom, alpha.
3983+
aq[qi] = SCHAModules.thermodynamic.w_to_a(wq[qi], self.current_T)
3984+
for mode in range(nat*3):
3985+
for atom in range(nat):
3986+
norm_pol_vecs[mode,atom*3:(atom+1)*3] = tmp_pol_vecs[mode,atom*3:(atom+1)*3]*aq[qi, mode]/np.sqrt(amass[ityp[atom]-1])
3987+
for mode in range(nat*3):
3988+
for Tx in range(self.supercell[0]):
3989+
for Ty in range(self.supercell[1]):
3990+
for Tz in range(self.supercell[2]):
3991+
T = np.array([Tx, Ty, Tz])
3992+
index = Tx*self.supercell[2]*self.supercell[1]+Ty*self.supercell[2]+Tz
3993+
l[qi,mode,index*nat*3:(index+1)*nat*3] = norm_pol_vecs[mode]*np.exp(2j*np.pi*np.matmul(q_cryst,T))/np.sqrt(self.supercell[0]*self.supercell[1]*self.supercell[2], dtype=np.complex128)
3994+
pol_vecs[qi,mode,index*nat*3:(index+1)*nat*3] = tmp_pol_vecs[mode]*np.exp(2j*np.pi*np.matmul(q_cryst,T))/np.sqrt(self.supercell[0]*self.supercell[1]*self.supercell[2], dtype=np.complex128)
3995+
q_list[qi] = q_cryst
3996+
q_list_cart[qi] = q
3997+
qi+=1
3998+
3999+
Nq = l.shape[0]
4000+
# Get translational modes
4001+
transq = np.zeros(wq.shape, dtype=bool)
4002+
for qi in range(Nq):
4003+
if not self.ignore_small_w:
4004+
with warnings.catch_warnings():
4005+
warnings.simplefilter("ignore")
4006+
transq[qi,:] = CC.Methods.get_translations(np.transpose(pol_vecs[qi,:,:nat*3]), super_structure.get_masses_array()[:nat])
4007+
else:
4008+
transq[qi,:] = np.abs(w) < CC.Phonons.__EPSILON_W__
4009+
for mode in range(nat*3):
4010+
if transq[qi, mode]:
4011+
l[qi,mode] = np.zeros(nat_sc*3, dtype=np.complex128)
4012+
pol_vecs[qi,mode] = np.zeros(nat_sc*3, dtype=np.complex128)
4013+
4014+
# Imposing eps(q)=[eps(-q)]* time-reversal criteria")
4015+
4016+
############################## Start impose TRS ##############################
4017+
mappingq, orbitq1a, orbitq1s, its_zb = qClassify.map_singlet(q_list_cart, q_list, rcell*__A_TO_BOHR__, rot_cart)
4018+
k = 0
4019+
trs_qlist = np.empty(q_list.shape, dtype=np.float64)
4020+
trs_qlist_cart = np.empty(q_list.shape, dtype=np.float64)
4021+
trs_polvecs = np.empty(l.shape, dtype=np.complex128)
4022+
trs_l = np.empty(l.shape, dtype=np.complex128)
4023+
trs_aq = np.empty(aq.shape, dtype=np.float64)
4024+
trs_wq = np.empty(wq.shape, dtype=np.float64)
4025+
4026+
for qi, q in enumerate(q_list):
4027+
if its_zb[qi] == 0:
4028+
trs_qlist[k] = q
4029+
trs_qlist_cart[k] = CC.Methods.cryst_to_cart(rcell*__A_TO_BOHR__, q)
4030+
trs_polvecs[k] = pol_vecs[qi]
4031+
trs_l[k] = l[qi]
4032+
trs_aq[k] = aq[qi]
4033+
trs_wq[k] = wq[qi]
4034+
k+=1
4035+
elif its_zb[qi] == 1:
4036+
trs_qlist[k] = q
4037+
trs_qlist_cart[k] = CC.Methods.cryst_to_cart(rcell*__A_TO_BOHR__, q)
4038+
trs_polvecs[k] = pol_vecs[qi]
4039+
trs_l[k] = l[qi]
4040+
trs_aq[k] = aq[qi]
4041+
trs_wq[k] = wq[qi]
4042+
k+=1
4043+
trs_qlist[k] = (-1)*q
4044+
trs_qlist_cart[k] = CC.Methods.cryst_to_cart(rcell*__A_TO_BOHR__, (-1)*q)
4045+
trs_polvecs[k] = np.conjugate(pol_vecs[qi])
4046+
trs_l[k] = np.conjugate(l[qi])
4047+
trs_aq[k] = aq[qi]
4048+
trs_wq[k] = wq[qi]
4049+
k+=1
4050+
############################## End impose TRS ##############################
4051+
4052+
# Redo the classification imposing the TRS criteria.
4053+
mappingq, orbitq1a, orbitq1s, its_zb = qClassify.map_singlet(trs_qlist_cart, trs_qlist, rcell*__A_TO_BOHR__, rot_cart)
4054+
refq2, refq2o, norbitq2, nrefq2 = qClassify.recognize_doublet(trs_qlist, mappingq)
4055+
4056+
mod = self.supercell
4057+
nat = self.current_dyn.structure.N_atoms
4058+
n_modes = self.current_dyn.structure.N_atoms*mod[0]*mod[1]*mod[2]*3
4059+
4060+
ref_3fc = SCHAModules.module_hess.get_ref3fc(nat, orbit3a, indep_3fc_elem, n_indep_3fc_elem, kernel_3fc, rot_3fc, ur, upsilon, f, self.rho, log_err, s_inv_cart, irt, translations_irt, True)
4061+
4062+
vs_red = np.empty([nrefq2,nat*3,nat*3,nat*3], dtype=np.complex128)
4063+
vs_red = SCHAModules.module_hess.get_ref_vsq(refq2,trs_l,rot_3fc,ref_3fc,mapping_triplet,True)
4064+
trs_gq, daq = SCHAModules.get_gq(trs_aq, trs_wq, transq, self.current_T)
4065+
indep_fc = SCHAModules.module_hess.get_indep2fc(vs_red, refq2, refq2o, norbitq2, orbit2a, n_indep_elem, indep_elem, rot_cart, mapping, map_uc, map_tr, T_list, trs_qlist, trs_gq, verbose)
4066+
4067+
if include_v4:
4068+
refq4, refq4o, norbitq4, nrefq4 = qClassify.recognize_quadruplet(trs_qlist,mappingq,verbose)
4069+
4070+
orbit4t, orbit4o, norbit_4, indep_4fc_elem, n_indep_4fc_elem, kernel_4fc, rot_4fc, mapping_quadruplet = Classify.recognize_quadruplet(self.current_dyn, mapping, map_uc, verbose)
4071+
4072+
ref_4fc = SCHAModules.module_hess.get_ref4fc(orbit4t, indep_4fc_elem, n_indep_4fc_elem, kernel_4fc, rot_4fc, ur, upsilon, f, self.rho, log_err, s_inv_cart, irt, translations_irt, True)
4073+
4074+
ws_red = np.zeros([nrefq4,nat*3,nat*3,nat*3,nat*3], dtype=np.complex128)
4075+
ws_red = SCHAModules.module_hess.get_ref_wsq(refq4,trs_l,rot_4fc,ref_4fc,mapping_quadruplet,True)
4076+
4077+
degs = qClassify.find_degeneracies(trs_wq)
4078+
Pmn = qClassify.construct_Pmn(mapping, orbitq1a, orbitq1s, trs_polvecs, rot_cart)
4079+
4080+
v_red, ref_3fc = SCHAModules.module_hess.get_v3_red(nat, norbit3, orbit3a, orbit3s, indep_3fc_elem, n_indep_3fc_elem, kernel_3fc, rot_3fc, ur, upsilon, f, self.rho, log_err, s_inv_cart, irt, translations_irt)
4081+
vs = SCHAModules.module_hess.get_all_vsq(trs_l, v_red, map_uc)
4082+
4083+
if do_scf:
4084+
ws_red_scf = SCHAModules.module_hess.get_scf_wsq(ws_red, trs_gq, refq4, refq4o, norbitq4, Pmn, degs, True, eps, alpha_mix)
4085+
indep_fc4 = SCHAModules.module_hess.get_indep2fc_v4(vs, ws_red_scf, refq4, refq4o, norbitq4, orbit2a, n_indep_elem, indep_elem, trs_gq, Pmn, degs, mapping, rot_cart, verbose)
4086+
else:
4087+
indep_fc4 = SCHAModules.module_hess.get_indep2fc_v4(vs, ws_red, refq4, refq4o, norbitq4, orbit2a, n_indep_elem, indep_elem, trs_gq, Pmn, degs, mapping, rot_cart, verbose)
4088+
indep_fc += indep_fc4
4089+
phi_sc_odd = np.zeros((n_modes, n_modes), dtype = np.double)
4090+
for ref2 in range(nref2):
4091+
for i in range(norbit[ref2]):
4092+
nat1, nat2 = orbit2a[ref2,i,:]
4093+
fc9 = np.dot(tensor[ref2,i,:, :n_indep_elem[ref2]], indep_fc[ref2, :n_indep_elem[ref2]])
4094+
for alpha in range(3):
4095+
for beta in range(3):
4096+
index = 3*alpha+beta
4097+
#Apply translation sym:
4098+
for r in range(nr):
4099+
# Translated Single atomic-cartesian index
4100+
# Fortran to Py: -1
4101+
phi_sc_odd[3*(translations_irt[nat1,r]-1)+alpha, 3*(translations_irt[nat2,r]-1)+beta] = fc9[index]
4102+
dynq_odd = CC.Phonons.GetDynQFromFCSupercell(phi_sc_odd, np.array(self.current_dyn.q_tot),
4103+
self.current_dyn.structure, super_structure)
4104+
self.convert_units(UNITS_DEFAULT)
4105+
dynq_odd *= 2 # Ha/bohr^2 -> Ry/bohr^2
4106+
4107+
# Generate the Phonon structure by including the odd correction
4108+
dyn_hessian = self.current_dyn.Copy()
4109+
for iq in range(len(self.current_dyn.q_tot)):
4110+
if get_full_hessian:
4111+
dyn_hessian.dynmats[iq] = self.current_dyn.dynmats[iq] + dynq_odd[iq, :, :]
4112+
else:
4113+
dyn_hessian.dynmats[iq] = dynq_odd[iq, :, :]
4114+
return dyn_hessian
38454115

38464116
def compute_ensemble(self, calculator, compute_stress = True, stress_numerical = False,
38474117
cluster = None, verbose = True, timer=None):

0 commit comments

Comments
 (0)