/gpaw/new/rttddft.py

https://gitlab.com/5rXUTAIYJSBcdxFmjqpuwaPo71b283/gpaw · Python · 138 lines · 92 code · 31 blank · 15 comment · 6 complexity · 531958614cacef6d8f0be73bd0b161b0 MD5 · raw file

  1. from __future__ import annotations
  2. from typing import Generator, NamedTuple
  3. import numpy as np
  4. from numpy.linalg import solve
  5. from gpaw.typing import Vector
  6. from gpaw.new.ase_interface import ASECalculator
  7. from gpaw.new.calculation import DFTState, DFTCalculation
  8. from gpaw.new.pot_calc import PotentialCalculator
  9. from gpaw.tddft.units import asetime_to_autime, autime_to_asetime, au_to_eA
  10. class TDAlgorithm:
  11. def propagate(self,
  12. time_step: float,
  13. state: DFTState,
  14. pot_calc: PotentialCalculator,
  15. hamiltonian):
  16. raise NotImplementedError()
  17. def get_description(self):
  18. return '%s' % self.__class__.__name__
  19. def propagate_wave_functions_numpy(source_C_nM: np.ndarray,
  20. target_C_nM: np.ndarray,
  21. S_MM: np.ndarray,
  22. H_MM: np.ndarray,
  23. dt: float):
  24. SjH_MM = S_MM + (0.5j * dt) * H_MM
  25. target_C_nM[:] = source_C_nM @ SjH_MM.conj().T
  26. target_C_nM[:] = solve(SjH_MM.T, target_C_nM.T).T
  27. class ECNAlgorithm(TDAlgorithm):
  28. def propagate(self,
  29. time_step: float,
  30. state: DFTState,
  31. pot_calc: PotentialCalculator,
  32. hamiltonian):
  33. matrix_calculator = hamiltonian.create_hamiltonian_matrix_calculator(
  34. state)
  35. for wfs in state.ibzwfs:
  36. H_MM = matrix_calculator.calculate_hamiltonian_matrix(wfs)
  37. # Phi_n <- U[H(t)] Phi_n
  38. propagate_wave_functions_numpy(wfs.C_nM.data, wfs.C_nM.data,
  39. wfs.S_MM,
  40. H_MM, time_step)
  41. # Update density
  42. state.density.update(pot_calc.nct_R, state.ibzwfs)
  43. # Calculate Hamiltonian H(t+dt) = H[n[Phi_n]]
  44. state.potential, state.vHt_x, _ = pot_calc.calculate(
  45. state.density, state.vHt_x)
  46. class RTTDDFTResult(NamedTuple):
  47. """ Results are stored in atomic units, but displayed to the user in
  48. ASE units
  49. """
  50. time: float # Time in atomic units
  51. dipolemoment: Vector # Dipole moment in atomic units
  52. def __repr__(self):
  53. timestr = f'{self.time*autime_to_asetime:.3f} Å√(u/eV)'
  54. dmstr = ', '.join([f'{dm*au_to_eA:.3f}' for dm in self.dipolemoment])
  55. dmstr = f'[{dmstr}]'
  56. return (f'{self.__class__.__name__}: '
  57. f'(time: {timestr}, dipolemoment: {dmstr} eÅ)')
  58. class RTTDDFT:
  59. def __init__(self,
  60. state: DFTState,
  61. pot_calc: PotentialCalculator,
  62. hamiltonian,
  63. propagator: TDAlgorithm | None = None):
  64. self.time = 0.0
  65. if propagator is None:
  66. propagator = ECNAlgorithm()
  67. self.state = state
  68. self.pot_calc = pot_calc
  69. self.propagator = propagator
  70. self.hamiltonian = hamiltonian
  71. @classmethod
  72. def from_dft_calculation(cls,
  73. calc: ASECalculator | DFTCalculation,
  74. propagator: TDAlgorithm | None = None):
  75. if isinstance(calc, DFTCalculation):
  76. calculation = calc
  77. else:
  78. assert calc.calculation is not None
  79. calculation = calc.calculation
  80. state = calculation.state
  81. pot_calc = calculation.pot_calc
  82. hamiltonian = calculation.scf_loop.hamiltonian
  83. return cls(state, pot_calc, hamiltonian, propagator=propagator)
  84. def ipropagate(self,
  85. time_step: float = 10.0,
  86. maxiter: int = 2000,
  87. ) -> Generator[RTTDDFTResult, None, None]:
  88. """Propagate the electronic system.
  89. Parameters
  90. ----------
  91. time_step
  92. Time step in ASE time units Å(u/eV)
  93. iterations
  94. Number of propagation steps
  95. """
  96. time_step = time_step * asetime_to_autime
  97. for iteration in range(maxiter):
  98. self.propagator.propagate(time_step,
  99. state=self.state,
  100. pot_calc=self.pot_calc,
  101. hamiltonian=self.hamiltonian)
  102. time = self.time + time_step
  103. self.time = time
  104. dipolemoment = self.state.density.calculate_dipole_moment()
  105. result = RTTDDFTResult(time=time, dipolemoment=dipolemoment)
  106. yield result