2424It is possible to use it to perform the anharmonic minimization
2525"""
2626
27+ from inspect import signature
28+
2729#import Ensemble
2830import numpy as np
2931import difflib
@@ -415,16 +417,19 @@ def minimization_step(self, custom_function_gradient = None):
415417 struct_grad , struct_grad_err = self .ensemble .get_average_forces (True )
416418 #print "SHAPE:", np.shape(struct_grad)
417419 struct_grad_reshaped = - struct_grad .reshape ( (3 * self .dyn .structure .N_atoms ))
418- t2 = time .time ()
419-
420- print ("Time elapsed to compute the structure gradient:" , t2 - t1 , "s" )
421420
422421
423422 # Preconditionate the gradient for the wyckoff minimization
424423 if self .precond_wyck :
425- struct_precond = GetStructPrecond (self .ensemble .current_dyn , ignore_small_w = self .ensemble .ignore_small_w )
424+ w_pols = None
425+ if len (self .dyn .q_tot ) == 1 :
426+ w_pols = (self .ensemble .current_w , self .ensemble .current_pols )
427+ struct_precond = GetStructPrecond (self .ensemble .current_dyn , ignore_small_w = self .ensemble .ignore_small_w , w_pols = w_pols )
426428 struct_grad_precond = struct_precond .dot (struct_grad_reshaped )
427429 struct_grad = struct_grad_precond .reshape ( (self .dyn .structure .N_atoms , 3 ))
430+ t2 = time .time ()
431+
432+ print ("Time elapsed to compute the structure gradient:" , t2 - t1 , "s" )
428433
429434
430435 # Apply the symmetries to the forces
@@ -448,7 +453,35 @@ def minimization_step(self, custom_function_gradient = None):
448453
449454 # Perform the gradient restriction
450455 if custom_function_gradient is not None :
451- custom_function_gradient (dyn_grad , struct_grad )
456+
457+ # Check the number of parameters
458+ try :
459+ sig = signature (custom_function_gradient ).parameters
460+ except Exception as e :
461+ print (e )
462+
463+ MSG = '''
464+ While inspecting the custom_function_gradient an error was rised.
465+ Maybe you did not pass the minimizer a valid function?
466+ '''
467+ raise ValueError (MSG )
468+
469+
470+ if len (sig ) not in [2 ,3 ]:
471+ MSG = '''
472+ Error, the custom_function_gradient must have either 2 or 3 arguments:
473+ - dynamical_matrix_gradient
474+ - structure gradient
475+ - [Optional] The minimizer (self) object
476+
477+ The function you provided accepts {} arguments instead.
478+ ''' .format (len (sig ))
479+ raise ValueError (MSG )
480+
481+ if len (sig ) == 3 :
482+ custom_function_gradient (dyn_grad , struct_grad , self )
483+ else :
484+ custom_function_gradient (dyn_grad , struct_grad )
452485
453486
454487 # Append the gradient modulus to the minimization info
@@ -500,22 +533,23 @@ def minimization_step(self, custom_function_gradient = None):
500533
501534
502535 # If we have imaginary frequencies, force the kl ratio to zero
536+
537+ # Update the ensemble
538+ try :
539+ self .update ()
540+ except np .linalg .LinAlgError as error :
541+ print ("Diagonalization error:" )
542+ print (error )
543+ print ("Reducing the minimization step..." )
544+ new_kl_ratio = 0 # Force step reduction
545+ is_diag_ok = False
546+ diag_error_counter += 1
547+
503548 if self .check_imaginary_frequencies ():
504549 print ("Immaginary frequencies found! Redoing the step." )
505550 new_kl_ratio = 0
506551 is_diag_ok = False
507552 imag_freq_counter += 1
508- else :
509- # Update the ensemble
510- try :
511- self .update ()
512- except np .linalg .LinAlgError as error :
513- print ("Diagonalization error:" )
514- print (error )
515- print ("Reducing the minimization step..." )
516- new_kl_ratio = 0 # Force step reduction
517- is_diag_ok = False
518- diag_error_counter += 1
519553
520554 if diag_error_counter >= self .max_diag_error_counter :
521555 ERROR_MSG = """
@@ -1134,7 +1168,7 @@ def run(self, verbose = 1, custom_function_pre = None, custom_function_post = No
11341168 self .__fe__ .append (np .real (fe ))
11351169 self .__fe_err__ .append (np .real (err ))
11361170
1137- harm_fe = self .dyn .GetHarmonicFreeEnergy (self .ensemble .current_T ) / np .prod (self .ensemble .supercell )
1171+ harm_fe = self .dyn .GetHarmonicFreeEnergy (self .ensemble .current_T , w_pols = ( self . ensemble . current_w , self . ensemble . current_pols ) ) / np .prod (self .ensemble .supercell )
11381172 anharm_fe = np .real (fe - harm_fe )
11391173
11401174 # Compute the KL ratio
@@ -1295,26 +1329,35 @@ def finalize(self, verbose = 1):
12951329 self .dyn .structure .coords [i ,2 ]))
12961330 print ()
12971331 print (" ==== FINAL FREQUENCIES [cm-1] ==== " )
1298- super_dyn = self .dyn .GenerateSupercellDyn (self .ensemble .supercell )
1299- w , pols = super_dyn .DyagDinQ (0 )
1300- trans = CC .Methods .get_translations (pols , super_dyn .structure .get_masses_array ())
1332+ #super_dyn = self.dyn.GenerateSupercellDyn(self.ensemble.supercell)
1333+ super_struct = self .dyn .structure .generate_supercell (self .dyn .GetSupercell ())
1334+ w = self .ensemble .current_w .copy ()
1335+ pols = self .ensemble .current_pols .copy ()
1336+
1337+ #w, pols = super_dyn.DyagDinQ(0)
1338+ trans = CC .Methods .get_translations (pols , super_struct .get_masses_array ())
13011339
13021340 for i in range (len (w )):
13031341 print ("Mode %5d: freq %16.8f cm-1 | is translation? " % (i + 1 , w [i ] * __RyToCm__ ), trans [i ])
13041342
13051343 print ()
13061344
13071345
1308-
13091346 def check_imaginary_frequencies (self ):
13101347 """
13111348 The following subroutine check if the current matrix has imaginary frequency. In this case
13121349 the minimization is stopped.
13131350 """
13141351
1352+ # Avoid the check if the dynamical matrix has been computed.
1353+ if not self .minim_dyn :
1354+ return False
1355+
13151356 # Get the frequencies
13161357 #superdyn = self.dyn.GenerateSupercellDyn(self.ensemble.supercell)
1317- w , pols = self .dyn .DiagonalizeSupercell ()#.DyagDinQ(0)
1358+ w = self .ensemble .current_w .copy ()
1359+ pols = self .ensemble .current_pols .copy ()
1360+ #w, pols = self.dyn.DiagonalizeSupercell()#.DyagDinQ(0)
13181361 ss = self .dyn .structure .generate_supercell (self .dyn .GetSupercell ())
13191362
13201363 # Get translations
@@ -1333,7 +1376,9 @@ def check_imaginary_frequencies(self):
13331376 if w [0 ] < 0 :
13341377 print ("Total frequencies (excluding translations):" )
13351378 #superdyn0 = self.ensemble.dyn_0.GenerateSupercellDyn(self.ensemble.supercell)
1336- wold , pold = self .ensemble .dyn_0 .DiagonalizeSupercell ()# superdyn0.DyagDinQ(0)
1379+ wold = self .ensemble .w_0 .copy ()
1380+ pold = self .ensemble .pols_0 .copy ()
1381+ #wold, pold = self.ensemble.dyn_0.DiagonalizeSupercell()# superdyn0.DyagDinQ(0)
13371382
13381383 ss0 = self .ensemble .dyn_0 .structure .generate_supercell (self .dyn .GetSupercell ())
13391384
@@ -1824,7 +1869,7 @@ def ApplyFCPrecond(current_dyn, matrix, T = 0):
18241869
18251870
18261871
1827- def GetStructPrecond (current_dyn , ignore_small_w = False ):
1872+ def GetStructPrecond (current_dyn , ignore_small_w = False , w_pols = None ):
18281873 r"""
18291874 GET THE PRECONDITIONER FOR THE STRUCTURE MINIMIZATION
18301875 =====================================================
@@ -1845,6 +1890,8 @@ def GetStructPrecond(current_dyn, ignore_small_w = False):
18451890 ----------
18461891 current_dyn : Phonons()
18471892 The current dynamical matrix
1893+ w_pols :
1894+ If given, do not diagonalize the gradient
18481895
18491896 Returns
18501897 -------
@@ -1854,7 +1901,11 @@ def GetStructPrecond(current_dyn, ignore_small_w = False):
18541901 """
18551902
18561903 # Dyagonalize the current dynamical matrix
1857- w , pols = current_dyn .DyagDinQ (0 )
1904+ if w_pols :
1905+ w = w_pols [0 ].copy ()
1906+ pols = w_pols [1 ].copy ()
1907+ else :
1908+ w , pols = current_dyn .DyagDinQ (0 )
18581909
18591910 # Get some usefull array
18601911 mass = current_dyn .structure .get_masses_array ()
0 commit comments