Skip to content

Commit 57e8789

Browse files
Merge branch 'fast_parallel_gradient' into timer
2 parents 3ea713a + eabce87 commit 57e8789

4 files changed

Lines changed: 69 additions & 6 deletions

File tree

Modules/Ensemble.py

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1895,6 +1895,50 @@ def get_fc_from_self_consistency(self, subtract_sscha = False, return_error = Fa
18951895

18961896
return new_phi
18971897

1898+
def get_preconditioned_gradient_parallel(self, *args, **kwargs):
1899+
"""
1900+
Compute the gradient using multiprocessing.
1901+
For documentation, see get_preconditioned_gradient
1902+
"""
1903+
1904+
print("force length:", len(self.force_computed))
1905+
1906+
def work_function(argument):
1907+
print("force length [inside]:", len(self.force_computed))
1908+
ensemble_start_config, ensemble_end_config = argument
1909+
mask = np.zeros(self.N, dtype = bool)
1910+
mask[ensemble_start_config : ensemble_end_config] = True
1911+
print("mask length:", np.sum(mask.astype(int))," total N:", len(mask))
1912+
new_ensemble = self.split(mask)
1913+
1914+
gradient, _ = new_ensemble.get_preconditioned_gradient(*args, **kwargs)
1915+
1916+
av_ensemble = np.sum(new_ensemble.rho)
1917+
1918+
return gradient * av_ensemble
1919+
1920+
nproc = CC.Settings.GetNProc()
1921+
list_of_inputs = []
1922+
index = 0
1923+
for i in range(nproc):
1924+
start_config = index
1925+
index += self.N // nproc
1926+
if i < self.N % nproc:
1927+
index += 1
1928+
end_config = index
1929+
1930+
list_of_inputs.append( (start_config, end_config) )
1931+
1932+
gradient = CC.Settings.GoParallel(work_function, list_of_inputs, "+")
1933+
gradient /= np.sum(self.rho)
1934+
1935+
return gradient, np.zeros_like(gradient) + 1
1936+
1937+
1938+
1939+
1940+
1941+
18981942
def get_preconditioned_gradient(self, subtract_sscha = True, return_error = False,
18991943
use_ups_supercell = True, preconditioned = 1,
19001944
fast_grad = False, verbose = True, timer=None):
@@ -1910,7 +1954,7 @@ def get_preconditioned_gradient(self, subtract_sscha = True, return_error = Fals
19101954
19111955
.. math::
19121956
1913-
\\Phi_{ab} = \\sum_c \\upsilon_{ac} \\left< u_c f_a\\right>_{\\Phi}
1957+
\\Phi_{ab} = \\sum_c \\Upsilon_{ac} \\left< u_c f_a\\right>_{\\Phi}
19141958
19151959
The previous equation is true only if the :math:`\\Phi` matrix is the solution
19161960
of the SCHA theory. Here :math:`\\vec u` are the displacements of the configurations
@@ -3109,9 +3153,12 @@ def compute_ensemble(self, calculator, compute_stress = True, stress_numerical =
31093153
else:
31103154
computing_ensemble.get_energy_forces(calculator, compute_stress, stress_numerical, verbose = verbose)
31113155

3156+
print("CE BEFORE MERGE:", len(self.force_computed))
3157+
31123158
if should_i_merge:
31133159
# Remove the noncomputed ensemble from here, and merge
31143160
self.merge(computing_ensemble)
3161+
print("CE AFTER MERGE:", len(self.force_computed))
31153162

31163163
print('ENSEMBLE ALL PROPERTIES:', self.all_properties)
31173164

@@ -3177,6 +3224,11 @@ def split(self, split_mask):
31773224
N = np.sum(split_mask.astype(int))
31783225
ens = Ensemble(self.dyn_0, self.T0, self.dyn_0.GetSupercell())
31793226
ens.init_from_structures(structs)
3227+
print("Split length:", len(split_mask))
3228+
print("original force legnth:", len(self.force_computed))
3229+
print("Expected length:", len(ens.force_computed))
3230+
print("Splitting force length:", len(self.force_computed[split_mask]))
3231+
31803232
ens.force_computed[:] = self.force_computed[split_mask]
31813233
ens.stress_computed[:] = self.stress_computed[split_mask]
31823234
ens.energies[:] = self.energies[split_mask]
@@ -3199,7 +3251,7 @@ def remove_noncomputed(self):
31993251
It may be used to run a minimization even if the ensemble was not completely calculated.
32003252
"""
32013253

3202-
good_mask = self.force_computed
3254+
good_mask = np.copy(self.force_computed)
32033255
if self.has_stress:
32043256
good_mask = good_mask & self.stress_computed
32053257

@@ -3211,6 +3263,8 @@ def remove_noncomputed(self):
32113263
self.sscha_energies = self.sscha_energies[good_mask]
32123264
self.xats = self.xats[good_mask, :, :]
32133265
self.u_disps = self.u_disps[good_mask, :]
3266+
self.force_computed = self.force_computed[good_mask]
3267+
self.stress_computed = self.stress_computed[good_mask]
32143268

32153269
self.structures = [self.structures[x] for x in np.arange(len(good_mask))[good_mask]]
32163270
self.all_properties = [self.all_properties[x] for x in np.arange(len(good_mask))[good_mask]]
@@ -3263,6 +3317,7 @@ def get_energy_forces(self, ase_calculator, compute_stress = True, stress_numeri
32633317

32643318
# Setup the calculator for each structure
32653319
parallel = False
3320+
print("Force computed shape:", len(self.force_computed))
32663321
if __MPI__:
32673322
comm = MPI.COMM_WORLD
32683323
size = comm.Get_size()
@@ -3419,6 +3474,7 @@ def get_energy_forces(self, ase_calculator, compute_stress = True, stress_numeri
34193474
# Reshape the arrays
34203475
self.forces[:, :, :] = np.reshape(total_forces, (N_rand, self.current_dyn.structure.N_atoms*np.prod(self.supercell), 3), order = "C")
34213476
self.force_computed[:] = True
3477+
print("Force computed shape:", len(self.force_computed))
34223478

34233479
if compute_stress:
34243480
self.stresses[:,:,:] = np.reshape(total_stress, (N_rand, 3, 3), order = "C")

Modules/Relax.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,15 +576,20 @@ def vc_relax(self, target_press = 0, static_bulk_modulus = 100,
576576
cluster = self.cluster)
577577
#self.minim.ensemble.get_energy_forces(self.calc, True, stress_numerical = stress_numerical)
578578

579+
print("RELAX force length:", len(self.minim.ensemble.force_computed))
580+
579581
if ensemble_loc is not None and self.save_ensemble:
580582
self.minim.ensemble.save_bin(ensemble_loc, pop)
583+
print("RELAX force length:", len(self.minim.ensemble.force_computed))
581584

582585
self.minim.population = pop
583586
self.minim.init(delete_previous_data = False)
584587

588+
print("RELAX force length:", len(self.minim.ensemble.force_computed))
585589
self.minim.run(custom_function_pre = self.__cfpre__,
586590
custom_function_post = self.__cfpost__,
587591
custom_function_gradient = self.__cfg__)
592+
588593

589594

590595
self.minim.finalize()

Modules/SchaMinimizer.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ def minimization_step(self, custom_function_gradient = None, timer=None):
313313
It takes as input the two gradient (the dynamical matrix one and the structure one), and
314314
modifies them (or does some I/O on it).
315315
"""
316+
print("Minimization step, force computed:", len(self.ensemble.force_computed))
316317

317318
# Setup the symmetries
318319
t1 = time.time()
@@ -337,14 +338,14 @@ def minimization_step(self, custom_function_gradient = None, timer=None):
337338
if self.minim_dyn:
338339
if self.precond_dyn:
339340
if timer is not None:
340-
dyn_grad, err = timer.execute_timed_function(self.ensemble.get_preconditioned_gradient, True, True, preconditioned=1)
341+
dyn_grad, err = timer.execute_timed_function(self.ensemble.get_preconditioned_gradient_parallel, True, True, preconditioned=1)
341342
else:
342-
dyn_grad, err = self.ensemble.get_preconditioned_gradient(True, True, preconditioned=1)
343+
dyn_grad, err = self.ensemble.get_preconditioned_gradient_parallel(True, True, preconditioned=1)
343344
else:
344345
if timer is not None:
345-
dyn_grad, err = timer.execute_timed_function(self.ensemble.get_preconditioned_gradient, True, True, preconditioned=0)
346+
dyn_grad, err = timer.execute_timed_function(self.ensemble.get_preconditioned_gradient_parallel, True, True, preconditioned=0)
346347
else:
347-
dyn_grad, err = self.ensemble.get_preconditioned_gradient(True, True, preconditioned=0)
348+
dyn_grad, err = self.ensemble.get_preconditioned_gradient_parallel(True, True, preconditioned=0)
348349
else:
349350
dyn_grad = np.zeros( (len(self.dyn.q_tot), 3 * self.dyn.structure.N_atoms, 3 * self.dyn.structure.N_atoms), dtype = np.complex128)
350351
err = np.zeros_like(dyn_grad)

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
mpi_compile_args = []
1010
mpi_link_args = []
1111

12+
1213
# If true, do not check for parallel
1314
avoid_parallel_test = True
1415

0 commit comments

Comments
 (0)