def cm_rk4(F_strings, F_args, x0, N, verbose=True): #you should really do this in a decorator if verbose: fs = sys.stdout # this is default for the print function else: fs = open(os.devnull, 'w') F, X = parse_symbolic(F_strings, F_args) print("system parsed successfully...", file=fs) J = F.jacobian(X) # symbolic jacobian matrix print("jacobian found", end=" ", file=fs) Jinv = J.inv() # calculate inverse (method can be specified) print("...and inverted!", end=" ", file=fs) #Jinv.simplify() # simplify symbolic expression (for logging) # note that this occurs in place! #print("...and simplified!", end=" ", file=fs) print("\n", file=fs) # get a value for F_0 = F(x0) F0 = F.subs(list(zip(X, x0))) print("initial system calculated", file=fs) # x`(λ) = [J(x(λ)]^(-1) * F0 # this is an nx1 matrix that describes the set of differential equations # dx_i / dλ = [x`(λ)]_i xpl = -Jinv.multiply(F0) # matmul syntax is different within sympy print("ODE system x`(λ) calculated", file=fs) print("...and simplified", file=fs) print("running RK4 with N={}".format(N), file=fs) # pass everything to RK4 (including verbosity setting) x_sol = rk4(xpl, X, x0, N, verbose=verbose) # do you need to close /dev/null? if not verbose: try: fs.close() except: pass # this is bad code return x_sol
args = "x,y,z" # really sloppy handling, use argparse if len(sys.argv) > 1: try: N = int(sys.argv[1]) except: raise Exception("argument must be an integer N (partition size in RK4)") else: N = 4 # just set verbosity based on size of N v = (N < 5) x0 = np.array([[1,1,1]]).T x_sol = cm_rk4(case_one, args, x0, N, verbose=v) # now just do some data F, X = parse_symbolic(case_one, args) # get F value at x* F1 = F.subs(list(zip(X, x_sol))) err = F1.norm() # wow, these methods are great print("||F(x*)|| = ", err) x_check = nsolve(F, X, (1,1,1)) print("solution according to sympy.solvers.nsolve:") print(x_check.T)