157 Convert STR%VAR into single local variable contained in compute (a-stmt)
158 and in if-then-stmt, else-if-stmt, where-stmt
160 ZA = 1 + CST%XG ==> ZA = 1 + XCST_G
161 ZA = 1 + PARAM_ICE%XRTMIN(3) ==> ZA = 1 + XPARAM_ICE_XRTMIN3
162 ZRSMIN(1:KRR) = ICED%XRTMIN(1:KRR) => ZRSMIN(1:KRR) = ICEDXRTMIN1KRR(1:KRR)
163 IF(TURBN%CSUBG_MF_PDF=='NONE')THEN => IF(CTURBNSUBG_MF_PDF=='NONE')THEN
165 RESTRICTION : works only if the r-component variable is contained in 1 parent structure.
166 Allowed for conversion : CST%XG
167 Not converted : TOTO%CST%XG (for now, recursion must be coded)
168 Not converted : TOTO%ARRAY(:) (shape of the array must be determined from E1)
169 Not converted : TOTO%TUTU(:) (type in a type)
171 def convertOneType(component, newVarList, scope):
173 objType = scope.getParent(component, 2)
174 objTypeStr = alltext(objType).upper()
175 namedENn = objType.find(
'.//{*}N/{*}n')
176 structure = namedENn.text
177 variable = component.find(
'.//{*}ct').text.upper()
178 if variable[0] ==
"T":
183 arrayRall = objType.findall(
'.//{*}array-R')
184 if len(arrayRall) > 0:
185 arrayR = copy.deepcopy(arrayRall[0])
186 txt = alltext(arrayR).replace(
',',
'')
187 txt = txt.replace(
':',
'')
188 txt = txt.replace(
'(',
'')
189 txt = txt.replace(
')',
'')
190 arrayIndices = arrayIndices + txt
191 elif len(objType.findall(
'.//{*}element-LT')) > 0:
193 for elem
in objType.findall(
'.//{*}element'):
194 arrayIndices = arrayIndices + alltext(elem)
195 newName = variable[0] + structure + variable[1:] + arrayIndices
196 newName = newName.upper()
200 namedENn.text = newName
201 objType.remove(objType.find(
'.//{*}R-LT'))
202 if len(arrayRall) > 0:
203 objType.insert(1, arrayR)
206 if newName
not in newVarList:
207 if len(arrayRall) == 0:
208 newVarList[newName] = (
None, objTypeStr)
210 newVarList[newName] = (arrayR, objTypeStr)
212 scopes = self.getScopes()
213 if scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
215 for scope
in [scope
for scope
in scopes
216 if 'sub:' in scope.path
and 'interface' not in scope.path]:
218 for ifStmt
in (scope.findall(
'.//{*}if-then-stmt') +
219 scope.findall(
'.//{*}else-if-stmt') +
220 scope.findall(
'.//{*}where-stmt')):
221 compo = ifStmt.findall(
'.//{*}component-R')
223 for elcompo
in compo:
224 convertOneType(elcompo, newVarList, scope)
226 for aStmt
in scope.findall(
'.//{*}a-stmt'):
229 if len(aStmt[0].findall(
'.//{*}component-R')) == 0:
230 compoE2 = aStmt.findall(
'.//{*}component-R')
237 nbNamedEinE2 = len(aStmt.findall(
'.//{*}E-2')[0].findall(
'.//{*}named-E/' +
239 if nbNamedEinE2 > 1
or nbNamedEinE2 == 1
and \
240 len(aStmt[0].findall(
'.//{*}R-LT')) == 1:
241 for elcompoE2
in compoE2:
242 convertOneType(elcompoE2, newVarList, scope)
246 for aStmt
in scope.findall(
'.//{*}a-stmt'):
248 if len(aStmt[0].findall(
'.//{*}component-R')) > 0:
250 for el
in newVarList.items():
251 if alltext(aStmt[0]) == el[1][1]:
252 stmtAffect = createExpr(el[0] +
"=" + alltext(aStmt[0]))
253 par = scope.getParent(aStmt)
255 if tag(par[list(par).index(aStmt)+1]) ==
'C':
257 par.insert(list(par).index(aStmt)+1+iExtra, stmtAffect[0])
261 for el, var
in newVarList.items():
262 if el[0].upper() ==
'X' or el[0].upper() ==
'P' or el[0].upper() ==
'Z':
264 elif el[0].upper() ==
'L' or el[0].upper() ==
'O':
266 elif el[0].upper() ==
'N' or el[0].upper() ==
'I' or el[0].upper() ==
'K':
268 elif el[0].upper() ==
'C':
269 varType =
'CHARACTER(LEN=LEN(' + var[1] +
'))'
271 raise PYFTError(
'Case not implemented for the first letter of the newVarName ' +
272 el +
' in convertTypesInCompute')
276 varArray =
', DIMENSION('
277 for i, sub
in enumerate(var[0].findall(
'.//{*}section-subscript')):
278 if len(sub.findall(
'.//{*}upper-bound')) > 0:
279 dimSize = simplifyExpr(
280 alltext(sub.findall(
'.//{*}upper-bound')[0]) +
281 '-' + alltext(sub.findall(
'.//{*}lower-bound')[0]) +
283 elif len(sub.findall(
'.//{*}lover-bound')) > 0:
284 dimSize = simplifyExpr(alltext(sub.findall(
'.//{*}lower-bound')[0]))
286 dimSize =
'SIZE(' + var[1] +
',' + str(i+1) +
')'
287 varArray =
', DIMENSION(' + dimSize +
','
288 varArray = varArray[:-1] +
')'
289 scope.addVar([[scope.path, el, varType + varArray +
' :: ' + el,
None]])
292 stmtAffect = createExpr(el +
"=" + var[1])[0]
293 scope.insertStatement(scope.indent(stmtAffect), first=
True)
362 Convert MODULE to SUBMODULE statements and add INTERFACE of SUBROUTINEs of PHYEX
363 ==> Applied only on MODE_
365 - if an INTERFACE already exists
366 - if no subroutine is present in the module
367 - to CONTAINS routines
368 1) Create interface statement if any
369 2) Add subroutines declaration (with MODULE statement)
370 3) Add SUBMODULE statements and convert SUBROUTINE to MODULE SUBROUTINE statements
372 scopes = self.getScopes()
375 oldModNode = self.find(
'.//{*}program-unit')
376 modNode = copy.deepcopy(self.find(
'.//{*}program-unit'))
378 interfaceStmt = self.findall(
'.//{*}interface-stmt')
379 subStmt = self.findall(
'.//{*}subroutine-stmt')
381 if modScope.path.split(
'/')[-1].split(
':')[1][:4] ==
'MODE' and \
382 len(interfaceStmt) == 0
and len(subStmt) > 0:
383 moduleName = modScope.path.split(
'/')[-1].split(
':')[1][:]
385 newMod = createElem(
'program-unit', text=
'MODULE ' + moduleName, tail=
'\n')
387 newMod.append(createElem(
'implicit-none-stmt', text=
'IMPLICIT NONE', tail=
'\n'))
388 interfaceStmt = createElem(
'interface-construct')
389 interfaceStmt.append(createElem(
'interface-stmt', text=
'INTERFACE', tail=
'\n'))
390 interfaceStmt.append(createElem(
'end-interface-stmt', text=
'END INTERFACE', tail=
'\n'))
391 newMod.append(interfaceStmt)
395 for scope
in scopes[1:]:
397 if sum(
'sub' in s
for s
in scope.path.split(
'/')) == 1:
398 subsModified.append(scope.path.split(
'/')[-1].split(
':')[1][:])
399 subroutineDecl = createElem(
'module-unit')
401 subroutineStmt = copy.deepcopy(scope[0])
402 declType = subroutineStmt.text
403 prefix = createElem(
'prefix')
404 prefix.text =
'MODULE'
405 subroutineStmt.text =
''
406 subroutineStmt.insert(0, prefix)
407 prefix.tail =
' ' + declType
408 subroutineDecl.append(subroutineStmt)
410 for use
in scope.findall(
'.//{*}use-stmt'):
411 subroutineDecl.append(copy.deepcopy(use))
412 subroutineDecl.append(createElem(
'implicit-none-stmt', text=
'IMPLICIT NONE',
415 for var
in [var
for var
in scope.varList
if var[
'arg']
or var[
'result']]:
416 subroutineDecl.append(createExpr(self.varSpec2stmt(var,
True))[0])
417 for external
in scope.findall(
'./{*}external-stmt'):
418 subroutineDecl.append(copy.deepcopy(external))
419 if 'SUBROUTINE' in declType:
420 endStmt = createElem(
'end-subroutine-stmt')
421 declName = subroutineStmt.find(
'./{*}subroutine-N/{*}N/{*}n').text
422 elif 'FUNCTION' in declType:
423 endStmt = createElem(
'end-function-stmt')
424 declName = subroutineStmt.find(
'./{*}function-N/{*}N/{*}n').text
426 raise PYFTError(
'declType in addSubmodulePHYEX not handled')
428 endStmt.text =
'END ' + declType + declName +
'\n'
429 subroutineDecl.append(endStmt)
430 interfaceStmt.insert(1, subroutineDecl)
433 newMod.append(createElem(
'end-program-unit', text=
'END MODULE ' + moduleName,
435 self[0].insert(0, newMod)
438 progUnit = createElem(
'program-unit')
449 submoduleStmt = createElem(
'submodule-stmt', text=
'SUBMODULE (')
450 parentId = createElem(
'parent-identifier')
452 ancestorModule = createElem(
'ancestor-module-N')
453 ancestorModuleN = createElem(
'n', text=moduleName)
454 ancestorModule.append(ancestorModuleN)
455 parentId.append(ancestorModule)
456 submoduleStmt.append(parentId)
457 submoduleModule = createElem(
'submodule-module-N')
458 submoduleModuleN = createElem(
'n', text=
'S' + moduleName, tail=
'\n')
459 submoduleModule.append(submoduleModuleN)
460 submoduleStmt.append(submoduleModule)
461 progUnit.append(submoduleStmt)
464 endSubmoduleStmt = createElem(
'end-submodule-stmt', text=
'END SUBMODULE ')
465 submoduleN = createElem(
'submodule-N')
466 submoduleNN = createElem(
'N')
467 submoduleNNn = createElem(
'n', text=
'S' + moduleName, tail=
'\n')
468 submoduleNN.append(submoduleNNn)
469 submoduleN.append(submoduleNN)
470 endSubmoduleStmt.append(submoduleN)
472 progUnit.append(endSubmoduleStmt)
473 progUnit.append(createElem(
'end-program-unit'))
477 modStmt = modNode.find(
'.//{*}module-stmt')
478 modEndStmt = modNode.find(
'.//{*}end-module-stmt')
479 modNode.remove(modStmt)
480 modNode.remove(modEndStmt)
483 publicStmts = modNode.findall(
'.//{*}public-stmt')
484 privateStmts = modNode.findall(
'.//{*}private-stmt')
485 if len(publicStmts) > 0:
486 for publicStmt
in publicStmts:
487 modNode.remove(publicStmt)
488 if len(privateStmts) > 0:
489 for privateStmt
in privateStmts:
490 modNode.remove(privateStmt)
493 subroutines = modNode.findall(
'.//{*}subroutine-stmt')
494 for sub
in subroutines:
495 if sub.find(
'.//{*}N/{*}n').text
in subsModified:
496 prefix = createElem(
'prefix')
497 prefix.text =
'MODULE'
499 sub.insert(0, prefix)
500 prefix.tail =
' SUBROUTINE '
501 progUnit.insert(1, modNode)
503 self.insert(1, progUnit)
506 self.remove(oldModNode)
512 Add MPPDB_CHEKS on all intent REAL arrays on subroutines.
513 ****** Not applied on modd_ routines. ********
514 Handle optional arguments.
515 Example, for a BL89 routine with 4 arguments, 1 INTENT(IN),
516 2 INTENT(INOUT), 1 INTENT(OUT), it produces :
517 IF (MPPDB_INITIALIZED) THEN
519 CALL MPPDB_CHECK(PZZ, "BL89 beg:PZZ")
520 !Check all INOUT arrays
521 CALL MPPDB_CHECK(PDZZ, "BL89 beg:PDZZ")
522 CALL MPPDB_CHECK(PTHVREF, "BL89 beg:PTHVREF")
525 IF (MPPDB_INITIALIZED) THEN
526 !Check all INOUT arrays
527 CALL MPPDB_CHECK(PDZZ, "BL89 end:PDZZ")
528 CALL MPPDB_CHECK(PTHVREF, "BL89 end:PTHVREF")
529 !Check all OUT arrays
530 CALL MPPDB_CHECK(PLM, "BL89 end:PLM")
532 param printsMode: if True, instead of CALL MPPDB_CHECK, add fortran prints for debugging
534 def addPrints_statement(var, typeofPrints='minmax'):
535 ifBeg, ifEnd =
'',
''
538 if typeofPrints ==
'minmax':
539 strMSG = f
'MINMAX {varName} = \",MINVAL({varName}), MAXVAL({varName})'
540 elif typeofPrints ==
'shape':
541 strMSG = f
'SHAPE {varName} = \",SHAPE({varName})'
543 raise PYFTError(
'typeofPrints is either minmax or shape in addPrints_statement')
545 strMSG = var[
'n'] +
' = \",' + var[
'n']
547 ifBeg = ifBeg +
'IF (PRESENT(' + var[
'n'] +
')) THEN\n '
548 ifEnd = ifEnd +
'\nEND IF'
549 return createExpr(ifBeg +
"print*,\"" + strMSG + ifEnd)[0]
551 def addMPPDB_CHECK_statement(var, subRoutineName, strMSG='beg:
'):
552 ifBeg, ifEnd, addD, addLastDim, addSecondDimType = '',
'',
'',
'',
''
556 if 'D%NIJT' in var[
'as'][0][1]:
558 if len(var[
'as']) == 2:
560 addLastDim =
', ' + var[
'as'][1][1]
561 if len(var[
'as']) >= 2:
564 if 'D%NK' in var[
'as'][1][1]:
565 addSecondDimType =
',' +
'''"VERTICAL"'''
567 addSecondDimType =
',' +
'''"OTHER"'''
568 if 'MERGE' in var[
'as'][-1][1]:
569 keyDimMerge = var[
'as'][-1][1].split(
',')[2][:-1]
570 ifBeg =
'IF (' + keyDimMerge +
') THEN\n'
573 ifBeg = ifBeg +
'IF (PRESENT(' + var[
'n'] +
')) THEN\n IF (SIZE(' + \
574 var[
'n'] +
',1) > 0) THEN\n'
575 ifEnd = ifEnd +
'\nEND IF\nEND IF'
576 argsMPPDB = var[
'n'] +
", " +
"\"" + subRoutineName +
" " + strMSG+var[
'n'] +
"\""
577 return createExpr(ifBeg +
"CALL MPPDB_CHECK(" + addD + argsMPPDB +
578 addLastDim + addSecondDimType +
")" + ifEnd)[0]
579 scopes = self.getScopes()
580 if scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
587 if 'sub:' in scope.path
and 'func' not in scope.path
and 'interface' not in scope.path:
588 subRoutineName = scope.path.split(
'/')[-1].split(
':')[1]
591 arraysIn, arraysInOut, arraysOut = [], [], []
593 for var
in scope.varList:
594 if var[
'arg']
and var[
'as']
and 'TYPE' not in var[
't']
and \
595 'REAL' in var[
't']
and var[
'scopePath'] == scope.path:
598 if var[
'i'] ==
'INOUT':
599 arraysInOut.append(var)
600 if var[
'i'] ==
'OUT':
601 arraysOut.append(var)
603 for var
in scope.varList:
604 if not var[
't']
or var[
't']
and 'TYPE' not in var[
't']:
607 if var[
'i'] ==
'INOUT':
608 arraysInOut.append(var)
609 if var[
'i'] ==
'OUT':
610 arraysOut.append(var)
612 if len(arraysIn) + len(arraysInOut) + len(arraysOut) == 0:
617 scope.addModuleVar([(scope.path,
'MODE_MPPDB',
None)])
619 scope.addModuleVar([(scope.path,
'MODD_BLANK_n', [
'LDUMMY1'])])
622 commentIN = createElem(
'C', text=
'!Check all IN arrays', tail=
'\n')
623 commentINOUT = createElem(
'C', text=
'!Check all INOUT arrays', tail=
'\n')
624 commentOUT = createElem(
'C', text=
'!Check all OUT arrays', tail=
'\n')
627 if len(arraysIn) + len(arraysInOut) > 0:
629 ifMPPDBinit = createExpr(
"IF (MPPDB_INITIALIZED) THEN\n END IF")[0]
631 ifMPPDBinit = createExpr(
"IF (LDUMMY1) THEN\n END IF")[0]
632 ifMPPDB = ifMPPDBinit.find(
'.//{*}if-block')
635 if len(arraysIn) > 0:
636 ifMPPDB.insert(1, commentIN)
637 for i, var
in enumerate(arraysIn):
639 ifMPPDB.insert(2 + i, addMPPDB_CHECK_statement(var, subRoutineName,
642 ifMPPDB.insert(2 + i, addPrints_statement(var,
643 typeofPrints=
'minmax'))
644 ifMPPDB.insert(3 + i, addPrints_statement(var,
645 typeofPrints=
'shape'))
648 if len(arraysInOut) > 0:
649 shiftLineNumber = 2
if len(arraysIn) > 0
else 1
651 ifMPPDB.insert(len(arraysIn) + shiftLineNumber, commentINOUT)
653 ifMPPDB.insert(len(arraysIn)*2 + shiftLineNumber-1, commentINOUT)
655 for i, var
in enumerate(arraysInOut):
657 ifMPPDB.insert(len(arraysIn) + shiftLineNumber + 1 + i,
658 addMPPDB_CHECK_statement(var, subRoutineName,
661 ifMPPDB.insert(len(arraysIn) + shiftLineNumber + 1 + i,
662 addPrints_statement(var, typeofPrints=
'minmax'))
665 scope.insertStatement(scope.indent(ifMPPDBinit), first=
True)
668 if len(arraysInOut) + len(arraysOut) > 0:
670 ifMPPDBend = createExpr(
"IF (MPPDB_INITIALIZED) THEN\n END IF")[0]
672 ifMPPDBend = createExpr(
"IF (LDUMMY1) THEN\n END IF")[0]
673 ifMPPDB = ifMPPDBend.find(
'.//{*}if-block')
676 if len(arraysInOut) > 0:
677 ifMPPDB.insert(1, commentINOUT)
678 for i, var
in enumerate(arraysInOut):
680 ifMPPDB.insert(2 + i, addMPPDB_CHECK_statement(var, subRoutineName,
683 ifMPPDB.insert(2 + i, addPrints_statement(var,
684 typeofPrints=
'minmax'))
687 if len(arraysOut) > 0:
688 shiftLineNumber = 2
if len(arraysInOut) > 0
else 1
690 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber, commentOUT)
692 ifMPPDB.insert(len(arraysInOut)*2 + shiftLineNumber-1, commentOUT)
693 for i, var
in enumerate(arraysOut):
695 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber + 1 + i,
696 addMPPDB_CHECK_statement(var, subRoutineName,
699 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber + 1 + i,
700 addPrints_statement(var, typeofPrints=
'minmax'))
703 scope.insertStatement(scope.indent(ifMPPDBend), first=
False)
811 def removeIJDim(self, stopScopes, parserOptions=None, wrapH=False, simplify=False):
813 Transform routines to be called in a loop on columns
814 :param stopScopes: scope paths where we stop to add the D argument (if needed)
815 :param parserOptions, wrapH: see the PYFT class
816 :param simplify: try to simplify code (remove useless dimensions in call)
818 ComputeInSingleColumn :
819 - Remove all Do loops on JI and JJ
820 - Initialize former indexes JI, JJ, JIJ to first array element:
821 JI=D%NIB, JJ=D%NJB, JIJ=D%NIJB
822 - If simplify is True, replace (:,*) on I/J/IJ dimension on argument
823 with explicit (:,*) on CALL statements:
824 e.g. CALL FOO(D, A(:,JK,1), B(:,:))
825 ==> CALL FOO(D, A(JIJ,JK,1), B(:,:)) only if the target argument is not an array
828 indexToCheck = {
'JI': (
'D%NIB',
'D%NIT'),
829 'JJ': (
'D%NJB',
'D%NJT'),
830 'JIJ': (
'D%NIJB',
'D%NIJT')}
832 def slice2index(namedE, scope):
834 Transform a slice on the horizontal dimension into an index
835 Eg.: X(1:D%NIJT, 1:D%NKT) => X(JIJ, 1:D%NKT) Be careful, this array is not contiguous.
836 X(1:D%NIJT, JK) => X(JIJ, JK)
837 :param namedE: array to transform
838 :param scope: scope where the array is
841 for isub, sub
in enumerate(namedE.findall(
'./{*}R-LT/{*}array-R/' +
842 '{*}section-subscript-LT/' +
843 '{*}section-subscript')):
844 if ':' in alltext(sub):
845 loopIndex, _, _ = scope.findIndexArrayBounds(namedE, isub, _loopVarPHYEX)
846 if loopIndex
in indexToCheck:
849 lowerBound = createElem(
'lower-bound')
850 sub.insert(0, lowerBound)
852 lowerBound = sub.find(
'./{*}lower-bound')
854 for item
in lowerBound:
855 lowerBound.remove(item)
856 upperBound = sub.find(
'./{*}upper-bound')
857 if upperBound
is not None:
858 sub.remove(upperBound)
859 lowerBound.append(createExprPart(loopIndex))
860 if loopIndex
not in indexRemoved:
861 indexRemoved.append(loopIndex)
864 if ':' not in alltext(namedE.find(
'./{*}R-LT/{*}array-R/{*}section-subscript-LT')):
865 namedE.find(
'./{*}R-LT/{*}array-R').tag = f
'{{{NAMESPACE}}}parens-R'
866 namedE.find(
'./{*}R-LT/{*}parens-R/' +
867 '{*}section-subscript-LT').tag = f
'{{{NAMESPACE}}}element-LT'
868 for ss
in namedE.findall(
'./{*}R-LT/{*}parens-R/' +
869 '{*}element-LT/{*}section-subscript'):
870 ss.tag = f
'{{{NAMESPACE}}}element'
871 lowerBound = ss.find(
'./{*}lower-bound')
872 for item
in lowerBound:
874 ss.remove(lowerBound)
877 self.addArrayParentheses()
880 self.attachArraySpecToEntity()
881 hUupperBounds = [v[1]
for v
in indexToCheck.values()]
885 for scope
in [scope
for scope
in self.getScopes()[::-1]
886 if 'func:' not in scope.path
and
887 (scope.path
in stopScopes
or
888 self.tree.isUnderStopScopes(scope.path, stopScopes,
889 includeInterfaces=
True))]:
895 for doNode
in scope.findall(
'.//{*}do-construct')[::-1]:
896 for loopI
in doNode.findall(
'./{*}do-stmt/{*}do-V/{*}named-E/{*}N'):
897 loopIname = n2name(loopI).upper()
898 if loopIname
in indexToCheck:
901 par = scope.getParent(doNode)
902 index = list(par).index(doNode)
903 for item
in doNode[1:-1][::-1]:
904 par.insert(index, item)
906 if loopIname
not in indexRemoved:
907 indexRemoved.append(loopIname)
912 for intr
in scope.findall(
'.//{*}R-LT/{*}parens-R/../..'):
913 intrName = n2name(intr.find(
'./{*}N')).upper()
914 if intrName
in (
'PACK',
'UNPACK',
'COUNT',
'MAXVAL',
'MINVAL',
'ALL',
'ANY',
'SUM'):
922 while par
is not None and not isStmt(par):
923 par = scope.getParent(par)
924 if tag(par)
in (
'a-stmt',
'op-E'):
929 for namedE
in parToUse.findall(
'.//{*}R-LT/{*}array-R/../..'):
930 slice2index(namedE, scope)
933 if intr.find(
'.//{*}R-LT/{*}array-R')
is None:
934 if intrName
in (
'MAXVAL',
'MINVAL',
'SUM',
'ALL',
'ANY'):
936 parens = intr.find(
'./{*}R-LT/{*}parens-R')
937 parens.tag = f
'{{{NAMESPACE}}}parens-E'
938 intrPar = scope.getParent(intr)
939 intrPar.insert(list(intrPar).index(intr), parens)
941 elif intrName ==
'COUNT':
943 nodeN = intr.find(
'./{*}N')
944 for item
in nodeN[1:]:
946 nodeN.find(
'./{*}n').text =
'MERGE'
947 elementLT = intr.find(
'./{*}R-LT/{*}parens-R/{*}element-LT')
949 element = createElem(
'element', tail=
', ')
950 element.append(createExprPart(val))
951 elementLT.insert(0, element)
964 assert scope.find(
'.//{*}include')
is None and \
965 scope.find(
'.//{*}include-stmt')
is None, \
966 "inlining must be performed before removing horizontal dimensions"
968 if scope.path
in stopScopes:
970 preserveShape = [v[
'n']
for v
in scope.varList
if v[
'arg']]
975 if 'sub:' in scope.path:
979 for namedE
in scope.findall(
'.//{*}named-E/{*}R-LT/{*}parens-R/../..'):
980 if n2name(namedE.find(
'./{*}N')).upper()
not in preserveShape:
981 var = scope.varList.findVar(n2name(namedE.find(
'./{*}N')).upper())
982 if var
is not None and var[
'as']
is not None and len(var[
'as']) > 0:
983 subs = namedE.findall(
'./{*}R-LT/{*}parens-R/' +
984 '{*}element-LT/{*}element')
985 if (len(subs) == 1
and var[
'as'][0][1]
in hUupperBounds)
or \
986 (len(subs) == 2
and (var[
'as'][0][1]
in hUupperBounds
and
987 var[
'as'][1][1]
in hUupperBounds)):
988 namedE.remove(namedE.find(
'./{*}R-LT'))
992 for call
in scope.findall(
'.//{*}call-stmt'):
993 for namedE
in call.findall(
'./{*}arg-spec//{*}named-E'):
994 subs = namedE.findall(
'.//{*}section-subscript')
995 var = scope.varList.findVar(n2name(namedE.find(
'./{*}N')).upper())
996 if len(subs) > 0
and (var
is None or var[
'as']
is None or
997 len(var[
'as']) < len(subs)):
1005 elif (len(subs) >= 2
and
1006 ':' in alltext(subs[0])
and var[
'as'][0][1]
in hUupperBounds
and
1007 ':' in alltext(subs[1])
and var[
'as'][1][1]
in hUupperBounds):
1009 remove = len(subs) == 2
1010 index = (len(subs) > 2
and
1011 len([sub
for sub
in subs
if ':' in alltext(sub)]) == 2)
1012 elif (len(subs) >= 1
and
1013 ':' in alltext(subs[0])
and var[
'as'][0][1]
in hUupperBounds):
1015 remove = len(subs) == 1
1016 index = (len(subs) > 1
and
1017 len([sub
for sub
in subs
if ':' in alltext(sub)]) == 1)
1022 if n2name(namedE.find(
'./{*}N')).upper()
in preserveShape:
1023 slice2index(namedE, scope)
1025 nodeRLT = namedE.find(
'.//{*}R-LT')
1026 scope.getParent(nodeRLT).remove(nodeRLT)
1028 slice2index(namedE, scope)
1033 for decl
in scope.findall(
'.//{*}T-decl-stmt/{*}EN-decl-LT/{*}EN-decl'):
1034 name = n2name(decl.find(
'./{*}EN-N/{*}N')).upper()
1035 if name
not in preserveShape:
1036 varsShape = decl.findall(
'.//{*}shape-spec-LT')
1037 for varShape
in varsShape:
1038 subs = varShape.findall(
'.//{*}shape-spec')
1039 if (len(subs) == 1
and alltext(subs[0])
in hUupperBounds)
or \
1040 (len(subs) == 2
and (alltext(subs[0])
in hUupperBounds
and
1041 alltext(subs[1])
in hUupperBounds)):
1043 itemToRemove = scope.getParent(varShape)
1044 scope.getParent(itemToRemove).remove(itemToRemove)
1049 for loopIndex
in indexRemoved:
1052 scope.insertStatement(
1053 createExpr(loopIndex +
" = " + indexToCheck[loopIndex][0])[0],
True)
1054 if len(indexRemoved) > 0:
1055 scope.addArgInTree(
'D',
'TYPE(DIMPHYEX_t) :: D',
1056 0, stopScopes, moduleVarList=[(
'MODD_DIMPHYEX', [
'DIMPHYEX_t'])],
1057 parserOptions=parserOptions, wrapH=wrapH)
1059 scope.addVar([[scope.path, loopIndex,
'INTEGER :: ' + loopIndex,
None]
1060 for loopIndex
in indexRemoved
1061 if scope.varList.findVar(loopIndex, exactScope=
True)
is None])
1257 Convert all calling of functions and gradient present in shumansGradients
1258 table into the use of subroutines
1259 and use mnh_expand_directives to handle intermediate computations
1261 def getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar=''):
1263 if zshugradwkDim == 1:
1264 dimSuffRoutine =
'2D'
1266 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE'
1267 localVariables = [
'JIJ']
1268 elif zshugradwkDim == 2:
1270 if 'D%NKT' in dimWorkingVar:
1271 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE,JK=1:IKT'
1272 localVariables = [
'JIJ',
'JK']
1273 elif 'D%NIT' in dimWorkingVar
and 'D%NJT' in dimWorkingVar:
1275 mnhExpandArrayIndexes =
'JI=1:IIT,JJ=1:IJT'
1276 localVariables = [
'JI',
'JJ']
1277 dimSuffRoutine =
'2D'
1283 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE,JK=1:IKT'
1284 localVariables = [
'JIJ',
'JK']
1285 elif zshugradwkDim == 3:
1287 mnhExpandArrayIndexes =
'JI=1:IIT,JJ=1:IJT,JK=1:IKT'
1288 localVariables = [
'JI',
'JJ',
'JK']
1290 raise PYFTError(
'Shuman func to routine conversion not implemented ' +
1291 'for 4D+ dimensions variables')
1292 return dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, localVariables
1294 def FUNCtoROUTINE(scope, stmt, itemFuncN, localShumansCount, inComputeStmt,
1295 nbzshugradwk, zshugradwkDim, dimWorkingVar):
1297 :param scope: node on which the calling function is present before transformation
1298 :param stmt: statement node (a-stmt or call-stmt) that contains the function(s) to be
1300 :param itemFuncN: <n>FUNCTIONNAME</n> node
1301 :param localShumansCount: instance of the shumansGradients dictionnary
1302 for the given scope (which contains the number of times a
1303 function has been called within a transformation)
1304 :param dimWorkingVar: string of the declaration of a potential working variable
1305 depending on the array on wich the shuman is applied
1306 (e.g. MZM(PRHODJ(:,IKB));
1307 dimWorkingVar = 'REAL, DIMENSION(D%NIJT) :: ' )
1309 :return callStmt: the new CALL to the routines statement
1310 :return computeStmt: the a-stmt computation statement if there was an operation
1311 in the calling function in stmt
1312 :return localVariables: list of local variables needed for the mnh_expand directive
1316 parStmt = scope.getParent(stmt)
1317 parItemFuncN = scope.getParent(itemFuncN)
1319 grandparItemFuncN = scope.getParent(itemFuncN, level=2)
1320 funcName = alltext(itemFuncN)
1323 indexForCall = list(parStmt).index(stmt)
1328 siblsItemFuncN = scope.getSiblings(parItemFuncN, after=
True, before=
False)
1329 workingItem = siblsItemFuncN[0][0][0]
1332 if len(siblsItemFuncN[0][0]) > 1:
1334 workingItem = scope.updateContinuation(siblsItemFuncN[0][0], removeALL=
True,
1335 align=
False, addBegin=
False)[0]
1339 opE = workingItem.findall(
'.//{*}op-E')
1340 scope.removeArrayParenthesesInNode(workingItem)
1341 computeStmt, remaningArgsofFunc = [],
''
1342 dimSuffVar = str(zshugradwkDim) +
'D'
1343 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, _ = \
1344 getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar)
1347 computingVarName =
'ZSHUGRADWK'+str(nbzshugradwk)+
'_'+str(zshugradwkDim)+
'D'
1349 if not scope.varList.findVar(computingVarName):
1350 scope.addVar([[scope.path, computingVarName,
1351 dimWorkingVar + computingVarName,
None]])
1355 computeVar = scope.varList.findVar(computingVarName)
1356 dimWorkingVar =
'REAL, DIMENSION('
1357 for dims
in computeVar[
'as'][:arrayDim]:
1358 dimWorkingVar += dims[1] +
','
1359 dimWorkingVar = dimWorkingVar[:-1] +
') ::'
1361 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, localVariables = \
1362 getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar)
1365 mnhOpenDir =
"!$mnh_expand_array(" + mnhExpandArrayIndexes +
")"
1366 mnhCloseDir =
"!$mnh_end_expand_array(" + mnhExpandArrayIndexes +
")"
1369 workingComputeItem = workingItem[0]
1371 if len(workingItem) == 2:
1372 remaningArgsofFunc =
',' + alltext(workingItem[1])
1373 elif len(workingItem) > 2:
1374 raise PYFTError(
'ShumanFUNCtoCALL: expected maximum 1 argument in shuman ' +
1375 'function to transform')
1376 computeStmt = createExpr(computingVarName +
" = " + alltext(workingComputeItem))[0]
1377 workingItem = computeStmt.find(
'.//{*}E-1')
1379 parStmt.insert(indexForCall, createElem(
'C', text=
'!$acc kernels', tail=
'\n'))
1380 parStmt.insert(indexForCall + 1, createElem(
'C', text=mnhOpenDir, tail=
'\n'))
1381 parStmt.insert(indexForCall + 2, computeStmt)
1382 parStmt.insert(indexForCall + 3, createElem(
'C', text=mnhCloseDir, tail=
'\n'))
1383 parStmt.insert(indexForCall + 4, createElem(
'C',
1384 text=
'!$acc end kernels', tail=
'\n'))
1385 parStmt.insert(indexForCall + 5, createElem(
'C',
1386 text=
'!', tail=
'\n'))
1390 if zshugradwkDim == 1:
1391 dimSuffRoutine =
'2D'
1392 workingVar =
'Z' + funcName + dimSuffVar +
'_WORK' + str(localShumansCount[funcName])
1393 if funcName
in (
'GY_U_UV',
'GX_V_UV'):
1394 gpuGradientImplementation =
'_DEVICE('
1395 newFuncName = funcName + dimSuffRoutine +
'_DEVICE'
1397 gpuGradientImplementation =
'_PHY(D, '
1398 newFuncName = funcName + dimSuffRoutine +
'_PHY'
1399 callStmt = createExpr(
"CALL " + funcName + dimSuffRoutine + gpuGradientImplementation
1400 + alltext(workingItem) + remaningArgsofFunc +
1401 ", " + workingVar +
")")[0]
1402 parStmt.insert(indexForCall, callStmt)
1405 parOfgrandparItemFuncN = scope.getParent(grandparItemFuncN)
1406 indexWorkingVar = list(parOfgrandparItemFuncN).index(grandparItemFuncN)
1407 savedTail = grandparItemFuncN.tail
1408 parOfgrandparItemFuncN.remove(grandparItemFuncN)
1411 xmlWorkingvar = createExprPart(workingVar)
1412 xmlWorkingvar.tail = savedTail
1413 parOfgrandparItemFuncN.insert(indexWorkingVar, xmlWorkingvar)
1416 if not scope.varList.findVar(workingVar):
1417 scope.addVar([[scope.path, workingVar, dimWorkingVar + workingVar,
None]])
1419 return callStmt, computeStmt, nbzshugradwk, newFuncName, localVariables
1421 shumansGradients = {
'MZM': 0,
'MXM': 0,
'MYM': 0,
'MZF': 0,
'MXF': 0,
'MYF': 0,
1422 'DZM': 0,
'DXM': 0,
'DYM': 0,
'DZF': 0,
'DXF': 0,
'DYF': 0,
1423 'GZ_M_W': 0,
'GZ_W_M': 0,
'GZ_U_UW': 0,
'GZ_V_VW': 0,
1424 'GX_M_U': 0,
'GX_U_M': 0,
'GX_W_UW': 0,
'GX_M_M': 0,
1425 'GY_V_M': 0,
'GY_M_V': 0,
'GY_W_VW': 0,
'GY_M_M': 0,
1426 'GX_V_UV': 0,
'GY_U_UV': 0}
1427 scopes = self.getScopes()
1428 if len(scopes) == 0
or scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
1430 for scope
in scopes:
1431 if 'sub:' in scope.path
and 'func' not in scope.path \
1432 and 'interface' not in scope.path:
1435 localVariablesToAdd = set()
1436 foundStmtandCalls, computeStmtforParenthesis = {}, []
1437 aStmt = scope.findall(
'.//{*}a-stmt')
1438 callStmts = scope.findall(
'.//{*}call-stmt')
1439 aStmtandCallStmts = aStmt + callStmts
1440 for stmt
in aStmtandCallStmts:
1441 elemN = stmt.findall(
'.//{*}n')
1443 if alltext(el)
in list(shumansGradients):
1446 parStmt = scope.getParent(stmt)
1447 if tag(parStmt) ==
'action-stmt':
1448 scope.changeIfStatementsInIfConstructs(
1449 singleItem=scope.getParent(parStmt))
1451 if str(stmt)
in foundStmtandCalls:
1452 foundStmtandCalls[str(stmt)][1] += 1
1454 foundStmtandCalls[str(stmt)] = [stmt, 1]
1457 subToInclude = set()
1458 for stmt
in foundStmtandCalls:
1459 localShumansGradients = copy.deepcopy(shumansGradients)
1460 elemToLookFor = [foundStmtandCalls[stmt][0]]
1461 previousComputeStmt = []
1464 while len(elemToLookFor) > 0:
1466 for elem
in elemToLookFor:
1467 elemN = elem.findall(
'.//{*}n')
1469 if alltext(el)
in list(localShumansGradients.keys()):
1474 nodeE1var = foundStmtandCalls[stmt][0].findall(
1475 './/{*}E-1/{*}named-E/{*}N')
1476 if len(nodeE1var) > 0:
1477 var = scope.varList.findVar(alltext(nodeE1var[0]))
1478 allSubscripts = foundStmtandCalls[stmt][0].findall(
1479 './/{*}E-1//{*}named-E/{*}R-LT/' +
1480 '{*}array-R/{*}section-subscript-LT')
1484 elPar = scope.getParent(el, level=2)
1485 callVar = elPar.findall(
'.//{*}named-E/{*}N')
1486 if alltext(el)[0] ==
'G':
1491 var = scope.varList.findVar(alltext(callVar[-1]))
1492 shumanIsCalledOn = scope.getParent(callVar[-1])
1495 var, inested =
None, 0
1497 while not var
or len(var[
'as']) == 0:
1501 var = scope.varList.findVar(
1502 alltext(callVar[inested]))
1504 shumanIsCalledOn = scope.getParent(callVar[inested-1])
1505 allSubscripts = shumanIsCalledOn.findall(
1506 './/{*}R-LT/{*}array-R/' +
1507 '{*}section-subscript-LT')
1511 arrayDim = len(var[
'as'])
1515 if len(allSubscripts) > 0:
1516 for subLT
in allSubscripts:
1518 lowerBound = sub.findall(
'.//{*}lower-bound')
1519 if len(lowerBound) > 0:
1520 if len(sub.findall(
'.//{*}upper-bound')) > 0:
1523 raise PYFTError(
'ShumanFUNCtoCALL does ' +
1524 'not handle conversion ' +
1525 'to routine of array ' +
1526 'subselection lower:upper' +
1527 ': how to set up the ' +
1528 'shape of intermediate ' +
1538 dimWorkingVar =
'REAL, DIMENSION('
1539 for dims
in var[
'as'][:arrayDim]:
1540 dimWorkingVar += dims[1] +
','
1541 dimWorkingVar = dimWorkingVar[:-1] +
') ::'
1544 localShumansGradients[alltext(el)] += 1
1548 if foundStmtandCalls[stmt][0].tail:
1549 foundStmtandCalls[stmt][0].tail = \
1550 foundStmtandCalls[stmt][0].tail.replace(
'\n',
'') +
'\n'
1552 foundStmtandCalls[stmt][0].tail =
'\n'
1555 result = FUNCtoROUTINE(scope, elem, el,
1556 localShumansGradients,
1557 elem
in previousComputeStmt,
1558 nbzshugradwk, arrayDim,
1560 (newCallStmt, newComputeStmt,
1561 nbzshugradwk, newFuncName, lv) = result
1562 localVariablesToAdd.update(lv)
1563 subToInclude.add(newFuncName)
1566 elemToLookFor.append(newCallStmt)
1570 if len(newComputeStmt) > 0:
1571 elemToLookFor.append(newComputeStmt)
1572 computeStmtforParenthesis.append(newComputeStmt)
1576 previousComputeStmt.append(newComputeStmt)
1580 elemToLookForNew = []
1581 for i
in elemToLookFor:
1582 nodeNs = i.findall(
'.//{*}n')
1585 if alltext(nnn)
in list(localShumansGradients):
1586 elemToLookForNew.append(i)
1588 elemToLookFor = elemToLookForNew
1591 if nbzshugradwk > maxnbZshugradwk:
1592 maxnbZshugradwk = nbzshugradwk
1595 scope.addArrayParenthesesInNode(foundStmtandCalls[stmt][0])
1599 if tag(foundStmtandCalls[stmt][0]) !=
'call-stmt':
1602 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, lv = \
1603 getDimsAndMNHExpandIndexes(arrayDim, dimWorkingVar)
1604 localVariablesToAdd.update(lv)
1606 parStmt = scope.getParent(foundStmtandCalls[stmt][0])
1607 indexForCall = list(parStmt).index(foundStmtandCalls[stmt][0])
1608 mnhOpenDir =
"!$mnh_expand_array(" + mnhExpandArrayIndexes +
")"
1609 mnhCloseDir =
"!$mnh_end_expand_array(" + mnhExpandArrayIndexes +
")"
1610 parStmt.insert(indexForCall,
1611 createElem(
'C', text=
"!$acc kernels", tail=
'\n'))
1612 parStmt.insert(indexForCall + 1,
1613 createElem(
'C', text=mnhOpenDir, tail=
'\n'))
1614 parStmt.insert(indexForCall + 3,
1615 createElem(
'C', text=mnhCloseDir, tail=
'\n'))
1616 parStmt.insert(indexForCall + 4,
1617 createElem(
'C', text=
"!$acc end kernels", tail=
'\n'))
1618 parStmt.insert(indexForCall + 5,
1619 createElem(
'C', text=
"!", tail=
'\n'))
1622 for stmt
in computeStmtforParenthesis:
1623 scope.addArrayParenthesesInNode(stmt)
1627 for sub
in sorted(subToInclude):
1628 if re.match(
r'[MD][XYZ][MF](2D)?_PHY', sub):
1629 moduleVars.append((scope.path,
'MODE_SHUMAN_PHY', sub))
1631 for kind
in (
'M',
'U',
'V',
'W'):
1632 if re.match(
r'G[XYZ]_' + kind +
r'_[MUVW]{1,2}_PHY', sub):
1633 moduleVars.append((scope.path, f
'MODE_GRADIENT_{kind}_PHY', sub))
1634 scope.addModuleVar(moduleVars)
1637 for varName
in localVariablesToAdd:
1638 if not scope.varList.findVar(varName):
1639 var = {
'as': [],
'asx': [],
1640 'n': varName,
'i':
None,
't':
'INTEGER',
'arg':
False,
1641 'use':
False,
'opt':
False,
'allocatable':
False,
1642 'parameter':
False,
'init':
None,
'scopePath': scope.path}
1643 scope.addVar([[scope.path, var[
'n'], scope.varSpec2stmt(var),
None]])