Skip to content

Commit 2f152e6

Browse files
Merge branch 'master' into memopt-get-odd-straight
2 parents da045e2 + aa725e6 commit 2f152e6

17 files changed

Lines changed: 548 additions & 99 deletions

File tree

.github/workflows/build.yml

Lines changed: 0 additions & 37 deletions
This file was deleted.

.github/workflows/python-testsuite.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020

2121
services:
2222
rabbitmq:
23-
image: rabbitmq:latest
23+
image: rabbitmq:3.12-management
2424
ports:
2525
- 5672:5672
2626

Modules/Cluster.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,30 @@ def __setattr__(self, name, value):
333333
super(Cluster, self).__setattr__(name, value)
334334

335335

336+
def __getstate__(self):
337+
"""
338+
Return the picklable state of the cluster.
339+
340+
The thread lock created by compute_ensemble_batch cannot be pickled,
341+
so it is dropped here. This allows sscha.Utilities.save_binary to
342+
store objects holding a cluster after a calculation has run.
343+
"""
344+
state = self.__dict__.copy()
345+
state["lock"] = None
346+
return state
347+
348+
349+
def __setstate__(self, state):
350+
"""
351+
Restore the cluster from a pickled state.
352+
353+
The thread lock is transient runtime state and is reset to None,
354+
as after __init__; compute_ensemble_batch recreates it when needed.
355+
"""
356+
state["lock"] = None
357+
self.__dict__.update(state)
358+
359+
336360

337361
def copy_file(self, source, destination, server_source = False, server_dest = True, raise_error=False, **kwargs):
338362
"""

Modules/Ensemble.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4230,7 +4230,57 @@ def w_to_a(self,w, T):
42304230
a[:] = np.sqrt((1.0 / np.tanh(0.5 * w * 315774.65221921849 / T)) / (2.0 * w))
42314231
return a
42324232

4233+
4234+
4235+
4236+
# ------------------------------------------------------------------------------
4237+
def load_ensemble_bin(directory, population, temperature, nqirr=-1):
4238+
"""
4239+
Load the ensemble from the given directory. This subroutine automatically initializes the ensemble
4240+
and avoids the hursle of having to define and initialize a dynamical matrix before loading the ensemble.
4241+
4242+
4243+
Parameters
4244+
----------
4245+
- directory : string
4246+
Path to the directory where the ensemble is located
4247+
- population : Int
4248+
The index of the ensemble
4249+
- temperature : Float
4250+
The temperature for the ensemble
4251+
- nqirr : Int
4252+
The number of irreducible points of the dynamical matrix.
4253+
If not provided (or negative), it is inferred from the files.
4254+
4255+
Returns
4256+
-------
4257+
- ensemble : Ensemble()
4258+
The Ensemble object.
4259+
"""
4260+
4261+
# Get the generated dyn
4262+
generated_name = os.path.join(directory, "dyn_gen_pop%d_" % population)
4263+
4264+
# Infer the nqirr if not provided
4265+
if nqirr < 0:
4266+
nqirr = len([x for x in os.listdir(directory) if x.startswith("dyn_gen_pop%d_" % population)])
4267+
if os.path.exists(generated_name + "0"):
4268+
nqirr -= 1
4269+
4270+
# Load the dynamical matrix
4271+
dyn = CC.Phonons.Phonons(generated_name, nqirr)
4272+
4273+
# Check if nqirr was correct
4274+
assert np.prod(dyn.GetSupercell()) == len(dyn.dynmats), "Error, the value of nqirr = {} is wrong. Check wether you specified the correct value.".format(nqirr)
4275+
4276+
ensemble = Ensemble(dyn, temperature)
4277+
ensemble.load_bin(directory, population)
4278+
4279+
return ensemble
4280+
4281+
42334282
#-------------------------------------------------------------------------------
4283+
42344284
def _wrapper_julia_get_upsilon_q(*args, **kwargs):
42354285
"""Worker function, just for testing"""
42364286
return julia.Main.get_upsilon_fourier(*args, **kwargs)

Modules/Minimizer.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,9 @@ def run_step(self, gradient, kl_new):
224224
# Enlarge the step
225225
if not self.fixed_step:
226226
self.step *= self.increment_step
227+
228+
# Perform the minimization step for new direction
229+
self.current_x = self.old_x - self.step * self.direction
227230
else:
228231
# Proceed with the line minimization
229232

@@ -243,14 +246,16 @@ def run_step(self, gradient, kl_new):
243246
print("Step too large (scalar = {} | kl_ratio = {}), reducing to {}".format(scalar, kl_ratio, self.step))
244247
#print("Direction: ", self.direction)
245248
#print("Gradient: ", gradient)
249+
250+
# Try again with reduced step
251+
self.current_x = self.old_x - self.step * self.direction
246252
else:
247253
# The step is good, therefore next step perform a new direction
248254
self.new_direction = True
249255
if self.verbose:
250256
print("Good step found with {}, try increment".format(self.step))
251-
252-
# Perform the minimiziation step
253-
self.current_x = self.old_x - self.step * self.direction
257+
# DO NOT update current_x - we accept the current position
258+
# (current_x was already updated in the previous step)
254259

255260

256261
def update_dyn(self, new_kl_ratio, dyn_gradient, structure_gradient = None):

Modules/SchaMinimizer.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ def minimization_step(self, custom_function_gradient = None, timer=None):
634634

635635
# Update the structure
636636
if self.minim_struct:
637-
self.dyn.structure.coords[:,:] = new_struct
637+
self.dyn.structure.coords[:,:] = np.real(new_struct)
638638

639639
# Check if we must enforce the symmetries and the sum rule:
640640
if self.enforce_sum_rule and (not self.neglect_symmetries):
@@ -643,6 +643,11 @@ def minimization_step(self, custom_function_gradient = None, timer=None):
643643
else:
644644
self.dyn.Symmetrize(use_spglib = self.use_spglib)
645645

646+
# Enforce the dynamical matrix to be real at q = -q + G (time-reversal symmetry)
647+
bg = self.dyn.structure.get_reciprocal_vectors() / (2 * np.pi)
648+
for iq, q in enumerate(self.dyn.q_tot):
649+
if CC.Methods.get_min_dist_into_cell(bg, q, -q) < 1e-6:
650+
self.dyn.dynmats[iq] = np.real(self.dyn.dynmats[iq])
646651

647652
# If we have imaginary frequencies, force the kl ratio to zero
648653

@@ -964,11 +969,11 @@ def print_info(self):
964969
print (" supercell size = ", " ".join([str(x) for x in self.ensemble.supercell]))
965970

966971
# Get the current frequencies
967-
w, pols = self.dyn.GenerateSupercellDyn(self.ensemble.supercell).DyagDinQ(0)
972+
w, pols = self.dyn.DiagonalizeSupercell()#self.dyn.GenerateSupercellDyn(self.ensemble.supercell).DyagDinQ(0)
968973
w *= __RyToCm__
969974

970975
# Get the starting frequencies
971-
w0, p0 = self.ensemble.dyn_0.GenerateSupercellDyn(self.ensemble.supercell).DyagDinQ(0)
976+
w0, p0 = self.ensemble.dyn_0.DiagonalizeSupercell()
972977
w0 *= __RyToCm__
973978

974979
print ()

Modules/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
"""
66

77

8-
__all__ = ["Ensemble", "SchaMinimizer"]
8+
__all__ = ["Ensemble", "SchaMinimizer", "cli"]

0 commit comments

Comments
 (0)