def slice_to_two(self, subscripts, out=None, factor=1.0, clear=True): """Returns a two-index contraction of the four-index object. **Arguments:** subscripts Any of ``aabb->ab``, ``abab->ab``, ``abba->ab`` **Optional arguments:** out, factor, clear See :py:meth:`DenseLinalgFactory.einsum` """ # Error checking check_options('subscripts', subscripts, 'aabb->ab', 'abab->ab', 'abba->ab') # Handle output argument if out is None: out = DenseTwoIndex(self.nbasis) else: check_type('out', out, DenseTwoIndex) if clear: out.clear() # Actual computation if subscripts == 'aabb->ab': out._array[:] += factor*np.einsum('xab,xab->ab', self._array, self._array2) elif subscripts == 'abab->ab': out._array[:] += factor*np.einsum('xaa,xbb->ab', self._array, self._array2) elif subscripts == 'abba->ab': out._array[:] += factor*np.einsum('xab,xba->ab', self._array, self._array2) return out
def slice_to_three(self, subscripts, out=None, factor=1.0, clear=True): """Returns a three-index contraction of the four-index object. **Arguments:** subscripts Any of ``abcc->bac``, ``abcc->abc``, ``abcb->abc``, ``abbc->abc`` **Optional arguments:** out, factor, clear See :py:meth:`DenseLinalgFactory.einsum` """ # Error checking check_options('subscripts', subscripts, 'abcc->bac', 'abcc->abc', 'abcb->abc', 'abbc->abc') if out is None: out = DenseThreeIndex(self.nbasis) else: check_type('out', out, DenseThreeIndex) if clear: out.clear() # Actual computation if subscripts == 'abbc->abc': slice_to_three_abbc_abc(self._array, self._array2, out._array, factor, clear) elif subscripts == 'abcc->bac': slice_to_three_abcc_bac(self._array, self._array2, out._array, factor, clear) elif subscripts == 'abcc->abc': slice_to_three_abcc_abc(self._array, self._array2, out._array, factor, clear) elif subscripts == 'abcb->abc': L_r = np.diagonal(self._array2, axis1=1, axis2=2) out._array[:] += factor*np.tensordot(self._array, L_r, [(0,),(0,)]).swapaxes(1,2) return out
def contract_two_to_two(self, subscripts, two, out=None, factor=1.0, clear=True): """Contract self with a two-index to obtain a two-index. **Arguments:** subscripts Any of ``abcd,bd->ac`` (direct), ``abcd,cb->ad`` (exchange) two The input two-index object. (DenseTwoIndex) **Optional arguments:** out, factor, clear See :py:meth:`DenseLinalgFactory.einsum` """ check_options('subscripts', subscripts, 'abcd,bd->ac', 'abcd,cb->ad') if out is None: out = DenseTwoIndex(self.nbasis) if clear: out.clear() else: check_type('out', out, DenseTwoIndex) if subscripts == 'abcd,bd->ac': tmp = np.tensordot(self._array2, two._array, axes=([(1,2),(1,0)])) out._array[:] += factor*np.tensordot(self._array, tmp, [0,0]) elif subscripts == 'abcd,cb->ad': tmp = np.tensordot(self._array2, two._array, axes=([1,1])) out._array[:] += factor*np.tensordot(self._array, tmp, ([0,2],[0,2])) return out
def assign_four_index_transform(self, ao_integrals, exp0, exp1=None, exp2=None, exp3=None, method='tensordot'): '''Perform four index transformation. **Arguments:** oa_integrals A CholeskyFourIndex with integrals in atomic orbitals. exp0 A DenseExpansion object with molecular orbitals **Optional arguments:** exp1, exp2, exp3 Can be provided to transform each index differently. See ``parse_four_index_transform_exps`` for details. method Either ``einsum`` or ``tensordot`` (default). ''' check_type('ao_integrals', ao_integrals, CholeskyFourIndex) exp0, exp1, exp2, exp3 = parse_four_index_transform_exps( exp0, exp1, exp2, exp3, DenseExpansion) if method == 'einsum': if ao_integrals.is_decoupled or not (exp0 is exp1 and exp2 is exp3): self.decouple_array2() self._array2[:] = np.einsum('bi,kbd->kid', exp1.coeffs, ao_integrals._array2) self._array2[:] = np.einsum('dj,kid->kij', exp3.coeffs, self._array2) self._array[:] = np.einsum('ai,kac->kic', exp0.coeffs, ao_integrals._array) self._array[:] = np.einsum('cj,kic->kij', exp2.coeffs, self._array) elif method == 'tensordot': if ao_integrals.is_decoupled or not (exp0 is exp1 and exp2 is exp3): self.decouple_array2() self._array2[:] = np.tensordot(ao_integrals._array2, exp1.coeffs, axes=([1], [0])) self._array2[:] = np.tensordot(self._array2, exp3.coeffs, axes=([1], [0])) self._array[:] = np.tensordot(ao_integrals._array, exp0.coeffs, axes=([1], [0])) self._array[:] = np.tensordot(self._array, exp2.coeffs, axes=([1], [0])) else: raise ValueError( 'The method must either be \'einsum\' or \'tensordot\'.')
def assign(self, other): """Assign with the contents of another object. Parameters ---------- other : Orbitals Another Orbitals object """ check_type('other', other, Orbitals) self._coeffs[:] = other._coeffs self._energies[:] = other._energies self._occupations[:] = other._occupations
def assign(self, other): """Assign with the contents of another object. Parameters ---------- other : Orbitals Another Orbitals object """ check_type('other', other, Orbitals) self._coeffs[:] = other._coeffs self._energies[:] = other._energies self._occupations[:] = other._occupations
def perm(self, a): '''Calculate the permament of a matrix **Arguements** a A np array ''' check_type('matrix', a, np.ndarray) n = len(a) r = range(n) s = permutations(r) import math # FIXME: fsum really needed for accuracy? return math.fsum(self.prod(a[i][sigma[i]] for i in r) for sigma in s)
def perm(self, a): '''Calculate the permament of a matrix **Arguements** a A np array ''' check_type('matrix', a, np.ndarray) n = len(a) r = range(n) s = permutations(r) import math # FIXME: fsum really needed for accuracy? return math.fsum(self.prod(a[i][sigma[i]] for i in r) for sigma in s)
def assign(self, other): '''Assign with the contents of another object **Arguments:** other Another CholeskyFourIndex object. ''' check_type('other', other, CholeskyFourIndex) self._array[:] = other._array if other._array is other._array2: self.reset_array2() else: self.decouple_array2() self._array2[:] = other._array2
def __init__(self, lf, occ_model, npairs=None, nvirt=None): ''' **Arguments:** lf A LinalgFactory instance. occ_model Occupation model **Optional arguments:** npairs Number of electron pairs, if not specified, npairs = number of occupied orbitals nvirt Number of virtual orbitals, if not specified, nvirt = (nbasis-npairs) ''' check_type('pairs', npairs, int, type(None)) check_type('virtuals', nvirt, int, type(None)) self._lf = lf self._nocc = occ_model.noccs[0] self._nbasis = lf.default_nbasis if npairs is None: npairs = occ_model.noccs[0] elif npairs >= lf.default_nbasis: raise ValueError( 'Number of electron pairs (%i) larger than number of basis functions (%i)' % (npairs, self.nbasis)) if nvirt is None: nvirt = (lf.default_nbasis - npairs) elif nvirt >= lf.default_nbasis: raise ValueError( 'Number of virtuals (%i) larger than number of basis functions (%i)' % (nvirt, self.nbasis)) self._npairs = npairs self._nvirt = nvirt self._cache = Cache() self._ecore = 0 self._geminal = lf.create_two_index(npairs, nvirt) self._lagrange = lf.create_two_index(npairs, nvirt)
def __init__(self, lf, occ_model, npairs=None, nvirt=None): ''' **Arguments:** lf A LinalgFactory instance. occ_model Occupation model **Optional arguments:** npairs Number of electron pairs, if not specified, npairs = number of occupied orbitals nvirt Number of virtual orbitals, if not specified, nvirt = (nbasis-npairs) ''' check_type('pairs', npairs, int, type(None)) check_type('virtuals', nvirt, int, type(None)) self._lf = lf self._nocc = occ_model.noccs[0] self._nbasis = lf.default_nbasis if npairs is None: npairs = occ_model.noccs[0] elif npairs >= lf.default_nbasis: raise ValueError('Number of electron pairs (%i) larger than number of basis functions (%i)' %(npairs, self.nbasis)) if nvirt is None: nvirt = (lf.default_nbasis-npairs) elif nvirt >= lf.default_nbasis: raise ValueError('Number of virtuals (%i) larger than number of basis functions (%i)' %(nvirt, self.nbasis)) self._npairs = npairs self._nvirt = nvirt self._cache = Cache() self._ecore = 0 self._geminal = lf.create_two_index(npairs, nvirt) self._lagrange = lf.create_two_index(npairs, nvirt)
def assign_four_index_transform(self, ao_integrals, exp0, exp1=None, exp2=None, exp3=None, method='tensordot'): '''Perform four index transformation. **Arguments:** oa_integrals A CholeskyFourIndex with integrals in atomic orbitals. exp0 A DenseExpansion object with molecular orbitals **Optional arguments:** exp1, exp2, exp3 Can be provided to transform each index differently. See ``parse_four_index_transform_exps`` for details. method Either ``einsum`` or ``tensordot`` (default). ''' check_type('ao_integrals', ao_integrals, CholeskyFourIndex) exp0, exp1, exp2, exp3 = parse_four_index_transform_exps(exp0, exp1, exp2, exp3, DenseExpansion) if method == 'einsum': if ao_integrals.is_decoupled or not (exp0 is exp1 and exp2 is exp3): self.decouple_array2() self._array2[:] = np.einsum('bi,kbd->kid', exp1.coeffs, ao_integrals._array2) self._array2[:] = np.einsum('dj,kid->kij', exp3.coeffs, self._array2) self._array[:] = np.einsum('ai,kac->kic', exp0.coeffs, ao_integrals._array) self._array[:] = np.einsum('cj,kic->kij', exp2.coeffs, self._array) elif method == 'tensordot': if ao_integrals.is_decoupled or not (exp0 is exp1 and exp2 is exp3): self.decouple_array2() self._array2[:] = np.tensordot(ao_integrals._array2, exp1.coeffs, axes=([1],[0])) self._array2[:] = np.tensordot(self._array2, exp3.coeffs, axes=([1],[0])) self._array[:] = np.tensordot(ao_integrals._array, exp0.coeffs, axes=([1],[0])) self._array[:] = np.tensordot(self._array, exp2.coeffs, axes=([1],[0])) else: raise ValueError('The method must either be \'einsum\' or \'tensordot\'.')
def generate_guess(self, guess, dim=None): '''Generate a guess of type 'guess'. **Arguments:** guess A dictionary, containing the type of guess. **Optional arguments:** dim Length of guess. ''' check_options('guess.type', guess['type'], 'random', 'const') check_type('guess.factor', guess['factor'], int, float) if guess['factor'] == 0: raise ValueError('Scaling factor must be different from 0.') if dim is None: dim = self.dimension if guess['type'] == 'random': return np.random.random(dim) * guess['factor'] elif guess['type'] == 'const': return np.ones(dim) * guess['factor']
def generate_guess(self, guess, dim=None): '''Generate a guess of type 'guess'. **Arguments:** guess A dictionary, containing the type of guess. **Optional arguments:** dim Length of guess. ''' check_options('guess.type', guess['type'], 'random', 'const') check_type('guess.factor', guess['factor'], int, float) if guess['factor'] == 0: raise ValueError('Scaling factor must be different from 0.') if dim is None: dim = self.dimension if guess['type'] == 'random': return np.random.random(dim)*guess['factor'] elif guess['type'] == 'const': return np.ones(dim)*guess['factor']
def parse_four_index_transform_exps(exp0, exp1, exp2, exp3, Class): '''Parse the optional arguments exp1, exp2 and exp3. **Arguments:** exp0, exp1, exp2, exp3 Four sets of orbitals for the mo transformation. Some may be None but only the following not None combinations are allowed: * ``(exp0,)``: maintain eight-fold symmetry (if any) * ``(exp0, exp1)``: maintain four-fold symmetry (if any) * ``(exp0, exp2)``: maintain two-fold symmetry (if any) * ``(exp0, exp1, exp2, exp3)``: break all symmetry Class The expected class of the exps objects. **Returns:** exp0, exp1, exp2, exp3. (All not None) ''' # Four supported situations if exp1 is None and exp2 is None and exp3 is None: # maintains eight-fold symmetry exp1 = exp0 exp2 = exp0 exp3 = exp0 elif exp2 is None and exp3 is None: # maintains four-fold symmetry exp2 = exp0 exp3 = exp1 elif exp1 is None and exp3 is None: # maintains two-fold symmetry exp1 = exp0 exp3 = exp2 elif exp1 is None or exp2 is None or exp3 is None: # the only other allowed case is no symmetry. raise TypeError( 'It is not clear how to interpret the optional arguments exp1, exp2 and exp3.' ) check_type('exp0', exp0, Class) check_type('exp1', exp1, Class) check_type('exp2', exp2, Class) check_type('exp3', exp3, Class) return exp0, exp1, exp2, exp3
def parse_four_index_transform_exps(exp0, exp1, exp2, exp3, Class): '''Parse the optional arguments exp1, exp2 and exp3. **Arguments:** exp0, exp1, exp2, exp3 Four sets of orbitals for the mo transformation. Some may be None but only the following not None combinations are allowed: * ``(exp0,)``: maintain eight-fold symmetry (if any) * ``(exp0, exp1)``: maintain four-fold symmetry (if any) * ``(exp0, exp2)``: maintain two-fold symmetry (if any) * ``(exp0, exp1, exp2, exp3)``: break all symmetry Class The expected class of the exps objects. **Returns:** exp0, exp1, exp2, exp3. (All not None) ''' # Four supported situations if exp1 is None and exp2 is None and exp3 is None: # maintains eight-fold symmetry exp1 = exp0 exp2 = exp0 exp3 = exp0 elif exp2 is None and exp3 is None: # maintains four-fold symmetry exp2 = exp0 exp3 = exp1 elif exp1 is None and exp3 is None: # maintains two-fold symmetry exp1 = exp0 exp3 = exp2 elif exp1 is None or exp2 is None or exp3 is None: # the only other allowed case is no symmetry. raise TypeError('It is not clear how to interpret the optional arguments exp1, exp2 and exp3.') check_type('exp0', exp0, Class) check_type('exp1', exp1, Class) check_type('exp2', exp2, Class) check_type('exp3', exp3, Class) return exp0, exp1, exp2, exp3
def split_core_active(one, two, ecore, orb, ncore, nactive, indextrans='tensordot'): '''Reduce a Hamiltonian to an active space Works only for restricted wavefunctions. **Arguments:** one/two One and two-electron integrals. ecore The core energy of the given Hamiltonian. In the case of a standard molecular system, this is the nuclear nuclear repulsion. orb The MO expansion coefficients. An Expansion instance. If None, integrals are assued to be already transformed into the mo basis and no transformation is carried out in this function. ncore The number of frozen core orbitals (int) nactive The number of active orbitals (int) **Optional arguments:** indextrans 4-index transformation (str). One of ``tensordot``, ``einsum`` **Returns** a tuple with three values: one_small The one-body operator in the small space two_small The two-body operator in the small space ecore The core energy, i.e. the sum of the given core energy and HF contributions from the core orbitals. ''' # # Check type/option of arguments # check_type('ncore', ncore, int) check_type('nactive', nactive, int) check_options('indextrans', indextrans, 'tensordot', 'einsum') if ncore <= 0 or nactive <= 0: raise ValueError('ncore and nactive must be strictly positive.') if nactive + ncore > one.nbasis: raise ValueError('More active orbitals than basis functions.') # # Optional transformation to mo basis # if orb is None: one_mo = one two_mo = two else: # No need to check orb. This is done in transform_integrals function (one_mo, ), (two_mo, ) = transform_integrals(one, two, indextrans, orb) # Core energy norb = one.nbasis # One body term ecore += 2 * one_mo.trace(0, ncore, 0, ncore) # Direct part ecore += two_mo.slice_to_two('abab->ab', None, 2.0, True, 0, ncore, 0, ncore, 0, ncore, 0, ncore).sum() # Exchange part ecore += two_mo.slice_to_two('abba->ab', None, -1.0, True, 0, ncore, 0, ncore, 0, ncore, 0, ncore).sum() # Active space one-body integrals one_mo_corr = one_mo.new() # Direct part two_mo.contract_to_two('abcb->ac', one_mo_corr, 2.0, True, 0, norb, 0, ncore, 0, norb, 0, ncore) # Exchange part two_mo.contract_to_two('abbc->ac', one_mo_corr, -1.0, False, 0, norb, 0, ncore, 0, ncore, 0, norb) one_mo.iadd(one_mo_corr, 1.0) #one_mo.iadd_t(one_mo_corr, 1.0) # # Store in smaller n-index objects # one_mo_small = one_mo.copy(ncore, ncore + nactive, ncore, ncore + nactive) two_mo_small = two_mo.copy(ncore, ncore + nactive, ncore, ncore + nactive, ncore, ncore + nactive, ncore, ncore + nactive) # Done return one_mo_small, two_mo_small, ecore
def __init__(self, lf, **kw): """ **Arguments:** lf A LinalgFactory instance **Keywords:** :method: step search method used, one of ``trust-region`` (default), ``None``, ``backtracking`` :alpha: scaling factor for step, used in ``backtracking`` and ``None`` method (default 0.75) :c1: parameter used in ``backtracking`` (default 1e-4) :minalpha: minimum step length used in ``backracking`` (default 1e-6) :maxiterouter: maximum number of step search steps (default 10) :maxiterinner: maximum number of optimization steps in each step search step (used only in pcg, default 500) :maxeta: upper bound for estimated vs actual change in ``trust-region`` (default 0.75) :mineta: lower bound for estimated vs actual change in ``trust-region`` (default 0.25) :upscale: scaling factor to increase trust radius in ``trust-region`` (default 2.0) :downscale: scaling factor to decrease trust radius in ``trust-region`` and step length in ``backtracking`` (float) (default 0.25) :trustradius: initial trust radius (default 0.75) :maxtrustradius: maximum trust radius (default 0.75) :threshold: trust-region optimization threshold, only used in ``pcg`` method of ``trust-region`` :optimizer: optimizes step to boundary of trust radius. One of ``pcg``, ``dogleg``, ``ddl`` (default ddl) """ self.lf = lf # # Check keywords and set default arguments, types and options are also # checked # names = [] def _helper(x,y): names.append(x) kw.setdefault(x,y) _helper('method', 'trust-region') _helper('alpha', 1.0) _helper('c1', 0.0001) _helper('minalpha', 1e-6) _helper('maxiterouter', 10) _helper('maxiterinner', 500) _helper('maxeta', 0.75) _helper('mineta', 0.25) _helper('upscale', 2.0) _helper('downscale', 0.25) _helper('trustradius', 0.75) _helper('maxtrustradius', 0.75) _helper('threshold', 1e-8) _helper('optimizer', 'ddl') for name, value in kw.items(): if name not in names: raise ValueError("Unknown keyword argument %s" % name) if value is not None: if value < 0: raise ValueError('Cannot set attribute %s because of illegal value %s' %(name, value)) setattr(self, name, kw[name]) check_options('method', self.method, 'None', 'backtracking', 'trust-region') check_options('optimizer', self.optimizer, 'pcg', 'dogleg', 'ddl') check_type('alpha', self.alpha, int, float) check_type('c1', self.c1, int, float) check_type('minalpha', self.minalpha, int, float) check_type('maxiterouter', self.maxiterouter, int) check_type('maxiterinner', self.maxiterinner, int) check_type('maxeta', self.maxeta, int, float) check_type('mineta', self.mineta, int, float) check_type('upscale', self.upscale, float) check_type('downscale', self.downscale, float) check_type('trustradius', self.trustradius, float) check_type('maxtrustradius', self.maxtrustradius, float) check_type('threshold', self.threshold, float) self.alpha0 = self.alpha def _get_lf(self): return self.lf lf = property(_get_lf) def _get_method(self): return kw.pop('method') method = property(_get_method) def _get_maxeta(self): return kw.pop('maxeta') maxeta = property(_get_maxeta) def _get_mineta(self): return kw.pop('mineta') mineta = property(_get_mineta) def _get_upscale(self): return kw.pop('upscale') upscale = property(_get_upscale) def _get_downscale(self): return kw.pop('downscale') downscale = property(_get_downscale) def _get_maxiterouter(self): return kw.pop('maxiterouter') maxiterouter = property(_get_maxiterouter) def _get_maxiterinner(self): return kw.pop('maxiterinner') maxiterinner = property(_get_maxiterinner) def _get_alpha(self): return kw.pop('alpha') alpha = property(_get_alpha) def _get_minalpha(self): return kw.pop('minalpha') minalpha = property(_get_minalpha) def _get_c1(self): return kw.pop('c1') c1 = property(_get_c1) def _get_maxtrustradius(self): return kw.pop('maxtrustradius') maxtrustradius = property(_get_maxtrustradius) def _get_trustradius(self): return kw.pop('trustradius') trustradius = property(_get_trustradius) def _get_threshold(self): return kw.pop('threshold') threshold = property(_get_threshold) def _get_optimizer(self): return kw.pop('optimizer') optimizer = property(_get_optimizer)
def __init__(self, lf, **kw): """ **Arguments:** lf A LinalgFactory instance **Keywords:** :method: step search method used, one of ``trust-region`` (default), ``None``, ``backtracking`` :alpha: scaling factor for step, used in ``backtracking`` and ``None`` method (default 0.75) :c1: parameter used in ``backtracking`` (default 1e-4) :minalpha: minimum step length used in ``backracking`` (default 1e-6) :maxiterouter: maximum number of step search steps (default 10) :maxiterinner: maximum number of optimization steps in each step search step (used only in pcg, default 500) :maxeta: upper bound for estimated vs actual change in ``trust-region`` (default 0.75) :mineta: lower bound for estimated vs actual change in ``trust-region`` (default 0.25) :upscale: scaling factor to increase trust radius in ``trust-region`` (default 2.0) :downscale: scaling factor to decrease trust radius in ``trust-region`` and step length in ``backtracking`` (float) (default 0.25) :trustradius: initial trust radius (default 0.75) :maxtrustradius: maximum trust radius (default 0.75) :threshold: trust-region optimization threshold, only used in ``pcg`` method of ``trust-region`` :optimizer: optimizes step to boundary of trust radius. One of ``pcg``, ``dogleg``, ``ddl`` (default ddl) """ self.lf = lf # # Check keywords and set default arguments, types and options are also # checked # names = [] def _helper(x, y): names.append(x) kw.setdefault(x, y) _helper('method', 'trust-region') _helper('alpha', 1.0) _helper('c1', 0.0001) _helper('minalpha', 1e-6) _helper('maxiterouter', 10) _helper('maxiterinner', 500) _helper('maxeta', 0.75) _helper('mineta', 0.25) _helper('upscale', 2.0) _helper('downscale', 0.25) _helper('trustradius', 0.75) _helper('maxtrustradius', 0.75) _helper('threshold', 1e-8) _helper('optimizer', 'ddl') for name, value in kw.items(): if name not in names: raise ValueError("Unknown keyword argument %s" % name) if value is not None: if value < 0: raise ValueError( 'Cannot set attribute %s because of illegal value %s' % (name, value)) setattr(self, name, kw[name]) check_options('method', self.method, 'None', 'backtracking', 'trust-region') check_options('optimizer', self.optimizer, 'pcg', 'dogleg', 'ddl') check_type('alpha', self.alpha, int, float) check_type('c1', self.c1, int, float) check_type('minalpha', self.minalpha, int, float) check_type('maxiterouter', self.maxiterouter, int) check_type('maxiterinner', self.maxiterinner, int) check_type('maxeta', self.maxeta, int, float) check_type('mineta', self.mineta, int, float) check_type('upscale', self.upscale, float) check_type('downscale', self.downscale, float) check_type('trustradius', self.trustradius, float) check_type('maxtrustradius', self.maxtrustradius, float) check_type('threshold', self.threshold, float) self.alpha0 = self.alpha def _get_lf(self): return self.lf lf = property(_get_lf) def _get_method(self): return kw.pop('method') method = property(_get_method) def _get_maxeta(self): return kw.pop('maxeta') maxeta = property(_get_maxeta) def _get_mineta(self): return kw.pop('mineta') mineta = property(_get_mineta) def _get_upscale(self): return kw.pop('upscale') upscale = property(_get_upscale) def _get_downscale(self): return kw.pop('downscale') downscale = property(_get_downscale) def _get_maxiterouter(self): return kw.pop('maxiterouter') maxiterouter = property(_get_maxiterouter) def _get_maxiterinner(self): return kw.pop('maxiterinner') maxiterinner = property(_get_maxiterinner) def _get_alpha(self): return kw.pop('alpha') alpha = property(_get_alpha) def _get_minalpha(self): return kw.pop('minalpha') minalpha = property(_get_minalpha) def _get_c1(self): return kw.pop('c1') c1 = property(_get_c1) def _get_maxtrustradius(self): return kw.pop('maxtrustradius') maxtrustradius = property(_get_maxtrustradius) def _get_trustradius(self): return kw.pop('trustradius') trustradius = property(_get_trustradius) def _get_threshold(self): return kw.pop('threshold') threshold = property(_get_threshold) def _get_optimizer(self): return kw.pop('optimizer') optimizer = property(_get_optimizer)
def split_core_active(one, two, ecore, orb, ncore, nactive, indextrans='tensordot'): '''Reduce a Hamiltonian to an active space Works only for restricted wavefunctions. **Arguments:** one/two One and two-electron integrals. ecore The core energy of the given Hamiltonian. In the case of a standard molecular system, this is the nuclear nuclear repulsion. orb The MO expansion coefficients. An Expansion instance. If None, integrals are assued to be already transformed into the mo basis and no transformation is carried out in this function. ncore The number of frozen core orbitals (int) nactive The number of active orbitals (int) **Optional arguments:** indextrans 4-index transformation (str). One of ``tensordot``, ``einsum`` **Returns** a tuple with three values: one_small The one-body operator in the small space two_small The two-body operator in the small space ecore The core energy, i.e. the sum of the given core energy and HF contributions from the core orbitals. ''' # # Check type/option of arguments # check_type('ncore', ncore, int) check_type('nactive', nactive, int) check_options('indextrans', indextrans, 'tensordot', 'einsum') if ncore <= 0 or nactive <= 0: raise ValueError('ncore and nactive must be strictly positive.') if nactive+ncore > one.nbasis: raise ValueError('More active orbitals than basis functions.') # # Optional transformation to mo basis # if orb is None: one_mo = one two_mo = two else: # No need to check orb. This is done in transform_integrals function (one_mo,), (two_mo,) = transform_integrals(one, two, indextrans, orb) # Core energy norb = one.nbasis # One body term ecore += 2*one_mo.trace(0, ncore, 0, ncore) # Direct part ecore += two_mo.slice_to_two('abab->ab', None, 2.0, True, 0, ncore, 0, ncore, 0, ncore, 0, ncore).sum() # Exchange part ecore += two_mo.slice_to_two('abba->ab', None,-1.0, True, 0, ncore, 0, ncore, 0, ncore, 0, ncore).sum() # Active space one-body integrals one_mo_corr = one_mo.new() # Direct part two_mo.contract_to_two('abcb->ac', one_mo_corr, 2.0, True, 0, norb, 0, ncore, 0, norb, 0, ncore) # Exchange part two_mo.contract_to_two('abbc->ac', one_mo_corr,-1.0, False, 0, norb, 0, ncore, 0, ncore, 0, norb) one_mo.iadd(one_mo_corr, 1.0) #one_mo.iadd_t(one_mo_corr, 1.0) # # Store in smaller n-index objects # one_mo_small = one_mo.copy(ncore, ncore+nactive, ncore, ncore+nactive) two_mo_small = two_mo.copy(ncore, ncore+nactive, ncore, ncore+nactive, ncore, ncore+nactive, ncore, ncore+nactive) # Done return one_mo_small, two_mo_small, ecore