Coverage for cclib/method/fragments.py : 70%
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"""Fragment analysis based on parsed ADF data."""
10import logging
11import random
13import numpy
14numpy.inv = numpy.linalg.inv
16from cclib.method.calculationmethod import Method
19class FragmentAnalysis(Method):
20 """Convert a molecule's basis functions from atomic-based to fragment MO-based"""
21 def __init__(self, data, progress=None, loglevel=logging.INFO,
22 logname="FragmentAnalysis of"):
24 # Call the __init__ method of the superclass.
25 super(FragmentAnalysis, self).__init__(data, progress, loglevel, logname)
26 self.parsed = False
28 def __str__(self):
29 """Return a string representation of the object."""
30 return "Fragment molecule basis of %s" % (self.data)
32 def __repr__(self):
33 """Return a representation of the object."""
34 return 'Fragment molecular basis("%s")' % (self.data)
36 def calculate(self, fragments, cupdate=0.05):
38 nFragBasis = 0
39 nFragAlpha = 0
40 nFragBeta = 0
41 self.fonames = []
43 unrestricted = ( len(self.data.mocoeffs) == 2 )
45 self.logger.info("Creating attribute fonames[]")
47 # Collect basis info on the fragments.
48 for j in range(len(fragments)):
49 nFragBasis += fragments[j].nbasis
50 nFragAlpha += fragments[j].homos[0] + 1
51 if unrestricted and len(fragments[j].homos) == 1:
52 nFragBeta += fragments[j].homos[0] + 1 #assume restricted fragment
53 elif unrestricted and len(fragments[j].homos) == 2:
54 nFragBeta += fragments[j].homos[1] + 1 #assume unrestricted fragment
56 #assign fonames based on fragment name and MO number
57 for i in range(fragments[j].nbasis):
58 if hasattr(fragments[j],"name"):
59 self.fonames.append("%s_%i"%(fragments[j].name,i+1))
60 else:
61 self.fonames.append("noname%i_%i"%(j,i+1))
63 nBasis = self.data.nbasis
64 nAlpha = self.data.homos[0] + 1
65 if unrestricted:
66 nBeta = self.data.homos[1] + 1
68 # Check to make sure calcs have the right properties.
69 if nBasis != nFragBasis:
70 self.logger.error("Basis functions don't match")
71 return False
73 if nAlpha != nFragAlpha:
74 self.logger.error("Alpha electrons don't match")
75 return False
77 if unrestricted and nBeta != nFragBeta:
78 self.logger.error("Beta electrons don't match")
79 return False
81 if len(self.data.atomcoords) != 1:
82 self.logger.warning("Molecule calc appears to be an optimization")
84 for frag in fragments:
85 if len(frag.atomcoords) != 1:
86 msg = "One or more fragment appears to be an optimization"
87 self.logger.warning(msg)
88 break
90 last = 0
91 for frag in fragments:
92 size = frag.natom
93 if self.data.atomcoords[0][last:last+size].tolist() != \
94 frag.atomcoords[0].tolist():
95 self.logger.error("Atom coordinates aren't aligned")
96 return False
97 if self.data.atomnos[last:last+size].tolist() != \
98 frag.atomnos.tolist():
99 self.logger.error("Elements don't match")
100 return False
102 last += size
104 # And let's begin!
105 self.mocoeffs = []
106 self.logger.info("Creating mocoeffs in new fragment MO basis: mocoeffs[]")
108 for spin in range(len(self.data.mocoeffs)):
109 blockMatrix = numpy.zeros((nBasis,nBasis), "d")
110 pos = 0
112 # Build up block-diagonal matrix from fragment mocoeffs.
113 # Need to switch ordering from [mo,ao] to [ao,mo].
114 for i in range(len(fragments)):
115 size = fragments[i].nbasis
116 if len(fragments[i].mocoeffs) == 1:
117 temp = numpy.transpose(fragments[i].mocoeffs[0])
118 blockMatrix[pos:pos+size, pos:pos+size] = temp
119 else:
120 temp = numpy.transpose(fragments[i].mocoeffs[spin])
121 blockMatrix[pos:pos+size, pos:pos+size] = temp
122 pos += size
124 # Invert and mutliply to result in fragment MOs as basis.
125 iBlockMatrix = numpy.inv(blockMatrix)
126 temp = numpy.transpose(self.data.mocoeffs[spin])
127 results = numpy.transpose(numpy.dot(iBlockMatrix, temp))
129 self.mocoeffs.append(results)
131 if hasattr(self.data, "aooverlaps"):
132 tempMatrix = numpy.dot(self.data.aooverlaps, blockMatrix)
133 tBlockMatrix = numpy.transpose(blockMatrix)
134 if spin == 0:
135 self.fooverlaps = numpy.dot(tBlockMatrix, tempMatrix)
136 self.logger.info("Creating fooverlaps: array[x,y]")
137 elif spin == 1:
138 self.fooverlaps2 = numpy.dot(tBlockMatrix, tempMatrix)
139 self.logger.info("Creating fooverlaps (beta): array[x,y]")
140 else:
141 self.logger.warning("Overlap matrix missing")
143 self.parsed = True
144 self.nbasis = nBasis
145 self.homos = self.data.homos
147 return True