-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix "unsupported operand" issue when accessing IOData.charge #196
Changes from all commits
457851f
d85e9a9
54c5873
714b4aa
0ee5295
5f37b0d
2975c35
7ea9300
32559be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -114,7 +114,8 @@ class IOData: | |
e.g. for a wire. Two vectors describe a 2D cell, e.g. for a membrane. | ||
Three vectors describe a 3D cell, e.g. a crystalline solid. | ||
charge | ||
The net charge of the system. | ||
The net charge of the system. When possible, this is derived from | ||
atcorenums and nelec. | ||
core_energy | ||
The Hartree-Fock energy due to the core orbitals | ||
cube | ||
|
@@ -247,36 +248,66 @@ class IOData: | |
two_ints: dict = {} | ||
two_rdms: dict = {} | ||
|
||
def __attrs_post_init__(self): | ||
# Trigger setter to acchieve consistency in properties | ||
# atcorenums, nelec, charge, spinmult. This is needed because the | ||
# attr constructor bypasses the setters. See | ||
# https://www.attrs.org/en/stable/init.html#private-attributes | ||
if self._atcorenums is not None: | ||
self.atcorenums = self._atcorenums | ||
if self._charge is not None: | ||
self.charge = self._charge | ||
if self._nelec is not None: | ||
self.nelec = self._nelec | ||
if self._spinpol is not None: | ||
self.spinpol = self._spinpol | ||
|
||
# Public interfaces to private attributes | ||
|
||
@property | ||
def atcorenums(self) -> np.ndarray: | ||
"""Return effective core charges.""" | ||
result = self._atcorenums | ||
if result is None and self.atnums is not None: | ||
if self._atcorenums is None and self.atnums is not None: | ||
# Known bug in pylint. See | ||
# https://stackoverflow.com/questions/47972143/using-attr-with-pylint | ||
# https://github.com/PyCQA/pylint/issues/1694 | ||
# pylint: disable=no-member | ||
result = self.atnums.astype(float) | ||
self._atcorenums = result | ||
return result | ||
self.atcorenums = self.atnums.astype(float) | ||
return self._atcorenums | ||
|
||
@atcorenums.setter | ||
def atcorenums(self, atcorenums): | ||
self._atcorenums = atcorenums | ||
if atcorenums is None: | ||
if self.nelec is not None and self._atcorenums is not None: | ||
# Set _charge because charge can no longer be derived from | ||
# atcorenums and nelec. | ||
self._charge = self._atcorenums.sum() - self.nelec | ||
self._atcorenums = None | ||
else: | ||
if self._charge is not None: | ||
# _charge is treated as the dependent one, while atcorenums and | ||
# nelec are treated as independent. | ||
if self._nelec is None: | ||
# Switch to storing _nelec. | ||
self._nelec = atcorenums.sum() - self._charge | ||
self._charge = None | ||
self._atcorenums = np.asarray(atcorenums, dtype=float) | ||
|
||
@property | ||
def charge(self) -> float: | ||
"""Return the net charge of the system.""" | ||
if self.atcorenums is None: | ||
# The internal _charge is used only if it cannot be derived. | ||
if self.atcorenums is None or self.nelec is None: | ||
return self._charge | ||
return self.atcorenums.sum() - self.nelec | ||
|
||
@charge.setter | ||
def charge(self, charge: float): | ||
# The internal _charge is used only if atcorenums is None. | ||
if self.atcorenums is None: | ||
self._charge = charge | ||
elif charge is None: | ||
self.nelec = None | ||
else: | ||
self.nelec = self.atcorenums.sum() - charge | ||
|
||
|
@@ -286,8 +317,8 @@ def natom(self) -> int: | |
natom = None | ||
if self.atcoords is not None: | ||
natom = len(self.atcoords) | ||
elif self.atcorenums is not None: | ||
natom = len(self.atcorenums) | ||
elif self._atcorenums is not None: | ||
natom = len(self._atcorenums) | ||
elif self.atgradient is not None: | ||
natom = len(self.atgradient) | ||
elif self.atfrozen is not None: | ||
|
@@ -301,9 +332,11 @@ def natom(self) -> int: | |
@property | ||
def nelec(self) -> float: | ||
"""Return the number of electrons.""" | ||
if self.mo is None: | ||
return self._nelec | ||
return self.mo.nelec | ||
# When the molecular orbitals are present, they determine the number | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If a IOData object is created with only mol = IOData(charge=-1, atnums=[8, 1, 1])
print(mol.nelec) printing out mol = IOData(charge=-1, atnums=[8, 1, 1])
print(mol.atnumcores)
print(mol.nelec) Is this the correct behaviour, or should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, and there was a way to fix it. pfew. |
||
# of electrons. Only when mo is absent, we use a stored value. | ||
if self.mo is not None: | ||
return self.mo.nelec | ||
return self._nelec | ||
|
||
@nelec.setter | ||
def nelec(self, nelec: float): | ||
|
@@ -320,12 +353,14 @@ def spinpol(self) -> float: | |
number in ]0, 2[ implies spin polarizaiton, which may not always be a | ||
valid assumption. | ||
""" | ||
if self.mo is None: | ||
return self._spinpol | ||
return self.mo.spinpol | ||
if self.mo is not None: | ||
return self.mo.spinpol | ||
return self._spinpol | ||
|
||
@spinpol.setter | ||
def spinpol(self, spinpol: float): | ||
# When the molecular orbitals are present, they determine the spin | ||
# polarization. Only when mo is absent, we use a stored value. | ||
if self.mo is None: | ||
self._spinpol = spinpol | ||
else: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this line will raise an error if
nelec
was set beforeatcorenums
and the latter is set to None afterwards.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I'll add a unit test for this scenario, and make sure it works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You were right! It should be fixed now. I also found another minor issue with the dtype of atcorenums, which is fixed too.