stage 3 to code
This commit is contained in:
parent
fd40814b36
commit
7f9ed4f632
2 changed files with 325 additions and 44 deletions
|
|
@ -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() )
|
||||
|
||||
|
|
|
|||
|
|
@ -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():
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue