From d08145b7887ca7ec0731733d60b696326abdb317 Mon Sep 17 00:00:00 2001 From: Chen Haoran Date: Sun, 19 Oct 2025 16:43:31 -0500 Subject: [PATCH 1/4] add dipole for neohf, and slightly modify Polarizability such that can calculate neo polarizability --- pyscf/neo/efield.py | 117 +++++++++++++++++++++++++++++----- pyscf/neo/hf.py | 31 ++++++++- pyscf/neo/test/test_efield.py | 24 ++++++- 3 files changed, 151 insertions(+), 21 deletions(-) diff --git a/pyscf/neo/efield.py b/pyscf/neo/efield.py index 0600bcb09f..a176d799d3 100644 --- a/pyscf/neo/efield.py +++ b/pyscf/neo/efield.py @@ -3,10 +3,12 @@ CNEO with electric field ''' import numpy +from pyscf import lib +from pyscf.lib import logger from pyscf.neo import cphf, CDFT from pyscf.neo.grad import Gradients from pyscf.neo.hessian import gen_vind -from pyscf import lib +from pyscf.neo.ks import KS def solve_mo1(mf, mo_energy, mo_coeff, mo_occ, h1ao=None, fx=None, atmlst=None, max_memory=4000, verbose=None, @@ -41,31 +43,61 @@ def solve_mo1(mf, mo_energy, mo_coeff, mo_occ, h1ao=None, return mo1, e1 -def polarizability(mf): - 'polarizability in CNEO' - +def polarizability(polobj,with_cphf=True): + log = logger.new_logger(polobj) + mf = polobj._scf + with_f1 = polobj.with_f1 mol = mf.mol - - mo1 = solve_mo1(mf, mf.mo_energy, mf.mo_coeff, mf.mo_occ)[0] + mo_energy = mf.mo_energy + mo_coeff = mf.mo_coeff + mo_occ = mf.mo_occ + #orbv = mo_coeff[:,~occidx] charges = mol.atom_charges() coords = mol.atom_coords() charge_center = numpy.einsum('i,ix->x', charges, coords) / charges.sum() + h1 = {} + s1 = {} + for t, comp in mf.components.items(): + with comp.mol.with_common_orig(charge_center): + int1e_r = comp.mol.intor_symmetric('int1e_r', comp=3) + occidx = mo_occ[t] > 0 + mocc = mo_coeff[t][:, occidx] + h1[t] = lib.einsum('xuv, ui, vj -> xij', int1e_r, mo_coeff[t], mocc) * comp.charge + s1[t] = numpy.zeros_like(h1[t]) + vind = polobj.gen_vind(mf, mo_coeff, mo_occ) + if with_cphf: + mo1 = cphf.solve(vind, mo_energy, mo_occ, h1, s1,with_f1=with_f1, + max_cycle=polobj.max_cycle_cphf,tol=polobj.conv_tol, + verbose=log)[0] + else: + raise NotImplementedError('without cphf is not implemented yet') + e2 = 0 + for t in mf.components.keys(): + if t == 'e': + e2 += 2*lib.einsum('xpi,ypi->xy', h1['e'], mo1['e']) #*2 for double occupancy + else: + ### if with_f1 is False, the contribution from quantum nuclei is included + if not with_f1 and t.startswith('n'): + e2 += lib.einsum('xpi,ypi->xy', h1[t], mo1[t]) + # *-1 from the definition of dipole moment. + e2 = (e2 + e2.T) * -1 + + if mf.verbose >= logger.INFO: + xx, yy, zz = e2.diagonal() + log.note('Isotropic polarizability %.12g', (xx+yy+zz)/3) + log.note('Polarizability anisotropy %.12g', + (.5 * ((xx-yy)**2 + (yy-zz)**2 + (zz-xx)**2))**.5) + log.debug('Static polarizability tensor\n%s', e2) + return e2 - with mol.components['e'].with_common_orig(charge_center): - int_r = mol.components['e'].intor_symmetric('int1e_r', comp=3) - mo_coeff = mf.components['e'].mo_coeff - mo_occ = mf.components['e'].mo_occ - mocc = mo_coeff[:, mo_occ>0] - h1 = numpy.einsum('xpq,pi,qj->xij', int_r, mo_coeff, mocc) +def hyper_polarizability(polobj, with_cphf=True): + return NotImplementedError('hyperpolarizability is not implemented yet') - e2 = numpy.einsum('xpi,ypi->xy', h1, mo1['e']) - # *-1 from the definition of dipole moment. *2 for double occupancy - e2 = (e2 + e2.T) * -2 - - return e2 +def polarizability_with_freq(polobj, freq, with_cphf=True): + return NotImplementedError('frequency-dependent polarizability is not implemented yet') def dipole_grad(mf): @@ -201,6 +233,57 @@ def grad_nuc(self, atmlst=None): SCFwithEfield.Gradients = lib.class_as_method(GradwithEfield) +class NEOwithEfield(KS): + '''NEO with electric field''' + _keys = {'efield'} + + def __init__(self, mol, *args, **kwargs): + KS.__init__(self, mol, *args, **kwargs) + self.efield = numpy.array([0, 0, 0]) + self.mol = mol + + def get_hcore(self, mol=None): + if mol is None: mol = self.mol + hcore = {} + for t, comp in mol.components.items(): + hcore[t] = self.components[t].get_hcore(mol=comp) + comp.set_common_orig([0, 0, 0]) # The gauge origin for dipole integral + hcore[t] += numpy.einsum('x,xij->ij', self.efield, comp.intor('int1e_r', comp=3)) * self.components[t].charge + + return hcore + + def energy_nuc(self): + enuc = self.components['e'].energy_nuc() + + nuclear_charges = self.mol.components['e'].atom_charges() + nuclear_coords = self.mol.atom_coords() + + E_nuc_field = -numpy.sum([Z * numpy.dot(self.efield, R) for Z, R in zip(nuclear_charges, nuclear_coords)]) + + return enuc + E_nuc_field + +class Polarizability(lib.StreamObject): + def __init__(self, mf): + mol = mf.mol + self.mol = mol + self.verbose = mol.verbose + self.stdout = mol.stdout + self._scf = mf + + self.with_f1 = True # True for CNEO, False for NEO + self.max_cycle_cphf = 100 + ### default: 1e-5 is already enough + self.conv_tol = 1e-5 + + self._keys = set(self.__dict__.keys()) + + def gen_vind(self, mf, mo_coeff, mo_occ): + return gen_vind(mf, mo_coeff, mo_occ) + + polarizability = polarizability + polarizability_with_freq = polarizability_with_freq + hyper_polarizability = hyper_polarizability + if __name__ == '__main__': from pyscf import neo mol = neo.M(atom='H 0 0 0; F 0 0 0.8', basis='ccpvdz') diff --git a/pyscf/neo/hf.py b/pyscf/neo/hf.py index ac20331546..888f5ecf9a 100644 --- a/pyscf/neo/hf.py +++ b/pyscf/neo/hf.py @@ -1425,7 +1425,36 @@ def canonicalize(self, mo_coeff, mo_occ, fock=None): def dip_moment(self, mol=None, dm=None, unit='Debye', origin=None, verbose=logger.NOTE, **kwargs): - raise TypeError('Use CDFT to calculate total dipole moment.') # CDFT will have this + if mol is None: mol = self.mol + if dm is None: dm = self.make_rdm1() + log = logger.new_logger(mol, verbose) + + # Suppress warning about nonzero charge (if neutral) + charge = self.components['e'].mol.charge + self.components['e'].mol.charge = self.mol.charge + el_dip = self.components['e'].dip_moment(mol.components['e'], + dm['e'], unit=unit, + origin=origin, verbose=verbose-1) + self.components['e'].mol.charge = charge + + # Quantum nuclei + if origin is None: + origin = numpy.zeros(3) + else: + origin = numpy.asarray(origin, dtype=numpy.float64) + assert origin.shape == (3,) + nucl_dip = 0 + for t, comp in self.components.items(): + if t.startswith('n'): + nucl_dip -= comp.charge * (lib.einsum('xij,ji->x', comp.mol.intor_symmetric('int1e_r', comp=3), dm[t]) - origin) + if unit.upper() == 'DEBYE': + nucl_dip *= nist.AU2DEBYE + mol_dip = nucl_dip + el_dip + log.note('Dipole moment(X, Y, Z, Debye): %8.5f, %8.5f, %8.5f', *mol_dip) + else: + mol_dip = nucl_dip + el_dip + log.note('Dipole moment(X, Y, Z, A.U.): %8.5f, %8.5f, %8.5f', *mol_dip) + return mol_dip def quad_moment(self, mol=None, dm=None, unit='DebyeAngstrom', origin=None, verbose=logger.NOTE, **kwargs): diff --git a/pyscf/neo/test/test_efield.py b/pyscf/neo/test/test_efield.py index af9c2ad14e..d77a2e66d5 100644 --- a/pyscf/neo/test/test_efield.py +++ b/pyscf/neo/test/test_efield.py @@ -3,7 +3,7 @@ import unittest import numpy from pyscf import neo, lib, scf -from pyscf.neo.efield import polarizability, dipole_grad, SCFwithEfield, GradwithEfield +from pyscf.neo.efield import Polarizability, dipole_grad, SCFwithEfield, GradwithEfield, NEOwithEfield class KnownValues(unittest.TestCase): @@ -51,10 +51,11 @@ def test_dipole_grad(self): def test_polarizability(self): - mol = neo.M(atom='H 0 0 0; F 0 0 0.9', basis='ccpvdz') + mol = neo.M(atom='H 0 0 0; F 0 0 0.9', basis='ccpvdz', quantum_nuc=['H']) mf = neo.CDFT(mol, xc='b3lyp') mf.run() - p = polarizability(mf) + polobj = Polarizability(mf) + p = polobj.polarizability() mf1 = SCFwithEfield(mol, xc='b3lyp') mf1.efield = numpy.array([0, 0, 0.001]) @@ -66,7 +67,24 @@ def test_polarizability(self): mf2.scf() dipole2 = mf2.dip_moment(unit='au') + mf5 = neo.KS(mol,xc='b3lyp') + mf5.run() + polobj1 = Polarizability(mf5) + polobj1.with_f1 = False + p1 = polobj1.polarizability() + + mf3 = NEOwithEfield(mol, xc='b3lyp') + mf3.efield = numpy.array([0, 0, 0.001]) + mf3.scf() + dipole3 = mf3.dip_moment(unit='au') + + mf4 = NEOwithEfield(mol, xc='b3lyp') + mf4.efield = numpy.array([0, 0, -0.001]) + mf4.scf() + dipole4 = mf4.dip_moment(unit='au') + self.assertAlmostEqual(p[-1,-1], (dipole1[-1] - dipole2[-1]) / 0.002, 4) + self.assertAlmostEqual(p1[-1,-1], (dipole3[-1] - dipole4[-1]) / 0.002, 4) def test_grad_with_efield(self): mol = neo.M(atom='H 0 0 0; F 0 0 0.8', basis='ccpvdz') From e9ba4925fbdb22185df88c7369464683c03eef9c Mon Sep 17 00:00:00 2001 From: Chen Haoran Date: Fri, 31 Oct 2025 17:50:13 -0500 Subject: [PATCH 2/4] Polarizability class for NEO and CNEO; add dipole to neo.HF --- pyscf/neo/efield.py | 46 ++++++++++++++++++++++++++--------- pyscf/neo/hf.py | 34 ++++++++++++-------------- pyscf/neo/test/test_efield.py | 13 +++++----- 3 files changed, 57 insertions(+), 36 deletions(-) diff --git a/pyscf/neo/efield.py b/pyscf/neo/efield.py index a176d799d3..2400624e26 100644 --- a/pyscf/neo/efield.py +++ b/pyscf/neo/efield.py @@ -43,7 +43,7 @@ def solve_mo1(mf, mo_energy, mo_coeff, mo_occ, h1ao=None, return mo1, e1 -def polarizability(polobj,with_cphf=True): +def polarizability(polobj, with_cphf=True): log = logger.new_logger(polobj) mf = polobj._scf with_f1 = polobj.with_f1 @@ -51,7 +51,6 @@ def polarizability(polobj,with_cphf=True): mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ - #orbv = mo_coeff[:,~occidx] charges = mol.atom_charges() coords = mol.atom_coords() @@ -62,24 +61,24 @@ def polarizability(polobj,with_cphf=True): with comp.mol.with_common_orig(charge_center): int1e_r = comp.mol.intor_symmetric('int1e_r', comp=3) occidx = mo_occ[t] > 0 - mocc = mo_coeff[t][:, occidx] - h1[t] = lib.einsum('xuv, ui, vj -> xij', int1e_r, mo_coeff[t], mocc) * comp.charge + orbo = mo_coeff[t][:, occidx] + h1[t] = lib.einsum('xpq, pi, qj -> xij', int1e_r, mo_coeff[t], orbo) * comp.charge s1[t] = numpy.zeros_like(h1[t]) vind = polobj.gen_vind(mf, mo_coeff, mo_occ) if with_cphf: - mo1 = cphf.solve(vind, mo_energy, mo_occ, h1, s1,with_f1=with_f1, - max_cycle=polobj.max_cycle_cphf,tol=polobj.conv_tol, + mo1 = cphf.solve(vind, mo_energy, mo_occ, h1, s1, with_f1=with_f1, + max_cycle=polobj.max_cycle_cphf, tol=polobj.conv_tol, verbose=log)[0] else: raise NotImplementedError('without cphf is not implemented yet') e2 = 0 for t in mf.components.keys(): if t == 'e': - e2 += 2*lib.einsum('xpi,ypi->xy', h1['e'], mo1['e']) #*2 for double occupancy + e2 += 2*numpy.einsum('xpi,ypi->xy', h1['e'], mo1['e']) #*2 for double occupancy else: ### if with_f1 is False, the contribution from quantum nuclei is included if not with_f1 and t.startswith('n'): - e2 += lib.einsum('xpi,ypi->xy', h1[t], mo1[t]) + e2 += numpy.einsum('xpi,ypi->xy', h1[t], mo1[t]) # *-1 from the definition of dipole moment. e2 = (e2 + e2.T) * -1 @@ -238,7 +237,7 @@ class NEOwithEfield(KS): _keys = {'efield'} def __init__(self, mol, *args, **kwargs): - KS.__init__(self, mol, *args, **kwargs) + super().__init__(mol, *args, **kwargs) self.efield = numpy.array([0, 0, 0]) self.mol = mol @@ -269,10 +268,35 @@ def __init__(self, mf): self.verbose = mol.verbose self.stdout = mol.stdout self._scf = mf - - self.with_f1 = True # True for CNEO, False for NEO + if isinstance(mf, CDFT): + self.with_f1 = True + else: + self.with_f1 = False self.max_cycle_cphf = 100 ### default: 1e-5 is already enough + """ + >>> from pyscf import neo + >>> from pyscf.lib import param + >>> from pyscf.neo.efield import Polarizability + >>> mol = neo.M(atom='H 0 0 0; F 0 0 0.8', basis='ccpvtz') + >>> mf = neo.CDFT(mol, xc='b3lyp') + >>> mf.kernel() + converged SCF energy = -100.414287028652 + np.float64(-100.4142870286517) + >>> pol = neo.Polarizability(mf) + >>> pol.conv_tol = 1e-5 + >>> pol.polarizability()*param.BOHR**3 + array([[ 4.06325330e-01, -1.24910351e-14, 6.32660972e-16], + [-1.24910351e-14, 4.06325330e-01, 9.83876264e-16], + [ 6.32660972e-16, 9.83876264e-16, 6.49102044e-01]]) + >>> pol.conv_tol = 1e-9 + >>> pol.polarizability()*param.BOHR**3 + array([[ 4.06325340e-01, -2.43939181e-14, 6.35205528e-16], + [-2.43939181e-14, 4.06325340e-01, 9.81337957e-16], + [ 6.35205528e-16, 9.81337957e-16, 6.49102043e-01]]) + Experimental uncertainty is generally 1e-3 angstrom^3. 1e-5 and 1e-9 conv_tol + differ by 1e-7 angstrom^3 for the first component, so 1e-5 of conv_tol is enough. + """ self.conv_tol = 1e-5 self._keys = set(self.__dict__.keys()) diff --git a/pyscf/neo/hf.py b/pyscf/neo/hf.py index 888f5ecf9a..0bb2a5b992 100644 --- a/pyscf/neo/hf.py +++ b/pyscf/neo/hf.py @@ -493,12 +493,20 @@ def mulliken_meta(self, mol=None, dm=None, verbose=logger.DEBUG, def dip_moment(self, mol=None, dm=None, unit='Debye', origin=None, verbose=logger.NOTE, **kwargs): if self.is_nucleus: - return None + if origin is None: + origin = numpy.zeros(3) + else: + origin = numpy.asarray(origin, dtype=numpy.float64) + assert origin.shape == (3,) + dip = -self.charge * (lib.einsum('xij,ji->x', self.mol.intor_symmetric('int1e_r', comp=3), dm) - origin) + if unit.upper() == 'DEBYE': + dip *= nist.AU2DEBYE # Temporarily modify charge to supress warning about nonzero charge for a neutral molecule - charge = self.mol.charge - self.mol.charge = self.mol.super_mol.charge - dip = super().dip_moment(mol, dm, unit, origin=origin, verbose=verbose, **kwargs) - self.mol.charge = charge + else: + charge = self.mol.charge + self.mol.charge = self.mol.super_mol.charge + dip = super().dip_moment(mol, dm, unit, origin=origin, verbose=verbose, **kwargs) + self.mol.charge = charge return dip def to_gpu(self): @@ -1438,22 +1446,12 @@ def dip_moment(self, mol=None, dm=None, unit='Debye', origin=None, self.components['e'].mol.charge = charge # Quantum nuclei - if origin is None: - origin = numpy.zeros(3) - else: - origin = numpy.asarray(origin, dtype=numpy.float64) - assert origin.shape == (3,) nucl_dip = 0 for t, comp in self.components.items(): if t.startswith('n'): - nucl_dip -= comp.charge * (lib.einsum('xij,ji->x', comp.mol.intor_symmetric('int1e_r', comp=3), dm[t]) - origin) - if unit.upper() == 'DEBYE': - nucl_dip *= nist.AU2DEBYE - mol_dip = nucl_dip + el_dip - log.note('Dipole moment(X, Y, Z, Debye): %8.5f, %8.5f, %8.5f', *mol_dip) - else: - mol_dip = nucl_dip + el_dip - log.note('Dipole moment(X, Y, Z, A.U.): %8.5f, %8.5f, %8.5f', *mol_dip) + nucl_dip += comp.dip_moment(mol.components[t], dm[t], unit=unit, origin=origin, verbose=verbose-1) + mol_dip = nucl_dip + el_dip + log.note('Dipole moment(X, Y, Z, Debye): %8.5f, %8.5f, %8.5f', *mol_dip) return mol_dip def quad_moment(self, mol=None, dm=None, unit='DebyeAngstrom', origin=None, diff --git a/pyscf/neo/test/test_efield.py b/pyscf/neo/test/test_efield.py index d77a2e66d5..38e0df8676 100644 --- a/pyscf/neo/test/test_efield.py +++ b/pyscf/neo/test/test_efield.py @@ -52,9 +52,9 @@ def test_dipole_grad(self): def test_polarizability(self): mol = neo.M(atom='H 0 0 0; F 0 0 0.9', basis='ccpvdz', quantum_nuc=['H']) - mf = neo.CDFT(mol, xc='b3lyp') - mf.run() - polobj = Polarizability(mf) + mfCNEO = neo.CDFT(mol, xc='b3lyp') + mfCNEO.run() + polobj = Polarizability(mfCNEO) p = polobj.polarizability() mf1 = SCFwithEfield(mol, xc='b3lyp') @@ -67,10 +67,9 @@ def test_polarizability(self): mf2.scf() dipole2 = mf2.dip_moment(unit='au') - mf5 = neo.KS(mol,xc='b3lyp') - mf5.run() - polobj1 = Polarizability(mf5) - polobj1.with_f1 = False + mfNEO = neo.KS(mol,xc='b3lyp') + mfNEO.run() + polobj1 = Polarizability(mfNEO) p1 = polobj1.polarizability() mf3 = NEOwithEfield(mol, xc='b3lyp') From 11ba673aa05f01f864b4f1eac840481b706f4b92 Mon Sep 17 00:00:00 2001 From: Chen Haoran Date: Thu, 6 Nov 2025 20:43:31 -0600 Subject: [PATCH 3/4] Fix trailing whitespace in neo/efield.py and test_efield.py --- pyscf/neo/efield.py | 44 ++++++++--------------------------- pyscf/neo/test/test_efield.py | 2 +- 2 files changed, 11 insertions(+), 35 deletions(-) diff --git a/pyscf/neo/efield.py b/pyscf/neo/efield.py index 2400624e26..e3395a4597 100644 --- a/pyscf/neo/efield.py +++ b/pyscf/neo/efield.py @@ -62,7 +62,7 @@ def polarizability(polobj, with_cphf=True): int1e_r = comp.mol.intor_symmetric('int1e_r', comp=3) occidx = mo_occ[t] > 0 orbo = mo_coeff[t][:, occidx] - h1[t] = lib.einsum('xpq, pi, qj -> xij', int1e_r, mo_coeff[t], orbo) * comp.charge + h1[t] = lib.einsum('xpq,pi,qj->xij', int1e_r, mo_coeff[t], orbo) * comp.charge s1[t] = numpy.zeros_like(h1[t]) vind = polobj.gen_vind(mf, mo_coeff, mo_occ) if with_cphf: @@ -76,9 +76,9 @@ def polarizability(polobj, with_cphf=True): if t == 'e': e2 += 2*numpy.einsum('xpi,ypi->xy', h1['e'], mo1['e']) #*2 for double occupancy else: - ### if with_f1 is False, the contribution from quantum nuclei is included + ### if with_f1 is False, the contribution from quantum nuclei is included if not with_f1 and t.startswith('n'): - e2 += numpy.einsum('xpi,ypi->xy', h1[t], mo1[t]) + e2 += numpy.einsum('xpi,ypi->xy', h1[t], mo1[t]) # *-1 from the definition of dipole moment. e2 = (e2 + e2.T) * -1 @@ -240,7 +240,7 @@ def __init__(self, mol, *args, **kwargs): super().__init__(mol, *args, **kwargs) self.efield = numpy.array([0, 0, 0]) self.mol = mol - + def get_hcore(self, mol=None): if mol is None: mol = self.mol hcore = {} @@ -250,12 +250,12 @@ def get_hcore(self, mol=None): hcore[t] += numpy.einsum('x,xij->ij', self.efield, comp.intor('int1e_r', comp=3)) * self.components[t].charge return hcore - + def energy_nuc(self): enuc = self.components['e'].energy_nuc() - nuclear_charges = self.mol.components['e'].atom_charges() - nuclear_coords = self.mol.atom_coords() + nuclear_charges = self.mol.components['e'].atom_charges() + nuclear_coords = self.mol.atom_coords() E_nuc_field = -numpy.sum([Z * numpy.dot(self.efield, R) for Z, R in zip(nuclear_charges, nuclear_coords)]) @@ -273,33 +273,9 @@ def __init__(self, mf): else: self.with_f1 = False self.max_cycle_cphf = 100 - ### default: 1e-5 is already enough - """ - >>> from pyscf import neo - >>> from pyscf.lib import param - >>> from pyscf.neo.efield import Polarizability - >>> mol = neo.M(atom='H 0 0 0; F 0 0 0.8', basis='ccpvtz') - >>> mf = neo.CDFT(mol, xc='b3lyp') - >>> mf.kernel() - converged SCF energy = -100.414287028652 - np.float64(-100.4142870286517) - >>> pol = neo.Polarizability(mf) - >>> pol.conv_tol = 1e-5 - >>> pol.polarizability()*param.BOHR**3 - array([[ 4.06325330e-01, -1.24910351e-14, 6.32660972e-16], - [-1.24910351e-14, 4.06325330e-01, 9.83876264e-16], - [ 6.32660972e-16, 9.83876264e-16, 6.49102044e-01]]) - >>> pol.conv_tol = 1e-9 - >>> pol.polarizability()*param.BOHR**3 - array([[ 4.06325340e-01, -2.43939181e-14, 6.35205528e-16], - [-2.43939181e-14, 4.06325340e-01, 9.81337957e-16], - [ 6.35205528e-16, 9.81337957e-16, 6.49102043e-01]]) - Experimental uncertainty is generally 1e-3 angstrom^3. 1e-5 and 1e-9 conv_tol - differ by 1e-7 angstrom^3 for the first component, so 1e-5 of conv_tol is enough. - """ - self.conv_tol = 1e-5 - - self._keys = set(self.__dict__.keys()) + self.conv_tol = 1e-9 + + self._keys = set(self.__dict__.keys()) def gen_vind(self, mf, mo_coeff, mo_occ): return gen_vind(mf, mo_coeff, mo_occ) diff --git a/pyscf/neo/test/test_efield.py b/pyscf/neo/test/test_efield.py index 38e0df8676..00ee1bfc30 100644 --- a/pyscf/neo/test/test_efield.py +++ b/pyscf/neo/test/test_efield.py @@ -81,7 +81,7 @@ def test_polarizability(self): mf4.efield = numpy.array([0, 0, -0.001]) mf4.scf() dipole4 = mf4.dip_moment(unit='au') - + self.assertAlmostEqual(p[-1,-1], (dipole1[-1] - dipole2[-1]) / 0.002, 4) self.assertAlmostEqual(p1[-1,-1], (dipole3[-1] - dipole4[-1]) / 0.002, 4) From 09dabe0ffbe929bebc56b2eccd7241957290c135 Mon Sep 17 00:00:00 2001 From: Chen Haoran Date: Thu, 6 Nov 2025 20:56:21 -0600 Subject: [PATCH 4/4] Fix line length issue in neo/efield.py (E501) --- pyscf/neo/efield.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyscf/neo/efield.py b/pyscf/neo/efield.py index e3395a4597..0b3d3aa4b2 100644 --- a/pyscf/neo/efield.py +++ b/pyscf/neo/efield.py @@ -247,7 +247,9 @@ def get_hcore(self, mol=None): for t, comp in mol.components.items(): hcore[t] = self.components[t].get_hcore(mol=comp) comp.set_common_orig([0, 0, 0]) # The gauge origin for dipole integral - hcore[t] += numpy.einsum('x,xij->ij', self.efield, comp.intor('int1e_r', comp=3)) * self.components[t].charge + hcore[t] += (numpy.einsum('x,xij->ij', self.efield, + comp.intor('int1e_r', comp=3)) + * self.components[t].charge) return hcore