File: _EXOperator.py

package info (click to toggle)
xmds2 3.0.0%2Bdfsg-5
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 52,068 kB
  • sloc: python: 63,652; javascript: 9,230; cpp: 3,929; ansic: 1,463; makefile: 121; sh: 54
file content (136 lines) | stat: -rw-r--r-- 6,394 bytes parent folder | download | duplicates (3)
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
#!/usr/bin/env python3
# encoding: utf-8
"""
_EXOperator.py

Created by Graham Dennis on 2008-02-21.

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 parserWarning

from xpdeint import CodeParser

class _EXOperator(Operator):
  evaluateOperatorFunctionArguments = []
  
  operatorKind = Operator.OtherOperatorKind
  
  def preflight(self):
    super(_EXOperator, self).preflight()
    
    for operatorName in self.operatorNames:
      self.operatorComponents[operatorName] = {}
    
    operatorNamesUsed = set()
    operatorNames = set(self.operatorNames)
    sharedCodeBlock = self.parent.sharedCodeBlock
    
    operatorTargetPairs = CodeParser.targetComponentsForOperatorsInString(self.operatorNames, sharedCodeBlock)
    
    targetComponents = set()
    for vector in sharedCodeBlock.dependencies:
      targetComponents.update(vector.components)
    
    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 EX operator, we have fewer constraints.
      # If the target matches something of the form 'phi' or 'phi[j+3, k*k][m % 3, n]'
      # Then we don't need to use our result vector to make 'phi' available to the operator
      # If it doesn't match, then we have to assume that the expression is well formed, and
      # copy it into the result vector then fourier transform it into the space of the operator
      targetVector = None
      replacementStringSuffix = ''
      
      if target in targetComponents:
        targetComponentName = target
        # We have direct access to the component, so just work out which vector it belongs to
        # Now we need to get the vector corresponding to componentName
        tempVectorList = [v for v in sharedCodeBlock.dependencies if targetComponentName in v.components]
        assert len(tempVectorList) == 1
        targetVector = tempVectorList[0]
      else:
        # The target of our EX operator isn't a simple component.
        # In principle, this could be OK. We just need to construct the variable using the result vector.
        # If the user has made a mistake with their code, the compiler will barf, not xpdeint. This isn't ideal
        # but we can't understand an arbitrary string; that's what the compiler is for.
        
        targetComponentName = sharedCodeBlock.addCodeStringToSpecialTargetsVector(target, codeSlice)
        targetVector = sharedCodeBlock.specialTargetsVector
      
      # We have our match, now we need to create the operatorComponents dictionary
      if not operatorName in self.operatorComponents:
        self.operatorComponents[operatorName] = {}
      
      if not targetVector in self.operatorComponents[operatorName]:
        self.operatorComponents[operatorName][targetVector] = [targetComponentName]
      elif not targetComponentName in self.operatorComponents[operatorName][targetVector]:
        self.operatorComponents[operatorName][targetVector].append(targetComponentName)
      
      if targetVector.type == 'complex':
        for v in [self.operatorVector, self.resultVector]:
          if v: v.type = 'complex'
      
      # Set the replacement string for the L[x] operator
      replacementString = "_%(operatorName)s_%(targetComponentName)s" % locals()
        
      
      sharedCodeBlock.codeString = sharedCodeBlock.codeString[:codeSlice.start] + replacementString + 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 EX operator names were declared but not used: %(unusedOperatorNamesString)s" % locals())
    
    # Iterate over the operator components adding the appropriate bits to the resultVector, but do it in
    # the order of the components in the targetVectors to make it easier to optimise out an FFT.
    for operatorName, operatorDict in self.operatorComponents.items():
      for targetVector, targetVectorUsedComponents in operatorDict.items():
        for targetComponent in targetVector.components:
          if targetComponent in targetVectorUsedComponents:
            self.resultVector.components.append("_%(operatorName)s_%(targetComponent)s" % locals())
    
    if self.resultVector.nComponents == 0:
      self.resultVector.remove()
      self.resultVector = None
    
    # Add the result vector to the shared dependencies for the operator container
    # These dependencies are just the delta a dependencies, so this is just adding
    # our result vector to the dependencies for the delta a operator
    if self.resultVector:
      sharedCodeBlock.dependencies.add(self.resultVector)
    
    # If we are nonconstant then we need to add the target vectors to the dependencies of our primary code block
    if not 'calculateOperatorField' in self.functions:
      self.primaryCodeBlock.dependencies.update(self.targetVectors)
    
    vectors = set(self.targetVectors)
    vectors.add(self.resultVector)
    self.registerVectorsRequiredInBasis(vectors, self.operatorBasis)