def initialize(self, paw): self.timer = paw.timer self.timer.start('Initialize TDDFT Hamiltonian') self.wfs = paw.wfs self.density = paw.density self.hamiltonian = paw.hamiltonian self.occupations = paw.occupations niter = paw.niter # Reset the density mixer # XXX: density mixer is not written to the gpw file # XXX: so we need to set it always self.density.set_mixer(DummyMixer()) self.update() # Initialize fxc self.initialize_fxc(niter) self.timer.stop('Initialize TDDFT Hamiltonian')
def __init__(self, filename, td_potential=None, propagator='SICN', calculate_energy=True, propagator_kwargs=None, solver='CSCG', tolerance=1e-8, **kwargs): """Create TDDFT-object. Parameters: filename: string File containing ground state or time-dependent state to propagate td_potential: class, optional Function class for the time-dependent potential. Must have a method 'strength(time)' which returns the strength of the linear potential to each direction as a vector of three floats. propagator: {'SICN','ETRSCN','ECN','SITE','SIKE4','SIKE5','SIKE6'} Name of the time propagator for the Kohn-Sham wavefunctions solver: {'CSCG','BiCGStab'} Name of the iterative linear equations solver for time propagation tolerance: float Tolerance for the linear solver The following parameters can be used: `txt`, `parallel`, `communicator` `mixer` and `dtype`. The internal parameters `mixer` and `dtype` are strictly used to specify a dummy mixer and complex type respectively. """ # Set initial time self.time = 0.0 # Set initial kick strength self.kick_strength = np.array([0.0, 0.0, 0.0], dtype=float) # Set initial value of iteration counter self.niter = 0 # Parallelization dictionary should default to strided bands self.default_parallel = GPAW.default_parallel.copy() self.default_parallel['stridebands'] = True self.default_parameters = GPAW.default_parameters.copy() self.default_parameters['mixer'] = DummyMixer() # NB: TDDFT restart files contain additional information which # will override the initial settings for time/kick/niter. GPAW.__init__(self, filename, **kwargs) assert isinstance(self.wfs, TimeDependentWaveFunctions) assert isinstance(self.wfs.overlap, TimeDependentOverlap) # Prepare for dipole moment file handle self.dm_file = None # Initialize wavefunctions and density # (necessary after restarting from file) if not self.initialized: self.initialize() self.set_positions() # Don't be too strict self.density.charge_eps = 1e-5 wfs = self.wfs self.rank = wfs.world.rank self.text = self.log self.text('') self.text('') self.text('------------------------------------------') self.text(' Time-propagation TDDFT ') self.text('------------------------------------------') self.text('') self.text('Charge epsilon: ', self.density.charge_eps) # Time-dependent variables and operators self.td_potential = td_potential self.td_hamiltonian = TimeDependentHamiltonian(self.wfs, self.spos_ac, self.hamiltonian, td_potential) self.td_overlap = self.wfs.overlap # TODO remove this property self.td_density = TimeDependentDensity(self) # Solver for linear equations self.text('Solver: ', solver) if solver == 'BiCGStab': self.solver = BiCGStab(gd=wfs.gd, timer=self.timer, tolerance=tolerance) elif solver == 'CSCG': self.solver = CSCG(gd=wfs.gd, timer=self.timer, tolerance=tolerance) else: raise RuntimeError('Solver %s not supported.' % solver) # Preconditioner # No preconditioner as none good found self.text('Preconditioner: ', 'None') self.preconditioner = None # TODO! check out SSOR preconditioning # self.preconditioner = InverseOverlapPreconditioner(self.overlap) # self.preconditioner = KineticEnergyPreconditioner( # wfs.gd, self.td_hamiltonian.hamiltonian.kin, np.complex) # Time propagator self.text('Propagator: ', propagator) if propagator_kwargs is None: propagator_kwargs = {} if propagator == 'ECN': self.propagator = ExplicitCrankNicolson( self.td_density, self.td_hamiltonian, self.td_overlap, self.solver, self.preconditioner, wfs.gd, self.timer, **propagator_kwargs) elif propagator == 'SICN': self.propagator = SemiImplicitCrankNicolson( self.td_density, self.td_hamiltonian, self.td_overlap, self.solver, self.preconditioner, wfs.gd, self.timer, **propagator_kwargs) elif propagator == 'EFSICN': self.propagator = EhrenfestPAWSICN(self.td_density, self.td_hamiltonian, self.td_overlap, self.solver, self.preconditioner, wfs.gd, self.timer, **propagator_kwargs) elif propagator == 'EFSICN_HGH': self.propagator = EhrenfestHGHSICN(self.td_density, self.td_hamiltonian, self.td_overlap, self.solver, self.preconditioner, wfs.gd, self.timer, **propagator_kwargs) elif propagator == 'ETRSCN': self.propagator = EnforcedTimeReversalSymmetryCrankNicolson( self.td_density, self.td_hamiltonian, self.td_overlap, self.solver, self.preconditioner, wfs.gd, self.timer, **propagator_kwargs) elif propagator == 'SITE': self.propagator = SemiImplicitTaylorExponential( self.td_density, self.td_hamiltonian, self.td_overlap, self.solver, self.preconditioner, wfs.gd, self.timer, **propagator_kwargs) elif propagator == 'SIKE': self.propagator = SemiImplicitKrylovExponential( self.td_density, self.td_hamiltonian, self.td_overlap, self.solver, self.preconditioner, wfs.gd, self.timer, **propagator_kwargs) elif propagator.startswith('SITE') or propagator.startswith('SIKE'): raise DeprecationWarning( 'Use propagator_kwargs to specify degree.') else: raise RuntimeError('Time propagator %s not supported.' % propagator) if self.rank == 0: if wfs.kd.comm.size > 1: if wfs.nspins == 2: self.text('Parallelization Over Spin') if wfs.gd.comm.size > 1: self.text('Using Domain Decomposition: %d x %d x %d' % tuple(wfs.gd.parsize_c)) if wfs.bd.comm.size > 1: self.text('Parallelization Over bands on %d Processors' % wfs.bd.comm.size) self.text('States per processor = ', wfs.bd.mynbands) self.hpsit = None self.eps_tmp = None self.mblas = MultiBlas(wfs.gd) # Restarting an FDTD run generates hamiltonian.fdtd_poisson, which # now overwrites hamiltonian.poisson if hasattr(self.hamiltonian, 'fdtd_poisson'): self.hamiltonian.poisson = self.hamiltonian.fdtd_poisson self.hamiltonian.poisson.set_grid_descriptor(self.density.finegd) # For electrodynamics mode if self.hamiltonian.poisson.get_description() == 'FDTD+TDDFT': self.initialize_FDTD() self.hamiltonian.poisson.print_messages(self.text) self.log.flush() self.calculate_energy = calculate_energy if self.hamiltonian.xc.name.startswith('GLLB'): self.text('GLLB model potential. Not updating energy.') self.calculate_energy = False
def initialize(self, reading=False): self.parameters.mixer = DummyMixer() self.parameters.experimental['reuse_wfs_method'] = None GPAW.initialize(self, reading=reading)
def tddft_init(self): if self.tddft_initialized: return self.blacs = self.wfs.ksl.using_blacs if self.blacs: self.ksl = ksl = self.wfs.ksl nao = ksl.nao nbands = ksl.bd.nbands mynbands = ksl.bd.mynbands blocksize = ksl.blocksize from gpaw.blacs import Redistributor if self.wfs.world.rank == 0: print('BLACS Parallelization') # Parallel grid descriptors grid = ksl.blockgrid assert grid.nprow * grid.npcol == self.wfs.ksl.block_comm.size # FOR DEBUG self.MM_descriptor = grid.new_descriptor(nao, nao, nao, nao) self.mm_block_descriptor = grid.new_descriptor( nao, nao, blocksize, blocksize) self.Cnm_block_descriptor = grid.new_descriptor( nbands, nao, blocksize, blocksize) # self.CnM_descriptor = ksl.blockgrid.new_descriptor(nbands, # nao, mynbands, nao) self.mM_column_descriptor = ksl.single_column_grid.new_descriptor( nao, nao, ksl.naoblocksize, nao) self.CnM_unique_descriptor = ksl.single_column_grid.new_descriptor( nbands, nao, mynbands, nao) # Redistributors self.mm2MM = Redistributor(ksl.block_comm, self.mm_block_descriptor, self.MM_descriptor) # XXX FOR DEBUG self.MM2mm = Redistributor(ksl.block_comm, self.MM_descriptor, self.mm_block_descriptor) # FOR DEBUG self.Cnm2nM = Redistributor(ksl.block_comm, self.Cnm_block_descriptor, self.CnM_unique_descriptor) self.CnM2nm = Redistributor(ksl.block_comm, self.CnM_unique_descriptor, self.Cnm_block_descriptor) self.mM2mm = Redistributor(ksl.block_comm, self.mM_column_descriptor, self.mm_block_descriptor) for kpt in self.wfs.kpt_u: scalapack_zero(self.mm_block_descriptor, kpt.S_MM, 'U') scalapack_zero(self.mm_block_descriptor, kpt.T_MM, 'U') # XXX to propagator class if self.propagator == 'taylor' and self.blacs: # cholS_mm = self.mm_block_descriptor.empty(dtype=complex) for kpt in self.wfs.kpt_u: kpt.invS_MM = kpt.S_MM.copy() scalapack_inverse(self.mm_block_descriptor, kpt.invS_MM, 'L') if self.propagator == 'taylor' and not self.blacs: tmp = inv(self.wfs.kpt_u[0].S_MM) self.wfs.kpt_u[0].invS = tmp # Reset the density mixer self.density.set_mixer(DummyMixer()) self.tddft_initialized = True for k, kpt in enumerate(self.wfs.kpt_u): kpt.C2_nM = kpt.C_nM.copy()
def tddft_init(self): if not self.tddft_initialized: if world.rank == 0: print('Initializing real time LCAO TD-DFT calculation.') print('XXX Warning: Array use not optimal for memory.') print('XXX Taylor propagator probably doesn\'t work') print('XXX ...and no arrays are listed in memory estimate yet.') self.blacs = self.wfs.ksl.using_blacs if self.blacs: self.ksl = ksl = self.wfs.ksl nao = ksl.nao nbands = ksl.bd.nbands mynbands = ksl.bd.mynbands blocksize = ksl.blocksize from gpaw.blacs import Redistributor if world.rank == 0: print('BLACS Parallelization') # Parallel grid descriptors self.MM_descriptor = ksl.blockgrid.new_descriptor(nao, nao, nao, nao) # FOR DEBUG self.mm_block_descriptor = ksl.blockgrid.new_descriptor(nao, nao, blocksize, blocksize) self.Cnm_block_descriptor = ksl.blockgrid.new_descriptor(nbands, nao, blocksize, blocksize) #self.CnM_descriptor = ksl.blockgrid.new_descriptor(nbands, nao, mynbands, nao) self.mM_column_descriptor = ksl.single_column_grid.new_descriptor(nao, nao, ksl.naoblocksize, nao) self.CnM_unique_descriptor = ksl.single_column_grid.new_descriptor(nbands, nao, mynbands, nao) # Redistributors self.mm2MM = Redistributor(ksl.block_comm, self.mm_block_descriptor, self.MM_descriptor) # XXX FOR DEBUG self.MM2mm = Redistributor(ksl.block_comm, self.MM_descriptor, self.mm_block_descriptor) # XXX FOR DEBUG self.Cnm2nM = Redistributor(ksl.block_comm, self.Cnm_block_descriptor, self.CnM_unique_descriptor) self.CnM2nm = Redistributor(ksl.block_comm, self.CnM_unique_descriptor, self.Cnm_block_descriptor) self.mM2mm = Redistributor(ksl.block_comm, self.mM_column_descriptor, self.mm_block_descriptor) for kpt in self.wfs.kpt_u: scalapack_zero(self.mm_block_descriptor, kpt.S_MM,'U') scalapack_zero(self.mm_block_descriptor, kpt.T_MM,'U') # XXX to propagator class if self.propagator == 'taylor' and self.blacs: # cholS_mm = self.mm_block_descriptor.empty(dtype=complex) for kpt in self.wfs.kpt_u: kpt.invS_MM = kpt.S_MM.copy() scalapack_inverse(self.mm_block_descriptor, kpt.invS_MM, 'L') if self.propagator_debug: if world.rank == 0: print('XXX Doing serial inversion of overlap matrix.') self.timer.start('Invert overlap (serial)') invS2_MM = self.MM_descriptor.empty(dtype=complex) for kpt in self.wfs.kpt_u: #kpt.S_MM[:] = 128.0*(2**world.rank) self.mm2MM.redistribute(self.wfs.S_qMM[kpt.q], invS2_MM) world.barrier() if world.rank == 0: tri2full(invS2_MM,'L') invS2_MM[:] = inv(invS2_MM.copy()) self.invS2_MM = invS2_MM kpt.invS2_MM = ksl.mmdescriptor.empty(dtype=complex) self.MM2mm.redistribute(invS2_MM, kpt.invS2_MM) verify(kpt.invS_MM, kpt.invS2_MM, 'overlap par. vs. serial', 'L') self.timer.stop('Invert overlap (serial)') if world.rank == 0: print('XXX Overlap inverted.') if self.propagator == 'taylor' and not self.blacs: tmp = inv(self.wfs.kpt_u[0].S_MM) self.wfs.kpt_u[0].invS = tmp # Reset the density mixer self.density.mixer = DummyMixer() self.tddft_initialized = True for k, kpt in enumerate(self.wfs.kpt_u): kpt.C2_nM = kpt.C_nM.copy()
def initialize(self, reading=False): self.parameters.mixer = DummyMixer() GPAW.initialize(self, reading=reading)