Coverage for cclib/method/cda.py : 83%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2#
3# Copyright (c) 2017, the cclib development team
4#
5# This file is part of cclib (http://cclib.github.io) and is distributed under
6# the terms of the BSD 3-Clause License.
8"""Charge Decomposition Analysis (CDA)"""
10import random
12import numpy
14from cclib.method.fragments import FragmentAnalysis
17class CDA(FragmentAnalysis):
18 """Charge Decomposition Analysis (CDA)"""
20 def __init__(self, *args):
22 # Call the __init__ method of the superclass.
23 super(FragmentAnalysis, self).__init__(logname="CDA", *args)
25 def __str__(self):
26 """Return a string representation of the object."""
27 return "CDA of %s" % (self.data)
29 def __repr__(self):
30 """Return a representation of the object."""
31 return 'CDA("%s")' % (self.data)
33 def calculate(self, fragments, cupdate=0.05):
34 """Perform the charge decomposition analysis.
36 Inputs:
37 fragments - list of ccData data objects
38 """
41 retval = super(CDA, self).calculate(fragments, cupdate)
42 if not retval:
43 return False
45 # At this point, there should be a mocoeffs and fooverlaps
46 # in analogy to a ccData object.
48 donations = []
49 bdonations = []
50 repulsions = []
51 residuals = []
53 if len(self.mocoeffs) == 2:
54 occs = 1
55 else:
56 occs = 2
58 # Intialize progress if available.
59 nstep = self.data.homos[0]
60 if len(self.data.homos) == 2:
61 nstep += self.data.homos[1]
62 if self.progress:
63 self.progress.initialize(nstep)
65 # Begin the actual method.
66 step = 0
67 for spin in range(len(self.mocoeffs)):
69 size = len(self.mocoeffs[spin])
70 homo = self.data.homos[spin]
72 if len(fragments[0].homos) == 2:
73 homoa = fragments[0].homos[spin]
74 else:
75 homoa = fragments[0].homos[0]
77 if len(fragments[1].homos) == 2:
78 homob = fragments[1].homos[spin]
79 else:
80 homob = fragments[1].homos[0]
82 self.logger.info("handling spin unrestricted")
83 if spin == 0:
84 fooverlaps = self.fooverlaps
85 elif spin == 1 and hasattr(self, "fooverlaps2"):
86 fooverlaps = self.fooverlaps2
88 offset = fragments[0].nbasis
90 self.logger.info("Creating donations, bdonations, and repulsions: array[]")
91 donations.append(numpy.zeros(size, "d"))
92 bdonations.append(numpy.zeros(size, "d"))
93 repulsions.append(numpy.zeros(size, "d"))
94 residuals.append(numpy.zeros(size, "d"))
96 for i in range(self.data.homos[spin] + 1):
98 # Calculate donation for each MO.
99 for k in range(0, homoa + 1):
100 for n in range(offset + homob + 1, self.data.nbasis):
101 donations[spin][i] += 2 * occs * self.mocoeffs[spin][i,k] \
102 * self.mocoeffs[spin][i,n] * fooverlaps[k][n]
104 for l in range(offset, offset + homob + 1):
105 for m in range(homoa + 1, offset):
106 bdonations[spin][i] += 2 * occs * self.mocoeffs[spin][i,l] \
107 * self.mocoeffs[spin][i,m] * fooverlaps[l][m]
109 for k in range(0, homoa + 1):
110 for m in range(offset, offset+homob + 1):
111 repulsions[spin][i] += 2 * occs * self.mocoeffs[spin][i,k] \
112 * self.mocoeffs[spin][i, m] * fooverlaps[k][m]
114 for m in range(homoa + 1, offset):
115 for n in range(offset + homob + 1, self.data.nbasis):
116 residuals[spin][i] += 2 * occs * self.mocoeffs[spin][i,m] \
117 * self.mocoeffs[spin][i, n] * fooverlaps[m][n]
119 step += 1
120 if self.progress and random.random() < cupdate:
121 self.progress.update(step, "Charge Decomposition Analysis...")
123 if self.progress:
124 self.progress.update(nstep, "Done.")
126 self.donations = donations
127 self.bdonations = bdonations
128 self.repulsions = repulsions
129 self.residuals = residuals
131 return True