Skip to content

Commit

Permalink
Update molecule.py
Browse files Browse the repository at this point in the history
  • Loading branch information
loriab authored Dec 18, 2024
1 parent 9d22d45 commit b8deeeb
Showing 1 changed file with 82 additions and 4 deletions.
86 changes: 82 additions & 4 deletions qcelemental/models/molecule.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
Molecule Object Model
"""

import collections
import hashlib
import json
import warnings
Expand Down Expand Up @@ -875,6 +875,10 @@ def get_molecular_formula(self, order: str = "alphabetical", chgmult: bool = Fal
>>> two_pentanol_radcat.get_molecular_formula(chgmult=True)
2^C5H12O+
Notes
-----
This includes all atoms in the molecule, including ghost atoms. See :py:meth:`element_composition` to exclude.
"""

from ..molutil import molecular_formula_from_symbols
Expand Down Expand Up @@ -1151,13 +1155,15 @@ def _inertial_tensor(geom, *, weight):
tensor[2][1] = tensor[1][2] = -1.0 * np.sum(weight * geom[:, 1] * geom[:, 2])
return tensor

def nuclear_repulsion_energy(self, ifr: int = None) -> float:
def nuclear_repulsion_energy(self, ifr: int = None, real_only: bool = True) -> float:
r"""Nuclear repulsion energy.
Parameters
----------
ifr
If not `None`, only compute for the `ifr`-th (0-indexed) fragment.
real_only
Only include real atoms in the sum.
Returns
-------
Expand All @@ -1166,6 +1172,10 @@ def nuclear_repulsion_energy(self, ifr: int = None) -> float:
"""
Zeff = [z * int(real) for z, real in zip(cast(Iterable[int], self.atomic_numbers), self.real)]

Check warning

Code scanning / CodeQL

Variable defined multiple times Warning

This assignment to 'Zeff' is unnecessary as it is
redefined
before this value is used.
This assignment to 'Zeff' is unnecessary as it is
redefined
before this value is used.
if real_only:
Zeff = [z * int(real) for z, real in zip(cast(Iterable[int], self.atomic_numbers), self.real)]
else:
Zeff = self.atomic_numbers
atoms = list(range(self.geometry.shape[0]))

if ifr is not None:
Expand All @@ -1178,21 +1188,26 @@ def nuclear_repulsion_energy(self, ifr: int = None) -> float:
nre += Zeff[at1] * Zeff[at2] / dist
return nre

def nelectrons(self, ifr: int = None) -> int:
def nelectrons(self, ifr: int = None, real_only: bool = True) -> int:
r"""Number of electrons.
Parameters
----------
ifr
If not `None`, only compute for the `ifr`-th (0-indexed) fragment.
real_only
Only include real atoms in the sum.
Returns
-------
nelec : int
Number of electrons in entire molecule or in fragment.
"""
Zeff = [z * int(real) for z, real in zip(cast(Iterable[int], self.atomic_numbers), self.real)]
if real_only:
Zeff = [z * int(real) for z, real in zip(cast(Iterable[int], self.atomic_numbers), self.real)]
else:
Zeff = self.atomic_numbers

if ifr is None:
nel = sum(Zeff) - self.molecular_charge
Expand All @@ -1202,6 +1217,69 @@ def nelectrons(self, ifr: int = None) -> int:

return int(nel)

def molecular_weight(self, ifr: int = None, real_only: bool = True) -> float:
r"""Molecular weight in uamu.
Parameters
----------
ifr
If not `None`, only compute for the `ifr`-th (0-indexed) fragment.
real_only
Only include real atoms in the sum.
Returns
-------
mw : float
Molecular weight in entire molecule or in fragment.
"""
if real_only:
masses = [mas * int(real) for mas, real in zip(cast(Iterable[float], self.masses), self.real)]
else:
masses = self.masses

if ifr is None:
mw = sum(masses)

else:
mw = sum([mas for iat, mas in enumerate(masses) if iat in self.fragments[ifr]])

return mw

def element_composition(self, ifr: int = None, real_only: bool = True) -> Dict[str, int]:
r"""Atomic count map.
Parameters
----------
ifr
If not `None`, only compute for the `ifr`-th (0-indexed) fragment.
real_only
Only include real atoms.
Returns
-------
composition : Dict[str, int]
Atomic count map.
Notes
-----
This excludes ghost atoms by default whereas get_molecular_formula always includes them.
"""
if real_only:
symbols = [sym * int(real) for sym, real in zip(cast(Iterable[str], self.symbols), self.real)]
else:
symbols = self.symbols

if ifr is None:
count = collections.Counter(sym.title() for sym in symbols)

else:
count = collections.Counter(sym.title() for iat, sym in enumerate(symbols) if iat in self.fragments[ifr])

count.pop("", None)
return dict(count)

def align(
self,
ref_mol: "Molecule",
Expand Down

0 comments on commit b8deeeb

Please sign in to comment.