Skip to content

Commit 947bdf6

Browse files
committed
Push get_free_energy_hessian_dev() and environment into clean tree (meson parallel not working)
1 parent aa725e6 commit 947bdf6

10 files changed

Lines changed: 3988 additions & 5 deletions

Modules/Classify.py

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

Modules/Ensemble.py

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import time
77
#from scipy.special import tanh, sinh, cosh
88

9+
import sscha.Classify as Classify
10+
import sscha.qClassify as qClassify
911

1012
"""
1113
This is part of the program python-sscha
@@ -250,6 +252,19 @@ def __init__(self, dyn0, T0, supercell = None, **kwargs):
250252
# A flag that memorize if the ensemble has also the stresses
251253
self.has_stress = True
252254

255+
# Store data for calculations of 3FC elements:
256+
self.a = np.zeros( (Nsc * 3), dtype = np.double)
257+
self.new_pol = np.zeros( (Nsc, Nsc * 3, 3), dtype = np.double)
258+
# If the element is sym:
259+
self.ur = np.zeros( (self.N, Nsc * 3))
260+
self.upsilon = np.zeros( (Nsc*3, Nsc * 3))
261+
# Symmetry data for sym 3FC:
262+
self.nsym = 0
263+
self.s_cart = np.zeros( (3, 3, 48) , dtype = np.float64, order = "F")
264+
self.s_inv_cart = np.zeros( (3, 3, 48) , dtype = np.float64, order = "F")
265+
self.irt = np.zeros( (48, Nsc), dtype = np.intc, order = "F")
266+
self.translations_irt = np.zeros( (Nsc, np.prod(self.supercell)), dtype = np.intc, order = "F")
267+
253268
# A flag for each configuration that check if it possess a force and a stress
254269
self.force_computed = None
255270
self.stress_computed = None
@@ -3831,7 +3846,253 @@ def get_free_energy_hessian(self, include_v4 = False, get_full_hessian = True, v
38313846
return dyn_hessian, d3* 2.0 # Ha to Ry
38323847
return dyn_hessian
38333848

3849+
def get_free_energy_hessian_dev(self, include_v4 = False, get_full_hessian = True, verbose = False):
3850+
"""
3851+
Dev function. With the meson installation, the OpenMP parallelization is NOT WORKING!
3852+
With the old installation everything is fine (old_setup.py)
3853+
3854+
GET THE FREE ENERGY ODD CORRECTION DEV
3855+
======================================
3856+
3857+
This function computes the third and fourth order corrections classifying the
3858+
polarization vector by wave-vector q. We rewrote the hessian from Bianco's paper
3859+
into smaller objects. The expression will be soon uploaded.
3860+
3861+
To reduce the required RAM, only the symmetry independent third and fourth order
3862+
force constants are saved in memory, computing the rest on the fly.
3863+
3864+
Parameters
3865+
----------
3866+
include_v4 : bool
3867+
If True we include the fourth order force constant matrix.
3868+
This requires a lot of memory
3869+
get_full_hessian : bool
3870+
If True the full hessian matrix is returned, if false, only the correction to
3871+
the SSCHA dynamical matrix is returned.
3872+
verbose : bool
3873+
If true, the third order force constant tensor is written in output [Ha/bohr^3 units].
3874+
This can be used to interpolate the result on a bigger mesh with cellconstructor.
3875+
3876+
Returns
3877+
-------
3878+
phi_sc : Phonons()
3879+
The dynamical matrix of the free energy hessian in (Ry/bohr^2)
3880+
"""
3881+
3882+
self.convert_units(UNITS_HARTREE)
3883+
super_structure = self.current_dyn.structure.generate_supercell(self.supercell)
3884+
dyn_supercell = self.current_dyn.GenerateSupercellDyn(self.supercell)
3885+
nr = np.prod(self.supercell)
3886+
3887+
nat_sc = dyn_supercell.structure.N_atoms
3888+
n_modes = nat_sc*3
3889+
3890+
mapping, rot_cart, map_uc, map_tr, T_list, T_list_frac = Classify.map_singlet(self.current_dyn, verbose = verbose)
3891+
3892+
orbit2a, orbit2s, norbit, indep_elem, n_indep_elem, tensor = Classify.recognize_doublet(self.current_dyn, mapping, map_uc, verbose = verbose)
3893+
3894+
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)
3895+
3896+
nref2 = orbit2a.shape[0]
3897+
indep_fc = np.zeros((nref2, max(n_indep_elem)), dtype=np.float64)
3898+
3899+
super_structure = self.current_dyn.structure.generate_supercell(self.supercell)
3900+
w, pols = self.current_dyn.DiagonalizeSupercell()
3901+
3902+
n_modes = len(w)
3903+
nat_sc = int(np.shape(pols)[0] / 3)
3904+
nat = self.dyn_0.structure.N_atoms
3905+
3906+
# Get the translational modes
3907+
if not self.ignore_small_w:
3908+
trans = CC.Methods.get_translations(pols, super_structure.get_masses_array())
3909+
else:
3910+
trans = np.abs(w) < CC.Phonons.__EPSILON_W__
3911+
3912+
3913+
# Get the atomic types
3914+
ityp = super_structure.get_ityp() + 1 #Py to Fortran indexing
3915+
n_typ = len(self.current_dyn.structure.masses)
3916+
3917+
amass = np.zeros(n_typ, dtype = np.double)
3918+
3919+
for at_type in self.current_dyn.structure.masses:
3920+
index = ityp[self.current_dyn.structure.atoms.index(at_type)] - 1
3921+
amass[index] = self.current_dyn.structure.masses[at_type]
3922+
3923+
# Get the forces and conver in the correct units
3924+
f = (self.forces - self.sscha_forces)# * Bohr
3925+
u = self.u_disps.reshape((self.N, nat_sc, 3), order = "C") #/ Bohr
3926+
3927+
log_err = "err_yesrho"
3928+
self.a = SCHAModules.thermodynamic.w_to_a(w, self.current_T)
3929+
# Get the polarization vectors in the correct format
3930+
for i in range(nat_sc):
3931+
for j in range(n_modes):
3932+
self.new_pol[i, j, :] = pols[3*i : 3*(i+1), j]
3933+
3934+
#Calculating rotated displacements and upsilon matrix"
3935+
self.ur, self.upsilon = SCHAModules.get_ur_upsilon_matrices(self.a, self.new_pol, trans, amass, ityp, u)
3936+
#Obtaining symmetry data
3937+
qe_sym = CC.symmetries.QE_Symmetry(super_structure)
3938+
qe_sym.SetupFromSPGLIB()
3939+
3940+
# SpaceGroup symmetries data
3941+
self.nsym, self.s_cart, self.s_inv_cart, self.irt = qe_sym.QE_nsym, qe_sym.QE_s_cart, qe_sym.QE_s_inv_cart, qe_sym.QE_irt
3942+
self.s_cart = np.asfortranarray(self.s_cart)
3943+
self.s_inv_cart = np.asfortranarray(self.s_inv_cart)
3944+
3945+
#Translations
3946+
self.translations_irt = qe_sym.QE_translations_irt
3947+
#self.prepare_sym_third_fc = False
3948+
3949+
wq = np.empty(nat*3, dtype=np.float64)
3950+
tmp_pol_vecs = np.empty([nat*3, nat*3], dtype=np.complex128)
3951+
norm_pol_vecs = np.empty([nat*3, nat*3], dtype=np.complex128)
3952+
pol_vecs = np.empty([self.supercell[0]*self.supercell[1]*self.supercell[2], nat*3, nat_sc*3], dtype=np.complex128)
3953+
l = np.empty([self.supercell[0]*self.supercell[1]*self.supercell[2], nat*3, nat_sc*3], dtype=np.complex128)
3954+
wq = np.empty([l.shape[0], l.shape[1]], dtype=np.float64)
3955+
aq = np.empty([l.shape[0], l.shape[1]], dtype=np.float64)
3956+
3957+
rcell = CC.Methods.get_reciprocal_vectors(self.current_dyn.structure.unit_cell)
3958+
q_list = np.empty([l.shape[0], 3], dtype=np.float64)
3959+
q_list_cart = np.empty([l.shape[0], 3], dtype=np.float64)
3960+
qi=0
3961+
for qstar in self.current_dyn.q_stars:
3962+
for q in qstar:
3963+
q_cryst = np.round(CC.Methods.cart_to_cryst(rcell, q)/__A_TO_BOHR__,6)
3964+
wq[qi], tmp_pol_vecs = self.current_dyn.DyagDinQ(iq=qi)
3965+
tmp_pol_vecs = np.transpose(tmp_pol_vecs) # First index mode. Second incex atom, alpha.
3966+
aq[qi] = SCHAModules.thermodynamic.w_to_a(wq[qi], self.current_T)
3967+
for mode in range(nat*3):
3968+
for atom in range(nat):
3969+
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])
3970+
for mode in range(nat*3):
3971+
for Tx in range(self.supercell[0]):
3972+
for Ty in range(self.supercell[1]):
3973+
for Tz in range(self.supercell[2]):
3974+
T = np.array([Tx, Ty, Tz])
3975+
index = Tx*self.supercell[2]*self.supercell[1]+Ty*self.supercell[2]+Tz
3976+
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)
3977+
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)
3978+
q_list[qi] = q_cryst
3979+
q_list_cart[qi] = q
3980+
qi+=1
3981+
3982+
Nq = l.shape[0]
3983+
# Get translational modes
3984+
transq = np.zeros(wq.shape, dtype=bool)
3985+
for qi in range(Nq):
3986+
if not self.ignore_small_w:
3987+
with warnings.catch_warnings():
3988+
warnings.simplefilter("ignore")
3989+
transq[qi,:] = CC.Methods.get_translations(np.transpose(pol_vecs[qi,:,:nat*3]), super_structure.get_masses_array()[:nat])
3990+
else:
3991+
transq[qi,:] = np.abs(w) < CC.Phonons.__EPSILON_W__
3992+
for mode in range(nat*3):
3993+
if transq[qi, mode]:
3994+
l[qi,mode] = np.zeros(nat_sc*3, dtype=np.complex128)
3995+
pol_vecs[qi,mode] = np.zeros(nat_sc*3, dtype=np.complex128)
3996+
3997+
# Imposing eps(q)=[eps(-q)]* time-reversal criteria")
3998+
3999+
############################## Start impose TRS ##############################
4000+
mappingq, orbitq1a, orbitq1s, its_zb = qClassify.map_singlet(q_list_cart, q_list, rcell*__A_TO_BOHR__, rot_cart)
4001+
k = 0
4002+
trs_qlist = np.empty(q_list.shape, dtype=np.float64)
4003+
trs_qlist_cart = np.empty(q_list.shape, dtype=np.float64)
4004+
trs_polvecs = np.empty(l.shape, dtype=np.complex128)
4005+
trs_l = np.empty(l.shape, dtype=np.complex128)
4006+
trs_aq = np.empty(aq.shape, dtype=np.float64)
4007+
trs_wq = np.empty(wq.shape, dtype=np.float64)
4008+
4009+
for qi, q in enumerate(q_list):
4010+
if its_zb[qi] == 0:
4011+
trs_qlist[k] = q
4012+
trs_qlist_cart[k] = CC.Methods.cryst_to_cart(rcell*__A_TO_BOHR__, q)
4013+
trs_polvecs[k] = pol_vecs[qi]
4014+
trs_l[k] = l[qi]
4015+
trs_aq[k] = aq[qi]
4016+
trs_wq[k] = wq[qi]
4017+
k+=1
4018+
elif its_zb[qi] == 1:
4019+
trs_qlist[k] = q
4020+
trs_qlist_cart[k] = CC.Methods.cryst_to_cart(rcell*__A_TO_BOHR__, q)
4021+
trs_polvecs[k] = pol_vecs[qi]
4022+
trs_l[k] = l[qi]
4023+
trs_aq[k] = aq[qi]
4024+
trs_wq[k] = wq[qi]
4025+
k+=1
4026+
trs_qlist[k] = (-1)*q
4027+
trs_qlist_cart[k] = CC.Methods.cryst_to_cart(rcell*__A_TO_BOHR__, (-1)*q)
4028+
trs_polvecs[k] = np.conjugate(pol_vecs[qi])
4029+
trs_l[k] = np.conjugate(l[qi])
4030+
trs_aq[k] = aq[qi]
4031+
trs_wq[k] = wq[qi]
4032+
k+=1
4033+
############################## End impose TRS ##############################
4034+
4035+
# Redo the classification imposing the TRS criteria.
4036+
mappingq, orbitq1a, orbitq1s, its_zb = qClassify.map_singlet(trs_qlist_cart, trs_qlist, rcell*__A_TO_BOHR__, rot_cart)
4037+
refq2, refq2o, norbitq2, nrefq2 = qClassify.recognize_doublet(trs_qlist, mappingq)
4038+
4039+
mod = self.supercell
4040+
nat = self.current_dyn.structure.N_atoms
4041+
n_modes = self.current_dyn.structure.N_atoms*mod[0]*mod[1]*mod[2]*3
4042+
4043+
ref_3fc = SCHAModules.module_hess.get_ref3fc(nat, orbit3a, indep_3fc_elem, n_indep_3fc_elem, kernel_3fc, rot_3fc, self.ur, self.upsilon, f, self.rho, log_err, self.s_inv_cart, self.irt, self.translations_irt, verbose)
38344044

4045+
vs_red = np.empty([nrefq2,nat*3,nat*3,nat*3], dtype=np.complex128)
4046+
vs_red = SCHAModules.module_hess.get_ref_vsq(refq2,trs_l,rot_3fc,ref_3fc,mapping_triplet,verbose)
4047+
trs_gq, daq = SCHAModules.get_gq(trs_aq, trs_wq, transq, self.current_T)
4048+
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)
4049+
4050+
if include_v4:
4051+
refq4, refq4o, norbitq4, nrefq4 = qClassify.recognize_quadruplet(trs_qlist,mappingq,verbose)
4052+
4053+
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)
4054+
4055+
ref_4fc = SCHAModules.module_hess.get_ref4fc(orbit4t, indep_4fc_elem, n_indep_4fc_elem, kernel_4fc, rot_4fc, self.ur, self.upsilon, f, self.rho, log_err, self.s_inv_cart, self.irt, self.translations_irt, verbose)
4056+
4057+
ws_red = np.zeros([nrefq4,nat*3,nat*3,nat*3,nat*3], dtype=np.complex128)
4058+
ws_red = SCHAModules.module_hess.get_ref_wsq(refq4,trs_l,rot_4fc,ref_4fc,mapping_quadruplet,verbose)
4059+
4060+
degs = qClassify.find_degeneracies(trs_wq)
4061+
Pmn = qClassify.construct_Pmn(mapping, orbitq1a, orbitq1s, trs_polvecs, rot_cart)
4062+
4063+
ws_red_scf = SCHAModules.module_hess.get_scf_wsq(ws_red, trs_gq, refq4, refq4o, norbitq4, Pmn, degs, verbose)
4064+
4065+
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, self.ur, self.upsilon, f, self.rho, log_err, self.s_inv_cart, self.irt, self.translations_irt)
4066+
vs = SCHAModules.module_hess.get_all_vsq(trs_l, v_red, map_uc)
4067+
4068+
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)
4069+
indep_fc += indep_fc4
4070+
phi_sc_odd = np.zeros((n_modes, n_modes), dtype = np.double)
4071+
for ref2 in range(nref2):
4072+
for i in range(norbit[ref2]):
4073+
nat1, nat2 = orbit2a[ref2,i,:]
4074+
fc9 = np.dot(tensor[ref2,i,:, :n_indep_elem[ref2]], indep_fc[ref2, :n_indep_elem[ref2]])
4075+
for alpha in range(3):
4076+
for beta in range(3):
4077+
index = 3*alpha+beta
4078+
#Apply translation sym:
4079+
for r in range(nr):
4080+
# Translated Single atomic-cartesian index
4081+
# Fortran to Py: -1
4082+
phi_sc_odd[3*(self.translations_irt[nat1,r]-1)+alpha, 3*(self.translations_irt[nat2,r]-1)+beta] = fc9[index]
4083+
dynq_odd = CC.Phonons.GetDynQFromFCSupercell(phi_sc_odd, np.array(self.current_dyn.q_tot),
4084+
self.current_dyn.structure, super_structure)
4085+
self.convert_units(UNITS_DEFAULT)
4086+
dynq_odd *= 2 # Ha/bohr^2 -> Ry/bohr^2
4087+
4088+
# Generate the Phonon structure by including the odd correction
4089+
dyn_hessian = self.current_dyn.Copy()
4090+
for iq in range(len(self.current_dyn.q_tot)):
4091+
if get_full_hessian:
4092+
dyn_hessian.dynmats[iq] = self.current_dyn.dynmats[iq] + dynq_odd[iq, :, :]
4093+
else:
4094+
dyn_hessian.dynmats[iq] = dynq_odd[iq, :, :]
4095+
return dyn_hessian
38354096

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

0 commit comments

Comments
 (0)