Source code for pyscf.qmmm.mm_mole

#!/usr/bin/env python
# Copyright 2019 The PySCF Developers. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Qiming Sun <osirpt.sun@gmail.com>
#

'''
Mole class for MM particles
'''

import numpy
from pyscf import gto
from pyscf.gto.mole import is_au
from pyscf.data.elements import charge
from pyscf.lib import param

[docs] class Mole(gto.Mole): '''Mole class for MM particles. Args: atoms : geometry of MM particles (unit Bohr). | [[atom1, (x, y, z)], | [atom2, (x, y, z)], | ... | [atomN, (x, y, z)]] Kwargs: charges : 1D array fractional charges of MM particles zeta : 1D array Gaussian charge distribution parameter. rho(r) = charge * Norm * exp(-zeta * r^2) ''' def __init__(self, atoms, charges=None, zeta=None): gto.Mole.__init__(self) self.atom = self._atom = atoms self.unit = 'Bohr' self.charge_model = 'point' # Initialize ._atm and ._env to save the coordinates and charges and # other info of MM particles natm = len(atoms) _atm = numpy.zeros((natm,6), dtype=numpy.int32) _atm[:,gto.CHARGE_OF] = [charge(a[0]) for a in atoms] coords = numpy.asarray([a[1] for a in atoms], dtype=numpy.double) if charges is None: _atm[:,gto.NUC_MOD_OF] = gto.NUC_POINT charges = _atm[:,gto.CHARGE_OF:gto.CHARGE_OF+1] else: _atm[:,gto.NUC_MOD_OF] = gto.NUC_FRAC_CHARGE charges = numpy.asarray(charges)[:,numpy.newaxis] self._env = numpy.append(numpy.zeros(gto.PTR_ENV_START), numpy.hstack((coords, charges)).ravel()) _atm[:,gto.PTR_COORD] = gto.PTR_ENV_START + numpy.arange(natm) * 4 _atm[:,gto.PTR_FRAC_CHARGE] = gto.PTR_ENV_START + numpy.arange(natm) * 4 + 3 if zeta is not None: self.charge_model = 'gaussian' zeta = numpy.asarray(zeta, dtype=float).ravel() self._env = numpy.append(self._env, zeta) _atm[:,gto.PTR_ZETA] = gto.PTR_ENV_START + natm*4 + numpy.arange(natm) self._atm = _atm self._built = True
[docs] def get_zetas(self): if self.charge_model == 'gaussian': return self._env[self._atm[:,gto.PTR_ZETA]] else: return 1e16
[docs] def create_mm_mol(atoms_or_coords, charges=None, radii=None, unit='Angstrom'): '''Create an MM object based on the given coordinates and charges of MM particles. Args: atoms_or_coords : array-like Cartesian coordinates of MM atoms, in the form of a 2D array: [(x1, y1, z1), (x2, y2, z2), ...] Kwargs: charges : 1D array The charges of MM atoms. radii : 1D array The Gaussian charge distribution radii of MM atoms. unit : string The unit of the input. Default is 'Angstrom'. ''' if isinstance(atoms_or_coords, numpy.ndarray): # atoms_or_coords == np.array([(xx, xx, xx)]) # Patch ghost atoms atoms = [(0, c) for c in atoms_or_coords] elif (isinstance(atoms_or_coords, (list, tuple)) and atoms_or_coords and isinstance(atoms_or_coords[0][1], (int, float))): # atoms_or_coords == [(xx, xx, xx)] # Patch ghost atoms atoms = [(0, c) for c in atoms_or_coords] else: atoms = atoms_or_coords atoms = gto.format_atom(atoms, unit=unit) if radii is None: zeta = None else: radii = numpy.asarray(radii, dtype=float).ravel() if not is_au(unit): radii = radii / param.BOHR zeta = 1 / radii**2 return Mole(atoms, charges=charges, zeta=zeta)