def velocity_bc(self): """ generate code for updating stress field boundary ghost cells - generate inner loop by inserting boundary code (saved in field.bc) - recursive insertion to generate nested loop - loop through all velocity fields and sides return generated code as string """ tmpl = self.lookup.get_template('generic_loop.txt') result = '' for d in range(self.dimension): # update the staggered field first # because other fields depends on it sequence = [f for f in self.vfields if f.staggered[d+1]] \ + [f for f in self.vfields if not f.staggered[d+1]] for field in sequence: for side in range(2): # skip if this boundary calculation is not needed if field.bc[d+1][side] == '': continue if self.omp: result += '#pragma omp for\n' body = '' for d2 in range(self.dimension-1, -1, -1): # loop through other dimensions if not d2 == d: i = self.index[d2] i0 = 1 i1 = self.dim[d2]-1 if body == '': # inner loop, populate ghost cell calculation body = field.bc[d+1][side] dict1 = {'i': i, 'i0': i0, 'i1': i1, 'body': body} body = render(tmpl, dict1).replace('[t]', '[t1]') if self.ivdep: body = '%s\n' % self.compiler._ivdep + body if self.simd: body = '#pragma simd\n' + body else: dict1 = {'i': i, 'i0': i0, 'i1': i1, 'body': body} body = render(tmpl, dict1).replace('[t]', '[t1]') result += body return result
def time_stepping(self): """ generate time index variable for time stepping e.g. for 2nd order time-accurate scheme, varibales are t0, t1 for 4th order time-accurate scheme, variables are t0, t1, t2, t3 the variables are used to address the field arrays e.g. in 2nd order scheme, U[t1] will be updated using U[t0] the variables are calculated by taking mod with time periodicity return generated code as string """ result = '' tmpl = self.lookup.get_template('time_stepping.txt') _ti = Symbol('_ti') body = '' for i in range(len(self.time)): lhs = self.time[i].name if i == 0: rhs = ccode(_ti % self.tp) else: rhs = ccode((self.time[i-1]+1) % self.tp) body += lhs + ' = ' + rhs + ';\n' dict1 = {'body': body} result = render(tmpl, dict1) return result
def converge_test(self): """ - generate code for convergence test - convergence test implemented by calculating L2 norm of the simulation against analytical solution - L2 norm of each field is calculated and output with printf() - return generated code as string """ result = '' if not self.converge: return result tmpl = self.lookup.get_template('generic_loop.txt') m = self.margin.value ti = self.ntsteps.value % 2 # last updated grid loop = [Symbol('_'+x.name) for x in self.index] # symbols for loop for i in range(len(self.spacing)): result += 'printf("' + str(self.spacing[i].value) + '\\n");\n' for field in self.sfields+self.vfields: body = '' l2 = ccode(field.label)+'_l2' idx = [ti] + loop result += self.real_t + ' ' + l2 + ' = 0.0;\n' # populate xvalue, yvalue zvalue code for d in range(self.dimension-1, -1, -1): i = loop[d] i0 = m if field.staggered[d+1]: i1 = ccode(self.dim[d]-m-1) expr = self.spacing[d]*(loop[d] - self.margin.value + 0.5) else: i1 = ccode(self.dim[d]-m) expr = self.spacing[d]*(loop[d] - self.margin.value) pre = self.real_t + ' ' + self.index[d].name + '= ' \ + ccode(expr) + ';\n' if d == self.dimension-1: # inner loop tn = self.dt.value*self.ntsteps.value \ if not field.staggered[0] \ else self.dt.value*self.ntsteps.value \ + self.dt.value/2.0 body = l2 + '+=' \ + ccode((field[idx] - (field.sol.subs(self.t, tn)))**2.0) + ';\n' body = pre + body dict1 = {'i': i, 'i0': i0, 'i1': i1, 'body': body} body = render(tmpl, dict1) result += body volume = 1.0 for i in range(len(self.spacing)): volume *= self.spacing[i].value l2_value = 'pow(' + l2 + '*' + ccode(volume) + ', 0.5)' result += 'conv->%s = %s;\n' % (l2, l2_value) return result
def vtk_save_field(self): """ generate code to output this field with vtk uses Mako template returns the generated code as string """ tmpl = self.lookup.get_template('save_field.txt') result = '' dict1 = {'filename': ccode(self.label)+'_', 'field': ccode(self.label)} result = render(tmpl, dict1) return result
def initialise(self): """ generate code for initialisation of the fields - substitute starting time to the analytical function of the fields - substitute field coordinates calculated from array indices to the analytical function of the fields - generate inner loop by inserting kernel into Mako template - recursive insertion to generate nested loop return generated code as string """ tmpl = self.lookup.get_template('generic_loop.txt') result = '' m = self.margin.value loop = [Symbol('_'+x.name) for x in self.index] # symbols for loop for field in self.sfields+self.vfields: body = '' if self.omp: result += '#pragma omp for\n' # populate xvalue, yvalue zvalue code for d in range(self.dimension-1, -1, -1): i = loop[d] i0 = m if field.staggered[d+1]: i1 = ccode(self.dim[d]-m-1) expr = self.spacing[d]*(loop[d] - self.margin.value + 0.5) else: i1 = ccode(self.dim[d]-m) expr = self.spacing[d]*(loop[d] - self.margin.value) pre = self.real_t + ' ' + self.index[d].name + '= ' \ + ccode(expr) + ';\n' post = '' if d == self.dimension-1: # inner loop # first time step t0 = self.dt.value/2 if field.staggered[0] else 0 sol = field.sol.subs(self.t, t0) if self.read: sol = sol.subs(field.media_param) for idx in self.index: sol = sol.subs(idx, '_'+idx.name) body = ccode(field[[0]+loop]) + '=' \ + ccode(sol) + ';\n' body = pre + body + post dict1 = {'i': i, 'i0': i0, 'i1': i1, 'body': body} body = render(tmpl, dict1) result += body return result
def vtk_save_field(self): """ generate code to output this field with vtk uses Mako template returns the generated code as string """ tmpl = self.lookup.get_template('save_field.txt') result = '' dict1 = { 'filename': ccode(self.label) + '_', 'field': ccode(self.label) } result = render(tmpl, dict1) return result
def simple_loop(self, kernel): """ - helper function to generate simple nested loop over the entire domain (not including ghost cells) with kernel at the inner loop - variables defined in self.index are used as loop variables """ result = '' tmpl = self.lookup.get_template('generic_loop.txt') m = self.margin.value for d in range(self.dimension-1, -1, -1): i = self.index[d] i0 = m i1 = ccode(self.dim[d]-m) if d == self.dimension-1: # inner loop result += kernel + ';\n' dict1 = {'i': i, 'i0': i0, 'i1': i1, 'body': result} result = render(tmpl, dict1) return result
def velocity_loop(self): """ generate code for velocity field update loop - loop through velocity fields to generate code of computation kernel - generate inner loop by inserting kernel into Mako template - recursive insertion to generate nested loop return generated code as string """ tmpl = self.lookup.get_template('generic_loop.txt') m = self.margin.value body = '' for d in range(self.dimension-1, -1, -1): i = self.index[d] i0 = m i1 = ccode(self.dim[d]-m) if d == self.dimension-1: # inner loop idx = [self.time[1]] + self.index for field in self.vfields: body += ccode(field[idx]) + '=' \ + ccode(field.fd_align.xreplace({self.t+1: self.time[1], self.t: self.time[0]})) \ + ';\n' dict1 = {'i': i, 'i0': i0, 'i1': i1, 'body': body} body = render(tmpl, dict1) if self.ivdep and d == self.dimension-1: body = '%s\n' % self.compiler._ivdep + body if self.simd and d == self.dimension-1: body = '#pragma simd\n' + body if self.omp: body = '#pragma omp for\n' + body return body