# TO DO
#-Figure out plausible units for initial values and constants
#-Determine correct coefficient for arbitrary order RK (i.e. RK4 -> 1/6, RK5 -> ?)
#-Try to find a way to make RK1 = Euler method and RK2 = Midpoint method
#-Dynamic number of steps (# of oscillations, etc.)
#-International System units!
@interact
def solver(method_choice = selector(['Euler', 'Midpoint', 'Runge-Kutta'], default='Runge-Kutta', nrows=1, label='Method'),
step_size = slider(vmin=0.0000001, vmax=0.1, step_size=0.0000001, default=1, label='Step size'),
rk_order = input_box(default="4", label='Order of Runge-Kutta'),
init_radius = input_box(default="1", label='Initial radius'),
init_rad_vel = input_box(default="0", label='Initial radial velocity'),
init_rad_acc = input_box(default="0", label='Initial radial acceleration'),
f_bubble_pressure = input_box(default="1", label='Initial gas pressure inside bubble', width=10),
f_v_pressure = input_box(default="1", label='Vapor pressure (p_v(T_inf))', width=10),
f_i_pressure = input_box(default="1", label='Fluid pressure far away from cavitation', width=10),
f_density = input_box(default="1", label='Liquid density', width=10), #f_var indicates fluid variable
f_viscosity = input_box(default="1", label='Liquid viscosity', width=10),
f_surface_tension = input_box(default="1", label='Bubble surface tension', width=10),
f_constant_k = input_box(default="1", label='Constant K', width=10)):
h = step_size
rk_order = int(rk_order)
R_0 = int(init_radius)
RV_0 = int(init_rad_vel)
RA_0 = int(init_rad_acc)
PB = int(f_bubble_pressure)
PV = int(f_v_pressure)
PI = int(f_i_pressure)
D = int(f_density)
V = int(f_viscosity)
S = int(f_surface_tension)
K = int(f_constant_k)
#Function for linearized Rayleigh-Plesset
def equation(r, rv):
return sin(r)#return rv*((3*RV_0/r) + (4*V/r^2)) + (R_0^K)/(r^(3*K+1)) + (2*S/(3*r^3)) + ((PB-PV-PI)/D) - (3*RV_0^2)/(2*r)
#Create some arrays to store values
R_array = [[0,R_0]]
RV_array = [[0,RV_0]]
RA_array = [[0,equation(R_0,RV_0)]]
slope_array = []
extrema_array = []
trend = True #True = ascending, False = descending
osc_goal = 10
osc_num = 0
#and variables to use in computations
r = R_0
rv = RV_0
ra = RA_0
i = 1
#BEGIN MAIN LOOP
while i < 1000 or osc_goal < osc_num:
if method_choice == 'Euler':
#calculate the radius based on previous radius and velocity
r = r + rv*h
R_array.append([i*h,r])
#calculate the velocity based on acceleration 'ra' and previous velocity
rv = rv + ra*h
RV_array.append([i*h,rv])
#find acceleration based on linearized equation function
ra = equation(r,rv)
RA_array.append([i*h,ra])
elif method_choice == 'Midpoint':
r = r + rv*h
rv = rv + ra*h
ra = equation(r,rv)
ra = equation(r+h/2, rv+ra/2)
#append to arrays
RA_array.append([i*h,ra])
RV_array.append([i*h,rv])
R_array.append([i*h,r])
elif method_choice == 'Runge-Kutta':
r = r + rv*h
R_array.append([i*h,r])
rv = rv + ra*h
RV_array.append([i*h,rv])
#calculation of 'ra' for arbitrary RK order with delta values stored in 'k_array'
k_array = []
k_array.append(h*equation(r,rv))
for a in range(rk_order-2):
k_array.append(2*h*equation(r+h/2, rv+k_array[a]/2))
k_array.append(h*equation(r+h,rv+k_array[rk_order-2]))
ra = ra + sum(k_array)/6
RA_array.append([i*h,ra])
#calculate slope and detect extrema
slope = (R_array[i][1] - R_array[i-1][1])/h
slope_array.append(slope.n())
if len(extrema_array) == 0:
trend = R_array[1][1] > R_array[0][1] #on first iteration, set 'trend'
elif R_array[i][1] > R_array[i-1][1] and trend == False: #detect the new slope; if it changes, declare an extrema and switch 'trend'
trend = True
extrema_array.append(R_array[i-1])
elif R_array[i][1] < R_array[i-1][1] and trend == True: #same as above but for the opposite direction
trend = False
extrema_array.append(R_array[i-1])
#check for low amounts of activity (overflow safeguard #1)
avg_change = 0
tot_change = 0 #not really the 'total' change - takes sign changes into account, unlike avg_change
l = len(slope_array)
if l > 5:
for a in range(5):
avg_change += abs(slope_array[l-a-1] - slope_array[l-a-2])
tot_change += slope_array[l-a-1] - slope_array[l-a-2]
avg_change /= 5
tot_change /= 5
if avg_change < 0.000005:
print "Computation interrupted due to lack of activity\n\t(Average change = %s)" % avg_change
break
if avg_change > 100 and avg_change == abs(tot_change):
print "Computation interrupted due to exponential behavior"
break
i += 1
#END MAIN LOOP
#Create a line that connects all of the points in r_array
L = line([(R_array[j][0], R_array[j][1]) for j in range(len(R_array))], color=(1,0,0), legend_label="Radial position")
show(L)
#Same thing, RV_array
M = line([(RV_array[j][0], RV_array[j][1]) for j in range(len(RV_array))], color=(0,1,0), legend_label="Radial velocity")
show(M)
#ctrl-c ctrl-v RA_array
N = line([(RA_array[j][0], RA_array[j][1]) for j in range(len(RA_array))], color=(0,0,1), legend_label="Radial accel")
show(N)
show(L+M+N)
|
|
Click to the left again to hide and once more to show the dynamic interactive window
|