274 Inline structure member accesses in compute statements.
276 Converts TYPE%VAR access patterns into single local variables
277 to improve performance by reducing pointer dereferences.
279 Transformation Examples
280 ----------------------
281 Simple member access:
282 - ZA = 1 + CST%XG => ZA = 1 + XCST_G
285 - ZA = 1 + PARAM_ICE%XRTMIN(3) => ZA = 1 + XPARAM_ICE_XRTMIN3
288 - ZRSMIN(1:KRR) = ICED%XRTMIN(1:KRR) => ZRSMIN(1:KRR) = ICEDXRTMIN1KRR(1:KRR)
291 - IF(TURBN%CSUBG_MF_PDF=='NONE') => IF(CTURBNSUBG_MF_PDF=='NONE')
295 - Only handles single-level structure access (not TOTO%CST%XG)
296 - Does not handle arrays with deferred shapes
297 - Type components must have known dimensions
299 def _getShapeFromLHS(aStmt, scope):
301 Get array shape from the LHS variable declaration.
304 varNode = e1.find(
'.//{*}N/{*}n')
307 varDesc = scope.varList.findVar(varNode.text)
308 if varDesc
is None or not varDesc.get(
'as')
or len(varDesc[
'as']) == 0:
312 def convertOneType(component, newVarList, scope, aStmt=None):
314 objType = scope.getParent(component, 2)
315 objTypeStr = alltext(objType).upper()
316 namedENn = objType.find(
'.//{*}N/{*}n')
317 structure = namedENn.text
318 variable = component.find(
'.//{*}ct').text.upper()
319 if variable[0] ==
"T":
324 arrayRall = objType.findall(
'.//{*}array-R')
325 if len(arrayRall) > 0:
326 arrayR = copy.deepcopy(arrayRall[0])
327 txt = alltext(arrayR).replace(
',',
'')
328 txt = txt.replace(
':',
'')
329 txt = txt.replace(
'(',
'')
330 txt = txt.replace(
')',
'')
331 arrayIndices = arrayIndices + txt
332 elif len(objType.findall(
'.//{*}element-LT')) > 0:
336 for elem
in objType.findall(
'.//{*}element'):
339 arrayIndices = arrayIndices + txt
340 newName = variable[0] + structure + variable[1:] + arrayIndices
341 newName = newName.upper()
345 namedENn.text = newName
346 objType.remove(objType.find(
'.//{*}R-LT'))
347 if len(arrayRall) > 0:
348 objType.insert(1, arrayR)
351 if newName
not in newVarList:
352 if len(arrayRall) == 0:
353 newVarList[newName] = (
None, objTypeStr)
355 newVarList[newName] = (arrayR, objTypeStr)
357 scopes = self.getScopes()
358 if scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
360 for scope
in [scope
for scope
in scopes
361 if 'sub:' in scope.path
and 'interface' not in scope.path]:
363 for ifStmt
in (scope.findall(
'.//{*}if-then-stmt') +
364 scope.findall(
'.//{*}else-if-stmt') +
365 scope.findall(
'.//{*}where-stmt')):
366 compo = ifStmt.findall(
'.//{*}component-R')
368 for elcompo
in compo:
369 convertOneType(elcompo, newVarList, scope)
371 for aStmt
in scope.findall(
'.//{*}a-stmt'):
374 if len(aStmt[0].findall(
'.//{*}component-R')) == 0:
375 compoE2 = aStmt.findall(
'.//{*}component-R')
382 nbNamedEinE2 = len(aStmt.findall(
'.//{*}E-2')[0].findall(
'.//{*}named-E/' +
384 if nbNamedEinE2 > 1
or nbNamedEinE2 == 1
and \
385 len(aStmt[0].findall(
'.//{*}R-LT')) == 1:
386 for elcompoE2
in compoE2:
387 convertOneType(elcompoE2, newVarList, scope,
392 for aStmt
in scope.findall(
'.//{*}a-stmt'):
394 if len(aStmt[0].findall(
'.//{*}component-R')) > 0:
396 for el
in newVarList.items():
397 if alltext(aStmt[0]) == el[1][1]:
398 stmtAffect = createExpr(el[0] +
"=" + alltext(aStmt[0]))
399 par = scope.getParent(aStmt)
401 if tag(par[list(par).index(aStmt)+1]) ==
'C':
403 par.insert(list(par).index(aStmt)+1+iExtra, stmtAffect[0])
407 for el, var
in newVarList.items():
408 if el[0].upper() ==
'X' or el[0].upper() ==
'P' or el[0].upper() ==
'Z':
410 elif el[0].upper() ==
'L' or el[0].upper() ==
'O':
412 elif el[0].upper() ==
'N' or el[0].upper() ==
'I' or el[0].upper() ==
'K':
414 elif el[0].upper() ==
'C':
415 varType =
'CHARACTER(LEN=LEN(' + var[1] +
'))'
417 raise PYFTError(
'Case not implemented for the first letter of the newVarName ' +
418 el +
' in convertTypesInCompute')
421 if isinstance(var[0], list):
424 varArray =
', DIMENSION('
425 for i, bound
in enumerate(memberShape):
436 varArray =
', DIMENSION('
437 for i, sub
in enumerate(var[0].findall(
'.//{*}section-subscript')):
438 if len(sub.findall(
'.//{*}upper-bound')) > 0:
439 dimSize = simplifyExpr(
440 alltext(sub.findall(
'.//{*}upper-bound')[0]) +
441 '-' + alltext(sub.findall(
'.//{*}lower-bound')[0]) +
443 elif len(sub.findall(
'.//{*}lover-bound')) > 0:
444 dimSize = simplifyExpr(alltext(sub.findall(
'.//{*}lower-bound')[0]))
446 dimSize =
'SIZE(' + var[1] +
',' + str(i+1) +
')'
447 varArray =
', DIMENSION(' + dimSize +
','
448 varArray = varArray[:-1] +
')'
449 scope.addVar([[scope.path, el, varType + varArray +
' :: ' + el,
None]])
452 if isinstance(var[0], list):
454 stmtAffect = createExpr(el +
"=" + var[2] +
'%' + var[3])[0]
456 stmtAffect = createExpr(el +
"=" + var[1])[0]
457 scope.insertStatement(scope.indent(stmtAffect), first=
True)
563 Convert MODULE to SUBMODULE statements and add INTERFACE of SUBROUTINEs of PHYEX
564 ==> Applied only on MODE_
566 - if an INTERFACE already exists
567 - if no subroutine is present in the module
568 - to CONTAINS routines
569 1) Create interface statement if any
570 2) Add subroutines declaration (with MODULE statement)
571 3) Add SUBMODULE statements and convert SUBROUTINE to MODULE SUBROUTINE statements
573 scopes = self.getScopes()
576 oldModNode = self.find(
'.//{*}program-unit')
577 modNode = copy.deepcopy(self.find(
'.//{*}program-unit'))
579 interfaceStmt = self.findall(
'.//{*}interface-stmt')
580 subStmt = self.findall(
'.//{*}subroutine-stmt')
582 if modScope.path.split(
'/')[-1].split(
':')[1][:4] ==
'MODE' and \
583 len(interfaceStmt) == 0
and len(subStmt) > 0:
584 moduleName = modScope.path.split(
'/')[-1].split(
':')[1][:]
586 newMod = createElem(
'program-unit', text=
'MODULE ' + moduleName, tail=
'\n')
588 newMod.append(createElem(
'implicit-none-stmt', text=
'IMPLICIT NONE', tail=
'\n'))
589 interfaceStmt = createElem(
'interface-construct')
590 interfaceStmt.append(createElem(
'interface-stmt', text=
'INTERFACE', tail=
'\n'))
591 interfaceStmt.append(createElem(
'end-interface-stmt', text=
'END INTERFACE', tail=
'\n'))
592 newMod.append(interfaceStmt)
596 for scope
in scopes[1:]:
598 if sum(
'sub' in s
for s
in scope.path.split(
'/')) == 1:
599 subsModified.append(scope.path.split(
'/')[-1].split(
':')[1][:])
600 subroutineDecl = createElem(
'module-unit')
602 subroutineStmt = copy.deepcopy(scope[0])
603 declType = subroutineStmt.text
604 prefix = createElem(
'prefix')
605 prefix.text =
'MODULE'
606 subroutineStmt.text =
''
607 subroutineStmt.insert(0, prefix)
608 prefix.tail =
' ' + declType
609 subroutineDecl.append(subroutineStmt)
611 for use
in scope.findall(
'.//{*}use-stmt'):
612 subroutineDecl.append(copy.deepcopy(use))
613 subroutineDecl.append(createElem(
'implicit-none-stmt', text=
'IMPLICIT NONE',
616 for var
in [var
for var
in scope.varList
if var[
'arg']
or var[
'result']]:
617 subroutineDecl.append(createExpr(self.varSpec2stmt(var,
True))[0])
618 for external
in scope.findall(
'./{*}external-stmt'):
619 subroutineDecl.append(copy.deepcopy(external))
620 if 'SUBROUTINE' in declType:
621 endStmt = createElem(
'end-subroutine-stmt')
622 declName = subroutineStmt.find(
'./{*}subroutine-N/{*}N/{*}n').text
623 elif 'FUNCTION' in declType:
624 endStmt = createElem(
'end-function-stmt')
625 declName = subroutineStmt.find(
'./{*}function-N/{*}N/{*}n').text
627 raise PYFTError(
'declType in addSubmodulePHYEX not handled')
629 endStmt.text =
'END ' + declType + declName +
'\n'
630 subroutineDecl.append(endStmt)
631 interfaceStmt.insert(1, subroutineDecl)
634 newMod.append(createElem(
'end-program-unit', text=
'END MODULE ' + moduleName,
636 self[0].insert(0, newMod)
639 progUnit = createElem(
'program-unit')
650 submoduleStmt = createElem(
'submodule-stmt', text=
'SUBMODULE (')
651 parentId = createElem(
'parent-identifier')
653 ancestorModule = createElem(
'ancestor-module-N')
654 ancestorModuleN = createElem(
'n', text=moduleName)
655 ancestorModule.append(ancestorModuleN)
656 parentId.append(ancestorModule)
657 submoduleStmt.append(parentId)
658 submoduleModule = createElem(
'submodule-module-N')
659 submoduleModuleN = createElem(
'n', text=
'S' + moduleName, tail=
'\n')
660 submoduleModule.append(submoduleModuleN)
661 submoduleStmt.append(submoduleModule)
662 progUnit.append(submoduleStmt)
665 endSubmoduleStmt = createElem(
'end-submodule-stmt', text=
'END SUBMODULE ')
666 submoduleN = createElem(
'submodule-N')
667 submoduleNN = createElem(
'N')
668 submoduleNNn = createElem(
'n', text=
'S' + moduleName, tail=
'\n')
669 submoduleNN.append(submoduleNNn)
670 submoduleN.append(submoduleNN)
671 endSubmoduleStmt.append(submoduleN)
673 progUnit.append(endSubmoduleStmt)
674 progUnit.append(createElem(
'end-program-unit'))
678 modStmt = modNode.find(
'.//{*}module-stmt')
679 modEndStmt = modNode.find(
'.//{*}end-module-stmt')
680 modNode.remove(modStmt)
681 modNode.remove(modEndStmt)
684 publicStmts = modNode.findall(
'.//{*}public-stmt')
685 privateStmts = modNode.findall(
'.//{*}private-stmt')
686 if len(publicStmts) > 0:
687 for publicStmt
in publicStmts:
688 modNode.remove(publicStmt)
689 if len(privateStmts) > 0:
690 for privateStmt
in privateStmts:
691 modNode.remove(privateStmt)
694 subroutines = modNode.findall(
'.//{*}subroutine-stmt')
695 for sub
in subroutines:
696 if sub.find(
'.//{*}N/{*}n').text
in subsModified:
697 prefix = createElem(
'prefix')
698 prefix.text =
'MODULE'
700 sub.insert(0, prefix)
701 prefix.tail =
' SUBROUTINE '
702 progUnit.insert(1, modNode)
704 self.insert(1, progUnit)
707 self.remove(oldModNode)
713 Add MPPDB_CHEKS on all intent REAL arrays on subroutines.
714 ****** Not applied on modd_ routines. ********
715 Handle optional arguments.
716 Example, for a BL89 routine with 4 arguments, 1 INTENT(IN),
717 2 INTENT(INOUT), 1 INTENT(OUT), it produces :
718 IF (MPPDB_INITIALIZED) THEN
720 CALL MPPDB_CHECK(PZZ, "BL89 beg:PZZ")
721 !Check all INOUT arrays
722 CALL MPPDB_CHECK(PDZZ, "BL89 beg:PDZZ")
723 CALL MPPDB_CHECK(PTHVREF, "BL89 beg:PTHVREF")
726 IF (MPPDB_INITIALIZED) THEN
727 !Check all INOUT arrays
728 CALL MPPDB_CHECK(PDZZ, "BL89 end:PDZZ")
729 CALL MPPDB_CHECK(PTHVREF, "BL89 end:PTHVREF")
730 !Check all OUT arrays
731 CALL MPPDB_CHECK(PLM, "BL89 end:PLM")
733 param printsMode: if True, instead of CALL MPPDB_CHECK, add fortran prints for debugging
735 def addPrints_statement(var, typeofPrints='minmax'):
736 ifBeg, ifEnd =
'',
''
739 if typeofPrints ==
'minmax':
740 strMSG = f
'MINMAX {varName} = \",MINVAL({varName}), MAXVAL({varName})'
741 elif typeofPrints ==
'shape':
742 strMSG = f
'SHAPE {varName} = \",SHAPE({varName})'
744 raise PYFTError(
'typeofPrints is either minmax or shape in addPrints_statement')
746 strMSG = var[
'n'] +
' = \",' + var[
'n']
748 ifBeg = ifBeg +
'IF (PRESENT(' + var[
'n'] +
')) THEN\n '
749 ifEnd = ifEnd +
'\nEND IF'
750 return createExpr(ifBeg +
"print*,\"" + strMSG + ifEnd)[0]
752 def addMPPDB_CHECK_statement(var, subRoutineName, strMSG='beg:
'):
753 ifBeg, ifEnd, addD, addLastDim, addSecondDimType = '',
'',
'',
'',
''
757 if 'D%NIJT' in var[
'as'][0][1]:
759 if len(var[
'as']) == 2:
761 addLastDim =
', ' + var[
'as'][1][1]
762 if len(var[
'as']) >= 2:
765 if 'D%NK' in var[
'as'][1][1]:
766 addSecondDimType =
',' +
'''"VERTICAL"'''
768 addSecondDimType =
',' +
'''"OTHER"'''
769 if 'MERGE' in var[
'as'][-1][1]:
770 keyDimMerge = var[
'as'][-1][1].split(
',')[2][:-1]
771 ifBeg =
'IF (' + keyDimMerge +
') THEN\n'
774 ifBeg = ifBeg +
'IF (PRESENT(' + var[
'n'] +
')) THEN\n IF (SIZE(' + \
775 var[
'n'] +
',1) > 0) THEN\n'
776 ifEnd = ifEnd +
'\nEND IF\nEND IF'
777 argsMPPDB = var[
'n'] +
", " +
"\"" + subRoutineName +
" " + strMSG+var[
'n'] +
"\""
778 return createExpr(ifBeg +
"CALL MPPDB_CHECK(" + addD + argsMPPDB +
779 addLastDim + addSecondDimType +
")" + ifEnd)[0]
780 scopes = self.getScopes()
781 if scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
788 if 'sub:' in scope.path
and 'func' not in scope.path
and 'interface' not in scope.path:
789 subRoutineName = scope.path.split(
'/')[-1].split(
':')[1]
792 arraysIn, arraysInOut, arraysOut = [], [], []
794 for var
in scope.varList:
795 if var[
'arg']
and var[
'as']
and 'TYPE' not in var[
't']
and \
796 'REAL' in var[
't']
and var[
'scopePath'] == scope.path:
799 if var[
'i'] ==
'INOUT':
800 arraysInOut.append(var)
801 if var[
'i'] ==
'OUT':
802 arraysOut.append(var)
804 for var
in scope.varList:
805 if not var[
't']
or var[
't']
and 'TYPE' not in var[
't']:
808 if var[
'i'] ==
'INOUT':
809 arraysInOut.append(var)
810 if var[
'i'] ==
'OUT':
811 arraysOut.append(var)
813 if len(arraysIn) + len(arraysInOut) + len(arraysOut) == 0:
818 scope.addModuleVar([(scope.path,
'MODE_MPPDB',
None)])
820 scope.addModuleVar([(scope.path,
'MODD_BLANK_n', [
'LDUMMY1'])])
823 commentIN = createElem(
'C', text=
'!Check all IN arrays', tail=
'\n')
824 commentINOUT = createElem(
'C', text=
'!Check all INOUT arrays', tail=
'\n')
825 commentOUT = createElem(
'C', text=
'!Check all OUT arrays', tail=
'\n')
828 if len(arraysIn) + len(arraysInOut) > 0:
830 ifMPPDBinit = createExpr(
"IF (MPPDB_INITIALIZED) THEN\n END IF")[0]
832 ifMPPDBinit = createExpr(
"IF (LDUMMY1) THEN\n END IF")[0]
833 ifMPPDB = ifMPPDBinit.find(
'.//{*}if-block')
836 if len(arraysIn) > 0:
837 ifMPPDB.insert(1, commentIN)
838 for i, var
in enumerate(arraysIn):
840 ifMPPDB.insert(2 + i, addMPPDB_CHECK_statement(var, subRoutineName,
843 ifMPPDB.insert(2 + i, addPrints_statement(var,
844 typeofPrints=
'minmax'))
845 ifMPPDB.insert(3 + i, addPrints_statement(var,
846 typeofPrints=
'shape'))
849 if len(arraysInOut) > 0:
850 shiftLineNumber = 2
if len(arraysIn) > 0
else 1
852 ifMPPDB.insert(len(arraysIn) + shiftLineNumber, commentINOUT)
854 ifMPPDB.insert(len(arraysIn)*2 + shiftLineNumber-1, commentINOUT)
856 for i, var
in enumerate(arraysInOut):
858 ifMPPDB.insert(len(arraysIn) + shiftLineNumber + 1 + i,
859 addMPPDB_CHECK_statement(var, subRoutineName,
862 ifMPPDB.insert(len(arraysIn) + shiftLineNumber + 1 + i,
863 addPrints_statement(var, typeofPrints=
'minmax'))
866 scope.insertStatement(scope.indent(ifMPPDBinit), first=
True)
869 if len(arraysInOut) + len(arraysOut) > 0:
871 ifMPPDBend = createExpr(
"IF (MPPDB_INITIALIZED) THEN\n END IF")[0]
873 ifMPPDBend = createExpr(
"IF (LDUMMY1) THEN\n END IF")[0]
874 ifMPPDB = ifMPPDBend.find(
'.//{*}if-block')
877 if len(arraysInOut) > 0:
878 ifMPPDB.insert(1, commentINOUT)
879 for i, var
in enumerate(arraysInOut):
881 ifMPPDB.insert(2 + i, addMPPDB_CHECK_statement(var, subRoutineName,
884 ifMPPDB.insert(2 + i, addPrints_statement(var,
885 typeofPrints=
'minmax'))
888 if len(arraysOut) > 0:
889 shiftLineNumber = 2
if len(arraysInOut) > 0
else 1
891 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber, commentOUT)
893 ifMPPDB.insert(len(arraysInOut)*2 + shiftLineNumber-1, commentOUT)
894 for i, var
in enumerate(arraysOut):
896 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber + 1 + i,
897 addMPPDB_CHECK_statement(var, subRoutineName,
900 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber + 1 + i,
901 addPrints_statement(var, typeofPrints=
'minmax'))
904 scope.insertStatement(scope.indent(ifMPPDBend), first=
False)
1029 def removeIJDim(self, stopScopes, parserOptions=None, wrapH=False, simplify=False):
1031 Transform routines to be called in a loop on columns
1032 :param stopScopes: scope paths where we stop to add the D argument (if needed)
1033 :param parserOptions, wrapH: see the PYFT class
1034 :param simplify: try to simplify code (remove useless dimensions in call)
1036 ComputeInSingleColumn :
1037 - Remove all Do loops on JI and JJ
1038 - Initialize former indexes JI, JJ, JIJ to first array element:
1039 JI=D%NIB, JJ=D%NJB, JIJ=D%NIJB
1040 - If simplify is True, replace (:,*) on I/J/IJ dimension on argument
1041 with explicit (:,*) on CALL statements:
1042 e.g. CALL FOO(D, A(:,JK,1), B(:,:))
1043 ==> CALL FOO(D, A(JIJ,JK,1), B(:,:)) only if the target argument is not an array
1046 indexToCheck = {
'JI': (
'D%NIB',
'D%NIT'),
1047 'JJ': (
'D%NJB',
'D%NJT'),
1048 'JIJ': (
'D%NIJB',
'D%NIJT')}
1049 hUupperBounds = [v[1]
for v
in indexToCheck.values()]
1051 def slice2index(namedE, scope):
1053 Transform a slice on the horizontal dimension into an index
1054 Eg.: X(1:D%NIJT, 1:D%NKT) => X(JIJ, 1:D%NKT) Be careful, this array is not contiguous.
1055 X(1:D%NIJT, JK) => X(JIJ, JK)
1056 :param namedE: array to transform
1057 :param scope: scope where the array is
1060 for isub, sub
in enumerate(namedE.findall(
'./{*}R-LT/{*}array-R/' +
1061 '{*}section-subscript-LT/' +
1062 '{*}section-subscript')):
1063 if ':' in alltext(sub):
1064 loopIndex, _, _ = scope.findIndexArrayBounds(namedE, isub, _loopVarPHYEX)
1065 if loopIndex
in indexToCheck:
1068 lowerBound = createElem(
'lower-bound')
1069 sub.insert(0, lowerBound)
1071 lowerBound = sub.find(
'./{*}lower-bound')
1072 lowerBound.tail =
''
1073 for item
in lowerBound:
1074 lowerBound.remove(item)
1075 upperBound = sub.find(
'./{*}upper-bound')
1076 if upperBound
is not None:
1077 sub.remove(upperBound)
1078 lowerBound.append(createExprPart(loopIndex))
1079 if loopIndex
not in indexRemoved:
1080 indexRemoved.append(loopIndex)
1083 if ':' not in alltext(namedE.find(
'./{*}R-LT/{*}array-R/{*}section-subscript-LT')):
1084 namedE.find(
'./{*}R-LT/{*}array-R').tag = f
'{{{NAMESPACE}}}parens-R'
1085 namedE.find(
'./{*}R-LT/{*}parens-R/' +
1086 '{*}section-subscript-LT').tag = f
'{{{NAMESPACE}}}element-LT'
1087 for ss
in namedE.findall(
'./{*}R-LT/{*}parens-R/' +
1088 '{*}element-LT/{*}section-subscript'):
1089 ss.tag = f
'{{{NAMESPACE}}}element'
1090 lowerBound = ss.find(
'./{*}lower-bound')
1091 for item
in lowerBound:
1093 ss.remove(lowerBound)
1096 self.attachArraySpecToEntity()
1100 for scope
in [scope
for scope
in self.getScopes()[::-1]
1101 if 'func:' not in scope.path
and
1102 (scope.path
in stopScopes
or
1103 self.tree.isUnderStopScopes(scope.path, stopScopes,
1104 includeInterfaces=
True))]:
1106 scope.addArrayParentheses()
1107 scope.expandAllArraysPHYEX()
1114 for doNode
in scope.findall(
'.//{*}do-construct')[::-1]:
1115 for loopI
in doNode.findall(
'./{*}do-stmt/{*}do-V/{*}named-E/{*}N'):
1116 loopIname = n2name(loopI).upper()
1117 if loopIname
in indexToCheck:
1120 par = scope.getParent(doNode)
1121 index = list(par).index(doNode)
1122 for item
in doNode[1:-1][::-1]:
1123 par.insert(index, item)
1125 if loopIname
not in indexRemoved:
1126 indexRemoved.append(loopIname)
1131 for intr
in scope.findall(
'.//{*}R-LT/{*}parens-R/../..'):
1132 intrName = n2name(intr.find(
'./{*}N')).upper()
1133 if intrName
in (
'PACK',
'UNPACK',
'COUNT',
'MAXVAL',
'MINVAL',
'ALL',
'ANY',
'SUM'):
1141 while par
is not None and not isStmt(par):
1142 par = scope.getParent(par)
1143 if tag(par)
in (
'a-stmt',
'op-E'):
1148 for namedE
in parToUse.findall(
'.//{*}R-LT/{*}array-R/../..'):
1149 slice2index(namedE, scope)
1152 if intr.find(
'.//{*}R-LT/{*}array-R')
is None:
1153 if intrName
in (
'MAXVAL',
'MINVAL',
'SUM',
'ALL',
'ANY'):
1155 parens = intr.find(
'./{*}R-LT/{*}parens-R')
1156 parens.tag = f
'{{{NAMESPACE}}}parens-E'
1157 intrPar = scope.getParent(intr)
1158 intrPar.insert(list(intrPar).index(intr), parens)
1159 intrPar.remove(intr)
1160 elif intrName ==
'COUNT':
1162 nodeN = intr.find(
'./{*}N')
1163 for item
in nodeN[1:]:
1165 nodeN.find(
'./{*}n').text =
'MERGE'
1166 elementLT = intr.find(
'./{*}R-LT/{*}parens-R/{*}element-LT')
1168 element = createElem(
'element', tail=
', ')
1169 element.append(createExprPart(val))
1170 elementLT.insert(0, element)
1183 assert scope.find(
'.//{*}include')
is None and \
1184 scope.find(
'.//{*}include-stmt')
is None, \
1185 "inlining must be performed before removing horizontal dimensions"
1187 if scope.path
in stopScopes:
1189 preserveShape = [v[
'n']
for v
in scope.varList
if v[
'arg']]
1194 if 'sub:' in scope.path:
1198 for namedE
in scope.findall(
'.//{*}named-E/{*}R-LT/{*}parens-R/../..'):
1199 if n2name(namedE.find(
'./{*}N')).upper()
not in preserveShape:
1200 var = scope.varList.findVar(n2name(namedE.find(
'./{*}N')).upper())
1201 if var
is not None and var[
'as']
is not None and len(var[
'as']) > 0:
1202 subs = namedE.findall(
'./{*}R-LT/{*}parens-R/' +
1203 '{*}element-LT/{*}element')
1204 if (len(subs) == 1
and var[
'as'][0][1]
in hUupperBounds)
or \
1205 (len(subs) == 2
and (var[
'as'][0][1]
in hUupperBounds
and
1206 var[
'as'][1][1]
in hUupperBounds)):
1207 namedE.remove(namedE.find(
'./{*}R-LT'))
1211 for call
in scope.findall(
'.//{*}call-stmt'):
1212 for namedE
in call.findall(
'./{*}arg-spec//{*}named-E'):
1213 subs = namedE.findall(
'.//{*}section-subscript')
1214 var = scope.varList.findVar(n2name(namedE.find(
'./{*}N')).upper())
1215 if len(subs) > 0
and (var
is None or var[
'as']
is None or
1216 len(var[
'as']) < len(subs)):
1224 elif (len(subs) >= 2
and
1225 ':' in alltext(subs[0])
and var[
'as'][0][1]
in hUupperBounds
and
1226 ':' in alltext(subs[1])
and var[
'as'][1][1]
in hUupperBounds):
1228 remove = len(subs) == 2
1229 index = (len(subs) > 2
and
1230 len([sub
for sub
in subs
if ':' in alltext(sub)]) == 2)
1231 elif (len(subs) >= 1
and
1232 ':' in alltext(subs[0])
and var[
'as'][0][1]
in hUupperBounds):
1234 remove = len(subs) == 1
1235 index = (len(subs) > 1
and
1236 len([sub
for sub
in subs
if ':' in alltext(sub)]) == 1)
1241 if n2name(namedE.find(
'./{*}N')).upper()
in preserveShape:
1242 slice2index(namedE, scope)
1244 nodeRLT = namedE.find(
'.//{*}R-LT')
1245 scope.getParent(nodeRLT).remove(nodeRLT)
1247 slice2index(namedE, scope)
1250 subs = namedE.findall(
'.//{*}section-subscript')
1251 if len(subs) > 0
and all(alltext(sub) ==
':' for sub
in subs):
1252 nodeRLT = namedE.find(
'.//{*}R-LT')
1253 scope.getParent(nodeRLT).remove(nodeRLT)
1258 for decl
in scope.findall(
'.//{*}T-decl-stmt/{*}EN-decl-LT/{*}EN-decl'):
1259 name = n2name(decl.find(
'./{*}EN-N/{*}N')).upper()
1260 if name
not in preserveShape:
1261 varsShape = decl.findall(
'.//{*}shape-spec-LT')
1262 for varShape
in varsShape:
1263 subs = varShape.findall(
'.//{*}shape-spec')
1264 if (len(subs) == 1
and alltext(subs[0])
in hUupperBounds)
or \
1265 (len(subs) == 2
and (alltext(subs[0])
in hUupperBounds
and
1266 alltext(subs[1])
in hUupperBounds)):
1268 itemToRemove = scope.getParent(varShape)
1269 scope.getParent(itemToRemove).remove(itemToRemove)
1274 for loopIndex
in indexRemoved:
1277 scope.insertStatement(
1278 createExpr(loopIndex +
" = " + indexToCheck[loopIndex][0])[0],
True)
1279 if len(indexRemoved) > 0:
1280 scope.addArgInTree(
'D',
'TYPE(DIMPHYEX_t), INTENT(IN) :: D',
1281 0, stopScopes, moduleVarList=[(
'MODD_DIMPHYEX', [
'DIMPHYEX_t'])],
1282 parserOptions=parserOptions, wrapH=wrapH)
1284 scope.addVar([[scope.path, loopIndex,
'INTEGER :: ' + loopIndex,
None]
1285 for loopIndex
in indexRemoved
1286 if scope.varList.findVar(loopIndex, exactScope=
True)
is None])
1482 Convert all calling of functions and gradient present in shumansGradients
1483 table into the use of subroutines
1484 and use mnh_expand_directives to handle intermediate computations
1486 def getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar=''):
1488 if zshugradwkDim == 1:
1489 dimSuffRoutine =
'2D'
1491 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE'
1492 localVariables = [
'JIJ']
1493 elif zshugradwkDim == 2:
1495 if 'D%NKT' in dimWorkingVar:
1496 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE,JK=1:IKT'
1497 localVariables = [
'JIJ',
'JK']
1498 elif 'D%NIT' in dimWorkingVar
and 'D%NJT' in dimWorkingVar:
1500 mnhExpandArrayIndexes =
'JI=1:IIT,JJ=1:IJT'
1501 localVariables = [
'JI',
'JJ']
1502 dimSuffRoutine =
'2D'
1508 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE,JK=1:IKT'
1509 localVariables = [
'JIJ',
'JK']
1510 elif zshugradwkDim == 3:
1512 mnhExpandArrayIndexes =
'JI=1:IIT,JJ=1:IJT,JK=1:IKT'
1513 localVariables = [
'JI',
'JJ',
'JK']
1515 raise PYFTError(
'Shuman func to routine conversion not implemented ' +
1516 'for 4D+ dimensions variables')
1517 return dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, localVariables
1519 def FUNCtoROUTINE(scope, stmt, itemFuncN, localShumansCount, inComputeStmt,
1520 nbzshugradwk, zshugradwkDim, dimWorkingVar):
1522 :param scope: node on which the calling function is present before transformation
1523 :param stmt: statement node (a-stmt or call-stmt) that contains the function(s) to be
1525 :param itemFuncN: <n>FUNCTIONNAME</n> node
1526 :param localShumansCount: instance of the shumansGradients dictionnary
1527 for the given scope (which contains the number of times a
1528 function has been called within a transformation)
1529 :param dimWorkingVar: string of the declaration of a potential working variable
1530 depending on the array on wich the shuman is applied
1531 (e.g. MZM(PRHODJ(:,IKB));
1532 dimWorkingVar = 'REAL, DIMENSION(D%NIJT) :: ' )
1534 :return callStmt: the new CALL to the routines statement
1535 :return computeStmt: the a-stmt computation statement if there was an operation
1536 in the calling function in stmt
1537 :return localVariables: list of local variables needed for the mnh_expand directive
1541 parStmt = scope.getParent(stmt)
1542 parItemFuncN = scope.getParent(itemFuncN)
1544 grandparItemFuncN = scope.getParent(itemFuncN, level=2)
1545 funcName = alltext(itemFuncN)
1548 indexForCall = list(parStmt).index(stmt)
1553 siblsItemFuncN = scope.getSiblings(parItemFuncN, after=
True, before=
False)
1554 workingItem = siblsItemFuncN[0][0][0]
1557 if len(siblsItemFuncN[0][0]) > 1:
1559 workingItem = scope.updateContinuation(siblsItemFuncN[0][0], removeALL=
True,
1560 align=
False, addBegin=
False)[0]
1564 opE = workingItem.findall(
'.//{*}op-E')
1565 scope.removeArrayParenthesesInNode(workingItem)
1566 computeStmt, remaningArgsofFunc = [],
''
1567 dimSuffVar = str(zshugradwkDim) +
'D'
1568 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, _ = \
1569 getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar)
1572 computingVarName =
'ZSHUGRADWK'+str(nbzshugradwk)+
'_'+str(zshugradwkDim)+
'D'
1574 if not scope.varList.findVar(computingVarName):
1575 scope.addVar([[scope.path, computingVarName,
1576 dimWorkingVar + computingVarName,
None]])
1580 computeVar = scope.varList.findVar(computingVarName)
1581 dimWorkingVar =
'REAL, DIMENSION('
1582 for dims
in computeVar[
'as'][:arrayDim]:
1583 dimWorkingVar += dims[1] +
','
1584 dimWorkingVar = dimWorkingVar[:-1] +
') ::'
1586 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, localVariables = \
1587 getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar)
1590 mnhOpenDir =
"!$mnh_expand_array(" + mnhExpandArrayIndexes +
")"
1591 mnhCloseDir =
"!$mnh_end_expand_array(" + mnhExpandArrayIndexes +
")"
1594 workingComputeItem = workingItem[0]
1596 if len(workingItem) == 2:
1597 remaningArgsofFunc =
',' + alltext(workingItem[1])
1598 elif len(workingItem) > 2:
1599 raise PYFTError(
'ShumanFUNCtoCALL: expected maximum 1 argument in shuman ' +
1600 'function to transform')
1601 computeStmt = createExpr(computingVarName +
" = " + alltext(workingComputeItem))[0]
1602 workingItem = computeStmt.find(
'.//{*}E-1')
1604 parStmt.insert(indexForCall, createElem(
'C', text=
'!$acc kernels', tail=
'\n'))
1605 parStmt.insert(indexForCall + 1, createElem(
'C', text=mnhOpenDir, tail=
'\n'))
1606 parStmt.insert(indexForCall + 2, computeStmt)
1607 parStmt.insert(indexForCall + 3, createElem(
'C', text=mnhCloseDir, tail=
'\n'))
1608 parStmt.insert(indexForCall + 4, createElem(
'C',
1609 text=
'!$acc end kernels', tail=
'\n'))
1610 parStmt.insert(indexForCall + 5, createElem(
'C',
1611 text=
'!', tail=
'\n'))
1615 if zshugradwkDim == 1:
1616 dimSuffRoutine =
'2D'
1617 workingVar =
'Z' + funcName + dimSuffVar +
'_WORK' + str(localShumansCount[funcName])
1618 if useDevice
and funcName
in (
'GY_U_UV',
'GX_V_UV'):
1619 gpuGradientImplementation =
'_DEVICE('
1620 newFuncName = funcName + dimSuffRoutine +
'_DEVICE'
1621 elif dimSuffRoutine ==
'2D' and funcName.endswith(
'2D'):
1622 gpuGradientImplementation =
'_PHY(D, '
1623 newFuncName = funcName +
'_PHY'
1625 gpuGradientImplementation =
'_PHY(D, '
1626 newFuncName = funcName + dimSuffRoutine +
'_PHY'
1627 callStmt = createExpr(
"CALL " + funcName + dimSuffRoutine + gpuGradientImplementation
1628 + alltext(workingItem) + remaningArgsofFunc +
1629 ", " + workingVar +
")")[0]
1630 parStmt.insert(indexForCall, callStmt)
1633 parOfgrandparItemFuncN = scope.getParent(grandparItemFuncN)
1634 indexWorkingVar = list(parOfgrandparItemFuncN).index(grandparItemFuncN)
1635 savedTail = grandparItemFuncN.tail
1636 parOfgrandparItemFuncN.remove(grandparItemFuncN)
1639 xmlWorkingvar = createExprPart(workingVar)
1640 xmlWorkingvar.tail = savedTail
1641 parOfgrandparItemFuncN.insert(indexWorkingVar, xmlWorkingvar)
1644 if not scope.varList.findVar(workingVar):
1645 scope.addVar([[scope.path, workingVar, dimWorkingVar + workingVar,
None]])
1647 return (callStmt, computeStmt, nbzshugradwk, newFuncName,
1648 localVariables, mnhExpandArrayIndexes)
1650 shumansGradients = {
'MZM': 0,
'MXM': 0,
'MYM': 0,
'MZF': 0,
'MXF': 0,
'MYF': 0,
1651 'DZM': 0,
'DXM': 0,
'DYM': 0,
'DZF': 0,
'DXF': 0,
'DYF': 0,
1652 'MXM2D': 0,
'MYM2D': 0,
'MXF2D': 0,
'MYF2D': 0,
1653 'DXM2D': 0,
'DYM2D': 0,
'DXF2D': 0,
'DYF2D': 0,
1654 'GZ_M_W': 0,
'GZ_W_M': 0,
'GZ_U_UW': 0,
'GZ_V_VW': 0,
1655 'GX_M_U': 0,
'GX_U_M': 0,
'GX_W_UW': 0,
'GX_M_M': 0,
1656 'GY_V_M': 0,
'GY_M_V': 0,
'GY_W_VW': 0,
'GY_M_M': 0,
1657 'GX_V_UV': 0,
'GY_U_UV': 0}
1658 scopes = self.getScopes()
1659 if len(scopes) == 0
or scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
1661 for scope
in scopes:
1662 if 'sub:' in scope.path
and 'func' not in scope.path \
1663 and 'interface' not in scope.path:
1666 localVariablesToAdd = set()
1667 foundStmtandCalls, computeStmtforParenthesis = {}, []
1668 aStmt = scope.findall(
'.//{*}a-stmt')
1669 callStmts = scope.findall(
'.//{*}call-stmt')
1670 aStmtandCallStmts = aStmt + callStmts
1671 funcToSuppress = set()
1672 for stmt
in aStmtandCallStmts:
1673 elemN = stmt.findall(
'.//{*}n')
1675 if alltext(el)
in list(shumansGradients):
1676 funcToSuppress.add(alltext(el))
1679 parStmt = scope.getParent(stmt)
1680 if tag(parStmt) ==
'action-stmt':
1681 scope.changeIfStatementsInIfConstructs(
1682 singleItem=scope.getParent(parStmt))
1684 if str(stmt)
in foundStmtandCalls:
1685 foundStmtandCalls[str(stmt)][1] += 1
1687 foundStmtandCalls[str(stmt)] = [stmt, 1]
1690 subToInclude = set()
1691 for stmt
in foundStmtandCalls:
1692 localShumansGradients = copy.deepcopy(shumansGradients)
1693 elemToLookFor = [foundStmtandCalls[stmt][0]]
1694 previousComputeStmt = []
1697 while len(elemToLookFor) > 0:
1699 for elem
in elemToLookFor:
1700 elemN = elem.findall(
'.//{*}n')
1702 if alltext(el)
in list(localShumansGradients.keys()):
1707 nodeE1var = foundStmtandCalls[stmt][0].findall(
1708 './/{*}E-1/{*}named-E/{*}N')
1709 if len(nodeE1var) > 0:
1710 var = scope.varList.findVar(alltext(nodeE1var[0]))
1711 allSubscripts = foundStmtandCalls[stmt][0].findall(
1712 './/{*}E-1//{*}named-E/{*}R-LT/' +
1713 '{*}array-R/{*}section-subscript-LT')
1717 elPar = scope.getParent(el, level=2)
1718 callVar = elPar.findall(
'.//{*}named-E/{*}N')
1719 if alltext(el)[0] ==
'G':
1724 var = scope.varList.findVar(alltext(callVar[-1]))
1725 shumanIsCalledOn = scope.getParent(callVar[-1])
1728 var, inested =
None, 0
1730 while (
not var
or var[
'as']
is None or
1731 len(var[
'as']) == 0):
1735 var = scope.varList.findVar(
1736 alltext(callVar[inested]))
1738 shumanIsCalledOn = scope.getParent(callVar[inested-1])
1739 allSubscripts = shumanIsCalledOn.findall(
1740 './/{*}R-LT/{*}array-R/' +
1741 '{*}section-subscript-LT')
1745 arrayDim = len(var[
'as'])
1749 if len(allSubscripts) > 0:
1750 for subLT
in allSubscripts:
1752 lowerBound = sub.findall(
'.//{*}lower-bound')
1753 if len(lowerBound) > 0:
1754 if len(sub.findall(
'.//{*}upper-bound')) > 0:
1757 raise PYFTError(
'ShumanFUNCtoCALL does ' +
1758 'not handle conversion ' +
1759 'to routine of array ' +
1760 'subselection lower:upper' +
1761 ': how to set up the ' +
1762 'shape of intermediate ' +
1772 dimWorkingVar =
'REAL, DIMENSION('
1773 for dims
in var[
'as'][:arrayDim]:
1774 dimWorkingVar += dims[1] +
','
1775 dimWorkingVar = dimWorkingVar[:-1] +
') ::'
1778 localShumansGradients[alltext(el)] += 1
1782 if foundStmtandCalls[stmt][0].tail:
1783 foundStmtandCalls[stmt][0].tail = \
1784 foundStmtandCalls[stmt][0].tail.replace(
'\n',
'') +
'\n'
1786 foundStmtandCalls[stmt][0].tail =
'\n'
1789 result = FUNCtoROUTINE(scope, elem, el,
1790 localShumansGradients,
1791 elem
in previousComputeStmt,
1792 nbzshugradwk, arrayDim,
1794 (newCallStmt, newComputeStmt,
1795 nbzshugradwk, newFuncName, lv,
1796 mnhExpandArrayIndexes) = result
1797 localVariablesToAdd.update(lv)
1798 subToInclude.add(newFuncName)
1801 elemToLookFor.append(newCallStmt)
1805 if len(newComputeStmt) > 0:
1806 elemToLookFor.append(newComputeStmt)
1807 computeStmtforParenthesis.append(
1808 [newComputeStmt, mnhExpandArrayIndexes])
1812 previousComputeStmt.append(newComputeStmt)
1816 elemToLookForNew = []
1817 for i
in elemToLookFor:
1818 nodeNs = i.findall(
'.//{*}n')
1821 if alltext(nnn)
in list(localShumansGradients):
1822 elemToLookForNew.append(i)
1824 elemToLookFor = elemToLookForNew
1827 if nbzshugradwk > maxnbZshugradwk:
1828 maxnbZshugradwk = nbzshugradwk
1833 if tag(foundStmtandCalls[stmt][0]) !=
'call-stmt':
1834 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, lv = \
1835 getDimsAndMNHExpandIndexes(arrayDim, dimWorkingVar)
1836 localVariablesToAdd.update(lv)
1838 scope.addArrayParenthesesInNode(foundStmtandCalls[stmt][0])
1840 table = {c.split(
'=')[0]: c.split(
'=')[1].split(
':')
1841 for c
in mnhExpandArrayIndexes.split(
',')}
1842 table.pop(
'OPENACC',
None)
1843 for namedE
in foundStmtandCalls[stmt][0].findall(
1845 arrayR = namedE.find(
'./{*}R-LT/{*}array-R')
1849 for ss
in arrayR.findall(
1850 './{*}section-subscript-LT/{*}section-subscript'):
1851 if ':' in (ss.text
or ''):
1853 varName = list(table.keys())[ivar]
1854 lowerStr, upperStr = table[varName]
1855 lb, ub = createArrayBounds(
1856 lowerStr, upperStr,
'ARRAY')
1860 parStmt = scope.getParent(foundStmtandCalls[stmt][0])
1861 indexForCall = list(parStmt).index(foundStmtandCalls[stmt][0])
1862 mnhOpenDir =
"!$mnh_expand_array(" + mnhExpandArrayIndexes +
")"
1863 mnhCloseDir =
"!$mnh_end_expand_array(" + mnhExpandArrayIndexes +
")"
1864 parStmt.insert(indexForCall,
1865 createElem(
'C', text=
"!$acc kernels", tail=
'\n'))
1866 parStmt.insert(indexForCall + 1,
1867 createElem(
'C', text=mnhOpenDir, tail=
'\n'))
1868 parStmt.insert(indexForCall + 3,
1869 createElem(
'C', text=mnhCloseDir, tail=
'\n'))
1870 parStmt.insert(indexForCall + 4,
1871 createElem(
'C', text=
"!$acc end kernels", tail=
'\n'))
1872 parStmt.insert(indexForCall + 5,
1873 createElem(
'C', text=
"!", tail=
'\n'))
1877 for stmt, mnhExpandArrayIndexes
in computeStmtforParenthesis:
1878 scope.addArrayParenthesesInNode(stmt)
1879 table = {c.split(
'=')[0]: c.split(
'=')[1].split(
':')
1880 for c
in mnhExpandArrayIndexes.split(
',')}
1881 table.pop(
'OPENACC',
None)
1882 for namedE
in stmt.findall(
'.//{*}R-LT/..'):
1883 arrayR = namedE.find(
'./{*}R-LT/{*}array-R')
1887 for ss
in arrayR.findall(
1888 './{*}section-subscript-LT/{*}section-subscript'):
1889 if ':' in (ss.text
or ''):
1891 varName = list(table.keys())[ivar]
1892 lowerStr, upperStr = table[varName]
1893 lb, ub = createArrayBounds(
1894 lowerStr, upperStr,
'ARRAY')
1900 for sub
in sorted(subToInclude):
1901 if re.match(
r'[MD][XYZ][MF](2D)?_PHY', sub):
1902 moduleVars.append((scope.path,
'MODE_SHUMAN_PHY', sub))
1903 if re.match(
r'[MD][XYZ][MF](2D)?_DEVICE', sub):
1904 moduleVars.append((scope.path,
'MODI_SHUMAN_DEVICE', sub))
1906 for kind
in (
'M',
'U',
'V',
'W'):
1907 if re.match(
r'G[XYZ]_' + kind +
r'_[MUVW]{1,2}_PHY', sub):
1908 moduleVars.append((scope.path, f
'MODE_GRADIENT_{kind}_PHY', sub))
1909 elif re.match(
r'G[XYZ]_' + kind +
r'_[MUVW]{1,2}_DEVICE', sub):
1910 moduleVars.append((scope.path, f
'MODI_GRADIENT_{kind}', sub))
1911 scope.addModuleVar(moduleVars)
1914 for sub
in funcToSuppress:
1915 if scope.varList.findVar(sub):
1916 scope.removeVar([(scope.path, sub)])
1919 for varName
in localVariablesToAdd:
1920 if not scope.varList.findVar(varName):
1921 var = {
'as': [],
'asx': [],
1922 'n': varName,
'i':
None,
't':
'INTEGER',
'arg':
False,
1923 'use':
False,
'opt':
False,
'allocatable':
False,
1924 'parameter':
False,
'init':
None,
'scopePath': scope.path}
1925 scope.addVar([[scope.path, var[
'n'], scope.varSpec2stmt(var),
None]])
1931 Convert all calling of functions and gradient into subroutines
1932 and use mnh_expand_directives to handle intermediate computations
1954 includeStmts = self.findall(
'.//{*}include-stmt')
1955 includeFound =
False
1956 for includeStmt
in includeStmts:
1957 filename = includeStmt.find(
'./{*}filename/{*}S').text.replace(
'"',
'').replace(
"'",
"")
1958 if 'shugrad.h' == filename:
1960 self.getParent(includeStmt).remove(includeStmt)
1961 self.removeEmptyCONTAINS()
1962 if not includeFound:
1965 shuman3D = (
'MZM',
'MXM',
'MYM',
'MZF',
'MXF',
'MYF',
1966 'DZM',
'DXM',
'DYM',
'DZF',
'DXF',
'DYF')
1967 shuman2D = (
'MXM2D',
'MYM2D',
'MXF2D',
'MYF2D',
1968 'DXM2D',
'DYM2D',
'DXF2D',
'DYF2D')
1969 gradient = (
'GZ_M_M',
'GZ_M_W',
'GZ_W_M',
'GZ_U_UW',
'GZ_V_VW',
1970 'GX_M_U',
'GX_U_M',
'GX_W_UW',
'GX_M_M',
1971 'GY_V_M',
'GY_M_V',
'GY_W_VW',
'GY_M_M',
1972 'GX_V_UV',
'GY_U_UV')
1973 shugrad = shuman3D + shuman2D + gradient
1975 def buildCall(function, result):
1977 Build the call statement equivalent to this function (named-E)
1979 def removeRange(array):
1981 Remove index range selection from a named-E, in place
1982 A(I:J, K:, :L, 1) -> A(:, :, :, 1)
1984 for ss
in array.findall(
'./{*}R-LT/{*}array-R/' +
1985 '{*}section-subscript-LT/{*}section-subscript'):
1986 lb = ss.find(
'./{*}lower-bound')
1987 ub = ss.find(
'./{*}upper-bound')
1988 if (ss.text
and ':' in ss.text)
or (lb
and lb.tail
and ':' in lb.tail):
1995 funcName = n2name(function.find(
'./{*}N'))
1996 if isinstance(result, str):
1997 result = createExprPart(result)
1999 args = function.findall(
'./{*}R-LT/{*}parens-R/{*}element-LT/{*}element/{*}named-E')
2002 result = f
'CALL {funcName}_PHY(D, ' + \
2003 ', '.join(alltext(arg)
for arg
in args + [result]) +
')'
2004 return createExpr(result)[0]
2006 def getFunctions(node):
2008 Returns the list of functions found in node
2010 def getPath(node, stmt):
2012 Return path of node relative to stmt
2017 result = [tag(item)] + result
2018 item = scope.getParent(item)
2019 return '/'.join(result)
2020 functions = [(elem, getPath(elem, node))
for elem
in node.findall(
'.//{*}named-E')
2021 if n2name(elem.find(
'./{*}N'))
in shugrad]
2024 def replace(old, new):
2026 Replace a node by another one, keeping the tail attribute
2028 if isinstance(new, str):
2029 new = createExprPart(new)
2031 parent = scope.getParent(old)
2032 parent.insert(list(parent).index(old), new)
2037 Extract horizontal computed dimensions
2040 for sslt
in node.findall(
'.//{*}section-subscript-LT'):
2042 for ss
in sslt.findall(
'./{*}section-subscript'):
2043 lb = ss.find(
'./{*}lower-bound')
2044 ub = ss.find(
'./{*}upper-bound')
2045 if (ss.text
and ':' in ss.text)
or (lb
and lb.tail
and ':' in lb.tail):
2046 onedim =
''.join(alltext(item)
for item
in lb)
2048 onedim +=
''.join(alltext(item)
for item
in ub)
2049 thisdims.append(onedim)
2053 if len(dims) != len(thisdims):
2054 raise PYFTError(
'Arrays with different shapes are found in ' +
2055 'the same shuman/gradient: ' + alltext(node))
2056 for i, _
in enumerate(dims):
2057 if 'MERGE' in dims[i]
and 'MERGE' not in thisdims[i]:
2058 thisdims[i] = dims[i]
2059 if 'MERGE' not in dims[i]
and 'MERGE' in thisdims[i]:
2060 dims[i] = thisdims[i]
2061 if not dims == thisdims:
2062 raise PYFTError(
'Arrays with different shapes are found in ' +
2063 'the same shuman/gradient: ' + alltext(node))
2066 def getTemp(node, funcName, nb):
2068 Return a temporary array suitable for the given function name
2070 dims = getHDims(node)
2071 kind =
'2D' if funcName
in shuman2D
else '3D'
2073 temp = f
'ZWORKSHUGRAD_{kind}_{nb[kind]}'
2074 temp = f
'{temp}({", ".join(dims)})'
2077 def insertBefore(present, new):
2079 Insert 'new' just before present
2081 parent = scope.getParent(present)
2082 if tag(parent) ==
'action-stmt':
2083 scope.changeIfStatementsInIfConstructs(singleItem=scope.getParent(parent))
2084 parent = scope.getParent(present)
2085 pos = list(parent).index(present)
2087 new.tail =
'\n' + parent[pos - 1].tail.split(
'\n')[-1]
2088 parent.insert(pos, new)
2090 def insertAfter(present, new):
2092 Insert 'new' just after present
2094 parent = scope.getParent(present)
2095 if tag(parent) ==
'action-stmt':
2096 scope.changeIfStatementsInIfConstructs(singleItem=scope.getParent(parent))
2097 parent = scope.getParent(present)
2098 new.tail =
'\n' + present.tail.split(
'\n')[-1]
2099 pos = list(parent).index(present)
2101 present.tail =
'\n' + parent[pos - 1].tail.split(
'\n')[-1]
2102 parent.insert(list(parent).index(present) + 1, new)
2104 def wrapCompute(stmt, dims):
2106 Insert mnhexpand/openacc directives around stmt (using dims)
2107 Returns integer variables needed for mnh_expand directive
2110 mnhExpandArrayIndexes = []
2111 for i, dim
in enumerate(dims):
2112 var = {0:
'JIJ', 1:
'JK'}[i]
2113 usedVariables.append(var)
2114 mnhExpandArrayIndexes.append(f
'{var}={dim}')
2115 mnhExpandArrayIndexes =
', '.join(mnhExpandArrayIndexes)
2116 mnhOpenDir =
"!$mnh_expand_array(" + mnhExpandArrayIndexes +
")"
2117 mnhCloseDir =
"!$mnh_end_expand_array(" + mnhExpandArrayIndexes +
")"
2118 insertBefore(stmt, createElem(
'C', text=
"!$acc kernels", tail=
'\n'))
2119 insertBefore(stmt, createElem(
'C', text=mnhOpenDir, tail=
'\n'))
2120 insertAfter(stmt, createElem(
'C', text=
"!$acc end kernels", tail=
'\n'))
2121 insertAfter(stmt, createElem(
'C', text=mnhCloseDir, tail=
'\n'))
2122 return usedVariables
2127 for scope
in self.getScopes():
2128 usedSubroutines = set()
2129 usedIntegerVariables = set()
2131 nbmax = {
'2D': 0,
'3D': 0}
2132 for stmt
in [stmt
for tag
in (
'a-stmt',
'call-stmt',
'if-then-stmt',
'else-if-stmt',
2133 'where-construct-stmt',
'else-where-stmt')
2134 for stmt
in scope.findall(
'.//{*}' + tag)]:
2135 nb = {
'2D': 0,
'3D': 0}
2137 functions = getFunctions(stmt)
2144 if tag(stmt) ==
'call-stmt':
2146 for arg
in [arg
for arg
in stmt.find(
'./{*}arg-spec')
2147 if getFunctions(arg)]:
2148 scope.addArrayParenthesesInNode(arg)
2149 scope.addExplicitArrayBounds(arg)
2151 scope.addArrayParenthesesInNode(stmt)
2152 scope.addExplicitArrayBounds(stmt)
2155 for function, _
in sorted(functions, key=
lambda f: f[1].count(
'/'), reverse=
True):
2156 funcName = n2name(function.find(
'./{*}N'))
2157 dims = getHDims(function)
2160 for arg
in function.findall(
'./{*}R-LT/{*}parens-R/' +
2161 '{*}element-LT/{*}element/{*}op-E'):
2162 temp = getTemp(function, funcName, nb)
2163 computeStmt = createExpr(f
'{temp}={alltext(arg)}')[0]
2164 insertBefore(stmt, computeStmt)
2165 usedIntegerVariables.update(wrapCompute(computeStmt, dims))
2172 if tag(stmt) ==
'a-stmt' and \
2173 (
not stmt.find(
'./{*}E-2/{*}op-E'))
and \
2174 (
not stmt.find(
'./{*}E-2/{*}named-E/{*}R-LT/{*}parens-R/' +
2175 '{*}element-LT/{*}element/{*}op-E'))
and \
2176 (function == stmt.find(
'./{*}E-2/{*}named-E')):
2179 callStmt = buildCall(stmt.find(
'./{*}E-2/{*}named-E'),
2180 stmt.find(
'./{*}E-1/{*}named-E'))
2182 replace(stmt, callStmt)
2186 temp = getTemp(function, funcName, nb)
2187 callStmt = buildCall(function, temp)
2188 insertBefore(stmt, callStmt)
2189 replace(function, temp)
2191 callList.append(callStmt)
2192 usedSubroutines.add(funcName +
'_PHY')
2194 if tag(stmt) ==
'a-stmt' and len(functions)
and not fastPath:
2197 usedIntegerVariables.update(wrapCompute(stmt, dims))
2200 for kind
in (
'2D',
'3D'):
2201 nbmax[kind] = max(nbmax[kind], nb[kind])
2205 for sub
in sorted(usedSubroutines):
2206 if re.match(
r'[MD][XYZ][MF](2D)?_PHY', sub):
2207 moduleName =
'MODE_SHUMAN_PHY'
2209 for kind
in (
'M',
'U',
'V',
'W'):
2210 if re.match(
r'G[XYZ]_' + kind +
r'_[MUVW]{1,2}_PHY', sub):
2211 moduleName = f
'MODE_GRADIENT_{kind}_PHY'
2212 if moduleName
not in moduleVars:
2213 moduleVars[moduleName] = []
2214 moduleVars[moduleName].append(sub)
2215 scope.addModuleVar([(scope.path, k, v)
for k, v
in moduleVars.items()])
2220 for varName
in [varName
for varName
in sorted(usedIntegerVariables)
2221 if not scope.varList.findVar(varName)]:
2222 var = {
'as': [],
'asx': [],
2223 'n': varName,
'i':
None,
't':
'INTEGER',
'arg':
False,
2224 'use':
False,
'opt':
False,
'allocatable':
False,
2225 'parameter':
False,
'init':
None,
'scopePath': scope.path}
2226 varDesc.append([scope.path, var[
'n'], scope.varSpec2stmt(var),
None])
2228 for kind
in (
'2D',
'3D'):
2229 for i
in range(1, nbmax[kind] + 1):
2230 var = {
'as': [(
None,
'D%NIJT')]
if kind ==
'2D'
2231 else [(
None,
'D%NIJT'), (
None,
'D%NKT')],
2232 'n': f
'ZWORKSHUGRAD_{kind}_{i}',
'i':
None,
't':
'REAL',
'arg':
False,
2233 'use':
False,
'opt':
False,
'allocatable':
False,
2234 'parameter':
False,
'init':
None,
'scopePath': scope.path}
2235 varDesc.append([scope.path, var[
'n'], scope.varSpec2stmt(var),
None])
2236 scope.addVar(varDesc)
2241 for callStmt
in callList:
2242 scope.removeArrayParenthesesInNode(callStmt)