Exemplo n.º 1
0
    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.iteritems():
                    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)