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)
170 def convertOneType(component, newVarList, scope):
172 objType = scope.getParent(component, 2)
173 objTypeStr = alltext(objType).upper()
174 namedENn = objType.find(
'.//{*}N/{*}n')
175 structure = namedENn.text
176 variable = component.find(
'.//{*}ct').text.upper()
180 arrayRall = objType.findall(
'.//{*}array-R')
181 if len(arrayRall) > 0:
182 arrayR = copy.deepcopy(arrayRall[0])
183 txt = alltext(arrayR).replace(
',',
'')
184 txt = txt.replace(
':',
'')
185 txt = txt.replace(
'(',
'')
186 txt = txt.replace(
')',
'')
187 arrayIndices = arrayIndices + txt
188 elif len(objType.findall(
'.//{*}element-LT')) > 0:
190 for elem
in objType.findall(
'.//{*}element'):
191 arrayIndices = arrayIndices + alltext(elem)
192 newName = variable[0] + structure + variable[1:] + arrayIndices
193 newName = newName.upper()
197 namedENn.text = newName
198 objType.remove(objType.find(
'.//{*}R-LT'))
199 if len(arrayRall) > 0:
200 objType.insert(1, arrayR)
203 if newName
not in newVarList:
204 if len(arrayRall) == 0:
205 newVarList[newName] = (
None, objTypeStr)
207 newVarList[newName] = (arrayR, objTypeStr)
209 scopes = self.getScopes()
210 if scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
212 for scope
in [scope
for scope
in scopes
213 if 'sub:' in scope.path
and 'interface' not in scope.path]:
215 for ifStmt
in (scope.findall(
'.//{*}if-then-stmt') +
216 scope.findall(
'.//{*}else-if-stmt') +
217 scope.findall(
'.//{*}where-stmt')):
218 compo = ifStmt.findall(
'.//{*}component-R')
220 for elcompo
in compo:
221 convertOneType(elcompo, newVarList, scope)
223 for aStmt
in scope.findall(
'.//{*}a-stmt'):
226 if len(aStmt[0].findall(
'.//{*}component-R')) == 0:
227 compoE2 = aStmt.findall(
'.//{*}component-R')
234 nbNamedEinE2 = len(aStmt.findall(
'.//{*}E-2')[0].findall(
'.//{*}named-E/' +
236 if nbNamedEinE2 > 1
or nbNamedEinE2 == 1
and \
237 len(aStmt[0].findall(
'.//{*}R-LT')) == 1:
238 for elcompoE2
in compoE2:
239 convertOneType(elcompoE2, newVarList, scope)
243 for aStmt
in scope.findall(
'.//{*}a-stmt'):
245 if len(aStmt[0].findall(
'.//{*}component-R')) > 0:
247 for el
in newVarList.items():
248 if alltext(aStmt[0]) == el[1][1]:
249 stmtAffect = createExpr(el[0] +
"=" + alltext(aStmt[0]))
250 par = scope.getParent(aStmt)
252 if tag(par[list(par).index(aStmt)+1]) ==
'C':
254 par.insert(list(par).index(aStmt)+1+iExtra, stmtAffect[0])
258 for el, var
in newVarList.items():
259 if el[0].upper() ==
'X' or el[0].upper() ==
'P' or el[0].upper() ==
'Z':
261 elif el[0].upper() ==
'L' or el[0].upper() ==
'O':
263 elif el[0].upper() ==
'N' or el[0].upper() ==
'I' or el[0].upper() ==
'K':
265 elif el[0].upper() ==
'C':
266 varType =
'CHARACTER(LEN=LEN(' + var[1] +
'))'
268 raise PYFTError(
'Case not implemented for the first letter of the newVarName' +
269 el +
' in convertTypesInCompute')
273 varArray =
', DIMENSION('
274 for i, sub
in enumerate(var[0].findall(
'.//{*}section-subscript')):
275 if len(sub.findall(
'.//{*}upper-bound')) > 0:
276 dimSize = simplifyExpr(
277 alltext(sub.findall(
'.//{*}upper-bound')[0]) +
278 '-' + alltext(sub.findall(
'.//{*}lower-bound')[0]) +
280 elif len(sub.findall(
'.//{*}lover-bound')) > 0:
281 dimSize = simplifyExpr(alltext(sub.findall(
'.//{*}lower-bound')[0]))
283 dimSize =
'SIZE(' + var[1] +
',' + str(i+1) +
')'
284 varArray =
', DIMENSION(' + dimSize +
','
285 varArray = varArray[:-1] +
')'
286 scope.addVar([[scope.path, el, varType + varArray +
' :: ' + el,
None]])
289 stmtAffect = createExpr(el +
"=" + var[1])[0]
290 scope.insertStatement(scope.indent(stmtAffect), first=
True)
359 Convert MODULE to SUBMODULE statements and add INTERFACE of SUBROUTINEs of PHYEX
360 ==> Applied only on MODE_
362 - if an INTERFACE already exists
363 - if no subroutine is present in the module
364 - to CONTAINS routines
365 1) Create interface statement if any
366 2) Add subroutines declaration (with MODULE statement)
367 3) Add SUBMODULE statements and convert SUBROUTINE to MODULE SUBROUTINE statements
369 scopes = self.getScopes()
372 oldModNode = self.find(
'.//{*}program-unit')
373 modNode = copy.deepcopy(self.find(
'.//{*}program-unit'))
375 interfaceStmt = self.findall(
'.//{*}interface-stmt')
376 subStmt = self.findall(
'.//{*}subroutine-stmt')
378 if modScope.path.split(
'/')[-1].split(
':')[1][:4] ==
'MODE' and \
379 len(interfaceStmt) == 0
and len(subStmt) > 0:
380 moduleName = modScope.path.split(
'/')[-1].split(
':')[1][:]
382 newMod = createElem(
'program-unit', text=
'MODULE ' + moduleName, tail=
'\n')
384 newMod.append(createElem(
'implicit-none-stmt', text=
'IMPLICIT NONE', tail=
'\n'))
385 interfaceStmt = createElem(
'interface-construct')
386 interfaceStmt.append(createElem(
'interface-stmt', text=
'INTERFACE', tail=
'\n'))
387 interfaceStmt.append(createElem(
'end-interface-stmt', text=
'END INTERFACE', tail=
'\n'))
388 newMod.append(interfaceStmt)
392 for scope
in scopes[1:]:
394 if sum(
'sub' in s
for s
in scope.path.split(
'/')) == 1:
395 subsModified.append(scope.path.split(
'/')[-1].split(
':')[1][:])
396 subroutineDecl = createElem(
'module-unit')
398 subroutineStmt = copy.deepcopy(scope[0])
399 declType = subroutineStmt.text
400 prefix = createElem(
'prefix')
401 prefix.text =
'MODULE'
402 subroutineStmt.text =
''
403 subroutineStmt.insert(0, prefix)
404 prefix.tail =
' ' + declType
405 subroutineDecl.append(subroutineStmt)
407 for use
in scope.findall(
'.//{*}use-stmt'):
408 subroutineDecl.append(copy.deepcopy(use))
409 subroutineDecl.append(createElem(
'implicit-none-stmt', text=
'IMPLICIT NONE',
412 for var
in [var
for var
in scope.varList
if var[
'arg']
or var[
'result']]:
413 subroutineDecl.append(createExpr(self.varSpec2stmt(var,
True))[0])
414 for external
in scope.findall(
'./{*}external-stmt'):
415 subroutineDecl.append(copy.deepcopy(external))
416 if 'SUBROUTINE' in declType:
417 endStmt = createElem(
'end-subroutine-stmt')
418 declName = subroutineStmt.find(
'./{*}subroutine-N/{*}N/{*}n').text
419 elif 'FUNCTION' in declType:
420 endStmt = createElem(
'end-function-stmt')
421 declName = subroutineStmt.find(
'./{*}function-N/{*}N/{*}n').text
423 raise PYFTError(
'declType in addSubmodulePHYEX not handled')
425 endStmt.text =
'END ' + declType + declName +
'\n'
426 subroutineDecl.append(endStmt)
427 interfaceStmt.insert(1, subroutineDecl)
430 newMod.append(createElem(
'end-program-unit', text=
'END MODULE ' + moduleName,
432 self[0].insert(0, newMod)
435 progUnit = createElem(
'program-unit')
446 submoduleStmt = createElem(
'submodule-stmt', text=
'SUBMODULE (')
447 parentId = createElem(
'parent-identifier')
449 ancestorModule = createElem(
'ancestor-module-N')
450 ancestorModuleN = createElem(
'n', text=moduleName)
451 ancestorModule.append(ancestorModuleN)
452 parentId.append(ancestorModule)
453 submoduleStmt.append(parentId)
454 submoduleModule = createElem(
'submodule-module-N')
455 submoduleModuleN = createElem(
'n', text=
'S' + moduleName, tail=
'\n')
456 submoduleModule.append(submoduleModuleN)
457 submoduleStmt.append(submoduleModule)
458 progUnit.append(submoduleStmt)
461 endSubmoduleStmt = createElem(
'end-submodule-stmt', text=
'END SUBMODULE ')
462 submoduleN = createElem(
'submodule-N')
463 submoduleNN = createElem(
'N')
464 submoduleNNn = createElem(
'n', text=
'S' + moduleName, tail=
'\n')
465 submoduleNN.append(submoduleNNn)
466 submoduleN.append(submoduleNN)
467 endSubmoduleStmt.append(submoduleN)
469 progUnit.append(endSubmoduleStmt)
470 progUnit.append(createElem(
'end-program-unit'))
474 modStmt = modNode.find(
'.//{*}module-stmt')
475 modEndStmt = modNode.find(
'.//{*}end-module-stmt')
476 modNode.remove(modStmt)
477 modNode.remove(modEndStmt)
480 publicStmts = modNode.findall(
'.//{*}public-stmt')
481 privateStmts = modNode.findall(
'.//{*}private-stmt')
482 if len(publicStmts) > 0:
483 for publicStmt
in publicStmts:
484 modNode.remove(publicStmt)
485 if len(privateStmts) > 0:
486 for privateStmt
in privateStmts:
487 modNode.remove(privateStmt)
490 subroutines = modNode.findall(
'.//{*}subroutine-stmt')
491 for sub
in subroutines:
492 if sub.find(
'.//{*}N/{*}n').text
in subsModified:
493 prefix = createElem(
'prefix')
494 prefix.text =
'MODULE'
496 sub.insert(0, prefix)
497 prefix.tail =
' SUBROUTINE '
498 progUnit.insert(1, modNode)
500 self.insert(1, progUnit)
503 self.remove(oldModNode)
509 Add MPPDB_CHEKS on all intent REAL arrays on subroutines.
510 ****** Not applied on modd_ routines. ********
511 Handle optional arguments.
512 Example, for a BL89 routine with 4 arguments, 1 INTENT(IN),
513 2 INTENT(INOUT), 1 INTENT(OUT), it produces :
514 IF (MPPDB_INITIALIZED) THEN
516 CALL MPPDB_CHECK(PZZ, "BL89 beg:PZZ")
517 !Check all INOUT arrays
518 CALL MPPDB_CHECK(PDZZ, "BL89 beg:PDZZ")
519 CALL MPPDB_CHECK(PTHVREF, "BL89 beg:PTHVREF")
522 IF (MPPDB_INITIALIZED) THEN
523 !Check all INOUT arrays
524 CALL MPPDB_CHECK(PDZZ, "BL89 end:PDZZ")
525 CALL MPPDB_CHECK(PTHVREF, "BL89 end:PTHVREF")
526 !Check all OUT arrays
527 CALL MPPDB_CHECK(PLM, "BL89 end:PLM")
529 param printsMode: if True, instead of CALL MPPDB_CHECK, add fortran prints for debugging
531 def addPrints_statement(var, typeofPrints='minmax'):
532 ifBeg, ifEnd =
'',
''
535 if typeofPrints ==
'minmax':
536 strMSG = f
'MINMAX {varName} = \",MINVAL({varName}), MAXVAL({varName})'
537 elif typeofPrints ==
'shape':
538 strMSG = f
'SHAPE {varName} = \",SHAPE({varName})'
540 raise PYFTError(
'typeofPrints is either minmax or shape in addPrints_statement')
542 strMSG = var[
'n'] +
' = \",' + var[
'n']
544 ifBeg = ifBeg +
'IF (PRESENT(' + var[
'n'] +
')) THEN\n '
545 ifEnd = ifEnd +
'\nEND IF'
546 return createExpr(ifBeg +
"print*,\"" + strMSG + ifEnd)[0]
548 def addMPPDB_CHECK_statement(var, subRoutineName, strMSG='beg:
'):
549 ifBeg, ifEnd, addD, addLastDim, addSecondDimType = '',
'',
'',
'',
''
553 if 'D%NIJT' in var[
'as'][0][1]:
555 if len(var[
'as']) == 2:
557 addLastDim =
', ' + var[
'as'][1][1]
558 if len(var[
'as']) >= 2:
561 if 'D%NK' in var[
'as'][1][1]:
562 addSecondDimType =
',' +
'''"VERTICAL"'''
564 addSecondDimType =
',' +
'''"OTHER"'''
565 if 'MERGE' in var[
'as'][-1][1]:
566 keyDimMerge = var[
'as'][-1][1].split(
',')[2][:-1]
567 ifBeg =
'IF (' + keyDimMerge +
') THEN\n'
570 ifBeg = ifBeg +
'IF (PRESENT(' + var[
'n'] +
')) THEN\n IF (SIZE(' + \
571 var[
'n'] +
',1) > 0) THEN\n'
572 ifEnd = ifEnd +
'\nEND IF\nEND IF'
573 argsMPPDB = var[
'n'] +
", " +
"\"" + subRoutineName +
" " + strMSG+var[
'n'] +
"\""
574 return createExpr(ifBeg +
"CALL MPPDB_CHECK(" + addD + argsMPPDB +
575 addLastDim + addSecondDimType +
")" + ifEnd)[0]
576 scopes = self.getScopes()
577 if scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
584 if 'sub:' in scope.path
and 'func' not in scope.path
and 'interface' not in scope.path:
585 subRoutineName = scope.path.split(
'/')[-1].split(
':')[1]
588 arraysIn, arraysInOut, arraysOut = [], [], []
590 for var
in scope.varList:
591 if var[
'arg']
and var[
'as']
and 'TYPE' not in var[
't']
and \
592 'REAL' in var[
't']
and var[
'scopePath'] == scope.path:
595 if var[
'i'] ==
'INOUT':
596 arraysInOut.append(var)
597 if var[
'i'] ==
'OUT':
598 arraysOut.append(var)
600 for var
in scope.varList:
601 if not var[
't']
or var[
't']
and 'TYPE' not in var[
't']:
604 if var[
'i'] ==
'INOUT':
605 arraysInOut.append(var)
606 if var[
'i'] ==
'OUT':
607 arraysOut.append(var)
609 if len(arraysIn) + len(arraysInOut) + len(arraysOut) == 0:
614 scope.addModuleVar([(scope.path,
'MODE_MPPDB',
None)])
616 scope.addModuleVar([(scope.path,
'MODD_BLANK_n', [
'LDUMMY1'])])
619 commentIN = createElem(
'C', text=
'!Check all IN arrays', tail=
'\n')
620 commentINOUT = createElem(
'C', text=
'!Check all INOUT arrays', tail=
'\n')
621 commentOUT = createElem(
'C', text=
'!Check all OUT arrays', tail=
'\n')
624 if len(arraysIn) + len(arraysInOut) > 0:
626 ifMPPDBinit = createExpr(
"IF (MPPDB_INITIALIZED) THEN\n END IF")[0]
628 ifMPPDBinit = createExpr(
"IF (LDUMMY1) THEN\n END IF")[0]
629 ifMPPDB = ifMPPDBinit.find(
'.//{*}if-block')
632 if len(arraysIn) > 0:
633 ifMPPDB.insert(1, commentIN)
634 for i, var
in enumerate(arraysIn):
636 ifMPPDB.insert(2 + i, addMPPDB_CHECK_statement(var, subRoutineName,
639 ifMPPDB.insert(2 + i, addPrints_statement(var,
640 typeofPrints=
'minmax'))
641 ifMPPDB.insert(3 + i, addPrints_statement(var,
642 typeofPrints=
'shape'))
645 if len(arraysInOut) > 0:
646 shiftLineNumber = 2
if len(arraysIn) > 0
else 1
648 ifMPPDB.insert(len(arraysIn) + shiftLineNumber, commentINOUT)
650 ifMPPDB.insert(len(arraysIn)*2 + shiftLineNumber-1, commentINOUT)
652 for i, var
in enumerate(arraysInOut):
654 ifMPPDB.insert(len(arraysIn) + shiftLineNumber + 1 + i,
655 addMPPDB_CHECK_statement(var, subRoutineName,
658 ifMPPDB.insert(len(arraysIn) + shiftLineNumber + 1 + i,
659 addPrints_statement(var, typeofPrints=
'minmax'))
662 scope.insertStatement(scope.indent(ifMPPDBinit), first=
True)
665 if len(arraysInOut) + len(arraysOut) > 0:
667 ifMPPDBend = createExpr(
"IF (MPPDB_INITIALIZED) THEN\n END IF")[0]
669 ifMPPDBend = createExpr(
"IF (LDUMMY1) THEN\n END IF")[0]
670 ifMPPDB = ifMPPDBend.find(
'.//{*}if-block')
673 if len(arraysInOut) > 0:
674 ifMPPDB.insert(1, commentINOUT)
675 for i, var
in enumerate(arraysInOut):
677 ifMPPDB.insert(2 + i, addMPPDB_CHECK_statement(var, subRoutineName,
680 ifMPPDB.insert(2 + i, addPrints_statement(var,
681 typeofPrints=
'minmax'))
684 if len(arraysOut) > 0:
685 shiftLineNumber = 2
if len(arraysInOut) > 0
else 1
687 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber, commentOUT)
689 ifMPPDB.insert(len(arraysInOut)*2 + shiftLineNumber-1, commentOUT)
690 for i, var
in enumerate(arraysOut):
692 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber + 1 + i,
693 addMPPDB_CHECK_statement(var, subRoutineName,
696 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber + 1 + i,
697 addPrints_statement(var, typeofPrints=
'minmax'))
700 scope.insertStatement(scope.indent(ifMPPDBend), first=
False)
808 def removeIJDim(self, stopScopes, parserOptions=None, wrapH=False, simplify=False):
810 Transform routines to be called in a loop on columns
811 :param stopScopes: scope paths where we stop to add the D argument (if needed)
812 :param parserOptions, wrapH: see the PYFT class
813 :param simplify: try to simplify code (remove useless dimensions in call)
815 ComputeInSingleColumn :
816 - Remove all Do loops on JI and JJ
817 - Initialize former indexes JI, JJ, JIJ to first array element:
818 JI=D%NIB, JJ=D%NJB, JIJ=D%NIJB
819 - If simplify is True, replace (:,*) on I/J/IJ dimension on argument
820 with explicit (:,*) on CALL statements:
821 e.g. CALL FOO(D, A(:,JK,1), B(:,:))
822 ==> CALL FOO(D, A(JIJ,JK,1), B(:,:)) only if the target argument is not an array
825 indexToCheck = {
'JI': (
'D%NIB',
'D%NIT'),
826 'JJ': (
'D%NJB',
'D%NJT'),
827 'JIJ': (
'D%NIJB',
'D%NIJT')}
829 def slice2index(namedE, scope):
831 Transform a slice on the horizontal dimension into an index
832 Eg.: X(1:D%NIJT, 1:D%NKT) => X(JIJ, 1:D%NKT) Be careful, this array is not contiguous.
833 X(1:D%NIJT, JK) => X(JIJ, JK)
834 :param namedE: array to transform
835 :param scope: scope where the array is
838 for isub, sub
in enumerate(namedE.findall(
'./{*}R-LT/{*}array-R/' +
839 '{*}section-subscript-LT/' +
840 '{*}section-subscript')):
841 if ':' in alltext(sub):
842 loopIndex, _, _ = scope.findIndexArrayBounds(namedE, isub, _loopVarPHYEX)
843 if loopIndex
in indexToCheck:
846 lowerBound = createElem(
'lower-bound')
847 sub.insert(0, lowerBound)
849 lowerBound = sub.find(
'./{*}lower-bound')
851 for item
in lowerBound:
852 lowerBound.remove(item)
853 upperBound = sub.find(
'./{*}upper-bound')
854 if upperBound
is not None:
855 sub.remove(upperBound)
856 lowerBound.append(createExprPart(loopIndex))
857 if loopIndex
not in indexRemoved:
858 indexRemoved.append(loopIndex)
861 if ':' not in alltext(namedE.find(
'./{*}R-LT/{*}array-R/{*}section-subscript-LT')):
862 namedE.find(
'./{*}R-LT/{*}array-R').tag = f
'{{{NAMESPACE}}}parens-R'
863 namedE.find(
'./{*}R-LT/{*}parens-R/' +
864 '{*}section-subscript-LT').tag = f
'{{{NAMESPACE}}}element-LT'
865 for ss
in namedE.findall(
'./{*}R-LT/{*}parens-R/' +
866 '{*}element-LT/{*}section-subscript'):
867 ss.tag = f
'{{{NAMESPACE}}}element'
868 lowerBound = ss.find(
'./{*}lower-bound')
869 for item
in lowerBound:
871 ss.remove(lowerBound)
874 self.addArrayParentheses()
877 self.attachArraySpecToEntity()
878 hUupperBounds = [v[1]
for v
in indexToCheck.values()]
882 for scope
in [scope
for scope
in self.getScopes()[::-1]
883 if 'func:' not in scope.path
and
884 (scope.path
in stopScopes
or
885 self.tree.isUnderStopScopes(scope.path, stopScopes,
886 includeInterfaces=
True))]:
892 for doNode
in scope.findall(
'.//{*}do-construct')[::-1]:
893 for loopI
in doNode.findall(
'./{*}do-stmt/{*}do-V/{*}named-E/{*}N'):
894 loopIname = n2name(loopI).upper()
895 if loopIname
in indexToCheck:
898 par = scope.getParent(doNode)
899 index = list(par).index(doNode)
900 for item
in doNode[1:-1][::-1]:
901 par.insert(index, item)
903 if loopIname
not in indexRemoved:
904 indexRemoved.append(loopIname)
909 for intr
in scope.findall(
'.//{*}R-LT/{*}parens-R/../..'):
910 intrName = n2name(intr.find(
'./{*}N')).upper()
911 if intrName
in (
'PACK',
'UNPACK',
'COUNT',
'MAXVAL',
'MINVAL',
'ALL',
'ANY',
'SUM'):
919 while par
is not None and not isStmt(par):
920 par = scope.getParent(par)
921 if tag(par)
in (
'a-stmt',
'op-E'):
926 for namedE
in parToUse.findall(
'.//{*}R-LT/{*}array-R/../..'):
927 slice2index(namedE, scope)
930 if intr.find(
'.//{*}R-LT/{*}array-R')
is None:
931 if intrName
in (
'MAXVAL',
'MINVAL',
'SUM',
'ALL',
'ANY'):
933 parens = intr.find(
'./{*}R-LT/{*}parens-R')
934 parens.tag = f
'{{{NAMESPACE}}}parens-E'
935 intrPar = scope.getParent(intr)
936 intrPar.insert(list(intrPar).index(intr), parens)
938 elif intrName ==
'COUNT':
940 nodeN = intr.find(
'./{*}N')
941 for item
in nodeN[1:]:
943 nodeN.find(
'./{*}n').text =
'MERGE'
944 elementLT = intr.find(
'./{*}R-LT/{*}parens-R/{*}element-LT')
946 element = createElem(
'element', tail=
', ')
947 element.append(createExprPart(val))
948 elementLT.insert(0, element)
961 assert scope.find(
'.//{*}include')
is None and \
962 scope.find(
'.//{*}include-stmt')
is None, \
963 "inlining must be performed before removing horizontal dimensions"
965 if scope.path
in stopScopes:
967 preserveShape = [v[
'n']
for v
in scope.varList
if v[
'arg']]
972 if 'sub:' in scope.path:
976 for namedE
in scope.findall(
'.//{*}named-E/{*}R-LT/{*}parens-R/../..'):
977 if n2name(namedE.find(
'./{*}N')).upper()
not in preserveShape:
978 var = scope.varList.findVar(n2name(namedE.find(
'./{*}N')).upper())
979 if var
is not None and var[
'as']
is not None and len(var[
'as']) > 0:
980 subs = namedE.findall(
'./{*}R-LT/{*}parens-R/' +
981 '{*}element-LT/{*}element')
982 if (len(subs) == 1
and var[
'as'][0][1]
in hUupperBounds)
or \
983 (len(subs) == 2
and (var[
'as'][0][1]
in hUupperBounds
and
984 var[
'as'][1][1]
in hUupperBounds)):
985 namedE.remove(namedE.find(
'./{*}R-LT'))
989 for call
in scope.findall(
'.//{*}call-stmt'):
990 for namedE
in call.findall(
'./{*}arg-spec//{*}named-E'):
991 subs = namedE.findall(
'.//{*}section-subscript')
992 var = scope.varList.findVar(n2name(namedE.find(
'./{*}N')).upper())
993 if len(subs) > 0
and (var
is None or var[
'as']
is None or
994 len(var[
'as']) < len(subs)):
1002 elif (len(subs) >= 2
and
1003 ':' in alltext(subs[0])
and var[
'as'][0][1]
in hUupperBounds
and
1004 ':' in alltext(subs[1])
and var[
'as'][1][1]
in hUupperBounds):
1006 remove = len(subs) == 2
1007 index = (len(subs) > 2
and
1008 len([sub
for sub
in subs
if ':' in alltext(sub)]) == 2)
1009 elif (len(subs) >= 1
and
1010 ':' in alltext(subs[0])
and var[
'as'][0][1]
in hUupperBounds):
1012 remove = len(subs) == 1
1013 index = (len(subs) > 1
and
1014 len([sub
for sub
in subs
if ':' in alltext(sub)]) == 1)
1019 if n2name(namedE.find(
'./{*}N')).upper()
in preserveShape:
1020 slice2index(namedE, scope)
1022 nodeRLT = namedE.find(
'.//{*}R-LT')
1023 scope.getParent(nodeRLT).remove(nodeRLT)
1025 slice2index(namedE, scope)
1030 for decl
in scope.findall(
'.//{*}T-decl-stmt/{*}EN-decl-LT/{*}EN-decl'):
1031 name = n2name(decl.find(
'./{*}EN-N/{*}N')).upper()
1032 if name
not in preserveShape:
1033 varsShape = decl.findall(
'.//{*}shape-spec-LT')
1034 for varShape
in varsShape:
1035 subs = varShape.findall(
'.//{*}shape-spec')
1036 if (len(subs) == 1
and alltext(subs[0])
in hUupperBounds)
or \
1037 (len(subs) == 2
and (alltext(subs[0])
in hUupperBounds
and
1038 alltext(subs[1])
in hUupperBounds)):
1040 itemToRemove = scope.getParent(varShape)
1041 scope.getParent(itemToRemove).remove(itemToRemove)
1046 for loopIndex
in indexRemoved:
1049 scope.insertStatement(
1050 createExpr(loopIndex +
" = " + indexToCheck[loopIndex][0])[0],
True)
1051 if len(indexRemoved) > 0:
1052 scope.addArgInTree(
'D',
'TYPE(DIMPHYEX_t) :: D',
1053 0, stopScopes, moduleVarList=[(
'MODD_DIMPHYEX', [
'DIMPHYEX_t'])],
1054 parserOptions=parserOptions, wrapH=wrapH)
1056 scope.addVar([[scope.path, loopIndex,
'INTEGER :: ' + loopIndex,
None]
1057 for loopIndex
in indexRemoved
1058 if scope.varList.findVar(loopIndex, exactScope=
True)
is None])
1254 Convert all calling of functions and gradient present in shumansGradients
1255 table into the use of subroutines
1256 and use mnh_expand_directives to handle intermediate computations
1258 def getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar=''):
1260 if zshugradwkDim == 1:
1261 dimSuffRoutine =
'2D'
1263 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE'
1264 localVariables = [
'JIJ']
1265 elif zshugradwkDim == 2:
1267 if 'D%NKT' in dimWorkingVar:
1268 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE,JK=1:IKT'
1269 localVariables = [
'JIJ',
'JK']
1270 elif 'D%NIT' in dimWorkingVar
and 'D%NJT' in dimWorkingVar:
1272 mnhExpandArrayIndexes =
'JI=1:IIT,JJ=1:IJT'
1273 localVariables = [
'JI',
'JJ']
1274 dimSuffRoutine =
'2D'
1280 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE,JK=1:IKT'
1281 localVariables = [
'JIJ',
'JK']
1282 elif zshugradwkDim == 3:
1284 mnhExpandArrayIndexes =
'JI=1:IIT,JJ=1:IJT,JK=1:IKT'
1285 localVariables = [
'JI',
'JJ',
'JK']
1287 raise PYFTError(
'Shuman func to routine conversion not implemented ' +
1288 'for 4D+ dimensions variables')
1289 return dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, localVariables
1291 def FUNCtoROUTINE(scope, stmt, itemFuncN, localShumansCount, inComputeStmt,
1292 nbzshugradwk, zshugradwkDim, dimWorkingVar):
1294 :param scope: node on which the calling function is present before transformation
1295 :param stmt: statement node (a-stmt or call-stmt) that contains the function(s) to be
1297 :param itemFuncN: <n>FUNCTIONNAME</n> node
1298 :param localShumansCount: instance of the shumansGradients dictionnary
1299 for the given scope (which contains the number of times a
1300 function has been called within a transformation)
1301 :param dimWorkingVar: string of the declaration of a potential working variable
1302 depending on the array on wich the shuman is applied
1303 (e.g. MZM(PRHODJ(:,IKB));
1304 dimWorkingVar = 'REAL, DIMENSION(D%NIJT) :: ' )
1306 :return callStmt: the new CALL to the routines statement
1307 :return computeStmt: the a-stmt computation statement if there was an operation
1308 in the calling function in stmt
1309 :return localVariables: list of local variables needed for the mnh_expand directive
1313 parStmt = scope.getParent(stmt)
1314 parItemFuncN = scope.getParent(itemFuncN)
1316 grandparItemFuncN = scope.getParent(itemFuncN, level=2)
1317 funcName = alltext(itemFuncN)
1320 indexForCall = list(parStmt).index(stmt)
1325 siblsItemFuncN = scope.getSiblings(parItemFuncN, after=
True, before=
False)
1326 workingItem = siblsItemFuncN[0][0][0]
1329 if len(siblsItemFuncN[0][0]) > 1:
1331 workingItem = scope.updateContinuation(siblsItemFuncN[0][0], removeALL=
True,
1332 align=
False, addBegin=
False)[0]
1336 opE = workingItem.findall(
'.//{*}op-E')
1337 scope.removeArrayParenthesesInNode(workingItem)
1338 computeStmt, remaningArgsofFunc = [],
''
1339 dimSuffVar = str(zshugradwkDim) +
'D'
1340 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, _ = \
1341 getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar)
1344 computingVarName =
'ZSHUGRADWK'+str(nbzshugradwk)+
'_'+str(zshugradwkDim)+
'D'
1346 if not scope.varList.findVar(computingVarName):
1347 scope.addVar([[scope.path, computingVarName,
1348 dimWorkingVar + computingVarName,
None]])
1352 computeVar = scope.varList.findVar(computingVarName)
1353 dimWorkingVar =
'REAL, DIMENSION('
1354 for dims
in computeVar[
'as'][:arrayDim]:
1355 dimWorkingVar += dims[1] +
','
1356 dimWorkingVar = dimWorkingVar[:-1] +
') ::'
1358 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, localVariables = \
1359 getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar)
1362 mnhOpenDir =
"!$mnh_expand_array(" + mnhExpandArrayIndexes +
")"
1363 mnhCloseDir =
"!$mnh_end_expand_array(" + mnhExpandArrayIndexes +
")"
1366 workingComputeItem = workingItem[0]
1368 if len(workingItem) == 2:
1369 remaningArgsofFunc =
',' + alltext(workingItem[1])
1370 elif len(workingItem) > 2:
1371 raise PYFTError(
'ShumanFUNCtoCALL: expected maximum 1 argument in shuman ' +
1372 'function to transform')
1373 computeStmt = createExpr(computingVarName +
" = " + alltext(workingComputeItem))[0]
1374 workingItem = computeStmt.find(
'.//{*}E-1')
1376 parStmt.insert(indexForCall, createElem(
'C', text=
'!$acc kernels', tail=
'\n'))
1377 parStmt.insert(indexForCall + 1, createElem(
'C', text=mnhOpenDir, tail=
'\n'))
1378 parStmt.insert(indexForCall + 2, computeStmt)
1379 parStmt.insert(indexForCall + 3, createElem(
'C', text=mnhCloseDir, tail=
'\n'))
1380 parStmt.insert(indexForCall + 4, createElem(
'C',
1381 text=
'!$acc end kernels', tail=
'\n'))
1382 parStmt.insert(indexForCall + 5, createElem(
'C',
1383 text=
'!', tail=
'\n'))
1387 if zshugradwkDim == 1:
1388 dimSuffRoutine =
'2D'
1389 workingVar =
'Z' + funcName + dimSuffVar +
'_WORK' + str(localShumansCount[funcName])
1390 if funcName
in (
'GY_U_UV',
'GX_V_UV'):
1391 gpuGradientImplementation =
'_DEVICE('
1392 newFuncName = funcName + dimSuffRoutine +
'_DEVICE'
1394 gpuGradientImplementation =
'_PHY(D, '
1395 newFuncName = funcName + dimSuffRoutine +
'_PHY'
1396 callStmt = createExpr(
"CALL " + funcName + dimSuffRoutine + gpuGradientImplementation
1397 + alltext(workingItem) + remaningArgsofFunc +
1398 ", " + workingVar +
")")[0]
1399 parStmt.insert(indexForCall, callStmt)
1402 parOfgrandparItemFuncN = scope.getParent(grandparItemFuncN)
1403 indexWorkingVar = list(parOfgrandparItemFuncN).index(grandparItemFuncN)
1404 savedTail = grandparItemFuncN.tail
1405 parOfgrandparItemFuncN.remove(grandparItemFuncN)
1408 xmlWorkingvar = createExprPart(workingVar)
1409 xmlWorkingvar.tail = savedTail
1410 parOfgrandparItemFuncN.insert(indexWorkingVar, xmlWorkingvar)
1413 if not scope.varList.findVar(workingVar):
1414 scope.addVar([[scope.path, workingVar, dimWorkingVar + workingVar,
None]])
1416 return callStmt, computeStmt, nbzshugradwk, newFuncName, localVariables
1418 shumansGradients = {
'MZM': 0,
'MXM': 0,
'MYM': 0,
'MZF': 0,
'MXF': 0,
'MYF': 0,
1419 'DZM': 0,
'DXM': 0,
'DYM': 0,
'DZF': 0,
'DXF': 0,
'DYF': 0,
1420 'GZ_M_W': 0,
'GZ_W_M': 0,
'GZ_U_UW': 0,
'GZ_V_VW': 0,
1421 'GX_M_U': 0,
'GX_U_M': 0,
'GX_W_UW': 0,
'GX_M_M': 0,
1422 'GY_V_M': 0,
'GY_M_V': 0,
'GY_W_VW': 0,
'GY_M_M': 0,
1423 'GX_V_UV': 0,
'GY_U_UV': 0}
1424 scopes = self.getScopes()
1425 if len(scopes) == 0
or scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
1427 for scope
in scopes:
1428 if 'sub:' in scope.path
and 'func' not in scope.path \
1429 and 'interface' not in scope.path:
1432 localVariablesToAdd = set()
1433 foundStmtandCalls, computeStmtforParenthesis = {}, []
1434 aStmt = scope.findall(
'.//{*}a-stmt')
1435 callStmts = scope.findall(
'.//{*}call-stmt')
1436 aStmtandCallStmts = aStmt + callStmts
1437 for stmt
in aStmtandCallStmts:
1438 elemN = stmt.findall(
'.//{*}n')
1440 if alltext(el)
in list(shumansGradients):
1443 parStmt = scope.getParent(stmt)
1444 if tag(parStmt) ==
'action-stmt':
1445 scope.changeIfStatementsInIfConstructs(
1446 singleItem=scope.getParent(parStmt))
1448 if str(stmt)
in foundStmtandCalls:
1449 foundStmtandCalls[str(stmt)][1] += 1
1451 foundStmtandCalls[str(stmt)] = [stmt, 1]
1454 subToInclude = set()
1455 for stmt
in foundStmtandCalls:
1456 localShumansGradients = copy.deepcopy(shumansGradients)
1457 elemToLookFor = [foundStmtandCalls[stmt][0]]
1458 previousComputeStmt = []
1461 while len(elemToLookFor) > 0:
1463 for elem
in elemToLookFor:
1464 elemN = elem.findall(
'.//{*}n')
1466 if alltext(el)
in list(localShumansGradients.keys()):
1471 nodeE1var = foundStmtandCalls[stmt][0].findall(
1472 './/{*}E-1/{*}named-E/{*}N')
1473 if len(nodeE1var) > 0:
1474 var = scope.varList.findVar(alltext(nodeE1var[0]))
1475 allSubscripts = foundStmtandCalls[stmt][0].findall(
1476 './/{*}E-1//{*}named-E/{*}R-LT/' +
1477 '{*}array-R/{*}section-subscript-LT')
1481 elPar = scope.getParent(el, level=2)
1482 callVar = elPar.findall(
'.//{*}named-E/{*}N')
1483 if alltext(el)[0] ==
'G':
1488 var = scope.varList.findVar(alltext(callVar[-1]))
1489 shumanIsCalledOn = scope.getParent(callVar[-1])
1492 var, inested =
None, 0
1494 while not var
or len(var[
'as']) == 0:
1498 var = scope.varList.findVar(
1499 alltext(callVar[inested]))
1501 shumanIsCalledOn = scope.getParent(callVar[inested-1])
1502 allSubscripts = shumanIsCalledOn.findall(
1503 './/{*}R-LT/{*}array-R/' +
1504 '{*}section-subscript-LT')
1508 arrayDim = len(var[
'as'])
1512 if len(allSubscripts) > 0:
1513 for subLT
in allSubscripts:
1515 lowerBound = sub.findall(
'.//{*}lower-bound')
1516 if len(lowerBound) > 0:
1517 if len(sub.findall(
'.//{*}upper-bound')) > 0:
1520 raise PYFTError(
'ShumanFUNCtoCALL does ' +
1521 'not handle conversion ' +
1522 'to routine of array ' +
1523 'subselection lower:upper' +
1524 ': how to set up the ' +
1525 'shape of intermediate ' +
1535 dimWorkingVar =
'REAL, DIMENSION('
1536 for dims
in var[
'as'][:arrayDim]:
1537 dimWorkingVar += dims[1] +
','
1538 dimWorkingVar = dimWorkingVar[:-1] +
') ::'
1541 localShumansGradients[alltext(el)] += 1
1545 if foundStmtandCalls[stmt][0].tail:
1546 foundStmtandCalls[stmt][0].tail = \
1547 foundStmtandCalls[stmt][0].tail.replace(
'\n',
'') +
'\n'
1549 foundStmtandCalls[stmt][0].tail =
'\n'
1552 result = FUNCtoROUTINE(scope, elem, el,
1553 localShumansGradients,
1554 elem
in previousComputeStmt,
1555 nbzshugradwk, arrayDim,
1557 (newCallStmt, newComputeStmt,
1558 nbzshugradwk, newFuncName, lv) = result
1559 localVariablesToAdd.update(lv)
1560 subToInclude.add(newFuncName)
1563 elemToLookFor.append(newCallStmt)
1567 if len(newComputeStmt) > 0:
1568 elemToLookFor.append(newComputeStmt)
1569 computeStmtforParenthesis.append(newComputeStmt)
1573 previousComputeStmt.append(newComputeStmt)
1577 elemToLookForNew = []
1578 for i
in elemToLookFor:
1579 nodeNs = i.findall(
'.//{*}n')
1582 if alltext(nnn)
in list(localShumansGradients):
1583 elemToLookForNew.append(i)
1585 elemToLookFor = elemToLookForNew
1588 if nbzshugradwk > maxnbZshugradwk:
1589 maxnbZshugradwk = nbzshugradwk
1592 scope.addArrayParenthesesInNode(foundStmtandCalls[stmt][0])
1596 if tag(foundStmtandCalls[stmt][0]) !=
'call-stmt':
1599 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, lv = \
1600 getDimsAndMNHExpandIndexes(arrayDim, dimWorkingVar)
1601 localVariablesToAdd.update(lv)
1603 parStmt = scope.getParent(foundStmtandCalls[stmt][0])
1604 indexForCall = list(parStmt).index(foundStmtandCalls[stmt][0])
1605 mnhOpenDir =
"!$mnh_expand_array(" + mnhExpandArrayIndexes +
")"
1606 mnhCloseDir =
"!$mnh_end_expand_array(" + mnhExpandArrayIndexes +
")"
1607 parStmt.insert(indexForCall,
1608 createElem(
'C', text=
"!$acc kernels", tail=
'\n'))
1609 parStmt.insert(indexForCall + 1,
1610 createElem(
'C', text=mnhOpenDir, tail=
'\n'))
1611 parStmt.insert(indexForCall + 3,
1612 createElem(
'C', text=mnhCloseDir, tail=
'\n'))
1613 parStmt.insert(indexForCall + 4,
1614 createElem(
'C', text=
"!$acc end kernels", tail=
'\n'))
1615 parStmt.insert(indexForCall + 5,
1616 createElem(
'C', text=
"!", tail=
'\n'))
1619 for stmt
in computeStmtforParenthesis:
1620 scope.addArrayParenthesesInNode(stmt)
1624 for sub
in sorted(subToInclude):
1625 if re.match(
r'[MD][XYZ][MF](2D)?_PHY', sub):
1626 moduleVars.append((scope.path,
'MODE_SHUMAN_PHY', sub))
1628 for kind
in (
'M',
'U',
'V',
'W'):
1629 if re.match(
r'G[XYZ]_' + kind +
r'_[MUVW]{1,2}_PHY', sub):
1630 moduleVars.append((scope.path, f
'MODE_GRADIENT_{kind}_PHY', sub))
1631 scope.addModuleVar(moduleVars)
1634 for varName
in localVariablesToAdd:
1635 if not scope.varList.findVar(varName):
1636 var = {
'as': [],
'asx': [],
1637 'n': varName,
'i':
None,
't':
'INTEGER',
'arg':
False,
1638 'use':
False,
'opt':
False,
'allocatable':
False,
1639 'parameter':
False,
'init':
None,
'scopePath': scope.path}
1640 scope.addVar([[scope.path, var[
'n'], scope.varSpec2stmt(var),
None]])