def from_file(cls, *args, **kwargs): """Create a System object from a file. A list of filenames may be provided, which will be loaded in that order. Each file complements or overrides the information loaded from a previous file in the list. Furthermore, keyword arguments may be used to specify additional constructor arguments. The ``lf`` optional argument is picked up from the kwargs list to contstruct (when needed) arrays to store the results loaded from file. When ``lf`` is not given, a DenseLinalgFactory is created by default. The filenames may also contain checkpoint files and open h5.File objects of checkpoint files. The last such checkpoint file will automatically be used as a checkpoint file for this class. If you want to override this behavior, provide the ``chk`` keyword argument (may be None). """ constructor_args = {} lf = kwargs.get('lf') if lf is None: lf = DenseLinalgFactory() for fn in args: fn_args = load_system_args(fn, lf) constructor_args.update(fn_args) constructor_args.update(kwargs) # If the basis comes from an external code and some operators are # loaded, rows and columns may need to be reordered. Similar for the # orbital coefficients and the density matrices. permutation = constructor_args.get('permutation') if permutation is not None: cache = constructor_args.get('cache') if cache is not None: for value, tags in cache.itervalues(): if isinstance(value, LinalgObject): value.apply_basis_permutation(permutation) wfn = constructor_args.get('wfn') if wfn is not None: wfn.apply_basis_permutation(permutation) del constructor_args['permutation'] # After the permutation, correct for different sign conventions of the # orbitals signs = constructor_args.get('signs') if signs is not None: cache = constructor_args.get('cache') if cache is not None: for value, tags in cache.itervalues(): if isinstance(value, LinalgObject): value.apply_basis_signs(signs) wfn = constructor_args.get('wfn') if wfn is not None: wfn.apply_basis_signs(signs) del constructor_args['signs'] return cls(**constructor_args)
def test_dense_two_index(): from horton.matrix import DenseLinalgFactory, DenseTwoIndex lf = DenseLinalgFactory() c = Cache() op1, new = c.load('egg', alloc=(lf.create_two_index, 10)) assert new assert isinstance(op1, DenseTwoIndex) assert op1.nbasis == 10 op2 = c.load('egg') assert op1 is op2 op3, new = c.load('egg', alloc=(lf.create_two_index, 10)) assert not new assert op1 is op3 # things that should not work with assert_raises(TypeError): op4, new = c.load('egg', alloc=(lf.create_two_index, 5)) with assert_raises(TypeError): op4, new = c.load('egg', alloc=5) # after clearing op1.set_element(1, 2, 5.2) c.clear() assert op1._array[1, 2] == 0.0 with assert_raises(KeyError): op4 = c.load('egg') op4, new = c.load('egg', alloc=(lf.create_two_index, 10)) assert new assert op1 is op4 op5 = c.load('egg') assert op1 is op5 # default_nbasis lf.default_nbasis = 5 with assert_raises(TypeError): c.load('egg', alloc=lf.create_two_index) c.clear() op6, new = c.load('egg', alloc=lf.create_two_index) assert new assert not op5 is op6 assert op6.nbasis == 5 # the new method of the two-index object op7, new = c.load('bork', alloc=op6.new) assert new assert not op5 is op7 assert op7.nbasis == 5
def test_dense_expansion(): from horton.matrix import DenseLinalgFactory, DenseExpansion lf = DenseLinalgFactory() c = Cache() exp1, new = c.load('egg', alloc=(lf.create_expansion, 10, 9)) assert new assert isinstance(exp1, DenseExpansion) assert exp1.nbasis == 10 assert exp1.nfn == 9 exp2 = c.load('egg') assert exp1 is exp2 exp3, new = c.load('egg', alloc=(lf.create_expansion, 10, 9)) assert not new assert exp1 is exp3 # things that should not work with assert_raises(TypeError): exp4, new = c.load('egg', alloc=(lf.create_expansion, 5)) with assert_raises(TypeError): exp4, new = c.load('egg', alloc=(lf.create_expansion, 10, 5)) with assert_raises(TypeError): exp4, new = c.load('egg', alloc=5) # after clearing exp1.coeffs[1, 2] = 5.2 c.clear() assert exp1.coeffs[1, 2] == 0.0 with assert_raises(KeyError): exp4 = c.load('egg') exp4, new = c.load('egg', alloc=(lf.create_expansion, 10, 9)) assert new assert exp1 is exp4 exp5 = c.load('egg') assert exp1 is exp5 # default_nbasis lf.set_default_nbasis(5) with assert_raises(TypeError): c.load('egg', alloc=lf.create_expansion) c.clear() exp6, new = c.load('egg', alloc=lf.create_expansion) assert new assert not exp5 is exp6 assert exp6.nbasis == 5 assert exp6.nfn == 5
def test_dense_two_body(): from horton.matrix import DenseLinalgFactory, DenseTwoBody lf = DenseLinalgFactory() c = Cache() op1, new = c.load('egg', alloc=(lf.create_two_body, 10)) assert new assert isinstance(op1, DenseTwoBody) assert op1.nbasis == 10 op2 = c.load('egg') assert op1 is op2 op3, new = c.load('egg', alloc=(lf.create_two_body, 10)) assert not new assert op1 is op3 # things that should not work with assert_raises(TypeError): op4, new = c.load('egg', alloc=(lf.create_two_body, 5)) with assert_raises(TypeError): op4, new = c.load('egg', alloc=5) # after clearing op1.set_element(1, 2, 1, 2, 5.2) c.clear() assert op1._array[1, 2, 1, 2] == 0.0 with assert_raises(KeyError): op4 = c.load('egg') op4, new = c.load('egg', alloc=(lf.create_two_body, 10)) assert new assert op1 is op4 op5 = c.load('egg') assert op1 is op5 # default_nbasis lf.set_default_nbasis(5) with assert_raises(TypeError): c.load('egg', alloc=lf.create_two_body) c.clear() op6, new = c.load('egg', alloc=lf.create_one_body) assert new assert not op5 is op6 assert op6.nbasis == 5
def __init__(self, coordinates, numbers, obasis=None, grid=None, wfn=None, lf=None, cache=None, extra=None, cell=None, pseudo_numbers=None, chk=None): """ **Arguments:** coordinates A (N, 3) float numpy array with Cartesian coordinates of the atoms. numbers A (N,) int numpy vector with the atomic numbers. **Optional arguments:** obasis A string or an instance of either the basis set or basis set description classes, e.g. 'STO-3G', GOBasisDesc('STO-3G'), ... for the orbitals. grid A grid object used for molecular integration. wfn A wavefunction object. lf A LinalgFactory instance. When not given, a DenseLinalgFactory is used by default. cache A cache object with computed results that depend on other attributes of the system class. Cached items should be tagged according to the attributes they depend on: - ``o``: obasis - ``c``: coordinates - ``g``: grid When given as a dictionary, each value must consist of two items: the object to be cached and the tags. extra A dictionary with additional information about the system. The keys must be strings. cell A Cell object that describes the (generally triclinic) periodic boundary conditions. So far, this is nearly nowhere supported in Horton, so don't get too excited. pseudo_numbers The core charges of the pseudo potential, if applicable chk A filename for the checkpoint file or an open h5.File object. If the file does not exist yet, it will be created. If the file already exists, it must be an HDF5 file that is structured such that it adheres to the format that Horton creates itself. If chk is an open h5.File object, it will not be closed when the System instance is deleted. """ # A) Assign all attributes self._coordinates = np.array(coordinates, dtype=float, copy=False) self._numbers = np.array(numbers, dtype=int, copy=False) # some checks if len(self._coordinates.shape ) != 2 or self._coordinates.shape[1] != 3: raise TypeError( 'coordinates argument must be a 2D array with three columns') if len(self._numbers.shape) != 1: raise TypeError('numbers must a vector of integers.') if self._numbers.shape[0] != self._coordinates.shape[0]: raise TypeError( 'numbers and coordinates must have compatible array shapes.') # self._grid = grid # self._wfn = wfn # if cache is None: self._cache = Cache() elif isinstance(cache, Cache): self._cache = cache elif isinstance(cache, dict): self._cache = Cache() for key, (value, tags) in cache.iteritems(): self._cache.dump(key, value, tags=tags) else: raise TypeError('Could not interpret the cache argument.') # if lf is None: self._lf = DenseLinalgFactory() else: self._lf = lf # if extra is None: self._extra = {} else: self._extra = extra # self._obasis = None self._obasis_desc = None if obasis is not None: self.update_obasis(obasis) self._cell = cell self._pseudo_numbers = pseudo_numbers # The checkpoint file self._chk = None self._close_chk = False self.assign_chk(chk) self._log_init()
def project_orbitals_mgs_low(obasis0, obasis1, exp0, exp1, eps=1e-10): '''Project the orbitals in ``exp0`` (wrt ``obasis0``) on ``obasis1`` and store in ``exp1`` with the modified Gram-Schmidt algorithm. **Arguments:** obasis0 The orbital basis for the original wavefunction expansion. obasis1 The new orbital basis for the projected wavefunction expansion. exp0 The expansion of the original orbitals. exp1 (output) An output argument in which the projected orbitals will be stored. **Optional arguments:** eps A threshold for the renormalization in the Gram-Schmidt procedure The projection is based on the Modified Gram-Schmidt (MGS) process. In each iteration of the MGS, a renormalization is carried out. If the norm in this step is smaller than ``eps``, an error is raised. Note that ``exp1`` will be incomplete in several ways. The orbital energies are not copied. Only the occupied orbitals in ``exp0`` are projected. Coefficients of higher orbitals are set to zero. The orbital occupations are simply copied. This should be sufficient to construct an initial guess in a new orbital basis set based on a previous solution. If the number of orbitals in ``exp1`` is too small to store all projected orbitals, an error is raised. ''' # Compute the overlap matrix of the combined orbital basis obasis_both = GOBasis.concatenate(obasis0, obasis1) lf = DenseLinalgFactory(obasis_both.nbasis) olp_both = lf.create_one_body() obasis_both.compute_overlap(olp_both) # Select the blocks of interest from the big overlap matrix olp_21 = olp_both._array[obasis0.nbasis:, :obasis0.nbasis] olp_22 = olp_both._array[obasis0.nbasis:, obasis0.nbasis:] # construct the projector projector = np.dot(np.linalg.pinv(olp_22), olp_21) # project occupied orbitals i1 = 0 for i0 in xrange(exp0.nfn): if exp0.occupations[i0] == 0.0: continue if i1 > exp1.nfn: raise ProjectionError( 'Not enough functions available in exp1 to store the projected orbitals.' ) exp1.coeffs[:, i1] = np.dot(projector, exp0.coeffs[:, i0]) exp1.occupations[i1] = exp0.occupations[i0] i1 += 1 # clear all parts of exp1 that were not touched by the projection loop ntrans = i1 del i1 exp1.coeffs[:, ntrans:] = 0.0 exp1.occupations[ntrans:] = 0.0 exp1.energies[:] = 0.0 # auxiliary function for the MGS algo def dot22(a, b): return np.dot(np.dot(a, olp_22), b) # Apply the MGS algorithm to orthogonalize the orbitals for i1 in xrange(ntrans): orb = exp1.coeffs[:, i1] # Subtract overlap with previous orbitals for j1 in xrange(i1): other = exp1.coeffs[:, j1] orb -= other * dot22(other, orb) / np.sqrt(dot22(orb, orb)) # Renormalize norm = np.sqrt(dot22(orb, orb)) if norm < eps: raise ProjectionError( 'The norm of a vector in the MGS algorithm becomes too small. Orbitals are redundant in new basis.' ) orb /= norm
def from_file(cls, *filenames, **kwargs): '''Load data from a file. **Arguments:** filename1, filename2, ... The files to load data from. When multiple files are given, data from the first file is overwritten by data from the second, etc. When one file contains sign and permutation changes for the orbital basis, these changes will be applied to data from all other files. **Optional arguments:** lf A LinalgFactory instance. DenseLinalgFactory is used as default. This routine uses the extension or prefix of the filename to determine the file format. It returns a dictionary with data loaded from the file. For each file format, a specialized function is called that returns a dictionary with data from the file. ''' result = {} lf = kwargs.pop('lf', None) if lf is None: lf = DenseLinalgFactory() if len(kwargs) > 0: raise TypeError('Keyword argument(s) not supported: %s' % kwargs.keys()) for filename in filenames: if isinstance(filename, h5.Group) or filename.endswith('.h5'): from horton.io.internal import load_h5 result.update(load_h5(filename)) elif filename.endswith('.xyz'): from horton.io.xyz import load_xyz result.update(load_xyz(filename)) elif filename.endswith('.fchk'): from horton.io.gaussian import load_fchk result.update(load_fchk(filename, lf)) elif filename.endswith('.log'): from horton.io.gaussian import load_operators_g09 result.update(load_operators_g09(filename, lf)) elif filename.endswith('.mkl'): from horton.io.molekel import load_mkl result.update(load_mkl(filename, lf)) elif filename.endswith('.molden.input') or filename.endswith( '.molden'): from horton.io.molden import load_molden result.update(load_molden(filename, lf)) elif filename.endswith('.cube'): from horton.io.cube import load_cube result.update(load_cube(filename)) elif filename.endswith('.wfn'): from horton.io.wfn import load_wfn result.update(load_wfn(filename, lf)) elif os.path.basename(filename).startswith('POSCAR'): from horton.io.vasp import load_poscar result.update(load_poscar(filename)) elif os.path.basename(filename)[:6] in ['CHGCAR', 'AECCAR']: from horton.io.vasp import load_chgcar result.update(load_chgcar(filename)) elif os.path.basename(filename).startswith('LOCPOT'): from horton.io.vasp import load_locpot result.update(load_locpot(filename)) elif filename.endswith('.cp2k.out'): from horton.io.cp2k import load_atom_cp2k result.update(load_atom_cp2k(filename, lf)) elif filename.endswith('.cif'): from horton.io.cif import load_cif result.update(load_cif(filename, lf)) elif 'FCIDUMP' in os.path.basename(filename): from horton.io.molpro import load_fcidump result.update(load_fcidump(filename, lf)) else: raise ValueError('Unknown file format for reading: %s' % filename) # Apply changes in orbital order and sign conventions if 'permutation' in result: for key, value in result.iteritems(): if isinstance(value, LinalgObject): value.permute_basis(result['permutation']) del result['permutation'] if 'signs' in result: for key, value in result.iteritems(): if isinstance(value, LinalgObject): value.change_basis_signs(result['signs']) del result['signs'] return cls(**result)