133 Convert STR%VAR into single local variable contained in compute (a-stmt)
134 and in if-then-stmt, else-if-stmt, where-stmt
136 ZA = 1 + CST%XG ==> ZA = 1 + XCST_G
137 ZA = 1 + PARAM_ICE%XRTMIN(3) ==> ZA = 1 + XPARAM_ICE_XRTMIN3
138 ZRSMIN(1:KRR) = ICED%XRTMIN(1:KRR) => ZRSMIN(1:KRR) = ICEDXRTMIN1KRR(1:KRR)
139 IF(TURBN%CSUBG_MF_PDF=='NONE')THEN => IF(CTURBNSUBG_MF_PDF=='NONE')THEN
141 RESTRICTION : works only if the r-component variable is contained in 1 parent structure.
142 Allowed for conversion : CST%XG
143 Not converted : TOTO%CST%XG (for now, recursion must be coded)
144 Not converted : TOTO%ARRAY(:) (shape of the array must be determined from E1)
146 def convertOneType(component, newVarList, scope):
148 objType = scope.getParent(component, 2)
149 objTypeStr = alltext(objType).upper()
150 namedENn = objType.find(
'.//{*}N/{*}n')
151 structure = namedENn.text
152 variable = component.find(
'.//{*}ct').text.upper()
156 arrayRall = objType.findall(
'.//{*}array-R')
157 if len(arrayRall) > 0:
158 arrayR = copy.deepcopy(arrayRall[0])
159 txt = alltext(arrayR).replace(
',',
'')
160 txt = txt.replace(
':',
'')
161 txt = txt.replace(
'(',
'')
162 txt = txt.replace(
')',
'')
163 arrayIndices = arrayIndices + txt
164 elif len(objType.findall(
'.//{*}element-LT')) > 0:
166 for elem
in objType.findall(
'.//{*}element'):
167 arrayIndices = arrayIndices + alltext(elem)
168 newName = variable[0] + structure + variable[1:] + arrayIndices
169 newName = newName.upper()
173 namedENn.text = newName
174 objType.remove(objType.find(
'.//{*}R-LT'))
175 if len(arrayRall) > 0:
176 objType.insert(1, arrayR)
179 if newName
not in newVarList:
180 if len(arrayRall) == 0:
181 newVarList[newName] = (
None, objTypeStr)
183 newVarList[newName] = (arrayR, objTypeStr)
185 scopes = self.getScopes()
186 if scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
188 for scope
in [scope
for scope
in scopes
189 if 'sub:' in scope.path
and 'interface' not in scope.path]:
191 for ifStmt
in (scope.findall(
'.//{*}if-then-stmt') +
192 scope.findall(
'.//{*}else-if-stmt') +
193 scope.findall(
'.//{*}where-stmt')):
194 compo = ifStmt.findall(
'.//{*}component-R')
196 for elcompo
in compo:
197 convertOneType(elcompo, newVarList, scope)
199 for aStmt
in scope.findall(
'.//{*}a-stmt'):
202 if len(aStmt[0].findall(
'.//{*}component-R')) == 0:
203 compoE2 = aStmt.findall(
'.//{*}component-R')
210 nbNamedEinE2 = len(aStmt.findall(
'.//{*}E-2')[0].findall(
'.//{*}named-E/' +
212 if nbNamedEinE2 > 1
or nbNamedEinE2 == 1
and \
213 len(aStmt[0].findall(
'.//{*}R-LT')) == 1:
214 for elcompoE2
in compoE2:
215 convertOneType(elcompoE2, newVarList, scope)
218 for el, var
in newVarList.items():
219 if el[0].upper() ==
'X' or el[0].upper() ==
'P' or el[0].upper() ==
'Z':
221 elif el[0].upper() ==
'L' or el[0].upper() ==
'O':
223 elif el[0].upper() ==
'N' or el[0].upper() ==
'I' or el[0].upper() ==
'K':
225 elif el[0].upper() ==
'C':
226 varType =
'CHARACTER(LEN=LEN(' + var[1] +
'))'
228 raise PYFTError(
'Case not implemented for the first letter of the newVarName' +
229 el +
' in convertTypesInCompute')
233 varArray =
', DIMENSION('
234 for i, sub
in enumerate(var[0].findall(
'.//{*}section-subscript')):
235 if len(sub.findall(
'.//{*}upper-bound')) > 0:
236 dimSize = simplifyExpr(
237 alltext(sub.findall(
'.//{*}upper-bound')[0]) +
238 '-' + alltext(sub.findall(
'.//{*}lower-bound')[0]) +
240 elif len(sub.findall(
'.//{*}lover-bound')) > 0:
241 dimSize = simplifyExpr(alltext(sub.findall(
'.//{*}lower-bound')[0]))
243 dimSize =
'SIZE(' + var[1] +
',' + str(i+1) +
')'
244 varArray =
', DIMENSION(' + dimSize +
','
245 varArray = varArray[:-1] +
')'
246 scope.addVar([[scope.path, el, varType + varArray +
' :: ' + el,
None]])
249 stmtAffect = createExpr(el +
"=" + var[1])[0]
250 scope.insertStatement(scope.indent(stmtAffect), first=
True)
319 Convert MODULE to SUBMODULE statements and add INTERFACE of SUBROUTINEs of PHYEX
320 ==> Applied only on MODE_
322 - if an INTERFACE already exists
323 - if no subroutine is present in the module
324 - to CONTAINS routines
325 1) Create interface statement if any
326 2) Add subroutines declaration (with MODULE statement)
327 3) Add SUBMODULE statements and convert SUBROUTINE to MODULE SUBROUTINE statements
329 scopes = self.getScopes()
332 oldModNode = self.find(
'.//{*}program-unit')
333 modNode = copy.deepcopy(self.find(
'.//{*}program-unit'))
335 interfaceStmt = self.findall(
'.//{*}interface-stmt')
336 subStmt = self.findall(
'.//{*}subroutine-stmt')
338 if modScope.path.split(
'/')[-1].split(
':')[1][:4] ==
'MODE' and \
339 len(interfaceStmt) == 0
and len(subStmt) > 0:
340 moduleName = modScope.path.split(
'/')[-1].split(
':')[1][:]
342 newMod = createElem(
'program-unit', text=
'MODULE ' + moduleName, tail=
'\n')
344 newMod.append(createElem(
'implicit-none-stmt', text=
'IMPLICIT NONE', tail=
'\n'))
345 interfaceStmt = createElem(
'interface-construct')
346 interfaceStmt.append(createElem(
'interface-stmt', text=
'INTERFACE', tail=
'\n'))
347 interfaceStmt.append(createElem(
'end-interface-stmt', text=
'END INTERFACE', tail=
'\n'))
348 newMod.append(interfaceStmt)
352 for scope
in scopes[1:]:
354 if sum(
'sub' in s
for s
in scope.path.split(
'/')) == 1:
355 subsModified.append(scope.path.split(
'/')[-1].split(
':')[1][:])
356 subroutineDecl = createElem(
'module-unit')
358 subroutineStmt = copy.deepcopy(scope[0])
359 declType = subroutineStmt.text
360 prefix = createElem(
'prefix')
361 prefix.text =
'MODULE'
362 subroutineStmt.text =
''
363 subroutineStmt.insert(0, prefix)
364 prefix.tail =
' ' + declType
365 subroutineDecl.append(subroutineStmt)
367 for use
in scope.findall(
'.//{*}use-stmt'):
368 subroutineDecl.append(copy.deepcopy(use))
369 subroutineDecl.append(createElem(
'implicit-none-stmt', text=
'IMPLICIT NONE',
372 for var
in [var
for var
in scope.varList
if var[
'arg']
or var[
'result']]:
373 subroutineDecl.append(createExpr(self.varSpec2stmt(var,
True))[0])
374 for external
in scope.findall(
'./{*}external-stmt'):
375 subroutineDecl.append(copy.deepcopy(external))
376 if 'SUBROUTINE' in declType:
377 endStmt = createElem(
'end-subroutine-stmt')
378 declName = subroutineStmt.find(
'./{*}subroutine-N/{*}N/{*}n').text
379 elif 'FUNCTION' in declType:
380 endStmt = createElem(
'end-function-stmt')
381 declName = subroutineStmt.find(
'./{*}function-N/{*}N/{*}n').text
383 raise PYFTError(
'declType in addSubmodulePHYEX not handled')
385 endStmt.text =
'END ' + declType + declName +
'\n'
386 subroutineDecl.append(endStmt)
387 interfaceStmt.insert(1, subroutineDecl)
390 newMod.append(createElem(
'end-program-unit', text=
'END MODULE ' + moduleName,
392 self[0].insert(0, newMod)
395 progUnit = createElem(
'program-unit')
406 submoduleStmt = createElem(
'submodule-stmt', text=
'SUBMODULE (')
407 parentId = createElem(
'parent-identifier')
409 ancestorModule = createElem(
'ancestor-module-N')
410 ancestorModuleN = createElem(
'n', text=moduleName)
411 ancestorModule.append(ancestorModuleN)
412 parentId.append(ancestorModule)
413 submoduleStmt.append(parentId)
414 submoduleModule = createElem(
'submodule-module-N')
415 submoduleModuleN = createElem(
'n', text=
'S' + moduleName, tail=
'\n')
416 submoduleModule.append(submoduleModuleN)
417 submoduleStmt.append(submoduleModule)
418 progUnit.append(submoduleStmt)
421 endSubmoduleStmt = createElem(
'end-submodule-stmt', text=
'END SUBMODULE ')
422 submoduleN = createElem(
'submodule-N')
423 submoduleNN = createElem(
'N')
424 submoduleNNn = createElem(
'n', text=
'S' + moduleName, tail=
'\n')
425 submoduleNN.append(submoduleNNn)
426 submoduleN.append(submoduleNN)
427 endSubmoduleStmt.append(submoduleN)
429 progUnit.append(endSubmoduleStmt)
430 progUnit.append(createElem(
'end-program-unit'))
434 modStmt = modNode.find(
'.//{*}module-stmt')
435 modEndStmt = modNode.find(
'.//{*}end-module-stmt')
436 modNode.remove(modStmt)
437 modNode.remove(modEndStmt)
440 publicStmts = modNode.findall(
'.//{*}public-stmt')
441 privateStmts = modNode.findall(
'.//{*}private-stmt')
442 if len(publicStmts) > 0:
443 for publicStmt
in publicStmts:
444 modNode.remove(publicStmt)
445 if len(privateStmts) > 0:
446 for privateStmt
in privateStmts:
447 modNode.remove(privateStmt)
450 subroutines = modNode.findall(
'.//{*}subroutine-stmt')
451 for sub
in subroutines:
452 if sub.find(
'.//{*}N/{*}n').text
in subsModified:
453 prefix = createElem(
'prefix')
454 prefix.text =
'MODULE'
456 sub.insert(0, prefix)
457 prefix.tail =
' SUBROUTINE '
458 progUnit.insert(1, modNode)
460 self.insert(1, progUnit)
463 self.remove(oldModNode)
469 Add MPPDB_CHEKS on all intent REAL arrays on subroutines.
470 ****** Not applied on modd_ routines. ********
471 Handle optional arguments.
472 Example, for a BL89 routine with 4 arguments, 1 INTENT(IN),
473 2 INTENT(INOUT), 1 INTENT(OUT), it produces :
474 IF (MPPDB_INITIALIZED) THEN
476 CALL MPPDB_CHECK(PZZ, "BL89 beg:PZZ")
477 !Check all INOUT arrays
478 CALL MPPDB_CHECK(PDZZ, "BL89 beg:PDZZ")
479 CALL MPPDB_CHECK(PTHVREF, "BL89 beg:PTHVREF")
482 IF (MPPDB_INITIALIZED) THEN
483 !Check all INOUT arrays
484 CALL MPPDB_CHECK(PDZZ, "BL89 end:PDZZ")
485 CALL MPPDB_CHECK(PTHVREF, "BL89 end:PTHVREF")
486 !Check all OUT arrays
487 CALL MPPDB_CHECK(PLM, "BL89 end:PLM")
489 param printsMode: if True, instead of CALL MPPDB_CHECK, add fortran prints for debugging
491 def addPrints_statement(var, typeofPrints='minmax'):
492 ifBeg, ifEnd =
'',
''
495 if typeofPrints ==
'minmax':
496 strMSG = f
'MINMAX {varName} = \",MINVAL({varName}), MAXVAL({varName})'
497 elif typeofPrints ==
'shape':
498 strMSG = f
'SHAPE {varName} = \",SHAPE({varName})'
500 raise PYFTError(
'typeofPrints is either minmax or shape in addPrints_statement')
502 strMSG = var[
'n'] +
' = \",' + var[
'n']
504 ifBeg = ifBeg +
'IF (PRESENT(' + var[
'n'] +
')) THEN\n '
505 ifEnd = ifEnd +
'\nEND IF'
506 return createExpr(ifBeg +
"print*,\"" + strMSG + ifEnd)[0]
508 def addMPPDB_CHECK_statement(var, subRoutineName, strMSG='beg:
'):
509 ifBeg, ifEnd, addD, addLastDim, addSecondDimType = '',
'',
'',
'',
''
513 if 'D%NIJT' in var[
'as'][0][1]:
515 if len(var[
'as']) == 2:
517 addLastDim =
', ' + var[
'as'][1][1]
518 if len(var[
'as']) >= 2:
521 if 'D%NK' in var[
'as'][1][1]:
522 addSecondDimType =
',' +
'''"VERTICAL"'''
524 addSecondDimType =
',' +
'''"OTHER"'''
525 if 'MERGE' in var[
'as'][-1][1]:
526 keyDimMerge = var[
'as'][-1][1].split(
',')[2][:-1]
527 ifBeg =
'IF (' + keyDimMerge +
') THEN\n'
530 ifBeg = ifBeg +
'IF (PRESENT(' + var[
'n'] +
')) THEN\n IF (SIZE(' + \
531 var[
'n'] +
',1) > 0) THEN\n'
532 ifEnd = ifEnd +
'\nEND IF\nEND IF'
533 argsMPPDB = var[
'n'] +
", " +
"\"" + subRoutineName +
" " + strMSG+var[
'n'] +
"\""
534 return createExpr(ifBeg +
"CALL MPPDB_CHECK(" + addD + argsMPPDB +
535 addLastDim + addSecondDimType +
")" + ifEnd)[0]
536 scopes = self.getScopes()
537 if scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
544 if 'sub:' in scope.path
and 'func' not in scope.path
and 'interface' not in scope.path:
545 subRoutineName = scope.path.split(
'/')[-1].split(
':')[1]
548 arraysIn, arraysInOut, arraysOut = [], [], []
550 for var
in scope.varList:
551 if var[
'arg']
and var[
'as']
and 'TYPE' not in var[
't']
and \
552 'REAL' in var[
't']
and var[
'scopePath'] == scope.path:
555 if var[
'i'] ==
'INOUT':
556 arraysInOut.append(var)
557 if var[
'i'] ==
'OUT':
558 arraysOut.append(var)
560 for var
in scope.varList:
561 if not var[
't']
or var[
't']
and 'TYPE' not in var[
't']:
564 if var[
'i'] ==
'INOUT':
565 arraysInOut.append(var)
566 if var[
'i'] ==
'OUT':
567 arraysOut.append(var)
569 if len(arraysIn) + len(arraysInOut) + len(arraysOut) == 0:
574 scope.addModuleVar([(scope.path,
'MODE_MPPDB',
None)])
576 scope.addModuleVar([(scope.path,
'MODD_BLANK_n', [
'LDUMMY1'])])
579 commentIN = createElem(
'C', text=
'!Check all IN arrays', tail=
'\n')
580 commentINOUT = createElem(
'C', text=
'!Check all INOUT arrays', tail=
'\n')
581 commentOUT = createElem(
'C', text=
'!Check all OUT arrays', tail=
'\n')
584 if len(arraysIn) + len(arraysInOut) > 0:
586 ifMPPDBinit = createExpr(
"IF (MPPDB_INITIALIZED) THEN\n END IF")[0]
588 ifMPPDBinit = createExpr(
"IF (LDUMMY1) THEN\n END IF")[0]
589 ifMPPDB = ifMPPDBinit.find(
'.//{*}if-block')
592 if len(arraysIn) > 0:
593 ifMPPDB.insert(1, commentIN)
594 for i, var
in enumerate(arraysIn):
596 ifMPPDB.insert(2 + i, addMPPDB_CHECK_statement(var, subRoutineName,
599 ifMPPDB.insert(2 + i, addPrints_statement(var,
600 typeofPrints=
'minmax'))
601 ifMPPDB.insert(3 + i, addPrints_statement(var,
602 typeofPrints=
'shape'))
605 if len(arraysInOut) > 0:
606 shiftLineNumber = 2
if len(arraysIn) > 0
else 1
608 ifMPPDB.insert(len(arraysIn) + shiftLineNumber, commentINOUT)
610 ifMPPDB.insert(len(arraysIn)*2 + shiftLineNumber-1, commentINOUT)
612 for i, var
in enumerate(arraysInOut):
614 ifMPPDB.insert(len(arraysIn) + shiftLineNumber + 1 + i,
615 addMPPDB_CHECK_statement(var, subRoutineName,
618 ifMPPDB.insert(len(arraysIn) + shiftLineNumber + 1 + i,
619 addPrints_statement(var, typeofPrints=
'minmax'))
622 scope.insertStatement(scope.indent(ifMPPDBinit), first=
True)
625 if len(arraysInOut) + len(arraysOut) > 0:
627 ifMPPDBend = createExpr(
"IF (MPPDB_INITIALIZED) THEN\n END IF")[0]
629 ifMPPDBend = createExpr(
"IF (LDUMMY1) THEN\n END IF")[0]
630 ifMPPDB = ifMPPDBend.find(
'.//{*}if-block')
633 if len(arraysInOut) > 0:
634 ifMPPDB.insert(1, commentINOUT)
635 for i, var
in enumerate(arraysInOut):
637 ifMPPDB.insert(2 + i, addMPPDB_CHECK_statement(var, subRoutineName,
640 ifMPPDB.insert(2 + i, addPrints_statement(var,
641 typeofPrints=
'minmax'))
644 if len(arraysOut) > 0:
645 shiftLineNumber = 2
if len(arraysInOut) > 0
else 1
647 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber, commentOUT)
649 ifMPPDB.insert(len(arraysInOut)*2 + shiftLineNumber-1, commentOUT)
650 for i, var
in enumerate(arraysOut):
652 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber + 1 + i,
653 addMPPDB_CHECK_statement(var, subRoutineName,
656 ifMPPDB.insert(len(arraysInOut) + shiftLineNumber + 1 + i,
657 addPrints_statement(var, typeofPrints=
'minmax'))
660 scope.insertStatement(scope.indent(ifMPPDBend), first=
False)
768 def removeIJDim(self, stopScopes, parserOptions=None, wrapH=False, simplify=False):
770 Transform routines to be called in a loop on columns
771 :param stopScopes: scope paths where we stop to add the D argument (if needed)
772 :param parserOptions, wrapH: see the PYFT class
773 :param simplify: try to simplify code (remove useless dimensions in call)
775 ComputeInSingleColumn :
776 - Remove all Do loops on JI and JJ
777 - Initialize former indexes JI, JJ, JIJ to first array element:
778 JI=D%NIB, JJ=D%NJB, JIJ=D%NIJB
779 - If simplify is True, replace (:,*) on I/J/IJ dimension on argument
780 with explicit (:,*) on CALL statements:
781 e.g. CALL FOO(D, A(:,JK,1), B(:,:))
782 ==> CALL FOO(D, A(JIJ,JK,1), B(:,:)) only if the target argument is not an array
785 indexToCheck = {
'JI': (
'D%NIB',
'D%NIT'),
786 'JJ': (
'D%NJB',
'D%NJT'),
787 'JIJ': (
'D%NIJB',
'D%NIJT')}
789 def slice2index(namedE, scope):
791 Transform a slice on the horizontal dimension into an index
792 Eg.: X(1:D%NIJT, 1:D%NKT) => X(JIJ, 1:D%NKT) Be careful, this array is not contiguous.
793 X(1:D%NIJT, JK) => X(JIJ, JK)
794 :param namedE: array to transform
795 :param scope: scope where the array is
798 for isub, sub
in enumerate(namedE.findall(
'./{*}R-LT/{*}array-R/' +
799 '{*}section-subscript-LT/' +
800 '{*}section-subscript')):
801 if ':' in alltext(sub):
802 loopIndex, _, _ = scope.findIndexArrayBounds(namedE, isub, _loopVarPHYEX)
803 if loopIndex
in indexToCheck:
806 lowerBound = createElem(
'lower-bound')
807 sub.insert(0, lowerBound)
809 lowerBound = sub.find(
'./{*}lower-bound')
811 for item
in lowerBound:
812 lowerBound.remove(item)
813 upperBound = sub.find(
'./{*}upper-bound')
814 if upperBound
is not None:
815 sub.remove(upperBound)
816 lowerBound.append(createExprPart(loopIndex))
817 if loopIndex
not in indexRemoved:
818 indexRemoved.append(loopIndex)
821 if ':' not in alltext(namedE.find(
'./{*}R-LT/{*}array-R/{*}section-subscript-LT')):
822 namedE.find(
'./{*}R-LT/{*}array-R').tag = f
'{{{NAMESPACE}}}parens-R'
823 namedE.find(
'./{*}R-LT/{*}parens-R/' +
824 '{*}section-subscript-LT').tag = f
'{{{NAMESPACE}}}element-LT'
825 for ss
in namedE.findall(
'./{*}R-LT/{*}parens-R/' +
826 '{*}element-LT/{*}section-subscript'):
827 ss.tag = f
'{{{NAMESPACE}}}element'
828 lowerBound = ss.find(
'./{*}lower-bound')
829 for item
in lowerBound:
831 ss.remove(lowerBound)
834 self.addArrayParentheses()
837 self.attachArraySpecToEntity()
838 hUupperBounds = [v[1]
for v
in indexToCheck.values()]
842 for scope
in [scope
for scope
in self.getScopes()[::-1]
843 if 'func:' not in scope.path
and
844 (scope.path
in stopScopes
or
845 self.tree.isUnderStopScopes(scope.path, stopScopes,
846 includeInterfaces=
True))]:
852 for doNode
in scope.findall(
'.//{*}do-construct')[::-1]:
853 for loopI
in doNode.findall(
'./{*}do-stmt/{*}do-V/{*}named-E/{*}N'):
854 loopIname = n2name(loopI).upper()
855 if loopIname
in indexToCheck:
858 par = scope.getParent(doNode)
859 index = list(par).index(doNode)
860 for item
in doNode[1:-1][::-1]:
861 par.insert(index, item)
863 if loopIname
not in indexRemoved:
864 indexRemoved.append(loopIname)
869 for intr
in scope.findall(
'.//{*}R-LT/{*}parens-R/../..'):
870 intrName = n2name(intr.find(
'./{*}N')).upper()
871 if intrName
in (
'PACK',
'UNPACK',
'COUNT',
'MAXVAL',
'MINVAL',
'ALL',
'ANY',
'SUM'):
879 while par
is not None and not isStmt(par):
880 par = scope.getParent(par)
881 if tag(par)
in (
'a-stmt',
'op-E'):
886 for namedE
in parToUse.findall(
'.//{*}R-LT/{*}array-R/../..'):
887 slice2index(namedE, scope)
890 if intr.find(
'.//{*}R-LT/{*}array-R')
is None:
891 if intrName
in (
'MAXVAL',
'MINVAL',
'SUM',
'ALL',
'ANY'):
893 parens = intr.find(
'./{*}R-LT/{*}parens-R')
894 parens.tag = f
'{{{NAMESPACE}}}parens-E'
895 intrPar = scope.getParent(intr)
896 intrPar.insert(list(intrPar).index(intr), parens)
898 elif intrName ==
'COUNT':
900 nodeN = intr.find(
'./{*}N')
901 for item
in nodeN[1:]:
903 nodeN.find(
'./{*}n').text =
'MERGE'
904 elementLT = intr.find(
'./{*}R-LT/{*}parens-R/{*}element-LT')
906 element = createElem(
'element', tail=
', ')
907 element.append(createExprPart(val))
908 elementLT.insert(0, element)
921 assert scope.find(
'.//{*}include')
is None and \
922 scope.find(
'.//{*}include-stmt')
is None, \
923 "inlining must be performed before removing horizontal dimensions"
925 if scope.path
in stopScopes:
927 preserveShape = [v[
'n']
for v
in scope.varList
if v[
'arg']]
932 if 'sub:' in scope.path:
936 for namedE
in scope.findall(
'.//{*}named-E/{*}R-LT/{*}parens-R/../..'):
937 if n2name(namedE.find(
'./{*}N')).upper()
not in preserveShape:
938 var = scope.varList.findVar(n2name(namedE.find(
'./{*}N')).upper())
939 if var
is not None and var[
'as']
is not None and len(var[
'as']) > 0:
940 subs = namedE.findall(
'./{*}R-LT/{*}parens-R/' +
941 '{*}element-LT/{*}element')
942 if (len(subs) == 1
and var[
'as'][0][1]
in hUupperBounds)
or \
943 (len(subs) == 2
and (var[
'as'][0][1]
in hUupperBounds
and
944 var[
'as'][1][1]
in hUupperBounds)):
945 namedE.remove(namedE.find(
'./{*}R-LT'))
949 for call
in scope.findall(
'.//{*}call-stmt'):
950 for namedE
in call.findall(
'./{*}arg-spec//{*}named-E'):
951 subs = namedE.findall(
'.//{*}section-subscript')
952 var = scope.varList.findVar(n2name(namedE.find(
'./{*}N')).upper())
953 if len(subs) > 0
and (var
is None or var[
'as']
is None or
954 len(var[
'as']) < len(subs)):
962 elif (len(subs) >= 2
and
963 ':' in alltext(subs[0])
and var[
'as'][0][1]
in hUupperBounds
and
964 ':' in alltext(subs[1])
and var[
'as'][1][1]
in hUupperBounds):
966 remove = len(subs) == 2
967 index = (len(subs) > 2
and
968 len([sub
for sub
in subs
if ':' in alltext(sub)]) == 2)
969 elif (len(subs) >= 1
and
970 ':' in alltext(subs[0])
and var[
'as'][0][1]
in hUupperBounds):
972 remove = len(subs) == 1
973 index = (len(subs) > 1
and
974 len([sub
for sub
in subs
if ':' in alltext(sub)]) == 1)
979 if n2name(namedE.find(
'./{*}N')).upper()
in preserveShape:
980 slice2index(namedE, scope)
982 nodeRLT = namedE.find(
'.//{*}R-LT')
983 scope.getParent(nodeRLT).remove(nodeRLT)
985 slice2index(namedE, scope)
990 for decl
in scope.findall(
'.//{*}T-decl-stmt/{*}EN-decl-LT/{*}EN-decl'):
991 name = n2name(decl.find(
'./{*}EN-N/{*}N')).upper()
992 if name
not in preserveShape:
993 varsShape = decl.findall(
'.//{*}shape-spec-LT')
994 for varShape
in varsShape:
995 subs = varShape.findall(
'.//{*}shape-spec')
996 if (len(subs) == 1
and alltext(subs[0])
in hUupperBounds)
or \
997 (len(subs) == 2
and (alltext(subs[0])
in hUupperBounds
and
998 alltext(subs[1])
in hUupperBounds)):
1000 itemToRemove = scope.getParent(varShape)
1001 scope.getParent(itemToRemove).remove(itemToRemove)
1006 for loopIndex
in indexRemoved:
1009 scope.insertStatement(
1010 createExpr(loopIndex +
" = " + indexToCheck[loopIndex][0])[0],
True)
1011 if len(indexRemoved) > 0:
1012 scope.addArgInTree(
'D',
'TYPE(DIMPHYEX_t) :: D',
1013 0, stopScopes, moduleVarList=[(
'MODD_DIMPHYEX', [
'DIMPHYEX_t'])],
1014 parserOptions=parserOptions, wrapH=wrapH)
1016 scope.addVar([[scope.path, loopIndex,
'INTEGER :: ' + loopIndex,
None]
1017 for loopIndex
in indexRemoved
1018 if scope.varList.findVar(loopIndex, exactScope=
True)
is None])
1214 Convert all calling of functions and gradient present in shumansGradients
1215 table into the use of subroutines
1216 and use mnh_expand_directives to handle intermediate computations
1218 def getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar=''):
1220 if zshugradwkDim == 1:
1221 dimSuffRoutine =
'2D'
1223 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE'
1224 localVariables = [
'JIJ']
1225 elif zshugradwkDim == 2:
1227 if 'D%NKT' in dimWorkingVar:
1228 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE,JK=1:IKT'
1229 localVariables = [
'JIJ',
'JK']
1230 elif 'D%NIT' in dimWorkingVar
and 'D%NJT' in dimWorkingVar:
1232 mnhExpandArrayIndexes =
'JI=1:IIT,JJ=1:IJT'
1233 localVariables = [
'JI',
'JJ']
1234 dimSuffRoutine =
'2D'
1240 mnhExpandArrayIndexes =
'JIJ=IIJB:IIJE,JK=1:IKT'
1241 localVariables = [
'JIJ',
'JK']
1242 elif zshugradwkDim == 3:
1244 mnhExpandArrayIndexes =
'JI=1:IIT,JJ=1:IJT,JK=1:IKT'
1245 localVariables = [
'JI',
'JJ',
'JK']
1247 raise PYFTError(
'Shuman func to routine conversion not implemented ' +
1248 'for 4D+ dimensions variables')
1249 return dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, localVariables
1251 def FUNCtoROUTINE(scope, stmt, itemFuncN, localShumansCount, inComputeStmt,
1252 nbzshugradwk, zshugradwkDim, dimWorkingVar):
1254 :param scope: node on which the calling function is present before transformation
1255 :param stmt: statement node (a-stmt or call-stmt) that contains the function(s) to be
1257 :param itemFuncN: <n>FUNCTIONNAME</n> node
1258 :param localShumansCount: instance of the shumansGradients dictionnary
1259 for the given scope (which contains the number of times a
1260 function has been called within a transformation)
1261 :param dimWorkingVar: string of the declaration of a potential working variable
1262 depending on the array on wich the shuman is applied
1263 (e.g. MZM(PRHODJ(:,IKB));
1264 dimWorkingVar = 'REAL, DIMENSION(D%NIJT) :: ' )
1266 :return callStmt: the new CALL to the routines statement
1267 :return computeStmt: the a-stmt computation statement if there was an operation
1268 in the calling function in stmt
1269 :return localVariables: list of local variables needed for the mnh_expand directive
1273 parStmt = scope.getParent(stmt)
1274 parItemFuncN = scope.getParent(itemFuncN)
1276 grandparItemFuncN = scope.getParent(itemFuncN, level=2)
1277 funcName = alltext(itemFuncN)
1280 indexForCall = list(parStmt).index(stmt)
1285 siblsItemFuncN = scope.getSiblings(parItemFuncN, after=
True, before=
False)
1286 workingItem = siblsItemFuncN[0][0][0]
1289 if len(siblsItemFuncN[0][0]) > 1:
1291 workingItem = scope.updateContinuation(siblsItemFuncN[0][0], removeALL=
True,
1292 align=
False, addBegin=
False)[0]
1296 opE = workingItem.findall(
'.//{*}op-E')
1297 scope.removeArrayParenthesesInNode(workingItem)
1298 computeStmt, remaningArgsofFunc = [],
''
1299 dimSuffVar = str(zshugradwkDim) +
'D'
1300 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, _ = \
1301 getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar)
1304 computingVarName =
'ZSHUGRADWK'+str(nbzshugradwk)+
'_'+str(zshugradwkDim)+
'D'
1306 if not scope.varList.findVar(computingVarName):
1307 scope.addVar([[scope.path, computingVarName,
1308 dimWorkingVar + computingVarName,
None]])
1312 computeVar = scope.varList.findVar(computingVarName)
1313 dimWorkingVar =
'REAL, DIMENSION('
1314 for dims
in computeVar[
'as'][:arrayDim]:
1315 dimWorkingVar += dims[1] +
','
1316 dimWorkingVar = dimWorkingVar[:-1] +
') ::'
1318 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, localVariables = \
1319 getDimsAndMNHExpandIndexes(zshugradwkDim, dimWorkingVar)
1322 mnhOpenDir =
"!$mnh_expand_array(" + mnhExpandArrayIndexes +
")"
1323 mnhCloseDir =
"!$mnh_end_expand_array(" + mnhExpandArrayIndexes +
")"
1326 workingComputeItem = workingItem[0]
1328 if len(workingItem) == 2:
1329 remaningArgsofFunc =
',' + alltext(workingItem[1])
1330 elif len(workingItem) > 2:
1331 raise PYFTError(
'ShumanFUNCtoCALL: expected maximum 1 argument in shuman ' +
1332 'function to transform')
1333 computeStmt = createExpr(computingVarName +
" = " + alltext(workingComputeItem))[0]
1334 workingItem = computeStmt.find(
'.//{*}E-1')
1336 parStmt.insert(indexForCall, createElem(
'C', text=
'!$acc kernels', tail=
'\n'))
1337 parStmt.insert(indexForCall + 1, createElem(
'C', text=mnhOpenDir, tail=
'\n'))
1338 parStmt.insert(indexForCall + 2, computeStmt)
1339 parStmt.insert(indexForCall + 3, createElem(
'C', text=mnhCloseDir, tail=
'\n'))
1340 parStmt.insert(indexForCall + 4, createElem(
'C',
1341 text=
'!$acc end kernels', tail=
'\n'))
1342 parStmt.insert(indexForCall + 5, createElem(
'C',
1343 text=
'!', tail=
'\n'))
1347 if zshugradwkDim == 1:
1348 dimSuffRoutine =
'2D'
1349 workingVar =
'Z' + funcName + dimSuffVar +
'_WORK' + str(localShumansCount[funcName])
1350 if funcName
in (
'GY_U_UV',
'GX_V_UV'):
1351 gpuGradientImplementation =
'_DEVICE('
1352 newFuncName = funcName + dimSuffRoutine +
'_DEVICE'
1354 gpuGradientImplementation =
'_PHY(D, '
1355 newFuncName = funcName + dimSuffRoutine +
'_PHY'
1356 callStmt = createExpr(
"CALL " + funcName + dimSuffRoutine + gpuGradientImplementation
1357 + alltext(workingItem) + remaningArgsofFunc +
1358 ", " + workingVar +
")")[0]
1359 parStmt.insert(indexForCall, callStmt)
1362 parOfgrandparItemFuncN = scope.getParent(grandparItemFuncN)
1363 indexWorkingVar = list(parOfgrandparItemFuncN).index(grandparItemFuncN)
1364 savedTail = grandparItemFuncN.tail
1365 parOfgrandparItemFuncN.remove(grandparItemFuncN)
1368 xmlWorkingvar = createExprPart(workingVar)
1369 xmlWorkingvar.tail = savedTail
1370 parOfgrandparItemFuncN.insert(indexWorkingVar, xmlWorkingvar)
1373 if not scope.varList.findVar(workingVar):
1374 scope.addVar([[scope.path, workingVar, dimWorkingVar + workingVar,
None]])
1376 return callStmt, computeStmt, nbzshugradwk, newFuncName, localVariables
1378 shumansGradients = {
'MZM': 0,
'MXM': 0,
'MYM': 0,
'MZF': 0,
'MXF': 0,
'MYF': 0,
1379 'DZM': 0,
'DXM': 0,
'DYM': 0,
'DZF': 0,
'DXF': 0,
'DYF': 0,
1380 'GZ_M_W': 0,
'GZ_W_M': 0,
'GZ_U_UW': 0,
'GZ_V_VW': 0,
1381 'GX_M_U': 0,
'GX_U_M': 0,
'GX_W_UW': 0,
'GX_M_M': 0,
1382 'GY_V_M': 0,
'GY_M_V': 0,
'GY_W_VW': 0,
'GY_M_M': 0,
1383 'GX_V_UV': 0,
'GY_U_UV': 0}
1384 scopes = self.getScopes()
1385 if len(scopes) == 0
or scopes[0].path.split(
'/')[-1].split(
':')[1][:4] ==
'MODD':
1387 for scope
in scopes:
1388 if 'sub:' in scope.path
and 'func' not in scope.path \
1389 and 'interface' not in scope.path:
1392 localVariablesToAdd = set()
1393 foundStmtandCalls, computeStmtforParenthesis = {}, []
1394 aStmt = scope.findall(
'.//{*}a-stmt')
1395 callStmts = scope.findall(
'.//{*}call-stmt')
1396 aStmtandCallStmts = aStmt + callStmts
1397 for stmt
in aStmtandCallStmts:
1398 elemN = stmt.findall(
'.//{*}n')
1400 if alltext(el)
in list(shumansGradients):
1403 parStmt = scope.getParent(stmt)
1404 if tag(parStmt) ==
'action-stmt':
1405 scope.changeIfStatementsInIfConstructs(
1406 singleItem=scope.getParent(parStmt))
1408 if str(stmt)
in foundStmtandCalls:
1409 foundStmtandCalls[str(stmt)][1] += 1
1411 foundStmtandCalls[str(stmt)] = [stmt, 1]
1414 subToInclude = set()
1415 for stmt
in foundStmtandCalls:
1416 localShumansGradients = copy.deepcopy(shumansGradients)
1417 elemToLookFor = [foundStmtandCalls[stmt][0]]
1418 previousComputeStmt = []
1421 while len(elemToLookFor) > 0:
1423 for elem
in elemToLookFor:
1424 elemN = elem.findall(
'.//{*}n')
1426 if alltext(el)
in list(localShumansGradients.keys()):
1431 nodeE1var = foundStmtandCalls[stmt][0].findall(
1432 './/{*}E-1/{*}named-E/{*}N')
1433 if len(nodeE1var) > 0:
1434 var = scope.varList.findVar(alltext(nodeE1var[0]))
1435 allSubscripts = foundStmtandCalls[stmt][0].findall(
1436 './/{*}E-1//{*}named-E/{*}R-LT/' +
1437 '{*}array-R/{*}section-subscript-LT')
1441 elPar = scope.getParent(el, level=2)
1442 callVar = elPar.findall(
'.//{*}named-E/{*}N')
1443 if alltext(el)[0] ==
'G':
1448 var = scope.varList.findVar(alltext(callVar[-1]))
1449 shumanIsCalledOn = scope.getParent(callVar[-1])
1452 var, inested =
None, 0
1454 while not var
or len(var[
'as']) == 0:
1458 var = scope.varList.findVar(
1459 alltext(callVar[inested]))
1461 shumanIsCalledOn = scope.getParent(callVar[inested-1])
1462 allSubscripts = shumanIsCalledOn.findall(
1463 './/{*}R-LT/{*}array-R/' +
1464 '{*}section-subscript-LT')
1468 arrayDim = len(var[
'as'])
1472 if len(allSubscripts) > 0:
1473 for subLT
in allSubscripts:
1475 lowerBound = sub.findall(
'.//{*}lower-bound')
1476 if len(lowerBound) > 0:
1477 if len(sub.findall(
'.//{*}upper-bound')) > 0:
1480 raise PYFTError(
'ShumanFUNCtoCALL does ' +
1481 'not handle conversion ' +
1482 'to routine of array ' +
1483 'subselection lower:upper' +
1484 ': how to set up the ' +
1485 'shape of intermediate ' +
1495 dimWorkingVar =
'REAL, DIMENSION('
1496 for dims
in var[
'as'][:arrayDim]:
1497 dimWorkingVar += dims[1] +
','
1498 dimWorkingVar = dimWorkingVar[:-1] +
') ::'
1501 localShumansGradients[alltext(el)] += 1
1505 if foundStmtandCalls[stmt][0].tail:
1506 foundStmtandCalls[stmt][0].tail = \
1507 foundStmtandCalls[stmt][0].tail.replace(
'\n',
'') +
'\n'
1509 foundStmtandCalls[stmt][0].tail =
'\n'
1512 result = FUNCtoROUTINE(scope, elem, el,
1513 localShumansGradients,
1514 elem
in previousComputeStmt,
1515 nbzshugradwk, arrayDim,
1517 (newCallStmt, newComputeStmt,
1518 nbzshugradwk, newFuncName, lv) = result
1519 localVariablesToAdd.update(lv)
1520 subToInclude.add(newFuncName)
1523 elemToLookFor.append(newCallStmt)
1527 if len(newComputeStmt) > 0:
1528 elemToLookFor.append(newComputeStmt)
1529 computeStmtforParenthesis.append(newComputeStmt)
1533 previousComputeStmt.append(newComputeStmt)
1537 elemToLookForNew = []
1538 for i
in elemToLookFor:
1539 nodeNs = i.findall(
'.//{*}n')
1542 if alltext(nnn)
in list(localShumansGradients):
1543 elemToLookForNew.append(i)
1545 elemToLookFor = elemToLookForNew
1548 if nbzshugradwk > maxnbZshugradwk:
1549 maxnbZshugradwk = nbzshugradwk
1552 scope.addArrayParenthesesInNode(foundStmtandCalls[stmt][0])
1556 if tag(foundStmtandCalls[stmt][0]) !=
'call-stmt':
1559 dimSuffRoutine, dimSuffVar, mnhExpandArrayIndexes, lv = \
1560 getDimsAndMNHExpandIndexes(arrayDim, dimWorkingVar)
1561 localVariablesToAdd.update(lv)
1563 parStmt = scope.getParent(foundStmtandCalls[stmt][0])
1564 indexForCall = list(parStmt).index(foundStmtandCalls[stmt][0])
1565 mnhOpenDir =
"!$mnh_expand_array(" + mnhExpandArrayIndexes +
")"
1566 mnhCloseDir =
"!$mnh_end_expand_array(" + mnhExpandArrayIndexes +
")"
1567 parStmt.insert(indexForCall,
1568 createElem(
'C', text=
"!$acc kernels", tail=
'\n'))
1569 parStmt.insert(indexForCall + 1,
1570 createElem(
'C', text=mnhOpenDir, tail=
'\n'))
1571 parStmt.insert(indexForCall + 3,
1572 createElem(
'C', text=mnhCloseDir, tail=
'\n'))
1573 parStmt.insert(indexForCall + 4,
1574 createElem(
'C', text=
"!$acc end kernels", tail=
'\n'))
1575 parStmt.insert(indexForCall + 5,
1576 createElem(
'C', text=
"!", tail=
'\n'))
1579 for stmt
in computeStmtforParenthesis:
1580 scope.addArrayParenthesesInNode(stmt)
1584 for sub
in sorted(subToInclude):
1585 if re.match(
r'[MD][XYZ][MF](2D)?_PHY', sub):
1586 moduleVars.append((scope.path,
'MODE_SHUMAN_PHY', sub))
1588 for kind
in (
'M',
'U',
'V',
'W'):
1589 if re.match(
r'G[XYZ]_' + kind +
r'_[MUVW]{1,2}_PHY', sub):
1590 moduleVars.append((scope.path, f
'MODE_GRADIENT_{kind}_PHY', sub))
1591 scope.addModuleVar(moduleVars)
1594 for varName
in localVariablesToAdd:
1595 if not scope.varList.findVar(varName):
1596 var = {
'as': [],
'asx': [],
1597 'n': varName,
'i':
None,
't':
'INTEGER',
'arg':
False,
1598 'use':
False,
'opt':
False,
'allocatable':
False,
1599 'parameter':
False,
'init':
None,
'scopePath': scope.path}
1600 scope.addVar([[scope.path, var[
'n'], scope.varSpec2stmt(var),
None]])