def genP3code(): autocode = CCodeGen(project="Salvus") r,s,t = symbols("r,s,t") rstn = p3ReferenceNodes() (rn,sn,tn) = rstn Np = len(rn) phi = p3ElementPolynomials(rstn,r,s,t) (dphi_dr,dphi_ds,dphi_dt) = p3ElementDerivatives(phi,r,s,t) dphi_dr_rstn = np.zeros((Np,Np)) dphi_ds_rstn = np.zeros((Np,Np)) dphi_dt_rstn = np.zeros((Np,Np)) for i in range(0,Np): dphi_dr_i = lambdify((r,s,t),dphi_dr[i]) dphi_ds_i = lambdify((r,s,t),dphi_ds[i]) dphi_dt_i = lambdify((r,s,t),dphi_dt[i]) for (n,(ri,si,ti)) in enumerate(zip(rn,sn,tn)): dphi_dr_rstn[i,n] = dphi_dr_i(ri,si,ti) dphi_ds_rstn[i,n] = dphi_ds_i(ri,si,ti) dphi_dt_rstn[i,n] = dphi_dt_i(ri,si,ti) dphi_dr_rstn = Matrix(dphi_dr_rstn) dphi_ds_rstn = Matrix(dphi_ds_rstn) dphi_dt_rstn = Matrix(dphi_dt_rstn) rn = Matrix([ri for (ri,si,ti) in zip(rn,sn,tn)]) sn = Matrix([si for (ri,si,ti) in zip(rn,sn,tn)]) tn = Matrix([ti for (ri,si,ti) in zip(rn,sn,tn)]) wn = Matrix(p3QuadratureWeights()) rn_routine = autocode.routine("coordinates_p3_tetrahedra_rn",rn, argument_sequence=None) sn_routine = autocode.routine("coordinates_p3_tetrahedra_sn",sn, argument_sequence=None) tn_routine = autocode.routine("coordinates_p3_tetrahedra_tn",tn, argument_sequence=None) wn_routine = autocode.routine("quadrature_weights_p3_tetrahedra",wn, argument_sequence=None) # NOTE: writes out in Row Major (so we write the # transpose). Salvus (via Eigen) assumes Column Major dphi_dr_rstn_routine = autocode.routine("dphi_dr_rstn_p3_tetrahedra", dphi_dr_rstn.transpose(), argument_sequence=None) dphi_ds_rstn_routine = autocode.routine("dphi_ds_rstn_p3_tetrahedra", dphi_ds_rstn.transpose(), argument_sequence=None) dphi_dt_rstn_routine = autocode.routine("dphi_dt_rstn_p3_tetrahedra", dphi_dt_rstn.transpose(), argument_sequence=None) routines = [rn_routine, sn_routine, tn_routine, wn_routine, dphi_dr_rstn_routine, dphi_ds_rstn_routine, dphi_dt_rstn_routine] autocode.write(routines,"p3_tetrahedra",to_files=True) buildVisualizationP3(rn,sn,tn)
def tensorized_basis_2D(order): total_integration_points = (order + 1) * (order + 1) eps, eta, rho = sym.symbols('epsilon eta rho') eps_gll = sym.symbols('epsilon_0:%d' % (order + 1)) eta_gll = sym.symbols('eta_0:%d' % (order + 1)) # Get N + 1 lagrange polynomials in each direction. generator_eps = generating_polynomial_lagrange(order, 'epsilon', eps_gll) generator_eta = generating_polynomial_lagrange(order, 'eta', eta_gll) # Get tensorized basis. basis = TensorProduct(generator_eta, generator_eps) basis = basis.subs([(v, c) for v, c in zip(eps_gll, gll_coordinates(order))]) basis = basis.subs([(v, c) for v, c in zip(eta_gll, gll_coordinates(order))]) sym.pprint(basis) # Get gradient of basis functions. basis_gradient_eps = sym.Matrix([sym.diff(i, eps) for i in basis]) basis_gradient_eta = sym.Matrix([sym.diff(i, eta) for i in basis]) # Get diagonal mass matrix mass_matrix = rho * basis * basis.T mass_matrix_diagonal = sym.Matrix( [mass_matrix[i, i] for i in range(total_integration_points)]) # Write code routines = [] autocode = CCodeGen() routines.append( autocode.routine('interpolate_order{}_square'.format(order), basis, argument_sequence=None)) routines.append( autocode.routine( 'interpolate_eps_derivative_order{}_square'.format(order), basis_gradient_eps, argument_sequence=None)) routines.append( autocode.routine( 'interpolate_eta_derivative_order{}_square'.format(order), basis_gradient_eta, argument_sequence=None)) routines.append( autocode.routine('diagonal_mass_matrix_order{}_square'.format(order), mass_matrix_diagonal, argument_sequence=None)) autocode.write(routines, 'order{}_square'.format(order), to_files=True)
def create_module(module_name, expression_name_tuples, directory): """Generates a cython module that can be imported.""" routines = [] for name, expression, args in expression_name_tuples: try: routine = make_routine(name, [expression], args) except CodeGenArgumentListError as e: new_args = [] for missing in e.missing_args: if not isinstance(missing, OutputArgument): raise new_args.append(missing.name) routine = make_routine(name, expression, list(args) + new_args) routines.append(routine) if not os.path.exists(directory): os.makedirs(directory) cg = CCodeGen() [(cf, cs), (hf, hs)] = cg.write(routines, module_name + '_code') with open(directory + '/' + cf, "w") as text_file: text_file.write(cs) with open(directory + '/' + hf, "w") as text_file: text_file.write(hs) ccw = CythonCodeWrapper(cg) with open(directory + '/' + module_name + '.pyx', "w") as text_file: ccw.dump_pyx(routines, text_file, module_name + '_code') create_setup(module_name + '.pyx', module_name + '_code.c', directory, module_name) open(directory + '/__init__.py', 'w').close() oldwork = os.getcwd() os.chdir(directory) workdir = os.getcwd() command = [sys.executable, "setup.py", "build_ext", "--inplace"] try: sys.path.append(workdir) retoutput = check_output(command, stderr=STDOUT) except CalledProcessError as e: raise CodeWrapError( "Error while executing command: %s. Command output is:\n%s" % (" ".join(command), e.output.decode())) finally: sys.path.remove(workdir) os.chdir(oldwork)
def tensorized_basis_2D(order): total_integration_points = (order + 1) * (order + 1) eps, eta, rho = sym.symbols("epsilon eta rho") eps_gll = sym.symbols("epsilon_0:%d" % (order + 1)) eta_gll = sym.symbols("eta_0:%d" % (order + 1)) # Get N + 1 lagrange polynomials in each direction. generator_eps = generating_polynomial_lagrange(order, "epsilon", eps_gll) generator_eta = generating_polynomial_lagrange(order, "eta", eta_gll) # Get tensorized basis. basis = TensorProduct(generator_eta, generator_eps) basis = basis.subs([(v, c) for v, c in zip(eps_gll, gll_coordinates(order))]) basis = basis.subs([(v, c) for v, c in zip(eta_gll, gll_coordinates(order))]) sym.pprint(basis) # Get gradient of basis functions. basis_gradient_eps = sym.Matrix([sym.diff(i, eps) for i in basis]) basis_gradient_eta = sym.Matrix([sym.diff(i, eta) for i in basis]) # Get diagonal mass matrix mass_matrix = rho * basis * basis.T mass_matrix_diagonal = sym.Matrix([mass_matrix[i, i] for i in range(total_integration_points)]) # Write code routines = [] autocode = CCodeGen() routines.append(autocode.routine("interpolate_order{}_square".format(order), basis, argument_sequence=None)) routines.append( autocode.routine( "interpolate_eps_derivative_order{}_square".format(order), basis_gradient_eps, argument_sequence=None ) ) routines.append( autocode.routine( "interpolate_eta_derivative_order{}_square".format(order), basis_gradient_eta, argument_sequence=None ) ) routines.append( autocode.routine( "diagonal_mass_matrix_order{}_square".format(order), mass_matrix_diagonal, argument_sequence=None ) ) autocode.write(routines, "order{}_square".format(order), to_files=True)
def genP3code(): autocode = CCodeGen(project="Salvus") r,s = symbols("r,s") rsn = p3ReferenceNodes() Np = len(rsn) phi = p3ElementPolynomials(rsn,r,s) (dphi_dr,dphi_ds) = p3ElementDerivatives(phi,r,s) dphi_dr_rsn = np.zeros((Np,Np)) dphi_ds_rsn = np.zeros((Np,Np)) for i in range(0,Np): dphi_dr_i = lambdify((r,s),dphi_dr[i]) dphi_ds_i = lambdify((r,s),dphi_ds[i]) for (n,(rn,sn)) in enumerate(rsn): dphi_dr_rsn[i,n] = dphi_dr_i(rn,sn) dphi_ds_rsn[i,n] = dphi_ds_i(rn,sn) dphi_dr_rsn = Matrix(dphi_dr_rsn) dphi_ds_rsn = Matrix(dphi_ds_rsn) print(dphi_dr_rsn[0,:]) rn = Matrix([ri for (ri,si) in rsn]) sn = Matrix([si for (ri,si) in rsn]) wn = Matrix(p3QuadratureWeights()) rn_routine = autocode.routine("coordinates_p3_triangle_rn",rn, argument_sequence=None) sn_routine = autocode.routine("coordinates_p3_triangle_sn",sn, argument_sequence=None) wn_routine = autocode.routine("quadrature_weights_p3_triangle",wn, argument_sequence=None) # NOTE: by default, it writes out in Row Major (so we write the # transpose). Salvus (via Eigen) assumes Column Major dphi_dr_rsn_routine = autocode.routine("dphi_dr_rsn_p3_triangle", dphi_dr_rsn.transpose(), argument_sequence=None) dphi_ds_rsn_routine = autocode.routine("dphi_ds_rsn_p3_triangle", dphi_ds_rsn.transpose(), argument_sequence=None) routines = [rn_routine, sn_routine, wn_routine, dphi_dr_rsn_routine, dphi_ds_rsn_routine] autocode.write(routines,"p3_triangle",to_files=True)
def test_output_arg_c(): from sympy import sin, cos, Equality x, y, z = symbols("x,y,z") r = Routine("foo", [Equality(y, sin(x)), cos(x)]) c = CCodeGen() result = c.write([r], "test", header=False, empty=False) assert result[0][0] == "test.c" expected = ('#include "test.h"\n' '#include <math.h>\n' 'double foo(double x, double &y) {\n' ' y = sin(x);\n' ' return cos(x);\n' '}\n') assert result[0][1] == expected
def test_output_arg_c(): from sympy import sin, cos, Equality x, y, z = symbols("x,y,z") r = Routine("foo", [Equality(y, sin(x)), cos(x)]) c = CCodeGen() result = c.write([r], "test", header=False, empty=False) assert result[0][0] == "test.c" expected = ( '#include "test.h"\n' '#include <math.h>\n' 'double foo(double x, double &y) {\n' ' y = sin(x);\n' ' return cos(x);\n' '}\n' ) assert result[0][1] == expected
def _fixed_autowrap(energy_expr, prefix, save_filename=None): codegen = CCodeGen() routines = [] _logger.debug('Writing code for energy_expr') routines.append(codegen.routine('autofunc', energy_expr)) [(c_name, bad_c_code), (h_name, h_code)] = codegen.write( routines, prefix, ) c_code = '#include <complex.h>\n' c_code += bad_c_code c_code = c_code.replace('conjugate', 'conj') write_directory = Path(tempfile.mkdtemp()).absolute() c_path = write_directory / Path(prefix + '.c') h_path = write_directory / Path(prefix + '.h') o_path = write_directory / Path(prefix + '.o') so_path = write_directory / Path(prefix + '.so') with open(c_path, 'w') as fh: fh.write(c_code) fh.write('\n') with open(h_path, 'w') as fh: fh.write(h_code) fh.write('\n') start = time.time() _logger.debug('Start compiling code.') os.system(f'gcc -c -lm {c_path} -o {o_path}') os.system(f'gcc -shared {o_path} -o {so_path}') _logger.debug(f'Compiling code took {time.time()-start} seconds.') if save_filename is not None: if Path(save_filename).exists(): Path(save_filename).unlink() shutil.copy(so_path, save_filename) cost_func = _load_func(so_path) shutil.rmtree(write_directory) return cost_func
def test_output_arg_c_reserved_words(): from sympy import sin, cos, Equality x, y, z = symbols("if, while, z") r = make_routine("foo", [Equality(y, sin(x)), cos(x)]) c = CCodeGen() result = c.write([r], "test", header=False, empty=False) assert result[0][0] == "test.c" expected = ( '#include "test.h"\n' '#include <math.h>\n' 'double foo(double if_, double *while_) {\n' ' (*while_) = sin(if_);\n' ' double foo_result;\n' ' foo_result = cos(if_);\n' ' return foo_result;\n' '}\n' ) assert result[0][1] == expected
def run_cc_test(label, routines, numerical_tests, friendly=True): """A driver for the codegen tests. This driver assumes that a compiler cc is present in the PATH and that cc is (at least) an ANSI C compiler. The generated code is written in a temporary directory, together with a main program that validates the generated code. The test passes when the compilation and the validation run correctly. """ # Do all the magic to compile, run and validate the test code # 1) prepare the temporary working directory, swith to that dir work = tempfile.mkdtemp("_sympy_cc_test", "%s_" % label) oldwork = os.getcwd() os.chdir(work) # 2) write the generated code if friendly: # interpret the routines as a name_expr list and call the friendly # function codegen codegen(routines, 'C', "codegen", to_files=True) else: code_gen = CCodeGen() code_gen.write(routines, "codegen", to_files=True) # 3) write a simple main program that links to the generated code, and that # includes the numerical tests test_strings = [] for fn_name, args, expected, threshold in numerical_tests: call_string = "%s(%s)-(%s)" % (fn_name, ",".join(str(arg) for arg in args), expected) test_strings.append(numerical_test_template % { "call": call_string, "threshold": threshold, }) f = file("main.c", "w") f.write(main_template % "".join(test_strings)) f.close() # 4) Compile and link compiled = try_run([ "cc -c codegen.c -o codegen.o", "cc -c main.c -o main.o", "cc main.o codegen.o -lm -o test" ]) # 5) Run if compiled if compiled: executed = try_run(["./test"]) else: executed = False # 6) Clean up stuff clean = os.getenv('SYMPY_TEST_CLEAN_TEMP', 'always').lower() if clean not in ('always', 'success', 'never'): raise ValueError("SYMPY_TEST_CLEAN_TEMP must be one of the following: 'always', 'success' or 'never'.") if clean == 'always' or (clean == 'success' and compiled and executed): def safe_remove(filename): if os.path.isfile(filename): os.remove(filename) safe_remove("codegen.c") safe_remove("codegen.h") safe_remove("codegen.o") safe_remove("main.c") safe_remove("main.o") safe_remove("test") os.chdir(oldwork) os.rmdir(work) else: print >> sys.stderr, "TEST NOT REMOVED: %s" % work os.chdir(oldwork) # 7) Do the assertions in the end assert compiled assert executed
def run_cc_test(label, routines, numerical_tests, friendly=True): """A driver for the codegen tests. This driver assumes that a compiler cc is present in the PATH and that cc is (at least) an ANSI C compiler. The generated code is written in a temporary directory, together with a main program that validates the generated code. The test passes when the compilation and the validation run correctly. """ # Do all the magic to compile, run and validate the test code # 1) prepare the temporary working directory, swith to that dir work = tempfile.mkdtemp("_sympy_cc_test", "%s_" % label) oldwork = os.getcwd() os.chdir(work) # 2) write the generated code if friendly: # interpret the routines as a name_expr list and call the friendly # function codegen codegen(routines, 'C', "codegen", to_files=True) else: code_gen = CCodeGen() code_gen.write(routines, "codegen", to_files=True) # 3) write a simple main program that links to the generated code, and that # includes the numerical tests test_strings = [] for fn_name, args, expected, threshold in numerical_tests: call_string = "%s(%s)-(%s)" % (fn_name, ",".join( str(arg) for arg in args), expected) test_strings.append(numerical_test_template % { "call": call_string, "threshold": threshold, }) f = file("main.c", "w") f.write(main_template % "".join(test_strings)) f.close() # 4) Compile and link compiled = try_run([ "cc -c codegen.c -o codegen.o", "cc -c main.c -o main.o", "cc main.o codegen.o -lm -o test" ]) # 5) Run if compiled if compiled: executed = try_run(["./test"]) else: executed = False # 6) Clean up stuff clean = os.getenv('SYMPY_TEST_CLEAN_TEMP', 'always').lower() if clean not in ('always', 'success', 'never'): raise ValueError( "SYMPY_TEST_CLEAN_TEMP must be one of the following: 'always', 'success' or 'never'." ) if clean == 'always' or (clean == 'success' and compiled and executed): def safe_remove(filename): if os.path.isfile(filename): os.remove(filename) safe_remove("codegen.c") safe_remove("codegen.h") safe_remove("codegen.o") safe_remove("main.c") safe_remove("main.o") safe_remove("test") os.chdir(oldwork) os.rmdir(work) else: print >> sys.stderr, "TEST NOT REMOVED: %s" % work os.chdir(oldwork) # 7) Do the assertions in the end assert compiled assert executed
def _make_energy_func_chunked(energy_expr_list, prefix, save_filename=None): codegen = CCodeGen() routines = [] for i, expr in enumerate(energy_expr_list): _logger.debug(f'Writing code for expr {i} of {len(energy_expr_list)}') routines.append(codegen.routine('expr' + str(i), expr)) [(c_name, bad_c_code), (h_name, h_code)] = codegen.write( routines, prefix, ) c_code = '#include <complex.h>\n' c_code += bad_c_code c_code += """ double autofunc(double *xs){ double autofunc_result; autofunc_result = %s; return autofunc_result; } """ % ('+'.join( ['expr' + str(i) + '(xs)' for i in range(len(energy_expr_list))])) c_code = c_code.replace('conjugate', 'conj') h_code = h_code.replace('\n#endif', """double autofunc(double *xs); #endif """) write_directory = Path(tempfile.mkdtemp()).absolute() c_path = write_directory / Path(prefix + '.c') h_path = write_directory / Path(prefix + '.h') o_path = write_directory / Path(prefix + '.o') so_path = write_directory / Path(prefix + '.so') with open(c_path, 'w') as fh: fh.write(c_code) fh.write('\n') with open(h_path, 'w') as fh: fh.write(h_code) fh.write('\n') start = time.time() _logger.debug('Start compiling code.') os.system(f'gcc -c -lm -fPIC {c_path} -o {o_path}') os.system(f'gcc -shared -fPIC {o_path} -o {so_path}') _logger.debug(f'Compiling code took {time.time()-start} seconds.') if save_filename is not None: if Path(save_filename).exists(): Path(save_filename).unlink() shutil.copy(so_path, save_filename) cost_func = _load_func(so_path) shutil.rmtree(write_directory) return cost_func
print mass_matrix_int print boun_shell_tops # // INTEGRATE STIFFNESS MATRIX // print 'Integrating stiffness matrix...' stiffness_matrix = dN.T * C * dN stiffness_matrix = stiffness_matrix.subs(replace_e) stiffness_matrix = stiffness_matrix.subs(replace_n) stiffness_matrix_int = sym.Matrix.zeros(dof_tot, dof_tot) for c_e, w_x in zip(coords, weights): for c_n, w_y in zip(coords, weights): stiffness_matrix_int += stiffness_matrix.subs( [(e, c_e), (n, c_n)]) * w_x * w_y * Jdet routines.append(sem_c.routine( 'stiffness_matrix', stiffness_matrix_int, argument_sequence=None)) # // OUTPUT DERIVATIVES // print 'Writing derivatives of shape functions.' routines.append(sem_c.routine( 'shape_derivatives', grad_N, argument_sequence=None)) # // OUTPUT JACOBIAN // print 'Writing Jacobian function.' routines.append(sem_c.routine( 'eval_jacobian', J, argument_sequence=None)) print 'Writing functions...' sem_c.write(routines, './src/functions', to_files=True)
def genP3code(): autocode = CCodeGen(project="Salvus") r, s, t = symbols("r,s,t") rstn = p3ReferenceNodes() (rn, sn, tn) = rstn Np = len(rn) phi = p3ElementPolynomials(rstn, r, s, t) (dphi_dr, dphi_ds, dphi_dt) = p3ElementDerivatives(phi, r, s, t) dphi_dr_rstn = np.zeros((Np, Np)) dphi_ds_rstn = np.zeros((Np, Np)) dphi_dt_rstn = np.zeros((Np, Np)) for i in range(0, Np): dphi_dr_i = lambdify((r, s, t), dphi_dr[i]) dphi_ds_i = lambdify((r, s, t), dphi_ds[i]) dphi_dt_i = lambdify((r, s, t), dphi_dt[i]) for (n, (ri, si, ti)) in enumerate(zip(rn, sn, tn)): dphi_dr_rstn[i, n] = dphi_dr_i(ri, si, ti) dphi_ds_rstn[i, n] = dphi_ds_i(ri, si, ti) dphi_dt_rstn[i, n] = dphi_dt_i(ri, si, ti) dphi_dr_rstn = Matrix(dphi_dr_rstn) dphi_ds_rstn = Matrix(dphi_ds_rstn) dphi_dt_rstn = Matrix(dphi_dt_rstn) rn = Matrix([ri for (ri, si, ti) in zip(rn, sn, tn)]) sn = Matrix([si for (ri, si, ti) in zip(rn, sn, tn)]) tn = Matrix([ti for (ri, si, ti) in zip(rn, sn, tn)]) wn = Matrix(p3QuadratureWeights()) rn_routine = autocode.routine("coordinates_p3_tetrahedra_rn", rn, argument_sequence=None) sn_routine = autocode.routine("coordinates_p3_tetrahedra_sn", sn, argument_sequence=None) tn_routine = autocode.routine("coordinates_p3_tetrahedra_tn", tn, argument_sequence=None) wn_routine = autocode.routine("quadrature_weights_p3_tetrahedra", wn, argument_sequence=None) # NOTE: writes out in Row Major (so we write the # transpose). Salvus (via Eigen) assumes Column Major dphi_dr_rstn_routine = autocode.routine("dphi_dr_rstn_p3_tetrahedra", dphi_dr_rstn.transpose(), argument_sequence=None) dphi_ds_rstn_routine = autocode.routine("dphi_ds_rstn_p3_tetrahedra", dphi_ds_rstn.transpose(), argument_sequence=None) dphi_dt_rstn_routine = autocode.routine("dphi_dt_rstn_p3_tetrahedra", dphi_dt_rstn.transpose(), argument_sequence=None) routines = [ rn_routine, sn_routine, tn_routine, wn_routine, dphi_dr_rstn_routine, dphi_ds_rstn_routine, dphi_dt_rstn_routine ] autocode.write(routines, "p3_tetrahedra", to_files=True) buildVisualizationP3(rn, sn, tn)
# Get gradient of basis functions gn = sym.Matrix(([sym.diff(i, eta) for i in n])).T sym.pprint(gn) # Mass matrix mm = (rho * n.T * n) mm = sym.Matrix([mm[i,i] for i in range(nPtsPelm)]) # Get mapping m = sym.Matrix(getMap(nPtsPvtx, nPtsPedg, nPtsPfac)) # Write code routines = [] sem_c = CCodeGen() routines.append(sem_c.routine( 'interpolateOrder%dDim%d' % (args.order, args.dimension), n, argument_sequence=None)) routines.append(sem_c.routine( 'massMatrixOrder%dDim%d' % (args.order, args.dimension), mm, argument_sequence=None)) routines.append(sem_c.routine( 'gradientOperatorOrder%dDim%d' % (args.order, args.dimension), gn, argument_sequence=None)) routines.append(sem_c.routine( 'mappingOrder%dDim%d' % (args.order, args.dimension), m, argument_sequence=None)) sem_c.write( routines, 'auto/order%dDim%d' % (args.order, args.dimension), to_files=True)