def from_files(cls, fns, agspec='fine'): ''' Construct a ProAtomDB from a series of HORTON checkpoint files. **Arguments:** fns_chk A list of atomic output files. **Optional arguments:** agspec A specifications of the atomic grid. This can either be an instance of the AtomicGridSpec object, or the first argument of its constructor. ''' if not isinstance(agspec, AtomicGridSpec): agspec = AtomicGridSpec(agspec) records = [] for fn in fns: # Load atomic data with timer.section('Load proatom'): mol = IOData.from_file(fn) with timer.section('Proatom grid'): records.append(ProAtomRecord.from_iodata(mol, agspec)) return cls(records)
def from_files(cls, fns, agspec='fine'): ''' Construct a ProAtomDB from a series of Horton checkpoint files. **Arguments:** fns_chk A list of system files. **Optional arguments:** agspec A specifications of the atomic grid. This can either be an instance of the AtomicGridSpec object, or the first argument of its constructor. ''' if not isinstance(agspec, AtomicGridSpec): agspec = AtomicGridSpec(agspec) records = [] for fn in fns: # Load system with timer.section('Load proatom'): sys = System.from_file(fn, chk=None) # avoid rewriting in case of chk file with timer.section('Proatom grid'): records.append(ProAtomRecord.from_system(sys, agspec)) return cls(records)
def from_dm(cls, center, number, pseudo_number, obasis, dm_full, energy, agspec='fine'): '''Construct a proatom record from a single-atom density matrix **Arguments:** center The position of the nuclues (needed for spherical average) number The atomic number pseudo_number The effective core charges obasis The orbital basis dm_full The spin-summed density matrix object energy The electronic energy of the atom **Optional arguments:** agspec A specifications of the atomic grid. This can either be an instance of the AtomicGridSpec object, or the first argument of its constructor. ''' if len(center) != 3: raise TypeError('Center should be a vector with three elements.') if not isinstance(agspec, AtomicGridSpec): agspec = AtomicGridSpec(agspec) # Compute the density and the gradient on a grid atgrid = AtomicGrid(number, pseudo_number, center, agspec) rho_all = obasis.compute_grid_density_dm(dm_full, atgrid.points) grad_all = obasis.compute_grid_gradient_dm(dm_full, atgrid.points) rho, deriv = atgrid.get_spherical_average(rho_all, grads=[grad_all]) # Derive the number of electrions and the charge overlap = dm_full.new() obasis.compute_overlap(overlap) nel = overlap.contract_two('ab,ba', dm_full) assert abs(nel - int(np.round(nel))) < 1e-4 # only integer nel are supported nel = int(np.round(nel)) charge = pseudo_number - nel # Create object return cls(number, charge, energy, atgrid.rgrid, rho, deriv, pseudo_number)
def from_hdf5(cls, grp, lf): return BeckeMolGrid( (grp['centers'][:], grp['numbers'][:], grp['psuedo_numbers'][:]), AtomicGridSpec.from_hdf5(grp['agspec'], lf), grp['k'][()], grp['random_rotate'][()], grp.attrs['mode'], )
def from_system(cls, system, agspec='fine'): '''Construct a proatom record from a system and an atomic grid **Arguments:** sys The one-atom system. **Optional arguments:** agspec A specifications of the atomic grid. This can either be an instance of the AtomicGridSpec object, or the first argument of its constructor. ''' if system.natom != 1: raise ValueError('Can only construct a proatom record from a one-atom system.') if not isinstance(agspec, AtomicGridSpec): agspec = AtomicGridSpec(agspec) # Compute the density and the gradient on a grid atgrid = AtomicGrid(system.numbers[0], system.pseudo_numbers[0], system.coordinates[0], agspec) rho_all = system.compute_grid_density(atgrid.points) grad_all = system.compute_grid_gradient(atgrid.points) rrgrad_all = ((atgrid.points-atgrid.center)*grad_all).sum(axis=1) # Compute spherical averages rho = atgrid.get_spherical_average(rho_all) deriv = atgrid.get_spherical_average(rrgrad_all)/atgrid.rgrid.rtransform.get_radii() # Derive the number of electrions try: nel = system.wfn.nel except NotImplementedError: nel = int(np.round(atgrid.rgrid.integrate(rho))) # Get all the other information from the atom energy = system.extra['energy'] try: homo_energy = system.wfn.homo_energy except AttributeError: homo_energy = None number = system.numbers[0] pseudo_number = system.pseudo_numbers[0] charge = pseudo_number - nel # Create object return cls(number, charge, energy, homo_energy, atgrid.rgrid, rho, deriv, pseudo_number)
def __init__(self, centers, numbers, pseudo_numbers=None, agspec='medium', k=3, random_rotate=True, mode='discard'): ''' **Arguments:** centers An array (N, 3) with centers for the atom-centered grids. numbers An array (N,) with atomic numbers. **Optional arguments:** pseudo_numbers An array (N,) with effective core charges. When not given, this defaults to ``numbers``. agspec A specifications of the atomic grid. This can either be an instance of the AtomicGridSpec object, or the first argument of its constructor. k The order of the switching function in Becke's weighting scheme. random_rotate Flag to control random rotation of spherical grids. mode Select one of the following options regarding atomic subgrids: * ``'discard'`` (the default) means that all information about subgrids gets discarded. * ``'keep'`` means that a list of subgrids is kept, including the integration weights of the local grids. * ``'only'`` means that only the subgrids are constructed and that the computation of the molecular integration weights (based on the Becke partitioning) is skipped. ''' natom, centers, numbers, pseudo_numbers = typecheck_geo(centers, numbers, pseudo_numbers) self._centers = centers self._numbers = numbers self._pseudo_numbers = pseudo_numbers # check if the mode argument is valid if mode not in ['discard', 'keep', 'only']: raise ValueError('The mode argument must be \'discard\', \'keep\' or \'only\'.') # transform agspec into a usable format if not isinstance(agspec, AtomicGridSpec): agspec = AtomicGridSpec(agspec) self._agspec = agspec # assign attributes self._k = k self._random_rotate = random_rotate self._mode = mode # allocate memory for the grid size = sum(agspec.get_size(self.numbers[i], self.pseudo_numbers[i]) for i in xrange(natom)) points = np.zeros((size, 3), float) weights = np.zeros(size, float) self._becke_weights = np.ones(size, float) # construct the atomic grids if mode != 'discard': atgrids = [] else: atgrids = None offset = 0 if mode != 'only': # More recent covalent radii are used than in the original work of Becke. # No covalent radius is defined for elements heavier than Curium and a # default value of 3.0 Bohr is used for heavier elements. cov_radii = np.array([(periodic[n].cov_radius or 3.0) for n in self.numbers]) # The actual work: if log.do_medium: log('Preparing Becke-Lebedev molecular integration grid.') pb = log.progress(natom) for i in xrange(natom): atsize = agspec.get_size(self.numbers[i], self.pseudo_numbers[i]) atgrid = AtomicGrid( self.numbers[i], self.pseudo_numbers[i], self.centers[i], agspec, random_rotate, points[offset:offset+atsize]) if mode != 'only': atbecke_weights = self._becke_weights[offset:offset+atsize] becke_helper_atom(points[offset:offset+atsize], atbecke_weights, cov_radii, self.centers, i, self._k) weights[offset:offset+atsize] = atgrid.weights*atbecke_weights if mode != 'discard': atgrids.append(atgrid) offset += atsize pb() # finish IntGrid.__init__(self, points, weights, atgrids) # Some screen info self._log_init()
def main_convert(args): # The atomic grid specification agspec = AtomicGridSpec(args.grid) # The program is detected based on the run script that is present run_scripts = glob("run_*.sh") if len(run_scripts) != 1: raise RuntimeError( 'Found %i run_*.sh scripts while exactly one is needed to know which program was used to run the atomic computations.' % len(run_scripts)) program = atom_programs[run_scripts[0][4:-3]] # Loop over all sensible directories energy_table = EnergyTable() records = [] for dn_state in sorted(glob("[01]??_??_[01]??_q[+-]??")): number = int(dn_state[:3]) pop = int(dn_state[7:10]) cases = [] for dn_mult in sorted(glob('%s/mult??' % dn_state)): if log.do_medium: log('Loading from', dn_mult) data, energy = program.load_atom(dn_mult) if energy is None: if log.do_medium: log('No (sensible) results found: ', dn_mult) continue cases.append((energy, data)) if len(cases) == 0: if log.do_medium: log('Nothing found in: ', dn_state) continue # Get the lowest in energy and write to chk file cases.sort() energy, data = cases[0] # Add case to energy table energy_table.add(number, pop, energy) # Write atom to HORTON file if possible if data is not None: data.to_file('%s/horton.h5' % dn_state) # Construct a record for the proatomdb records.append(ProAtomRecord.from_iodata(data, agspec)) # Release memory data = None del cases # Let user know we are alive. if log.do_medium: log('Succesfull: ', dn_state) # Report energies if log.do_medium: energy_table.log() # Write out atoms file proatomdb = ProAtomDB(records) proatomdb.to_file('atoms.h5') if log.do_medium: log('Written atoms.h5') # Make nice figures plot_atoms(proatomdb)
def __init__(self, centers, numbers, pseudo_numbers=None, agspec='medium', k=3, random_rotate=True, mode='discard'): ''' **Arguments:** centers An array (N, 3) with centers for the atom-centered grids. numbers An array (N,) with atomic numbers. **Optional arguments:** pseudo_numbers An array (N,) with effective core charges. When not given, this defaults to ``numbers``. agspec A specifications of the atomic grid. This can either be an instance of the AtomicGridSpec object, or the first argument of its constructor. k The order of the switching function in Becke's weighting scheme. random_rotate Flag to control random rotation of spherical grids. mode Select one of the following options regarding atomic subgrids: * ``'discard'`` (the default) means that all information about subgrids gets discarded. * ``'keep'`` means that a list of subgrids is kept, including the integration weights of the local grids. * ``'only'`` means that only the subgrids are constructed and that the computation of the molecular integration weights (based on the Becke partitioning) is skipped. ''' natom, centers, numbers, pseudo_numbers = typecheck_geo( centers, numbers, pseudo_numbers) self._centers = centers self._numbers = numbers self._pseudo_numbers = pseudo_numbers # check if the mode argument is valid if mode not in ['discard', 'keep', 'only']: raise ValueError( 'The mode argument must be \'discard\', \'keep\' or \'only\'.') # transform agspec into a usable format if not isinstance(agspec, AtomicGridSpec): agspec = AtomicGridSpec(agspec) self._agspec = agspec # assign attributes self._k = k self._random_rotate = random_rotate self._mode = mode # allocate memory for the grid size = sum( agspec.get_size(self.numbers[i], self.pseudo_numbers[i]) for i in xrange(natom)) points = np.zeros((size, 3), float) weights = np.zeros(size, float) self._becke_weights = np.ones(size, float) # construct the atomic grids if mode != 'discard': atgrids = [] else: atgrids = None offset = 0 if mode != 'only': # More recent covalent radii are used than in the original work of Becke. # No covalent radius is defined for elements heavier than Curium and a # default value of 3.0 Bohr is used for heavier elements. cov_radii = np.array([(periodic[n].cov_radius or 3.0) for n in self.numbers]) # The actual work: if log.do_medium: log('Preparing Becke-Lebedev molecular integration grid.') pb = log.progress(natom) for i in xrange(natom): atsize = agspec.get_size(self.numbers[i], self.pseudo_numbers[i]) atgrid = AtomicGrid(self.numbers[i], self.pseudo_numbers[i], self.centers[i], agspec, random_rotate, points[offset:offset + atsize]) if mode != 'only': atbecke_weights = self._becke_weights[offset:offset + atsize] becke_helper_atom(points[offset:offset + atsize], atbecke_weights, cov_radii, self.centers, i, self._k) weights[offset:offset + atsize] = atgrid.weights * atbecke_weights if mode != 'discard': atgrids.append(atgrid) offset += atsize pb() # finish IntGrid.__init__(self, points, weights, atgrids) # Some screen info self._log_init()
def __init__(self, system, agspec='medium', k=3, random_rotate=True, mode='discard'): ''' **Arguments:** system The System object for which the molecular grid must be made. Alternatively, this may also be a tuple (centers, numbers, pseudo_numbers). **Optional arguments:** agspec A specifications of the atomic grid. This can either be an instance of the AtomicGridSpec object, or the first argument of its constructor. k The order of the switching function in Becke's weighting scheme. random_rotate Flag to control random rotation of spherical grids. mode Select one of the following options regarding atomic subgrids: * ``'discard'`` (the default) means that all information about subgrids gets discarded. * ``'keep'`` means that a list of subgrids is kept, including the integration weights of the local grids. * ``'only'`` means that only the subgrids are constructed and that the computation of the molecular integration weights (based on the Becke partitioning) is skipped. ''' if isinstance(system, System): self._centers = system.coordinates.copy() self._numbers = system.numbers.copy() self._pseudo_numbers = system.pseudo_numbers.copy() natom = system.natom else: self._centers, self._numbers, self._pseudo_numbers = system natom = len(self.centers) # check if the mode argument is valid if mode not in ['discard', 'keep', 'only']: raise ValueError('The mode argument must be \'discard\', \'keep\' or \'only\'.') # transform agspec into a usable format if not isinstance(agspec, AtomicGridSpec): agspec = AtomicGridSpec(agspec) self._agspec = agspec # assign attributes self._k = k self._random_rotate = random_rotate self._mode = mode # allocate memory for the grid size = sum(agspec.get_size(self.numbers[i], self.pseudo_numbers[i]) for i in xrange(natom)) points = np.zeros((size, 3), float) weights = np.zeros(size, float) log.mem.announce(points.nbytes + weights.nbytes) # construct the atomic grids if mode != 'discard': atgrids = [] else: atgrids = None offset = 0 if mode != 'only': # More recent covalent radii are used than in the original work of Becke. cov_radii = np.array([periodic[n].cov_radius for n in self.numbers]) # The actual work: if log.do_medium: log('Preparing Becke-Lebedev molecular integration grid.') pb = log.progress(natom) for i in xrange(natom): atsize = agspec.get_size(self.numbers[i], self.pseudo_numbers[i]) atgrid = AtomicGrid( self.numbers[i], self.pseudo_numbers[i], self.centers[i], agspec, random_rotate, points[offset:offset+atsize]) if mode != 'only': weights[offset:offset+atsize] = atgrid.weights becke_helper_atom( points[offset:offset+atsize], weights[offset:offset+atsize], cov_radii, self.centers, i, self._k) if mode != 'discard': atgrids.append(atgrid) offset += atsize pb() # finish IntGrid.__init__(self, points, weights, atgrids) # Some screen info self._log_init()