From 7f9ed4f632fdd3b3e77d6c3ca77e94fbcf85328d Mon Sep 17 00:00:00 2001 From: ignis Date: Wed, 8 May 2019 01:20:17 +0900 Subject: [PATCH] stage 3 to code --- code/code_gen/code_gen.py | 26 ++- code/code_gen/post.py | 343 ++++++++++++++++++++++++++++++++++---- 2 files changed, 325 insertions(+), 44 deletions(-) diff --git a/code/code_gen/code_gen.py b/code/code_gen/code_gen.py index 725e104..04d5f92 100644 --- a/code/code_gen/code_gen.py +++ b/code/code_gen/code_gen.py @@ -377,21 +377,7 @@ class FortranProgram: tree = self.tree_parser.parse(terms_input) - print "< IR 1 >" - ir1 = Stage1(tree) - - print "< IR 2 >" - ir2 = Stage2(ir1) - - print "dependency graph" - pp.pprint (ir2.dependency()) - - - print "< IR 3 >" - ir3 = Stage3(ir2) - - - + self.tree = tree self.parser.transform(tree) @@ -634,6 +620,16 @@ def test(): fp = FortranProgram(terms_raw) + ir1 = Stage1(fp.tree) + + ir2 = Stage2(ir1) + + ir3 = Stage3(ir2) + + print mod_form.format( ir3.print_program() ) + + + # print mod_form.format( fp.print_program() ) diff --git a/code/code_gen/post.py b/code/code_gen/post.py index 2dd8ce2..8cc37ee 100644 --- a/code/code_gen/post.py +++ b/code/code_gen/post.py @@ -30,6 +30,84 @@ class ExpInspector(Visitor): self.deriv.add((op.data, v.value)) +@v_args(inline=True) # Affects the signatures of the methods +class ExpToCode(Transformer): + + def __init__(self, fdict): + self.fdict = fdict + + def number(self, numeral): + return str(float(numeral)) + + def env(self, name): + return name.value + + def var(self, name): + try: + arrname = self.fdict[name.value].array + except KeyError: + arrname = name.value + + return arrname + "(i,j,k)" + + def fluc(self, name): + try: + arrname = self.fdict[name.value].array + except KeyError: + arrname = name.value + + fmt = "({0}(i,j,k) - {{0}}avg_{1}(i))" + return fmt.format(arrname, name.value) + + def dnx (self, partial, b): + signature = "{}_{}".format(partial.data, b.value) + try: + arrname = self.fdict[signature].array + except KeyError: + arrname = signature + + return arrname + "(i,j,k)" + + def icall (self, a, b): + if a.data == "sqr": + fcode = "(({0})*({0}))".format(b) + elif a.data == "pow3": + fcode = "(({0})*({0})*({0}))".format(b) + else: + fcode = "({0})".format(b) + return fcode + + def fcall (self, a, b): + fcode = "( {} ( {} ) )".format(a, b) + return fcode + + def neg(self, b): + fcode = "( - {} )".format(b) + return fcode + + def add(self, a, b): + fcode = "( {} + {} )".format(a, b) + return fcode + + def sub(self, a, b): + fcode = "( {} - {} )".format(a, b) + return fcode + + def mul(self, a, b): + fcode = "( {} * {} )".format(a, b) + return fcode + + def div(self, a, b): + fcode = "( {} / {} )".format(a, b) + return fcode + + log = lambda self : "log" + exp = lambda self : "exp" + sqrt = lambda self : "sqrt" + abs = lambda self : "dabs" + rxn_rate = lambda self : "rxn_rate" + + class FieldBase (object): def __init__ (self, name, fdict): self.name = name @@ -37,12 +115,14 @@ class FieldBase (object): self.dep = set([]) self.fluc = False self.fdict = fdict + self.shape = "nxp,nyp,nzp" + self.dim = ":,:,:" def depends_on (self, a): return (a in self.dep) def is_fluctuation (self): - return False + return self.fluc def __repr__ (self): return self.name @@ -51,17 +131,36 @@ class FieldBase (object): fset = set([]) - if self.is_fluctuation(): - fset.add(self.name) - for d in map(self.fdict.get, self.dep): fset.update(d.checkFluctuation()) - if len(fset) > 0: + if self.is_fluctuation() or len(fset) > 0: fset.add(self.name) return fset + def depClosure (self): + + fset = set(self.dep) + + for d in self.dep: + fset.update(self.fdict[d].depClosure()) + + return fset + + + def code_decl (self): + real_array_alloc = "allocate({0}({1}), stat=ierr) ; {0} = 0." + return real_array_alloc.format(self.name, self.shape) + + def code_alloc (self): + real_array_decl = "real*8, allocatable, dimension({1}) :: {0}" + return real_array_decl.format(self.name, self.dim) + + def code_free (self): + real_array_free = "deallocate({})" + return real_array_free.format(self.name) + class Field (FieldBase): @@ -69,6 +168,7 @@ class Field (FieldBase): super(Field,self).__init__(name, fdict) self.exp = exp self.fluc, self.dep, self.derivs = ExpInspector.inspect(exp) + self.comment = ExpToCode(self.fdict).transform(self.exp) ''' for a in self.dep: @@ -76,13 +176,68 @@ class Field (FieldBase): raise StandardError(a + " is not defined") ''' - def is_fluctuation (self): - return self.fluc + def code (self): + real_array_loop = """ +! {1} +do k = 1, nzp +do j = 1, nyp +do i = 1, nxp +{0[0]}(i,j,k) = {0[1]} +end do +end do +end do +""" + rhs = ExpToCode(self.fdict).transform(self.exp) + return real_array_loop.format((self.array, rhs), self.comment) - def code (self, alloc): - transform(self.exp) - return (a in self.dep) +class FluctuationField (FieldBase): + + def __init__ (self, w, field, fset, fdict): + + super(FluctuationField,self).__init__(self.id(w,field), fdict) + + if w is not None: + self.w = w + "_" + else: + self.w = "" + + self.field = fdict[field] + self.dep = self.field.dep - fset + for df in self.field.dep & fset: + self.dep.add(self.id(w,df)) + + self.comment = ExpToCode(self.fdict).transform(self.field.exp) + + if self.field.is_fluctuation(): + self.comment = self.comment.format(self.w) + + + def code (self): + real_array_loop = """ +! {1} +do k = 1, nzp +do j = 1, nyp +do i = 1, nxp +{0[0]}(i,j,k) = {0[1]} +end do +end do +end do +""" + rhs = ExpToCode(self.fdict).transform(self.field.exp) + + if self.field.is_fluctuation(): + rhs = rhs.format(self.w) + + return real_array_loop.format((self.array, rhs), self.comment) + + @classmethod + def id (cls, w, field): + if w: + name = "{}____{}_avg".format(field, w) + else: + name = "{}____avg".format(field) + return name class PrimaryField (FieldBase): @@ -91,7 +246,7 @@ class PrimaryField (FieldBase): self.derivs = set([]) def code (self): - return "" + return "! {} is read from file".format(self.name) class DerivedField (FieldBase): @@ -109,28 +264,69 @@ class DerivedField (FieldBase): class AveragedField (FieldBase): + @classmethod + def id (cls, w, tgt): + if w: + return "{}_avg_{}".format(w, tgt) + else: + return "avg_{}".format(tgt) + + def __init__ (self, w, tgt, fdict): - if w: - name = "{}_avg_{}".format(w, tgt) - else: - name = "avg_{}".format(tgt) - + name = self.id(w,tgt) super(AveragedField,self).__init__(name, fdict) + self.shape = "nxp" + self.dim = ":" - self.tgt = fdict[tgt] - self.dep.add(tgt) - self.weighted = False + tfield = fdict[tgt] + self.fset = tfield.checkFluctuation() + if not self.fset: + self.tgt = tgt + self.dep.add(tgt) + else: + ftgt = FluctuationField.id(w,tgt) + self.tgt = ftgt + self.dep.add(ftgt) + + self.weighted = w if w: - self.weighted = True self.w = fdict[w] self.dep.add(w) - self.fset = self.checkFluctuation() - set([self.name]) + def code (self): + + avg_array_sum = """ +do k = 1, nzp +do j = 1, nyp +do i = 1, nxp +{0}(i) = {0}(i) + {1} +end do +end do +end do +""" + arrname = self.fdict[self.tgt].array + "(i,j,k)" + if self.weighted is not None: + arrname = arrname + " * " + self.w.array + "(i,j,k)" + + return avg_array_sum.format(self.name, arrname) + + + def code_avg (self): + + avg_array_divide = """ +call MPI_ALLREDUCE(MPI_IN_PLACE, {0}, nxp, MPI_REAL8, MPI_SUM, MPI_COMM_TASK, mpi_err) + +{0} = {0} {1} / denum +""" + meanw = "/ avg_{}" + dWeight = (meanw.format(self.weighted) if self.weighted else "") + + return avg_array_divide.format(self.name, dWeight) def isWeighted (self): - return self.weighted + return self.weighted is not None def pass1 (self): return not self.pass2() @@ -180,7 +376,7 @@ class Stage1(): return "\n".join(map(str, [self.primary, self.derived, self.averaged])) class Stage2(): - ''' expand derivatives ''' + ''' expand derivatives and averages''' def __init__ (self, src): self.src = src @@ -199,12 +395,15 @@ class Stage2(): self.derived[a.name] = a self.derivative[tup] = a - # Construct Derivative Field objects + # Construct Averaged Field objects for w, tgts in src.averaged.iteritems(): for t in tgts: a = AveragedField(w, t, self.derived) self.averaged[a.name] = a + for ff in a.fset: + b = FluctuationField(w, ff, a.fset, self.derived) + self.derived[b.name] = b def __repr__ (self): return "\n".join(map(str, [self.derived, self.derivative, self.averaged])) @@ -230,16 +429,102 @@ class Stage3(): self.averaged = src.averaged self.dependency = src.dependency() - pass1set = filter(AveragedField.pass1, self.averaged.values()) - pass2set = filter(AveragedField.pass2, self.averaged.values()) + assert set(self.derived.keys()).isdisjoint(self.averaged.keys()) + + pass1set = set(filter(AveragedField.pass1, self.averaged.values())) + pass2set = set(filter(AveragedField.pass2, self.averaged.values())) + + self.avg1 = pass1set + self.avg2 = pass2set + + pass1calc = set(map(repr, pass1set)) + apply (pass1calc.update, map(AveragedField.depClosure, pass1set)) + self.pass1 = self.sort_vars(self.dependency, pass1calc) + + pass2calc = set(map(repr, pass2set)) + apply (pass2calc.update, map(AveragedField.depClosure, pass2set)) + self.pass2 = self.sort_vars(self.dependency, pass2calc) - print pass1set - print pass2set def __repr__ (self): - return "\n".join(map(str, [self.derived, self.derivative])) + return "\n".join(map(str, [self.pass1, self.pass2])) + def sort_vars (self, dependency, group): + order = [] + remain = list(group) + remain.sort() + + while len(remain) > 0: + for v in remain: + if dependency[v].isdisjoint(remain): + order.append(v) + remain.remove(v) + + return order + + + def print_program (self): + + allvar = dict(self.derived) + allvar.update(self.averaged) + + decl = "\n".join(allvar[v].code_decl() for v in set(self.pass1+self.pass2)) + + alloc = "\n".join(allvar[v].code_alloc() for v in set(self.pass1+self.pass2)) + + free = "\n".join(allvar[v].code_free() for v in set(self.pass1+self.pass2)) + + calc1 = "\n".join(allvar[v].code() for v in self.pass1) + calc2 = "\n".join(allvar[v].code() for v in self.pass2) + + set1 = [a.name for a in filter(AveragedField.pass1, self.averaged.values())] + set2 = [a.name for a in filter(AveragedField.pass2, self.averaged.values())] + + set1.sort() + set2.sort() + + avg1 = "\n".join(allvar[v].code() for v in set1) + avg2 = "\n".join(allvar[v].code() for v in set2) + + + hfmt = 'character (len = *), parameter :: output_header="{}"' + declh = hfmt.format(" ".join(["x"] + set1 + set2)) + + + avg_array_write = ''' +integer :: i + +open (200, file="qEdge_X.dat") + +write (200,*) output_header + +do i=1,nxp + write (200,'({0}e20.10)') real(i)*hxp, {1} +end do + +close (200) +''' + + avgarr = "{}(i)" + write_avg = avg_array_write.format( + len(self.averaged)+1, + ", ".join(map(avgarr.format, set1+set2)) + ) + + + md = {} + md["module_name"] = "terms" + md["module_data"] = "\n".join((declh, decl)) + md["module_init"] = alloc + md["module_finalize"] = free + md["module_pass1"] = calc1 + md["module_pass1_avg"] = avg1 + md["module_pass2"] = calc2 + md["module_pass2_avg"] = avg2 + md["module_write_result"] = write_avg + + return md class Stage4():