#ifdef PASS_PRE1 #define _AND_ && #define _OR_ || #define _NOT_ ! #define IS_INNER_LAYER (_NOT_ (IS_BOTTOM_LEVEL _OR_ IS_TOP_LAYER)) #define IS_INNER_INTERFACE (_NOT_ (IS_BOTTOM_LEVEL _OR_ IS_TOP_INTERFACE)) #endif #ifdef PASS_PRE2 #define BARRIER !$OMP BARRIER #define IS_INNER_INTERFACE (.NOT. (IS_BOTTOM_LEVEL .OR. IS_TOP_INTERFACE)) #define KERNEL(name) {% call() define_kernel(#name) %} #define FORALL_CELLS(...) {% call(lrange,flags) forall_cells(__VA_ARGS__) %} #define FORALL_CELLS_EXT(...) {% call(lrange,flags) forall_cells(__VA_ARGS__) %} #define ON_PRIMAL {% call(mesh, degree=0) on_mesh('primal',lrange,flags) %} #define ON_DUAL {% call(mesh, degree=0) on_mesh('dual',lrange,flags) %} #define ON_EDGES {% call(mesh, degree=0) on_edges('edge',lrange,flags) %} #define FORALL_EDGES {% call forall_edges(mesh,degree) %} #define FORALL_VERTICES {% call forall_vertices(mesh,degree) %} #define FORALL_TRISK {% call forall_trisk(degree) %} #define END_BLOCK {% endcall %} #define SEQUENCE_C0 {% call(body,at_level) sequence_primal() %} #define SEQUENCE_C1 {% call(body,at_level) sequence_primal() %} #define SEQUENCE_E0 {% call(body,at_level) sequence_edge() %} #define PROLOGUE(level) {% call at_level(level) %} #define EPILOGUE(level) {% call at_level(level) %} #define BODY(range) {% call body(range) %} #define CST_IF(condition, action) {{ cst_if(#condition, #action) }} #define CST_IFTHEN(condition) {{flat}}if condition #define CST_ELSEIF(condition) {{flat}}elif condition #define CST_ELSE {{flat}}else #define CST_ENDIF {{flat}}endif #endif #ifdef PASS_JINJA {# -------------------------- Design notes ------------------------------ The syntax {% call(ARGNAMES) macro(ARGS) %} ... {% endcall %} passes ARGS to macro ; this macro "calls" the body using the syntax 'caller(arg1,...)' ; these arguments are available in the body under the names ARGNAMES, as if it were a macro caller(ARGNAMES). Using its optional argument 'options', forall_cells() sets variable 'flags' and passes it on to on_mesh() / on_edges() Similarly variable 'lrange' is passed from forall_cells to on_mesh() / on_egdes() -------------------------------------------------------------------------- #} {# NB : degree = number of elements in stencil, for instance number of edges of primal cell #} {# define the degrees for which a special version of code is generated #} {% set degree_primal, degree_dual, degree_trisk = (4,5,6), (3,4), (4,10) %} {# ----------------------- SEQUENCE, FORALL ----------------------- #} {% macro sequence_primal() -%} !$OMP DO SCHEDULE(STATIC) DO ij=1,primal_num {{ caller(body_primal, at_level_primal) }} END DO !$OMP END DO {%- endmacro %} {% macro sequence_edge() -%} {% set thecode = caller(body_edge, at_level_edge) %} !$OMP DO SCHEDULE(STATIC) DO edge=1,edge_num {{ 'ij_left = left(edge)' if 'CELL1' in thecode }} {{ 'ij_right = right(edge)' if 'CELL2' in thecode }} {{ 'ij_up = up(edge)' if 'VERTEX1' in thecode }} {{ 'ij_down = down(edge)' if 'VERTEX2' in thecode }} {{ thecode }} END DO !$OMP END DO {%- endmacro %} {% macro body_primal(range) -%} {{ define('CELL','l,ij') }} DO l = {{ range }} {{ caller() }} END DO {{ undef('CELL') }} {%- endmacro %} {% macro body_edge(range) -%} {% set thecode = caller() %} {{ define('EDGE', 'l,edge') }} {{ cdef(thecode, 'LE_DE', 'le_de(edge)') }} {{ cdef(thecode, 'LE', 'le(edge)') }} {{ cdef(thecode, 'DE', 'de(edge)') }} {{ cdef(thecode, 'SIGN', '1.') }} {{ cdef(thecode, 'CELL1', 'l,ij_left') }} {{ cdef(thecode, 'CELL2', 'l,ij_right') }} {{ cdef(thecode, 'VERTEX1', 'l,ij_down') }} {{ cdef(thecode, 'VERTEX2', 'l,ij_up') }} DO l = {{ range }} {{ thecode }} END DO {{ cundef(thecode, ('EDGE','LE_DE','SIGN','CELL1','CELL2','VERTEX1','VERTEX2') ) }} {%- endmacro %} {% macro at_level_primal(lev) -%} {{ define('CELL','%s,ij'%lev) }} {{ caller() }} {{ undef('CELL') }} {%- endmacro %} {% macro at_level_edge(lev) -%} {{ define('EDGE','%s,edge'%lev) }} {{ caller() }} {{ undef('EDGE') }} {%- endmacro %} {% macro forall_cells(start='1', end='llm', options=[]) -%} {% set flags=[options] if options is string else options %} {{ caller((start,end),flags) }} {%- endmacro %} {# ---------------------- PRELOAD STENCIL INDICES ---------------------- #} {% macro get_edges(thecode, mesh,degree) %} {% for iedge in range(1,degree+1) %} {{ 'edge%d = %s_edge(%d,ij)'%(iedge,mesh,iedge) if 'EDGE' in thecode }} {% endfor %} {% for iedge in range(1,degree+1) %} {{ 'le_de%d = le_de(edge%d)'%(iedge,iedge) if 'LE_DE' in thecode }} {% endfor %} {% for iedge in range(1,degree+1) %} {{ 'sign%d = %s_ne(%d,ij)'%(iedge,mesh,iedge) if 'SIGN' in thecode }} {% endfor %} {% for iedge in range(1,degree+1) %} {{ 'ij_up%d = up(edge%d)'%(iedge,iedge) if 'VERTEX1' in thecode }} {% endfor %} {% for iedge in range(1,degree+1) %} {{ 'ij_down%d = down(edge%d)'%(iedge,iedge) if 'VERTEX2' in thecode }} {% endfor %} {% endmacro %} {% macro get_vertices(thecode, mesh,degree) %} {% for ivertex in range(1,degree+1) %} {{ 'vertex%d = %s_vertex(%d,ij)'%(ivertex,mesh,ivertex) if 'VERTEX' in thecode }} {% endfor %} {% endmacro %} {# ------------------------------ MESHES --------------------------- #} {# argument 'code' is the body enclosed by ON_XXX ... END_BLOCK ; it takes arguments : mesh,degree=0 #} {% macro vloop_unroll(mesh, lrange, flags, code) %} {% set thecode, has_primal, has_dual, has_trisk, has_none = code(mesh), False, False, False, True %} {% if 'primal_deg' in thecode %} ! this VLOOP iterates over primal cell edges {% set has_primal, has_none = True,False %} {% endif %} {% if 'dual_deg' in thecode %} ! this VLOOP iterates over dual cell edges {% set has_dual,has_none = True,False %} {% endif %} {% if 'trisk_deg' in thecode %} ! this VLOOP iterates over the TRISK stencil {% set has_trisk,has_none = True,False %} {% endif %} {% if has_none %} {{ vloop(mesh, lrange, flags, code) }} {% endif %} {% if has_primal %} SELECT CASE(primal_deg(ij)) {% for degree in degree_primal %} CASE({{ degree }}) {{ get_edges(thecode, mesh, degree) }} {{ vloop(mesh, lrange, flags, code, degree) }} {% endfor %} CASE DEFAULT {{ vloop(mesh, lrange, flags, code) }} END SELECT {% endif %} {% if has_dual %} SELECT CASE(dual_deg(ij)) {% for degree in degree_dual %} CASE({{ degree }}) {{ get_edges(thecode, mesh, degree) }} {{ get_vertices(thecode,mesh,degree) }} {{ vloop(mesh, lrange, flags, code, degree) }} {% endfor %} CASE DEFAULT {{ vloop(mesh, lrange, flags, code) }} END SELECT {% endif %} {% if has_trisk %} SELECT CASE(trisk_deg(edge)) {% for degree in degree_trisk %} CASE({{ degree }}) {{ vloop(mesh, lrange, flags, code, degree) }} {% endfor %} CASE DEFAULT {{ vloop(mesh, lrange, flags, code) }} END SELECT {% endif %} {%- endmacro %} {% macro vloop(mesh, lrange, flags, code, degree=0) %} {% set start,end = lrange %} {% set thecode, is_top_layer, is_top_inter = code(mesh,degree), False, False %} {{ define('IS_TOP_LAYER', '_FALSE_') }} {{ define('IS_TOP_INTERFACE', '_FALSE_') }} {% if 'IS_BOTTOM_LEVEL' in thecode or 'KDOWN' in thecode%} {# the code in the loop checks whether l==1, for the sake of performance we shall write special code for l=1 and start the loop at l=2 #} {{ define('IS_BOTTOM_LEVEL', '_TRUE_') }} {{ 'kdown = 1' if 'KDOWN' in thecode }} {{ 'kup = 1' if 'KUP' in thecode }} l=1 {{ thecode }} {% set start='2' %} {% endif %} {% if 'IS_TOP_LAYER' in thecode %} {{ 'ERROR : using IS_TOP_LAYER in a loop ending at l=llm+1' if end=='llm+1' }} {# the code checks whether l==llm, write special code for l=llm and end the loop at l=llm-1 #} {% set end, is_top_layer = 'llm-1', True %} {% endif %} {% if 'IS_TOP_INTERFACE' in thecode or 'KUP' in thecode %} {# the code checks whether l==llm+1, write special code for l=llm+1 and end the loop at l=llm #} {{ 'ERROR : using IS_TOP_INTERFACE in a loop ending at l=llm' if end=='llm' }} {% set end, is_top_inter ='llm', True %} {% endif %} {{ define('IS_BOTTOM_LEVEL', '_FALSE_') }} !DIR$ SIMD DO l = {{start}}, {{end}} {{ 'kdown = l-1' if 'KDOWN' in thecode }} {{ 'kup = l' if 'KUP' in thecode }} {{ thecode }} END DO {% if is_top_layer %} {{ define('IS_TOP_LAYER', '_TRUE_') }} {{ 'kdown = llm-1' if 'KDOWN' in thecode }} {{ 'kup = llm' if 'KUP' in thecode }} l=llm {{ thecode }} {% endif %} {% if is_top_inter %} {{ define('IS_TOP_INTERFACE', '_TRUE_') }} {{ 'kdown = llm' if 'KDOWN' in thecode }} {{ 'kup = llm' if 'KUP' in thecode }} l=llm+1 {{ thecode }} {% endif %} {% endmacro %} {% macro on_mesh(mesh,lrange,flags) -%} {{ define('CELL','l,ij') if mesh=='primal' }} {{ define('DUAL_CELL', 'l,ij') if mesh=='dual'}} !$OMP DO SCHEDULE(STATIC) DO ij = 1, {{ mesh }}_num {{ vloop_unroll(mesh, lrange, flags, caller) }} END DO !$OMP END DO {{ undef('CELL') }} {{ undef('DUAL_CELL') }} {%- endmacro %} {# ------------------------------ STENCILS --------------------------- #} {% macro on_edges(mesh,lrange,flags) -%} {% set thecode = caller(mesh) %} {{ define('EDGE', 'l,edge') }} {{ cdef(thecode, 'LE_DE', 'le_de(edge)') }} {{ cdef(thecode, 'DE', 'de(edge)') }} {{ cdef(thecode, 'LE', 'le(edge)') }} {{ cdef(thecode, 'SIGN', '1.') }} {{ cdef(thecode, 'CELL1', 'l,ij_left') }} {{ cdef(thecode, 'CELL2', 'l,ij_right') }} {{ cdef(thecode, 'VERTEX1', 'l,ij_down') }} {{ cdef(thecode, 'VERTEX2', 'l,ij_up') }} !$OMP DO SCHEDULE(STATIC) DO edge = 1, edge_num {{ 'ij_left = left(edge)' if 'CELL1' in thecode }} {{ 'ij_right = right(edge)' if 'CELL2' in thecode }} {{ 'ij_up = up(edge)' if 'VERTEX1' in thecode }} {{ 'ij_down = down(edge)' if 'VERTEX2' in thecode }} {{ vloop_unroll(mesh, lrange, flags, caller) }} END DO !$OMP END DO {{ cundef(thecode, ('EDGE','LE_DE','SIGN','CELL1','CELL2','VERTEX1','VERTEX2') ) }} {%- endmacro %} {% macro forall_edges(mesh,degree) -%} {% set thecode = caller() %} {% if degree>1 %} {% for iedge in range(1,degree+1) %} {{ cdef(thecode, 'EDGE', 'l,edge%d'%iedge) }} {{ cdef(thecode, 'SIGN', 'sign%d'%iedge) }} {{ cdef(thecode, 'LE_DE', 'le_de%d'%iedge) }} {{ cdef(thecode, 'VERTEX1', 'l,ij_up%d'%iedge) }} {{ cdef(thecode, 'VERTEX2', 'l,ij_down%d'%iedge) }} {{ thecode }} {% endfor %} {% else %} {{ cdef(thecode, 'EDGE', 'l,edge') }} {{ cdef(thecode, 'SIGN', mesh + '_ne(iedge,ij)') }} {{ cdef(thecode, 'LE_DE', 'le_de(edge)') }} {{ cdef(thecode, 'VERTEX1', 'l,ij_up') }} {{ cdef(thecode, 'VERTEX2', 'l,ij_down') }} DO iedge = 1, {{ mesh }}_deg(ij) edge = {{ mesh }}_edge(iedge,ij) {{ 'ij_up = up(edge)' if 'VERTEX1' in thecode }} {{ 'ij_down = down(edge)' if 'VERTEX2' in thecode }} {{ thecode }} END DO {% endif %} {{ cundef(thecode, ('EDGE', 'SIGN', 'LE_DE', 'VERTEX1', 'VERTEX2') ) }} {%- endmacro %} {% macro forall_trisk(degree) -%} {% set thecode = caller() %} {{ define('EDGE_TRISK', 'l,edge_trisk') }} {% if degree>1 %} {% for itrisk in range(1,degree+1) %} itrisk = {{ itrisk }} edge_trisk = trisk({{ itrisk }},edge) {{ thecode }} {% endfor %} {% else %} DO itrisk = 1, trisk_deg(edge) edge_trisk = trisk(itrisk,edge) {{ thecode }} END DO {% endif %} {{ undef('EDGE_TRISK') }} {%- endmacro %} {% macro forall_vertices(mesh,degree) -%} {% set thecode = caller() %} {% if degree>1 %} {% for ivertex in range(1,degree+1) %} {{ define('RIV2', 'Riv2(%d,ij)'%ivertex ) }} {{ define('VERTEX', 'l,vertex%d'%ivertex ) }} {{ thecode }} {% endfor %} {% else %} {{ define('RIV2', 'Riv2(ivertex,ij)') }} {{ define('VERTEX', 'l,vertex') }} DO ivertex = 1, {{ mesh }}_deg(ij) vertex = {{ mesh }}_vertex(ivertex,ij) {{ thecode }} END DO {% endif %} {{ undef('VERTEX') }} {{ undef('RIV2') }} {%- endmacro %} {# --------------------------------------------------------- #} {% set llm='llm' %} {{ undef('SIGN') }} {{ undef('CELL') }} {{ undef('CELL1') }} {{ undef('CELL2') }} {{ undef('VERTEX1') }} {{ undef('VERTEX2') }} {{ undef('EDGE_TRISK') }} {# --------------------- END JINJA ------------------------- #} #endif #ifdef PASS_POST1 #define _TRUE_ (0==0) #define _FALSE_ (0==1) #define AI Ai(ij) #define AV Av(ij) #define FV fv(ij) #define WEE wee(itrisk,edge,1) #define edge_ne(iedge,ij) 1. #endif #ifdef PASS_POST2 #define AT_LEVEL(l,ij,lev) lev,ij #define KUP(l,ij) kup,ij #define KDOWN(l,ij) kdown,ij #define DOWN(l,ij) l-1,ij #define UP(l,ij) l+1,ij #define HIDX(l,ij) ij #define VIDX(l,ij) l #endif