1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
#!/usr/bin/env python3
# encoding: utf-8
"""
_IPOperator.py
Created by Graham Dennis on 2008-02-20.
Copyright (c) 2008-2012, Graham Dennis
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from xpdeint.Operators.Operator import Operator
from xpdeint.ParserException import ParserException, parserWarning
from xpdeint import CodeParser
from xpdeint.Utilities import lazy_property
class _IPOperator(Operator):
evaluateOperatorFunctionArguments = [('int', '_exponent')]
operatorKind = Operator.IPOperatorKind
expFunction = 'exp'
valueSuffix = ''
@lazy_property
def integrator(self):
# Our parent is an OperatorContainer, and its parent is the Integrator
return self.parent.parent
def preflight(self):
super(_IPOperator, self).preflight()
for operatorName in self.operatorNames:
self.operatorComponents[operatorName] = {}
sharedCodeBlock = self.parent.sharedCodeBlock
operatorTargetPairs = CodeParser.targetComponentsForOperatorsInString(self.operatorNames, sharedCodeBlock)
operatorNamesUsed = set()
operatorNames = set(self.operatorNames)
integrationVectors = self.parent.deltaAOperator.integrationVectors
field = self.field
legalTargetComponentNames = set()
for v in integrationVectors:
legalTargetComponentNames.update(v.components)
targetComponentNamesUsed = set()
indexAccessedVariables = None
# We loop over this in reverse order as we will be modifying the code string. So in order to not have to
# re-run targetComponentsForOperatorsInString after each modification, we loop over the operatorTargetPairs in
# reverse order so that slices (character index ranges) for earlier operator-target pairs don't change
for operatorName, target, codeSlice in reversed(operatorTargetPairs):
operatorNamesUsed.add(operatorName)
# Target is what is inside the square brackets in the integration code block
# As this is the IP operator, we have a few additional constraints
# Firstly, the targets must be of the form 'phi' or 'phi[j,k][m,n]'
# where j, k, m, n are the names of the integer dimension
if target in legalTargetComponentNames:
# Everything is OK
componentName = target
else:
if indexAccessedVariables == None:
indexAccessedVariables = CodeParser.nonlocalDimensionAccessForVectors(integrationVectors, sharedCodeBlock)
try:
# This will extract the componentName corresponding to the indexed variable in the target
# or it will fail because it isn't of that form.
componentName, resultDict = [(l[0], l[2]) for l in indexAccessedVariables if sharedCodeBlock.codeString[l[3]] == target][0]
except IndexError:
# Target didn't match something of the form 'phi[j, k][m+3,n-9]'
raise ParserException(self.xmlElement,
"IP operators can only act on components of integration vectors. "
"The '%(operatorName)s' operator acting on '%(target)s' doesn't seem to be of the right form "
"or '%(target)s' isn't in one of the integration vectors."
% locals())
# Check that nonlocally-accessed dimensions are being accessed with the dimension names
# i.e. of the form 'phi(j: j, k:k, m:m, n:n)' not 'phi(j: j-7, k: k*2, m: 3, n: n+1)'
for dimName, (indexString, codeSlice) in resultDict.items():
if not dimName == indexString:
raise ParserException(self.xmlElement,
"IP operators can only act on every value of a dimension. "
"The problem was caused by the '%(operatorName)s' operator acting on '%(target)s'. "
"EX operators do not have this restriction."
% locals())
if componentName in targetComponentNamesUsed:
raise ParserException(self.xmlElement,
"Check the documentation, only one IP operator can act on a given component, "
"and this operator can only appear once. "
"The problem was with the '%(componentName)s' term appearing more than once in an IP operator. "
"You may be able to accomplish what you are trying with an EX operator."
% locals())
targetComponentNamesUsed.add(componentName)
# Now we need to get the vector corresponding to componentName
tempVectorList = [v for v in integrationVectors if componentName in v.components]
assert len(tempVectorList) == 1
targetVector = tempVectorList[0]
# We have our match, now we need to create the operatorComponents dictionary
if not targetVector in self.operatorComponents[operatorName]:
self.operatorComponents[operatorName][targetVector] = [componentName]
else:
self.operatorComponents[operatorName][targetVector].append(componentName)
if targetVector.type == 'real':
self.operatorVector.type = 'real'
# Check the sanity of the integration code.
# i.e. check that we don't have something of the form:
# dy_dt = L[x].
# Obviously the user could hide this from us, but if we can check the most
# common case that frequently goes wrong, then we should.
CodeParser.performIPOperatorSanityCheck(componentName, self.propagationDimension, codeSlice, sharedCodeBlock)
# Replace the L[x] string with 0.0
sharedCodeBlock.codeString = sharedCodeBlock.codeString[:codeSlice.start] + '0.0' + sharedCodeBlock.codeString[codeSlice.stop:]
# If any operator names weren't used in the code, issue a warning
unusedOperatorNames = operatorNames.difference(operatorNamesUsed)
if unusedOperatorNames:
unusedOperatorNamesString = ', '.join(unusedOperatorNames)
parserWarning(self.xmlElement,
"The following operator names weren't used: %(unusedOperatorNamesString)s" % locals())
del self.functions['evaluate']
vectors = set(self.targetVectors)
self.registerVectorsRequiredInBasis(vectors, self.parent.ipOperatorBasis)
|