sqlalchemy / mako

Mako Templates for Python
https://www.makotemplates.org
MIT License
368 stars 62 forks source link

Create fusion of several inehrit template #276

Closed sqlalchemy-bot closed 6 years ago

sqlalchemy-bot commented 6 years ago

Migrated issue, originally created by Bertrand MICHEL (@bemichel)

Hi Mako team,

Sorry, this ticket is not really an issue, but moreover a question about the usage of Mako template, but I do not know whedre to post such question ?

I have a base mako template for a generic loop "loop.tmpl.for" :

      subroutine ${self.subroutine()}(ncell,
     & nface,
     & ...
     ! Inherit arguments
${self.args()})
      implicit none
      INTEGER_E ncell
      INTEGER_E nface
      ...

     ! Inherit declaration
${self.decl()}

     ! =================================================================
      do iVec = 0, nVectPack(iSub)-1
      iBeg  = nVectPackIdx(iSub)
      iBegV = iBeg+iVec
FOR_OPT_DIR_NODEP_E
        do iloop=FaceVectTile(iBegV), FaceVectTile(iBegV+1)-1
          il = indicvoll(iloop)
          ir = indicvolr(iloop)
${self.code()}
        end do
      end do

      end

From this loop, several implementations can inherit from this base mako described the generic loop. I give for exemple two implementations :

<%inherit file="loop.tmpl.for"/>

<%block name="subroutine">complimphys${var}${nbi}equ</%block>

<%block name="args">
     & cellcenter,
     & facecenter,
     & ${var},
     & grad2${var},
     & min2${var},
     & max2${var},
     & lim2${var}
</%block>

<%block name="decl">
      REAL_E cellcenter(0:ncell-1,3)
      REAL_E facecenter(0:nface-1,3)
      REAL_E ${var}(0:ncell-1, ${nbi})
      REAL_E grad2${var}(0:ncell-1, 3, ${nbi})
      REAL_E min2${var}(0:ncell-1, ${nbi})
      REAL_E max2${var}(0:ncell-1, ${nbi})
      REAL_E lim2${var}(0:ncell-1, ${nbi})
      ! Local variables
      REAL_E dxl, dxr
      REAL_E dyl, dyr
      REAL_E dzl, dzr
      REAL_E gslope
      REAL_E Dm
      REAL_E tmp
      REAL_E phi
</%block>

<%block name="code">
        ! Left contribution computation
        ! -----------------------------

        ! Compute face center <-> cell center vector
        dxl = facecenter(iloop,1) - cellcenter(il,1)
        dyl = facecenter(iloop,2) - cellcenter(il,2)
        dzl = facecenter(iloop,3) - cellcenter(il,3)

% for i in range(nbi):
        ! ${var} number ${i+1} treatment
        gslope = grad2${var}(il,1,${i+1})*dxl+
     &           grad2${var}(il,2,${i+1})*dyl+
     &           grad2${var}(il,3,${i+1})*dzl

        Dm = gslope
        if (Dm > ZERO) then
          tmp = (max2${var}(il,${i+1}) - ${var}(il,${i+1}))/(Dm+E_CUTOFF)
        else
          tmp = (min2${var}(il,${i+1}) - ${var}(il,${i+1}))/(Dm+E_CUTOFF)
        endif

        phi = (tmp**2+TWO*tmp)/(tmp**2+tmp+TWO)
        lim2${var}(il,${i+1}) = MIN(lim2${var}(il,${i+1}), phi)

%endfor

        ! Right contribution computation
        ! ------------------------------

        ! Compute face center <-> cell center vector
        dxr = facecenter(iloop,1) - cellcenter(ir,1)
        dyr = facecenter(iloop,2) - cellcenter(ir,2)
        dzr = facecenter(iloop,3) - cellcenter(ir,3)

% for i in range(nbi):
        ! ${var} number ${i+1} treatment
        gslope = grad2${var}(ir,1,${i+1})*dxr+
     &           grad2${var}(ir,2,${i+1})*dyr+
     &           grad2${var}(ir,3,${i+1})*dzr

        Dm = gslope
        IF (Dm > ZERO) THEN
          tmp = (max2${var}(ir,${i+1}) - ${var}(ir,${i+1}))/(Dm+E_CUTOFF)
        ELSE
          tmp = (min2${var}(ir,${i+1}) - ${var}(ir,${i+1}))/(Dm+E_CUTOFF)
        ENDIF

        phi = (tmp**2+TWO*tmp)/(tmp**2+tmp+TWO)
        lim2${var}(ir,${i+1}) = MIN(lim2${var}(ir,${i+1}), phi)

%endfor

</%block>
<%inherit file="loop.tmpl.for"/>

<%block name="subroutine">compgradgg2${var}u</%block>

<%block name="args">
     & surf,
     & ${var},
     & grad2${var}
</%block>

<%block name="decl">
      REAL_E surf(0:nface-1, 3)
      REAL_E ${var}(0:ncell-1, ${nbi})
      REAL_E grad2${var}(0:ncell-1, 3, ${nbi})
      ! Local variables
      REAL_E varx, vary, varz
</%block>

<%block name="code">
% for l in range(nbi):
      ! Gradient of ${var} for variable number ${l+1}
      varx = HALF * ( ${var}(ir, ${l+1}) + ${var}(il,${l+1}) ) * surf(iloop,1)
      vary = HALF * ( ${var}(ir, ${l+1}) + ${var}(il,${l+1}) ) * surf(iloop,2)
      varz = HALF * ( ${var}(ir, ${l+1}) + ${var}(il,${l+1}) ) * surf(iloop,3)

      grad2${var}(ir, 1, ${l+1}) = grad2${var}(ir, 1, ${l+1}) - varx
      grad2${var}(ir, 2, ${l+1}) = grad2${var}(ir, 2, ${l+1}) - vary
      grad2${var}(ir, 3, ${l+1}) = grad2${var}(ir, 3, ${l+1}) - varz

      grad2${var}(il, 1, ${l+1}) = grad2${var}(il, 1, ${l+1}) + varx
      grad2${var}(il, 2, ${l+1}) = grad2${var}(il, 2, ${l+1}) + vary
      grad2${var}(il, 3, ${l+1}) = grad2${var}(il, 3, ${l+1}) + varz

%endfor

</%block>

For several reason, for a scenario, I want to make a fusion of every implementation that are involved in the scenario.

For the moment, I can write by hand a mako template called fusion of this 2 implementation exemple "fusion.tmpl.for" :

<%inherit file="loop.tmpl.for"/>

<%namespace name="impl1" file="impl1.tmpl.for"/>
<%namespace name="impl2" file="impl2.tmpl.for"/>

<%block name="subroutine">fusion_${impl1.subroutine()}_${impl2.subroutine()}</%block>

<%block name="args">
      ! Arguments from impl1.tmpl.for
${impl1.args()},
      ! Arguments from impl2.tmpl.for
${impl2.args()}</%block>

<%block name="decl">
      ! Declaration from impl1.tmpl.for
${impl1.decl()}
      ! Declaration from impl2.tmpl.for
${impl2.decl()}</%block>

<%block name="code">
      ! Code from impl1.tmpl.for
${impl1.code()}
      ! Code from impl2.tmpl.for
${impl2.code()}</%block>

But my question is there a way with mako to create dynamically this fusion template with any number of implementation ?

A way to solve my problem is to write a "dynamic_fusion.tmpl.for" with to Python :

from mako.template import Template
from mako import lookup
from mako.lookup import TemplateLookup
from collections import Iterable, OrderedDict
collection = lookup.TemplateLookup()
mylookup = TemplateLookup(directories=['.'])

# --------------------------------------------------------------------------
fnamespace = lambda n,f:"""<%namespace name="{n}" file="{f}"/>""".format(n=n,f=f)
fblock     = lambda n,c:"""<%block name="{n}">{c}</%block>\n""".format(n=n,c=c)
fcall      = lambda n,c:"""$`n}.{c}()}}""".format(n=n,c=c)

def dynamic_fusion(names, implementations):
    gnamespace = '\n'.join([fnamespace(n=i, f=f) for i,f in implementations.items()])
    gblock = ""
    for n in names:
        if n == "subroutine":
            w = '_'
        elif n == "args":
            w = ',\n'
        else:
            w = '\n'
        gcall = w.join([fcall(n=i, c=n) for i in implementations])
        gcall = ('fusion_' if n == "subroutine" else '') + gcall
        gblock += fblock(n=n, c=gcall) + "\n"
    return """<%inherit file="loop.tmpl.for"/>

{gnamespace}

{gblock}
""".format(**{'gnamespace':gnamespace, 'gblock':gblock})

implementations = OrderedDict([('impl1','impl1.tmpl.for'), ('impl2','impl2.tmpl.for')])
with open('dynamic_fusion.tmpl.for','w') as f:
    f.write(dynamic_fusion(["subroutine", "args", "decl", "code"], implementations))

# --------------------------------------------------------------------------
# Load the Mako source into a string
tpl = Template(filename='dynamic_fusion.tmpl.for', lookup=mylookup)
# Render the kernel
print tpl.render(var='prim', nbi=7)

Is it the proper way to create this "dynamic_fusion.tmpl.for" ?

Thanks for your help !

Best regards.

PS: you can find the code in the archive attached to this ticket !

Bertrand M.


Attachments: DynamicFusion.tgz

sqlalchemy-bot commented 6 years ago

Michael Bayer (@zzzeek) wrote:

since I don't have the resources to work on this question, there actually are some folks on the list who often do so your best bet is to use the list:

https://groups.google.com/forum/#!forum/mako-discuss

sqlalchemy-bot commented 6 years ago

Changes by Michael Bayer (@zzzeek):