Skip to content

Commit d93d685

Browse files
committed
Merge branch 'line_minimization' of github.com:SSCHAcode/python-sscha into line_minimization
2 parents a6c0837 + 0196cb6 commit d93d685

3 files changed

Lines changed: 78 additions & 28 deletions

File tree

Modules/Ensemble.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -836,13 +836,11 @@ def load_bin(self, data_dir, population_id = 1, avoid_loading_dyn = False):
836836

837837
# Setup the initial weights
838838
self.rho = np.ones(self.N, dtype = np.float64)
839-
840-
839+
841840
# Setup that both forces and stresses are not computed
842841
self.stress_computed = np.ones(self.N, dtype = bool)
843842
self.force_computed = np.ones(self.N, dtype = bool)
844843

845-
846844

847845
def init_from_structures(self, structures):
848846
"""

Modules/Relax.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ def __init__(self, minimizer = None, ase_calculator=None, N_configs=1, max_pop =
9898
self.target_pressure = 0
9999
self.fix_volume = False
100100

101+
# Options for the cell relaxation
102+
# If true the cell shape is fixed in a variable-cell relaxation
103+
# even if the symmetries allows for more degrees of freedom in the cell shape.
104+
# Usefull (for example) if you want to enfoce a cubic cell even if the structure brakes the symmetries
105+
self.fix_cell_shape = False
106+
101107

102108
# Setup the attribute control
103109
self.__total_attributes__ = [item for item in self.__dict__.keys()]
@@ -351,7 +357,10 @@ def vc_relax(self, target_press = 0, static_bulk_modulus = 100,
351357
This function performs a variable cell SCHA relaxation at constant pressure,
352358
It is similar to the relax calculation, but the unit cell is updated according
353359
to the anharmonic stress tensor at each new population.
354-
The cell optimization is performed with the BFGS algorithm.
360+
361+
By default, all the degrees of freedom compatible with the symmetry group are relaxed in the cell.
362+
You can constrain the cell to keep the same shape by setting fix_cell_shape = True.
363+
355364
356365
NOTE:
357366
remember to setup the stress_offset variable of the SCHA_Minimizer,
@@ -360,6 +369,7 @@ def vc_relax(self, target_press = 0, static_bulk_modulus = 100,
360369
stress tensor difference between a single very high-cutoff calculation and a
361370
single low-cutoff (the one you use), this difference will be added at the final
362371
stress tensor to get a better estimation of the true stress.
372+
363373
364374
Parameters
365375
----------
@@ -393,7 +403,8 @@ def vc_relax(self, target_press = 0, static_bulk_modulus = 100,
393403
does not support it by default)
394404
cell_relax_algorithm : string
395405
This identifies the stress algorithm. It can be both sd (steepest-descent),
396-
cg (conjugate-gradient) or bfgs (Quasi-newton)
406+
cg (conjugate-gradient) or bfgs (Quasi-newton).
407+
The most robust one is SD. Do not change if you are not sure what you are doing.
397408
fix_volume : bool, optional
398409
If true (default False) the volume is fixed, therefore only the cell shape is relaxed.
399410
@@ -558,7 +569,11 @@ def vc_relax(self, target_press = 0, static_bulk_modulus = 100,
558569
# print ""
559570

560571
# Perform the cell step
561-
cell_gradient = (stress_tensor - I *target_press_evA3)
572+
if self.fix_cell_shape:
573+
# Use a isotropic stress tensor to keep the same cell shape
574+
cell_gradient = I * (Press - target_press_evA3)
575+
else:
576+
cell_gradient = (stress_tensor - I *target_press_evA3)
562577

563578
new_uc = self.minim.dyn.structure.unit_cell.copy()
564579
BFGS.UpdateCell(new_uc, cell_gradient, fix_volume)

Modules/SchaMinimizer.py

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ def __init__(self, ensemble = None, root_representation = "normal",
160160

161161
self.minimizer = None#
162162

163+
self.max_diag_error_counter = __MAX_DIAG_ERROR_COUNTER__
164+
163165
# Projection. This is chosen to fix some constraint on the minimization
164166
self.projector_dyn = None
165167
self.projector_struct = None
@@ -190,6 +192,9 @@ def __init__(self, ensemble = None, root_representation = "normal",
190192
# If true use spglib to impose symmetries
191193
# NOTE: It is slower, but it enables using supercells
192194
self.use_spglib = False
195+
196+
# If True, enforce the symmetrization and the sum rule after each step
197+
self.enforce_sum_rule = False
193198

194199

195200
# Setup the statistical threshold
@@ -461,32 +466,41 @@ def minimization_step(self, custom_function_gradient = None):
461466
if self.minim_struct:
462467
self.dyn.structure.coords[:,:] = new_struct
463468

469+
# Check if we must enforce the symmetries and the sum rule:
470+
if self.enforce_sum_rule and (not self.neglect_symmetries):
471+
self.dyn.Symmetrize(use_spglib = self.use_spglib)
472+
473+
464474
# If we have imaginary frequencies, force the kl ratio to zero
465475
if self.check_imaginary_frequencies():
466476
print("Immaginary frequencies found! Redoing the step.")
467477
new_kl_ratio = 0
468478
is_diag_ok = False
469-
470-
471-
# Update the ensemble
472-
try:
473-
self.update()
474-
except np.linalg.LinAlgError as error:
475-
print("Diagonalization error:")
476-
print(error)
477-
print("Reducing the minimization step...")
478-
new_kl_ratio = 0 # Force step reduction
479-
is_diag_ok = False
480-
diag_error_counter += 1
481-
482-
if diag_error_counter >= __MAX_DIAG_ERROR_COUNTER__:
479+
diag_error_counter += 1
480+
else:
481+
# Update the ensemble
482+
try:
483+
self.update()
484+
except np.linalg.LinAlgError as error:
485+
print("Diagonalization error:")
486+
print(error)
487+
print("Reducing the minimization step...")
488+
new_kl_ratio = 0 # Force step reduction
489+
is_diag_ok = False
490+
diag_error_counter += 1
491+
492+
if diag_error_counter >= self.max_diag_error_counter:
483493
ERROR_MSG = """
484-
Error, exceeded the maximum number of diagonalization error.
485-
something is very wrong with the dynamical matrix.
494+
Error, exceeded the maximum number of diagonalization error. (or imaginary steps)
495+
496+
you can get rid of this error by increasing max_diag_error_counter variable.
497+
498+
Something is very wrong with the dynamical matrix.
486499
I'm saving the dynamical matrix as error_dyn,
487500
if you want to check it or restart the calculation from there.
488501
"""
489502
print(ERROR_MSG)
503+
sys.stdout.flush()
490504
self.dyn.save_qe("error_dyn")
491505
raise ValueError(ERROR_MSG)
492506

@@ -1227,11 +1241,14 @@ def check_imaginary_frequencies(self):
12271241
"""
12281242

12291243
# Get the frequencies
1230-
superdyn = self.dyn.GenerateSupercellDyn(self.ensemble.supercell)
1231-
w, pols = superdyn.DyagDinQ(0)
1244+
#superdyn = self.dyn.GenerateSupercellDyn(self.ensemble.supercell)
1245+
w, pols = self.dyn.DiagonalizeSupercell()#.DyagDinQ(0)
1246+
ss = self.dyn.structure.generate_supercell(self.dyn.GetSupercell())
12321247

12331248
# Get translations
1234-
trans_mask = ~CC.Methods.get_translations(pols, superdyn.structure.get_masses_array())
1249+
trans_mask = ~CC.Methods.get_translations(pols, ss.get_masses_array())
1250+
1251+
current_n_trans = np.sum((~trans_mask).astype(int))
12351252

12361253
# Remove translations
12371254
w = w[trans_mask]
@@ -1240,10 +1257,30 @@ def check_imaginary_frequencies(self):
12401257
# Frequencies are ordered, check if the first one is negative.
12411258
if w[0] < 0:
12421259
print ("Total frequencies (excluding translations):")
1243-
superdyn0 = self.ensemble.dyn_0.GenerateSupercellDyn(self.ensemble.supercell)
1244-
wold, pold = superdyn0.DyagDinQ(0)
1260+
#superdyn0 = self.ensemble.dyn_0.GenerateSupercellDyn(self.ensemble.supercell)
1261+
wold, pold = self.ensemble.dyn_0.DiagonalizeSupercell()# superdyn0.DyagDinQ(0)
1262+
1263+
ss0 = self.ensemble.dyn_0.structure.generate_supercell(self.dyn.GetSupercell())
12451264

1246-
trans_mask = ~CC.Methods.get_translations(pold, superdyn0.structure.get_masses_array())
1265+
trans_mask = ~CC.Methods.get_translations(pold, ss0.get_masses_array())
1266+
1267+
old_n_trans = np.sum((~trans_mask).astype(int))
1268+
1269+
if old_n_trans != current_n_trans:
1270+
ERR_MSG = """
1271+
Error, the number of translational modes before and after the step is different.
1272+
original translational modes: {}
1273+
new translational modes: {}
1274+
1275+
You can try to fix this error setting the {} variable of {} class to True.
1276+
""".format(old_n_trans, current_n_trans, "enforce_sum_rule", self.__class__.__name__)
1277+
print(ERR_MSG)
1278+
if not self.enforce_sum_rule:
1279+
raise ValueError(ERR_MSG)
1280+
else:
1281+
return True
1282+
1283+
12471284
wold = wold[trans_mask] * __RyToCm__
12481285
pold = pold[:, trans_mask]
12491286
total_mask = list(range(len(w)))

0 commit comments

Comments
 (0)