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 allConst = all(t.lstrip(
'-').isdigit()
for t
in elements)
341 if not allConst
and aStmt
is not None:
343 memberShape = _getShapeFromLHS(aStmt, scope)
344 if memberShape
is not None:
346 newName = variable[0] + structure + variable[1:]
347 newName = newName.upper()
349 namedENn.text = newName
350 rlt = objType.find(
'.//{*}R-LT')
351 compR = rlt.find(
'.//{*}component-R')
354 if newName
not in newVarList:
355 newVarList[newName] = (memberShape, objTypeStr,
358 newName = variable[0] + structure + variable[1:] + arrayIndices
359 newName = newName.upper()
363 namedENn.text = newName
364 objType.remove(objType.find(
'.//{*}R-LT'))
365 if len(arrayRall) > 0:
366 objType.insert(1, arrayR)
369 if newName
not in newVarList:
370 if len(arrayRall) == 0:
371 newVarList[newName] = (
None, objTypeStr)
373 newVarList[newName] = (arrayR, objTypeStr)
375 scopes = self.getScopes()
376 if scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
378 for scope
in [scope
for scope
in scopes
379 if 'sub:' in scope.path
and 'interface' not in scope.path]:
381 for ifStmt
in (scope.findall(
'.//{*}if-then-stmt') +
382 scope.findall(
'.//{*}else-if-stmt') +
383 scope.findall(
'.//{*}where-stmt')):
384 compo = ifStmt.findall(
'.//{*}component-R')
386 for elcompo
in compo:
387 convertOneType(elcompo, newVarList, scope)
389 for aStmt
in scope.findall(
'.//{*}a-stmt'):
392 if len(aStmt[0].findall(
'.//{*}component-R')) == 0:
393 compoE2 = aStmt.findall(
'.//{*}component-R')
400 nbNamedEinE2 = len(aStmt.findall(
'.//{*}E-2')[0].findall(
'.//{*}named-E/' +
402 if nbNamedEinE2 > 1
or nbNamedEinE2 == 1
and \
403 len(aStmt[0].findall(
'.//{*}R-LT')) == 1:
404 for elcompoE2
in compoE2:
405 convertOneType(elcompoE2, newVarList, scope,
410 for aStmt
in scope.findall(
'.//{*}a-stmt'):
412 if len(aStmt[0].findall(
'.//{*}component-R')) > 0:
414 for el
in newVarList.items():
415 if alltext(aStmt[0]) == el[1][1]:
416 stmtAffect = createExpr(el[0] +
"=" + alltext(aStmt[0]))
417 par = scope.getParent(aStmt)
419 if tag(par[list(par).index(aStmt)+1]) ==
'C':
421 par.insert(list(par).index(aStmt)+1+iExtra, stmtAffect[0])
425 for el, var
in newVarList.items():
426 if el[0].upper() ==
'X' or el[0].upper() ==
'P' or el[0].upper() ==
'Z':
428 elif el[0].upper() ==
'L' or el[0].upper() ==
'O':
430 elif el[0].upper() ==
'N' or el[0].upper() ==
'I' or el[0].upper() ==
'K':
432 elif el[0].upper() ==
'C':
433 varType =
'CHARACTER(LEN=LEN(' + var[1] +
'))'
435 raise PYFTError(
'Case not implemented for the first letter of the newVarName ' +
436 el +
' in convertTypesInCompute')
439 if isinstance(var[0], list):
442 varArray =
', DIMENSION('
443 for i, bound
in enumerate(memberShape):
454 varArray =
', DIMENSION('
455 for i, sub
in enumerate(var[0].findall(
'.//{*}section-subscript')):
456 if len(sub.findall(
'.//{*}upper-bound')) > 0:
457 dimSize = simplifyExpr(
458 alltext(sub.findall(
'.//{*}upper-bound')[0]) +
459 '-' + alltext(sub.findall(
'.//{*}lower-bound')[0]) +
461 elif len(sub.findall(
'.//{*}lover-bound')) > 0:
462 dimSize = simplifyExpr(alltext(sub.findall(
'.//{*}lower-bound')[0]))
464 dimSize =
'SIZE(' + var[1] +
',' + str(i+1) +
')'
465 varArray =
', DIMENSION(' + dimSize +
','
466 varArray = varArray[:-1] +
')'
467 scope.addVar([[scope.path, el, varType + varArray +
' :: ' + el,
None]])
470 if isinstance(var[0], list):
472 stmtAffect = createExpr(el +
"=" + var[2] +
'%' + var[3])[0]
474 stmtAffect = createExpr(el +
"=" + var[1])[0]
475 scope.insertStatement(scope.indent(stmtAffect), first=
True)
581 Convert MODULE to SUBMODULE statements and add INTERFACE of SUBROUTINEs of PHYEX
582 ==> Applied only on MODE_
584 - if an INTERFACE already exists
585 - if no subroutine is present in the module
586 - to CONTAINS routines
587 1) Create interface statement if any
588 2) Add subroutines declaration (with MODULE statement)
589 3) Add SUBMODULE statements and convert SUBROUTINE to MODULE SUBROUTINE statements
591 scopes = self.getScopes()
594 oldModNode = self.find(
'.//{*}program-unit')
595 modNode = copy.deepcopy(self.find(
'.//{*}program-unit'))
597 interfaceStmt = self.findall(
'.//{*}interface-stmt')
598 subStmt = self.findall(
'.//{*}subroutine-stmt')
600 if modScope.path.split(
'/')[-1].split(
':')[1][:4] ==
'MODE' and \
601 len(interfaceStmt) == 0
and len(subStmt) > 0:
602 moduleName = modScope.path.split(
'/')[-1].split(
':')[1][:]
604 newMod = createElem(
'program-unit', text=
'MODULE ' + moduleName, tail=
'\n')
606 newMod.append(createElem(
'implicit-none-stmt', text=
'IMPLICIT NONE', tail=
'\n'))
607 interfaceStmt = createElem(
'interface-construct')
608 interfaceStmt.append(createElem(
'interface-stmt', text=
'INTERFACE', tail=
'\n'))
609 interfaceStmt.append(createElem(
'end-interface-stmt', text=
'END INTERFACE', tail=
'\n'))
610 newMod.append(interfaceStmt)
614 for scope
in scopes[1:]:
616 if sum(
'sub' in s
for s
in scope.path.split(
'/')) == 1:
617 subsModified.append(scope.path.split(
'/')[-1].split(
':')[1][:])
618 subroutineDecl = createElem(
'module-unit')
620 subroutineStmt = copy.deepcopy(scope[0])
621 declType = subroutineStmt.text
622 prefix = createElem(
'prefix')
623 prefix.text =
'MODULE'
624 subroutineStmt.text =
''
625 subroutineStmt.insert(0, prefix)
626 prefix.tail =
' ' + declType
627 subroutineDecl.append(subroutineStmt)
629 for use
in scope.findall(
'.//{*}use-stmt'):
630 subroutineDecl.append(copy.deepcopy(use))
631 subroutineDecl.append(createElem(
'implicit-none-stmt', text=
'IMPLICIT NONE',
634 for var
in [var
for var
in scope.varList
if var[
'arg']
or var[
'result']]:
635 subroutineDecl.append(createExpr(self.varSpec2stmt(var,
True))[0])
636 for external
in scope.findall(
'./{*}external-stmt'):
637 subroutineDecl.append(copy.deepcopy(external))
638 if 'SUBROUTINE' in declType:
639 endStmt = createElem(
'end-subroutine-stmt')
640 declName = subroutineStmt.find(
'./{*}subroutine-N/{*}N/{*}n').text
641 elif 'FUNCTION' in declType:
642 endStmt = createElem(
'end-function-stmt')
643 declName = subroutineStmt.find(
'./{*}function-N/{*}N/{*}n').text
645 raise PYFTError(
'declType in addSubmodulePHYEX not handled')
647 endStmt.text =
'END ' + declType + declName +
'\n'
648 subroutineDecl.append(endStmt)
649 interfaceStmt.insert(1, subroutineDecl)
652 newMod.append(createElem(
'end-program-unit', text=
'END MODULE ' + moduleName,
654 self[0].insert(0, newMod)
657 progUnit = createElem(
'program-unit')
668 submoduleStmt = createElem(
'submodule-stmt', text=
'SUBMODULE (')
669 parentId = createElem(
'parent-identifier')
671 ancestorModule = createElem(
'ancestor-module-N')
672 ancestorModuleN = createElem(
'n', text=moduleName)
673 ancestorModule.append(ancestorModuleN)
674 parentId.append(ancestorModule)
675 submoduleStmt.append(parentId)
676 submoduleModule = createElem(
'submodule-module-N')
677 submoduleModuleN = createElem(
'n', text=
'S' + moduleName, tail=
'\n')
678 submoduleModule.append(submoduleModuleN)
679 submoduleStmt.append(submoduleModule)
680 progUnit.append(submoduleStmt)
683 endSubmoduleStmt = createElem(
'end-submodule-stmt', text=
'END SUBMODULE ')
684 submoduleN = createElem(
'submodule-N')
685 submoduleNN = createElem(
'N')
686 submoduleNNn = createElem(
'n', text=
'S' + moduleName, tail=
'\n')
687 submoduleNN.append(submoduleNNn)
688 submoduleN.append(submoduleNN)
689 endSubmoduleStmt.append(submoduleN)
691 progUnit.append(endSubmoduleStmt)
692 progUnit.append(createElem(
'end-program-unit'))
696 modStmt = modNode.find(
'.//{*}module-stmt')
697 modEndStmt = modNode.find(
'.//{*}end-module-stmt')
698 modNode.remove(modStmt)
699 modNode.remove(modEndStmt)
702 publicStmts = modNode.findall(
'.//{*}public-stmt')
703 privateStmts = modNode.findall(
'.//{*}private-stmt')
704 if len(publicStmts) > 0:
705 for publicStmt
in publicStmts:
706 modNode.remove(publicStmt)
707 if len(privateStmts) > 0:
708 for privateStmt
in privateStmts:
709 modNode.remove(privateStmt)
712 subroutines = modNode.findall(
'.//{*}subroutine-stmt')
713 for sub
in subroutines:
714 if sub.find(
'.//{*}N/{*}n').text
in subsModified:
715 prefix = createElem(
'prefix')
716 prefix.text =
'MODULE'
718 sub.insert(0, prefix)
719 prefix.tail =
' SUBROUTINE '
720 progUnit.insert(1, modNode)
722 self.insert(1, progUnit)
725 self.remove(oldModNode)
731 Add MPPDB_CHEKS on all intent REAL arrays on subroutines.
732 ****** Not applied on modd_ routines. ********
733 Handle optional arguments.
734 Example, for a BL89 routine with 4 arguments, 1 INTENT(IN),
735 2 INTENT(INOUT), 1 INTENT(OUT), it produces :
736 IF (MPPDB_INITIALIZED) THEN
738 CALL MPPDB_CHECK(PZZ, "BL89 beg:PZZ")
739 !Check all INOUT arrays
740 CALL MPPDB_CHECK(PDZZ, "BL89 beg:PDZZ")
741 CALL MPPDB_CHECK(PTHVREF, "BL89 beg:PTHVREF")
744 IF (MPPDB_INITIALIZED) THEN
745 !Check all INOUT arrays
746 CALL MPPDB_CHECK(PDZZ, "BL89 end:PDZZ")
747 CALL MPPDB_CHECK(PTHVREF, "BL89 end:PTHVREF")
748 !Check all OUT arrays
749 CALL MPPDB_CHECK(PLM, "BL89 end:PLM")
751 param printsMode: if True, instead of CALL MPPDB_CHECK, add fortran prints for debugging
753 def addPrints_statement(var, typeofPrints='minmax'):
754 ifBeg, ifEnd =
'',
''
757 if typeofPrints ==
'minmax':
758 strMSG = f
'MINMAX {varName} = \",MINVAL({varName}), MAXVAL({varName})'
759 elif typeofPrints ==
'shape':
760 strMSG = f
'SHAPE {varName} = \",SHAPE({varName})'
762 raise PYFTError(
'typeofPrints is either minmax or shape in addPrints_statement')
764 strMSG = var[
'n'] +
' = \",' + var[
'n']
766 ifBeg = ifBeg +
'IF (PRESENT(' + var[
'n'] +
')) THEN\n '
767 ifEnd = ifEnd +
'\nEND IF'
768 return createExpr(ifBeg +
"print*,\"" + strMSG + ifEnd)[0]
770 def addMPPDB_CHECK_statement(var, subRoutineName, strMSG='beg:
'):
771 ifBeg, ifEnd, addD, addLastDim, addSecondDimType = '',
'',
'',
'',
''
775 if 'D%NIJT' in var[
'as'][0][1]:
777 if len(var[
'as']) == 2:
779 addLastDim =
', ' + var[
'as'][1][1]
780 if len(var[
'as']) >= 2:
783 if 'D%NK' in var[
'as'][1][1]:
784 addSecondDimType =
',' +
'''"VERTICAL"'''
786 addSecondDimType =
',' +
'''"OTHER"'''
787 if 'MERGE' in var[
'as'][-1][1]:
788 keyDimMerge = var[
'as'][-1][1].split(
',')[2][:-1]
789 ifBeg =
'IF (' + keyDimMerge +
') THEN\n'
792 ifBeg = ifBeg +
'IF (PRESENT(' + var[
'n'] +
')) THEN\n IF (SIZE(' + \
793 var[
'n'] +
',1) > 0) THEN\n'
794 ifEnd = ifEnd +
'\nEND IF\nEND IF'
795 argsMPPDB = var[
'n'] +
", " +
"\"" + subRoutineName +
" " + strMSG+var[
'n'] +
"\""
796 return createExpr(ifBeg +
"CALL MPPDB_CHECK(" + addD + argsMPPDB +
797 addLastDim + addSecondDimType +
")" + ifEnd)[0]
798 scopes = self.getScopes()
799 if scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
806 if 'sub:' in scope.path
and 'func' not in scope.path
and 'interface' not in scope.path:
807 subRoutineName = scope.path.split(
'/')[-1].split(
':')[1]
810 arraysIn, arraysInOut, arraysOut = [], [], []
812 for var
in scope.varList:
813 if var[
'arg']
and var[
'as']
and 'TYPE' not in var[
't']
and \
814 'REAL' in var[
't']
and var[
'scopePath'] == scope.path:
817 if var[
'i'] ==
'INOUT':
818 arraysInOut.append(var)
819 if var[
'i'] ==
'OUT':
820 arraysOut.append(var)
822 for var
in scope.varList:
823 if not var[
't']
or var[
't']
and 'TYPE' not in var[
't']:
826 if var[
'i'] ==
'INOUT':
827 arraysInOut.append(var)
828 if var[
'i'] ==
'OUT':
829 arraysOut.append(var)
831 if len(arraysIn) + len(arraysInOut) + len(arraysOut) == 0:
836 scope.addModuleVar([(scope.path,
'MODE_MPPDB',
None)])
838 scope.addModuleVar([(scope.path,
'MODD_BLANK_n', [
'LDUMMY1'])])
841 commentIN = createElem(
'C', text=
'!Check all IN arrays', tail=
'\n')
842 commentINOUT = createElem(
'C', text=
'!Check all INOUT arrays', tail=
'\n')
843 commentOUT = createElem(
'C', text=
'!Check all OUT arrays', tail=
'\n')
846 if len(arraysIn) + len(arraysInOut) > 0:
848 ifMPPDBinit = createExpr(
"IF (MPPDB_INITIALIZED) THEN\n END IF")[0]
850 ifMPPDBinit = createExpr(
"IF (LDUMMY1) THEN\n END IF")[0]
851 ifMPPDB = ifMPPDBinit.find(
'.//{*}if-block')
854 if len(arraysIn) > 0:
855 ifMPPDB.insert(1, commentIN)
856 for i, var
in enumerate(arraysIn):
858 ifMPPDB.insert(2 + i, addMPPDB_CHECK_statement(var, subRoutineName,
861 ifMPPDB.insert(2 + i, addPrints_statement(var,
862 typeofPrints=
'minmax'))
863 ifMPPDB.insert(3 + i, addPrints_statement(var,
864 typeofPrints=
'shape'))
867 if len(arraysInOut) > 0:
868 shiftLineNumber = 2
if len(arraysIn) > 0
else 1
870 ifMPPDB.insert(len(arraysIn) + shiftLineNumber, commentINOUT)
872 ifMPPDB.insert(len(arraysIn)*2 + shiftLineNumber-1, commentINOUT)
874 for i, var
in enumerate(arraysInOut):
876 ifMPPDB.insert(len(arraysIn) + shiftLineNumber + 1 + i,
877 addMPPDB_CHECK_statement(var, subRoutineName,
880 ifMPPDB.insert(len(arraysIn) + shiftLineNumber + 1 + i,
881 addPrints_statement(var, typeofPrints=
'minmax'))
884 scope.insertStatement(scope.indent(ifMPPDBinit), first=
True)
887 if len(arraysInOut) + len(arraysOut) > 0:
889 ifMPPDBend = createExpr(
"IF (MPPDB_INITIALIZED) THEN\n END IF")[0]
891 ifMPPDBend = createExpr(
"IF (LDUMMY1) THEN\n END IF")[0]
892 ifMPPDB = ifMPPDBend.find(
'.//{*}if-block')
895 if len(arraysInOut) > 0:
896 ifMPPDB.insert(1, commentINOUT)
897 for i, var
in enumerate(arraysInOut):
899 ifMPPDB.insert(2 + i, addMPPDB_CHECK_statement(var, subRoutineName,
902 ifMPPDB.insert(2 + i, addPrints_statement(var,
903 typeofPrints=
'minmax'))
906 if len(arraysOut) > 0:
907 shiftLineNumber = 2
if len(arraysInOut) > 0
else 1
909 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber, commentOUT)
911 ifMPPDB.insert(len(arraysInOut)*2 + shiftLineNumber-1, commentOUT)
912 for i, var
in enumerate(arraysOut):
914 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber + 1 + i,
915 addMPPDB_CHECK_statement(var, subRoutineName,
918 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber + 1 + i,
919 addPrints_statement(var, typeofPrints=
'minmax'))
922 scope.insertStatement(scope.indent(ifMPPDBend), first=
False)
1047 def removeIJDim(self, stopScopes, parserOptions=None, wrapH=False, simplify=False):
1049 Transform routines to be called in a loop on columns
1050 :param stopScopes: scope paths where we stop to add the D argument (if needed)
1051 :param parserOptions, wrapH: see the PYFT class
1052 :param simplify: try to simplify code (remove useless dimensions in call)
1054 ComputeInSingleColumn :
1055 - Remove all Do loops on JI and JJ
1056 - Initialize former indexes JI, JJ, JIJ to first array element:
1057 JI=D%NIB, JJ=D%NJB, JIJ=D%NIJB
1058 - If simplify is True, replace (:,*) on I/J/IJ dimension on argument
1059 with explicit (:,*) on CALL statements:
1060 e.g. CALL FOO(D, A(:,JK,1), B(:,:))
1061 ==> CALL FOO(D, A(JIJ,JK,1), B(:,:)) only if the target argument is not an array
1064 indexToCheck = {
'JI': (
'D%NIB',
'D%NIT'),
1065 'JJ': (
'D%NJB',
'D%NJT'),
1066 'JIJ': (
'D%NIJB',
'D%NIJT')}
1067 hUupperBounds = [v[1]
for v
in indexToCheck.values()]
1069 def slice2index(namedE, scope):
1071 Transform a slice on the horizontal dimension into an index
1072 Eg.: X(1:D%NIJT, 1:D%NKT) => X(JIJ, 1:D%NKT) Be careful, this array is not contiguous.
1073 X(1:D%NIJT, JK) => X(JIJ, JK)
1074 :param namedE: array to transform
1075 :param scope: scope where the array is
1078 for isub, sub
in enumerate(namedE.findall(
'./{*}R-LT/{*}array-R/' +
1079 '{*}section-subscript-LT/' +
1080 '{*}section-subscript')):
1081 if ':' in alltext(sub):
1082 loopIndex, _, _ = scope.findIndexArrayBounds(namedE, isub, _loopVarPHYEX)
1083 if loopIndex
in indexToCheck:
1086 lowerBound = createElem(
'lower-bound')
1087 sub.insert(0, lowerBound)
1089 lowerBound = sub.find(
'./{*}lower-bound')
1090 lowerBound.tail =
''
1091 for item
in lowerBound:
1092 lowerBound.remove(item)
1093 upperBound = sub.find(
'./{*}upper-bound')
1094 if upperBound
is not None:
1095 sub.remove(upperBound)
1096 lowerBound.append(createExprPart(loopIndex))
1097 if loopIndex
not in indexRemoved:
1098 indexRemoved.append(loopIndex)
1101 if ':' not in alltext(namedE.find(
'./{*}R-LT/{*}array-R/{*}section-subscript-LT')):
1102 namedE.find(
'./{*}R-LT/{*}array-R').tag = f
'{{{NAMESPACE}}}parens-R'
1103 namedE.find(
'./{*}R-LT/{*}parens-R/' +
1104 '{*}section-subscript-LT').tag = f
'{{{NAMESPACE}}}element-LT'
1105 for ss
in namedE.findall(
'./{*}R-LT/{*}parens-R/' +
1106 '{*}element-LT/{*}section-subscript'):
1107 ss.tag = f
'{{{NAMESPACE}}}element'
1108 lowerBound = ss.find(
'./{*}lower-bound')
1109 for item
in lowerBound:
1111 ss.remove(lowerBound)
1114 self.attachArraySpecToEntity()
1118 for scope
in [scope
for scope
in self.getScopes()[::-1]
1119 if 'func:' not in scope.path
and
1120 (scope.path
in stopScopes
or
1121 self.tree.isUnderStopScopes(scope.path, stopScopes,
1122 includeInterfaces=
True))]:
1124 scope.addArrayParentheses()
1125 scope.expandAllArraysPHYEX()
1132 for doNode
in scope.findall(
'.//{*}do-construct')[::-1]:
1133 for loopI
in doNode.findall(
'./{*}do-stmt/{*}do-V/{*}named-E/{*}N'):
1134 loopIname = n2name(loopI).upper()
1135 if loopIname
in indexToCheck:
1138 par = scope.getParent(doNode)
1139 index = list(par).index(doNode)
1140 for item
in doNode[1:-1][::-1]:
1141 par.insert(index, item)
1143 if loopIname
not in indexRemoved:
1144 indexRemoved.append(loopIname)
1149 for intr
in scope.findall(
'.//{*}R-LT/{*}parens-R/../..'):
1150 intrName = n2name(intr.find(
'./{*}N')).upper()
1151 if intrName
in (
'PACK',
'UNPACK',
'COUNT',
'MAXVAL',
'MINVAL',
'ALL',
'ANY',
'SUM'):
1159 while par
is not None and not isStmt(par):
1160 par = scope.getParent(par)
1161 if tag(par)
in (
'a-stmt',
'op-E'):
1166 for namedE
in parToUse.findall(
'.//{*}R-LT/{*}array-R/../..'):
1167 slice2index(namedE, scope)
1170 if intr.find(
'.//{*}R-LT/{*}array-R')
is None:
1171 if intrName
in (
'MAXVAL',
'MINVAL',
'SUM',
'ALL',
'ANY'):
1173 parens = intr.find(
'./{*}R-LT/{*}parens-R')
1174 parens.tag = f
'{{{NAMESPACE}}}parens-E'
1175 intrPar = scope.getParent(intr)
1176 intrPar.insert(list(intrPar).index(intr), parens)
1177 intrPar.remove(intr)
1178 elif intrName ==
'COUNT':
1180 nodeN = intr.find(
'./{*}N')
1181 for item
in nodeN[1:]:
1183 nodeN.find(
'./{*}n').text =
'MERGE'
1184 elementLT = intr.find(
'./{*}R-LT/{*}parens-R/{*}element-LT')
1186 element = createElem(
'element', tail=
', ')
1187 element.append(createExprPart(val))
1188 elementLT.insert(0, element)
1201 assert scope.find(
'.//{*}include')
is None and \
1202 scope.find(
'.//{*}include-stmt')
is None, \
1203 "inlining must be performed before removing horizontal dimensions"
1205 if scope.path
in stopScopes:
1207 preserveShape = [v[
'n']
for v
in scope.varList
if v[
'arg']]
1212 if 'sub:' in scope.path:
1216 for namedE
in scope.findall(
'.//{*}named-E/{*}R-LT/{*}parens-R/../..'):
1217 if n2name(namedE.find(
'./{*}N')).upper()
not in preserveShape:
1218 var = scope.varList.findVar(n2name(namedE.find(
'./{*}N')).upper())
1219 if var
is not None and var[
'as']
is not None and len(var[
'as']) > 0:
1220 subs = namedE.findall(
'./{*}R-LT/{*}parens-R/' +
1221 '{*}element-LT/{*}element')
1222 if (len(subs) == 1
and var[
'as'][0][1]
in hUupperBounds)
or \
1223 (len(subs) == 2
and (var[
'as'][0][1]
in hUupperBounds
and
1224 var[
'as'][1][1]
in hUupperBounds)):
1225 namedE.remove(namedE.find(
'./{*}R-LT'))
1229 for call
in scope.findall(
'.//{*}call-stmt'):
1230 for namedE
in call.findall(
'./{*}arg-spec//{*}named-E'):
1231 subs = namedE.findall(
'.//{*}section-subscript')
1232 var = scope.varList.findVar(n2name(namedE.find(
'./{*}N')).upper())
1233 if len(subs) > 0
and (var
is None or var[
'as']
is None or
1234 len(var[
'as']) < len(subs)):
1242 elif (len(subs) >= 2
and
1243 ':' in alltext(subs[0])
and var[
'as'][0][1]
in hUupperBounds
and
1244 ':' in alltext(subs[1])
and var[
'as'][1][1]
in hUupperBounds):
1246 remove = len(subs) == 2
1247 index = (len(subs) > 2
and
1248 len([sub
for sub
in subs
if ':' in alltext(sub)]) == 2)
1249 elif (len(subs) >= 1
and
1250 ':' in alltext(subs[0])
and var[
'as'][0][1]
in hUupperBounds):
1252 remove = len(subs) == 1
1253 index = (len(subs) > 1
and
1254 len([sub
for sub
in subs
if ':' in alltext(sub)]) == 1)
1259 if n2name(namedE.find(
'./{*}N')).upper()
in preserveShape:
1260 slice2index(namedE, scope)
1262 nodeRLT = namedE.find(
'.//{*}R-LT')
1263 scope.getParent(nodeRLT).remove(nodeRLT)
1265 slice2index(namedE, scope)
1268 subs = namedE.findall(
'.//{*}section-subscript')
1269 if len(subs) > 0
and all(alltext(sub) ==
':' for sub
in subs):
1270 nodeRLT = namedE.find(
'.//{*}R-LT')
1271 scope.getParent(nodeRLT).remove(nodeRLT)
1276 for decl
in scope.findall(
'.//{*}T-decl-stmt/{*}EN-decl-LT/{*}EN-decl'):
1277 name = n2name(decl.find(
'./{*}EN-N/{*}N')).upper()
1278 if name
not in preserveShape:
1279 varsShape = decl.findall(
'.//{*}shape-spec-LT')
1280 for varShape
in varsShape:
1281 subs = varShape.findall(
'.//{*}shape-spec')
1282 if (len(subs) == 1
and alltext(subs[0])
in hUupperBounds)
or \
1283 (len(subs) == 2
and (alltext(subs[0])
in hUupperBounds
and
1284 alltext(subs[1])
in hUupperBounds)):
1286 itemToRemove = scope.getParent(varShape)
1287 scope.getParent(itemToRemove).remove(itemToRemove)
1292 for loopIndex
in indexRemoved:
1295 scope.insertStatement(
1296 createExpr(loopIndex +
" = " + indexToCheck[loopIndex][0])[0],
True)
1297 if len(indexRemoved) > 0:
1298 scope.addArgInTree(
'D',
'TYPE(DIMPHYEX_t), INTENT(IN) :: D',
1299 0, stopScopes, moduleVarList=[(
'MODD_DIMPHYEX', [
'DIMPHYEX_t'])],
1300 parserOptions=parserOptions, wrapH=wrapH)
1302 scope.addVar([[scope.path, loopIndex,
'INTEGER :: ' + loopIndex,
None]
1303 for loopIndex
in indexRemoved
1304 if scope.varList.findVar(loopIndex, exactScope=
True)
is None])
1500 Convert all calling of functions and gradient present in shumansGradients
1501 table into the use of subroutines
1502 and use mnh_expand_directives to handle intermediate computations
1504 def getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar=''):
1506 if zshugradwkDim == 1:
1507 dimSuffRoutine =
'2D'
1509 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE'
1510 localVariables = [
'JIJ']
1511 elif zshugradwkDim == 2:
1513 if 'D%NKT' in dimWorkingVar:
1514 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE,JK=1:IKT'
1515 localVariables = [
'JIJ',
'JK']
1516 elif 'D%NIT' in dimWorkingVar
and 'D%NJT' in dimWorkingVar:
1518 mnhExpandArrayIndexes =
'JI=1:IIT,JJ=1:IJT'
1519 localVariables = [
'JI',
'JJ']
1520 dimSuffRoutine =
'2D'
1526 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE,JK=1:IKT'
1527 localVariables = [
'JIJ',
'JK']
1528 elif zshugradwkDim == 3:
1530 mnhExpandArrayIndexes =
'JI=1:IIT,JJ=1:IJT,JK=1:IKT'
1531 localVariables = [
'JI',
'JJ',
'JK']
1533 raise PYFTError(
'Shuman func to routine conversion not implemented ' +
1534 'for 4D+ dimensions variables')
1535 return dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, localVariables
1537 def FUNCtoROUTINE(scope, stmt, itemFuncN, localShumansCount, inComputeStmt,
1538 nbzshugradwk, zshugradwkDim, dimWorkingVar):
1540 :param scope: node on which the calling function is present before transformation
1541 :param stmt: statement node (a-stmt or call-stmt) that contains the function(s) to be
1543 :param itemFuncN: <n>FUNCTIONNAME</n> node
1544 :param localShumansCount: instance of the shumansGradients dictionnary
1545 for the given scope (which contains the number of times a
1546 function has been called within a transformation)
1547 :param dimWorkingVar: string of the declaration of a potential working variable
1548 depending on the array on wich the shuman is applied
1549 (e.g. MZM(PRHODJ(:,IKB));
1550 dimWorkingVar = 'REAL, DIMENSION(D%NIJT) :: ' )
1552 :return callStmt: the new CALL to the routines statement
1553 :return computeStmt: the a-stmt computation statement if there was an operation
1554 in the calling function in stmt
1555 :return localVariables: list of local variables needed for the mnh_expand directive
1559 parStmt = scope.getParent(stmt)
1560 parItemFuncN = scope.getParent(itemFuncN)
1562 grandparItemFuncN = scope.getParent(itemFuncN, level=2)
1563 funcName = alltext(itemFuncN)
1566 indexForCall = list(parStmt).index(stmt)
1571 siblsItemFuncN = scope.getSiblings(parItemFuncN, after=
True, before=
False)
1572 workingItem = siblsItemFuncN[0][0][0]
1575 if len(siblsItemFuncN[0][0]) > 1:
1577 workingItem = scope.updateContinuation(siblsItemFuncN[0][0], removeALL=
True,
1578 align=
False, addBegin=
False)[0]
1582 opE = workingItem.findall(
'.//{*}op-E')
1583 scope.removeArrayParenthesesInNode(workingItem)
1584 computeStmt, remaningArgsofFunc = [],
''
1585 dimSuffVar = str(zshugradwkDim) +
'D'
1586 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, _ = \
1587 getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar)
1590 computingVarName =
'ZSHUGRADWK'+str(nbzshugradwk)+
'_'+str(zshugradwkDim)+
'D'
1592 if not scope.varList.findVar(computingVarName):
1593 scope.addVar([[scope.path, computingVarName,
1594 dimWorkingVar + computingVarName,
None]])
1598 computeVar = scope.varList.findVar(computingVarName)
1599 dimWorkingVar =
'REAL, DIMENSION('
1600 for dims
in computeVar[
'as'][:arrayDim]:
1601 dimWorkingVar += dims[1] +
','
1602 dimWorkingVar = dimWorkingVar[:-1] +
') ::'
1604 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, localVariables = \
1605 getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar)
1608 mnhOpenDir =
"!$mnh_expand_array(" + mnhExpandArrayIndexes +
")"
1609 mnhCloseDir =
"!$mnh_end_expand_array(" + mnhExpandArrayIndexes +
")"
1612 workingComputeItem = workingItem[0]
1614 if len(workingItem) == 2:
1615 remaningArgsofFunc =
',' + alltext(workingItem[1])
1616 elif len(workingItem) > 2:
1617 raise PYFTError(
'ShumanFUNCtoCALL: expected maximum 1 argument in shuman ' +
1618 'function to transform')
1619 computeStmt = createExpr(computingVarName +
" = " + alltext(workingComputeItem))[0]
1620 workingItem = computeStmt.find(
'.//{*}E-1')
1622 parStmt.insert(indexForCall, createElem(
'C', text=
'!$acc kernels', tail=
'\n'))
1623 parStmt.insert(indexForCall + 1, createElem(
'C', text=mnhOpenDir, tail=
'\n'))
1624 parStmt.insert(indexForCall + 2, computeStmt)
1625 parStmt.insert(indexForCall + 3, createElem(
'C', text=mnhCloseDir, tail=
'\n'))
1626 parStmt.insert(indexForCall + 4, createElem(
'C',
1627 text=
'!$acc end kernels', tail=
'\n'))
1628 parStmt.insert(indexForCall + 5, createElem(
'C',
1629 text=
'!', tail=
'\n'))
1633 if zshugradwkDim == 1:
1634 dimSuffRoutine =
'2D'
1635 workingVar =
'Z' + funcName + dimSuffVar +
'_WORK' + str(localShumansCount[funcName])
1636 if funcName
in (
'GY_U_UV',
'GX_V_UV'):
1637 gpuGradientImplementation =
'_DEVICE('
1638 newFuncName = funcName + dimSuffRoutine +
'_DEVICE'
1640 gpuGradientImplementation =
'_PHY(D, '
1641 newFuncName = funcName + dimSuffRoutine +
'_PHY'
1642 callStmt = createExpr(
"CALL " + funcName + dimSuffRoutine + gpuGradientImplementation
1643 + alltext(workingItem) + remaningArgsofFunc +
1644 ", " + workingVar +
")")[0]
1645 parStmt.insert(indexForCall, callStmt)
1648 parOfgrandparItemFuncN = scope.getParent(grandparItemFuncN)
1649 indexWorkingVar = list(parOfgrandparItemFuncN).index(grandparItemFuncN)
1650 savedTail = grandparItemFuncN.tail
1651 parOfgrandparItemFuncN.remove(grandparItemFuncN)
1654 xmlWorkingvar = createExprPart(workingVar)
1655 xmlWorkingvar.tail = savedTail
1656 parOfgrandparItemFuncN.insert(indexWorkingVar, xmlWorkingvar)
1659 if not scope.varList.findVar(workingVar):
1660 scope.addVar([[scope.path, workingVar, dimWorkingVar + workingVar,
None]])
1662 return (callStmt, computeStmt, nbzshugradwk, newFuncName,
1663 localVariables, mnhExpandArrayIndexes)
1665 shumansGradients = {
'MZM': 0,
'MXM': 0,
'MYM': 0,
'MZF': 0,
'MXF': 0,
'MYF': 0,
1666 'DZM': 0,
'DXM': 0,
'DYM': 0,
'DZF': 0,
'DXF': 0,
'DYF': 0,
1667 'GZ_M_W': 0,
'GZ_W_M': 0,
'GZ_U_UW': 0,
'GZ_V_VW': 0,
1668 'GX_M_U': 0,
'GX_U_M': 0,
'GX_W_UW': 0,
'GX_M_M': 0,
1669 'GY_V_M': 0,
'GY_M_V': 0,
'GY_W_VW': 0,
'GY_M_M': 0,
1670 'GX_V_UV': 0,
'GY_U_UV': 0}
1671 scopes = self.getScopes()
1672 if len(scopes) == 0
or scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
1674 for scope
in scopes:
1675 if 'sub:' in scope.path
and 'func' not in scope.path \
1676 and 'interface' not in scope.path:
1679 localVariablesToAdd = set()
1680 foundStmtandCalls, computeStmtforParenthesis = {}, []
1681 aStmt = scope.findall(
'.//{*}a-stmt')
1682 callStmts = scope.findall(
'.//{*}call-stmt')
1683 aStmtandCallStmts = aStmt + callStmts
1684 funcToSuppress = set()
1685 for stmt
in aStmtandCallStmts:
1686 elemN = stmt.findall(
'.//{*}n')
1688 if alltext(el)
in list(shumansGradients):
1689 funcToSuppress.add(alltext(el))
1692 parStmt = scope.getParent(stmt)
1693 if tag(parStmt) ==
'action-stmt':
1694 scope.changeIfStatementsInIfConstructs(
1695 singleItem=scope.getParent(parStmt))
1697 if str(stmt)
in foundStmtandCalls:
1698 foundStmtandCalls[str(stmt)][1] += 1
1700 foundStmtandCalls[str(stmt)] = [stmt, 1]
1703 subToInclude = set()
1704 for stmt
in foundStmtandCalls:
1705 localShumansGradients = copy.deepcopy(shumansGradients)
1706 elemToLookFor = [foundStmtandCalls[stmt][0]]
1707 previousComputeStmt = []
1710 while len(elemToLookFor) > 0:
1712 for elem
in elemToLookFor:
1713 elemN = elem.findall(
'.//{*}n')
1715 if alltext(el)
in list(localShumansGradients.keys()):
1720 nodeE1var = foundStmtandCalls[stmt][0].findall(
1721 './/{*}E-1/{*}named-E/{*}N')
1722 if len(nodeE1var) > 0:
1723 var = scope.varList.findVar(alltext(nodeE1var[0]))
1724 allSubscripts = foundStmtandCalls[stmt][0].findall(
1725 './/{*}E-1//{*}named-E/{*}R-LT/' +
1726 '{*}array-R/{*}section-subscript-LT')
1730 elPar = scope.getParent(el, level=2)
1731 callVar = elPar.findall(
'.//{*}named-E/{*}N')
1732 if alltext(el)[0] ==
'G':
1737 var = scope.varList.findVar(alltext(callVar[-1]))
1738 shumanIsCalledOn = scope.getParent(callVar[-1])
1741 var, inested =
None, 0
1743 while (
not var
or var[
'as']
is None or
1744 len(var[
'as']) == 0):
1748 var = scope.varList.findVar(
1749 alltext(callVar[inested]))
1751 shumanIsCalledOn = scope.getParent(callVar[inested-1])
1752 allSubscripts = shumanIsCalledOn.findall(
1753 './/{*}R-LT/{*}array-R/' +
1754 '{*}section-subscript-LT')
1758 arrayDim = len(var[
'as'])
1762 if len(allSubscripts) > 0:
1763 for subLT
in allSubscripts:
1765 lowerBound = sub.findall(
'.//{*}lower-bound')
1766 if len(lowerBound) > 0:
1767 if len(sub.findall(
'.//{*}upper-bound')) > 0:
1770 raise PYFTError(
'ShumanFUNCtoCALL does ' +
1771 'not handle conversion ' +
1772 'to routine of array ' +
1773 'subselection lower:upper' +
1774 ': how to set up the ' +
1775 'shape of intermediate ' +
1785 dimWorkingVar =
'REAL, DIMENSION('
1786 for dims
in var[
'as'][:arrayDim]:
1787 dimWorkingVar += dims[1] +
','
1788 dimWorkingVar = dimWorkingVar[:-1] +
') ::'
1791 localShumansGradients[alltext(el)] += 1
1795 if foundStmtandCalls[stmt][0].tail:
1796 foundStmtandCalls[stmt][0].tail = \
1797 foundStmtandCalls[stmt][0].tail.replace(
'\n',
'') +
'\n'
1799 foundStmtandCalls[stmt][0].tail =
'\n'
1802 result = FUNCtoROUTINE(scope, elem, el,
1803 localShumansGradients,
1804 elem
in previousComputeStmt,
1805 nbzshugradwk, arrayDim,
1807 (newCallStmt, newComputeStmt,
1808 nbzshugradwk, newFuncName, lv,
1809 mnhExpandArrayIndexes) = result
1810 localVariablesToAdd.update(lv)
1811 subToInclude.add(newFuncName)
1814 elemToLookFor.append(newCallStmt)
1818 if len(newComputeStmt) > 0:
1819 elemToLookFor.append(newComputeStmt)
1820 computeStmtforParenthesis.append(
1821 [newComputeStmt, mnhExpandArrayIndexes])
1825 previousComputeStmt.append(newComputeStmt)
1829 elemToLookForNew = []
1830 for i
in elemToLookFor:
1831 nodeNs = i.findall(
'.//{*}n')
1834 if alltext(nnn)
in list(localShumansGradients):
1835 elemToLookForNew.append(i)
1837 elemToLookFor = elemToLookForNew
1840 if nbzshugradwk > maxnbZshugradwk:
1841 maxnbZshugradwk = nbzshugradwk
1846 if tag(foundStmtandCalls[stmt][0]) !=
'call-stmt':
1847 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, lv = \
1848 getDimsAndMNHExpandIndexes(arrayDim, dimWorkingVar)
1849 localVariablesToAdd.update(lv)
1851 scope.addArrayParenthesesInNode(foundStmtandCalls[stmt][0])
1853 table = {c.split(
'=')[0]: c.split(
'=')[1].split(
':')
1854 for c
in mnhExpandArrayIndexes.split(
',')}
1855 table.pop(
'OPENACC',
None)
1856 for namedE
in foundStmtandCalls[stmt][0].findall(
1858 arrayR = namedE.find(
'./{*}R-LT/{*}array-R')
1862 for ss
in arrayR.findall(
1863 './{*}section-subscript-LT/{*}section-subscript'):
1864 if ':' in (ss.text
or ''):
1866 varName = list(table.keys())[ivar]
1867 lowerStr, upperStr = table[varName]
1868 lb, ub = createArrayBounds(
1869 lowerStr, upperStr,
'ARRAY')
1873 parStmt = scope.getParent(foundStmtandCalls[stmt][0])
1874 indexForCall = list(parStmt).index(foundStmtandCalls[stmt][0])
1875 mnhOpenDir =
"!$mnh_expand_array(" + mnhExpandArrayIndexes +
")"
1876 mnhCloseDir =
"!$mnh_end_expand_array(" + mnhExpandArrayIndexes +
")"
1877 parStmt.insert(indexForCall,
1878 createElem(
'C', text=
"!$acc kernels", tail=
'\n'))
1879 parStmt.insert(indexForCall + 1,
1880 createElem(
'C', text=mnhOpenDir, tail=
'\n'))
1881 parStmt.insert(indexForCall + 3,
1882 createElem(
'C', text=mnhCloseDir, tail=
'\n'))
1883 parStmt.insert(indexForCall + 4,
1884 createElem(
'C', text=
"!$acc end kernels", tail=
'\n'))
1885 parStmt.insert(indexForCall + 5,
1886 createElem(
'C', text=
"!", tail=
'\n'))
1890 for stmt, mnhExpandArrayIndexes
in computeStmtforParenthesis:
1891 scope.addArrayParenthesesInNode(stmt)
1892 table = {c.split(
'=')[0]: c.split(
'=')[1].split(
':')
1893 for c
in mnhExpandArrayIndexes.split(
',')}
1894 table.pop(
'OPENACC',
None)
1895 for namedE
in stmt.findall(
'.//{*}R-LT/..'):
1896 arrayR = namedE.find(
'./{*}R-LT/{*}array-R')
1900 for ss
in arrayR.findall(
1901 './{*}section-subscript-LT/{*}section-subscript'):
1902 if ':' in (ss.text
or ''):
1904 varName = list(table.keys())[ivar]
1905 lowerStr, upperStr = table[varName]
1906 lb, ub = createArrayBounds(
1907 lowerStr, upperStr,
'ARRAY')
1913 for sub
in sorted(subToInclude):
1914 if re.match(
r'[MD][XYZ][MF](2D)?_PHY', sub):
1915 moduleVars.append((scope.path,
'MODE_SHUMAN_PHY', sub))
1916 if re.match(
r'[MD][XYZ][MF](2D)?_DEVICE', sub):
1917 moduleVars.append((scope.path,
'MODI_SHUMAN_DEVICE', sub))
1919 for kind
in (
'M',
'U',
'V',
'W'):
1920 if re.match(
r'G[XYZ]_' + kind +
r'_[MUVW]{1,2}_PHY', sub):
1921 moduleVars.append((scope.path, f
'MODE_GRADIENT_{kind}_PHY', sub))
1922 elif re.match(
r'G[XYZ]_' + kind +
r'_[MUVW]{1,2}_DEVICE', sub):
1923 moduleVars.append((scope.path, f
'MODI_GRADIENT_{kind}', sub))
1924 scope.addModuleVar(moduleVars)
1927 for sub
in funcToSuppress:
1928 if scope.varList.findVar(sub):
1929 scope.removeVar([(scope.path, sub)])
1932 for varName
in localVariablesToAdd:
1933 if not scope.varList.findVar(varName):
1934 var = {
'as': [],
'asx': [],
1935 'n': varName,
'i':
None,
't':
'INTEGER',
'arg':
False,
1936 'use':
False,
'opt':
False,
'allocatable':
False,
1937 'parameter':
False,
'init':
None,
'scopePath': scope.path}
1938 scope.addVar([[scope.path, var[
'n'], scope.varSpec2stmt(var),
None]])