Related
I’ve been trying to solve the water hammer PDE’s from the Maple example linked below in python (numpy/scipy). I’m getting very unstable results. Can anyone see my mistake? Guessing something is wrong with the boundary conditions.
https://www.maplesoft.com/support/help/view.aspx?path=applications/WaterHammer
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
## Parameters
Dia = 0.1
V = 14.19058741 # Stead state
p = 1000 # Liquid density
u = 0.001 # Viscosity
L = 25
e = 0.0001 # Roughness
Psource = 0.510E6
thick = 0.001
E= 7010*10**9
K=20010E6
Vsteady= 14.19058741
Ks = 1/((1/K)+(Dia/E*thick))
# Darcy-Weisbach
def Friction(V):
Rey = ((Dia*V*p)/u)
fL = 64/Rey
fT = 1/((1.8*np.log10((6.9/Rey) + (e/(3.7*Dia))**1.11))**2)
if Rey >= 0 and Rey < 2000:
return fL
if Rey >= 2000 and Rey<4000:
return fL + ((fT-fL)*(Rey-2000))/(4000-2000)
if Rey >= 4000:
return fT
return 0
def model(D, t):
V = D[:N]
P = D[N:]
dVdt = np.zeros(N)
for i in range(1, len(dVdt)-1):
dVdt[i] = -(1/p)*((P[i+1]-P[i-1])/2*dx)-((Friction(np.abs(V[i]))*(np.abs(V[i])**2))/(2*Dia))
dPdt = np.zeros(N)
for i in range(1, len(dPdt)-1):
dPdt[i] = -((V[i+1]-V[i-1])/(2*dx))*Ks
if t < 2:
dVdt[29] = 0
else:
dVdt[29] = -1
dPdt[29] = 0
dVdt[0] = dVdt[1]
return np.append(dVdt,dPdt)
N = 30
x = np.linspace(0, L, N)
dx = x[1] - x[0]
## Initial conditions
Vi_0 = np.ones(N)*Vsteady
Pi_0 = np.arange(N)
for i in Pi_0:
Pi_0[i] = Psource - (i*dx/L)*Psource
# initial condition
y0 = np.append(Vi_0, Pi_0)
# time points
t = np.linspace(0,3,10000)
# solve ODE
y = odeint(model,y0,t)
Vr = y[:,0:N]
Pr = y[:,N:]
plt.plot(t,Pr[:,5])
I need help with getting the temp using Antoine Eq by making use of classes.
My root action is failing and I don't know why.
My code:
from __future__ import division, print_function
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import root
class Chemical(object):
def __init__(self, name_1, balance_1, name_2, balance_2):
self.name = name_1 + ' ' + '+' + ' ' + name_2
self.data_1 = []
self.data_2 = []
self.data_1 = balance_1
self.data_2 = balance_2
def __str__(self):
if (self.name):
return "Mixture: %s" % (self.name)
else:
return None
def bubble_solve(self,a,P = 1.01,T = 300):
A1,B1,C1 = self.data_1
A2,B2,C2 = self.data_2
PA = 10**(A1 - B1/(C1+T))
PB = 10**(A2 - B2/(C2+T))
sol = root(lambda T: P - (a*PA + (1-a)*PB),T)
return sol.x[0]
def dew_solve(self, b, P = 1.01, T = 300):
A1,B1,C1 = self.data_1
A2,B2,C2 = self.data_2
PA = 10**(A1 - B1/(C1+T))
PB = 10**(A2 - B2/(C2+T))
sol = root(lambda T: 1 - (b*P/PA + (1-b)*P/PB), T)
return sol.x[0]
mixture = Chemical('benzene', [ 3.98523 , 1184.24 , -55.578], 'toulene',
[4.05043 , 1327.62 , -55.528])
print(mixture)
print()
print(mixture.bubble_solve(0.5)) #at a = 0.5
print(mixture.bubble_solve(0.5,2)) #at a = 0.5 and P = 2
print(mixture.dew_solve(0.5)) #at b = 0.5
print(mixture.dew_solve(0.5,2)) #at b = 0.5 and P = 2
This is what my code is printing:
Mixture: benzene + toulene
300.0
300.0
300.0
300.0
However, the answers need to be:
365.087, 390.14188, 371.7743, 396.688.
Why does the root action fail?
Welcome to StackOverflow, #Nathaniel!
The issue is in your PA, PB, and sol lines in bubble_solve and dew_solve. You seem to be mixing constants with independent variables! For instance, with your bubble solve, you have the default value of 300 set for T. Thus in the PA line, the value 300 is being used for T! One way to fix this would be the following:
...
def bubble_solve(self,a,P = 1.01,T = 300):
A1,B1,C1 = self.data_1
A2,B2,C2 = self.data_2
PA = lambda x: 10**(A1 - B1/(C1+x))
PB = lambda x: 10**(A2 - B2/(C2+x))
sol = root(lambda x: P - (a*PA(x) + (1-a)*PB(x)),T)
return sol.x[0]
def dew_solve(self, b, P = 1.01, T = 300):
A1,B1,C1 = self.data_1
A2,B2,C2 = self.data_2
PA = lambda x: 10**(A1 - B1/(C1+x))
PB = lambda x: 10**(A2 - B2/(C2+x))
sol = root(lambda x: 1 - (b*P/PA(x) + (1-b)*P/PB(x)), T)
return sol.x[0]
...
This will return the values you have expected. Note that I use x as the independent variable for PA and PB, but that it's arbitrary. However, it's probably best to not reuse T for your anonymous functions if you are passing values to it.
I am trying to run the minimization process found in this publication. The equation is seen on page 6 of the document 16 of the pdf.
I have a dataframe that looks like the below
df = pd.DataFrame({'h_t':[7.06398,6.29948,5.04570,6.20774,4.80106],
'p_atm':[101057.772801,101324.416001,101857.702401,101724.380801,101991.024001],
'q_p':[5.768132,3.825600,2.772215,5.830429,2.619304],
'q_s':[2.684433,3.403679,2.384275,1.008078,2.387106],
'tdg_f':[117.678100,110.131579,108.376963,103.669725,113.594771],
'tdg_tw':[121.052635,119.710907,114.921463,112.156868,115.444900],
'temp_water':[11.92,19.43,16.87,7.45,11.83]})
I have a constraint that says the below function must be positive where b1 and b3 are the coefficients I am optimizing.
def q_ge(q_p,q_s,b1,b3):
return min(q_p,(b1*q_s+b3))
I wrote my constraint below, but I am not sure if it is right.
def constraint_q_ge(x):
b1,b2,b3=x
power_flow = df.apply(lambda x:q_ge(x['q_p'],x['q_s'],b1,b3), axis = 1)
const = power_flow<0
return -const.sum()
Is this correct? I run the function on all rows and check if any are less than 0 and sum this. The negative of that sum should be greater than or equal to 0. If there is even a single value less than 0 this constraint is not met.
EDIT:
Below is the full problem.
from scipy.constants import g as gravity
from sklearn.metrics import mean_squared_error
from math import sqrt
from scipy.optimize import minimize
import warnings
try:
from numpy import any as _any
except ImportError:
def _any(arg):
if arg is True:
return True
if arg is False:
return False
return any(arg)
def water_density(T=None, T0=None, units=None, a=None,
just_return_a=False, warn=True):
if units is None:
K = 1
m = 1
kg = 1
else:
K = units.Kelvin
m = units.meter
kg = units.kilogram
if T is None:
T = 298.15*K
m3 = m**3
if a is None:
a = (-3.983035*K, # C
301.797*K, # C
522528.9*K*K, # C**2
69.34881*K, # C
999.974950*kg/m3)
if just_return_a:
return a
if T0 is None:
T0 = 273.15*K
t = T - T0
if warn and (_any(t < 0*K) or _any(t > 40*K)):
warnings.warn("Temperature is outside range (0-40 degC)")
return a[4]*(1-((t + a[0])**2*(t + a[1]))/(a[2]*(t + a[3])))
def celsius_to_kelvin(t_celsius):
return t_celsius+273.15
def tailwater(h_t, temp_water, p_atm):
t_water_kelvin = celsius_to_kelvin(temp_water)
rho = water_density(t_water_kelvin)
g = gravity
return (1+(rho*g*h_t)/(2*p_atm))
def tailwater_tdg(q_s,q_p,x, h_t,temp_water,p_atm,tdg_f):
b1,b2,b3=x
A = ((q_s+b1*q_s+b3)/(q_s+q_p))
B = tailwater(h_t, temp_water, p_atm)
C = ((q_p-b1*q_s-b3)/(q_s+q_p))
return 100*A*B*b2+tdg_f*C
def q_ge(q_p,q_s,b1,b3):
return min(q_p,(b1*q_s+b3))
def rmse(y, y_hat):
return sqrt(mean_squared_error(y,y_hat))
def objective(x):
y_hat = df.apply(lambda r:tailwater_tdg(q_s=r['q_s'],q_p=r['q_p'],x=x, h_t=r['h_t'],temp_water=r['temp_water'],p_atm=r['p_atm'],tdg_f=r['tdg_f']), axis = 1)
y = df['tdg_tw']
return rmse(y, y_hat)
#constraints and bounds for optimization model. See reference for more information
def constraint_q_ge(x):
b1,b2,b3=x
power_flow = df.apply(lambda x:q_ge(x['q_p'],x['q_s'],b1,b3), axis = 1)
const = power_flow<0
return -const.sum()
constraints = [{'type':'ineq', 'fun':constraint_q_ge}]
bounds = [(-500,10000),(.00001,10000),(-500,10000)]
x0=[1,1,1]
sol = minimize(objective, x0, method = 'SLSQP',constraints = constraints, bounds = bounds,options={'disp':True, 'maxiter':100})
I am trying to accelerate and/or decelerate a movie clip with the help of Python's moviepy module, but I can't seem to work it out properly. The script runs quite smoothly, and without any errors, but I do not see any effects. Might be my script is wrong and I can't detect the problem. Looking for help/tips from you. I do not need a complete solution, any hints will be of great help. I have been working on this solution for sometime and I think I should post my problem here. Any help, tips, guidance will be greatly appreciated. Thank you.
from moviepy.editor import *
from moviepy.video.tools.drawing import color_split
import os
dir = os.path.split(os.path.realpath(__file__))[0]
img = os.path.join('tmp', 'stock.jpg')
folder = 'tmp'
def f_accel_decel(t, old_d, new_d, abruptness=1, soonness=1.0):
"""
abruptness
negative abruptness (>-1): speed up down up
zero abruptness : no effect
positive abruptness: speed down up down
soonness
for positive abruptness, determines how soon the
speedup occurs (0<soonness < inf)
"""
a = 1.0+abruptness
def _f(t):
f1 = lambda t: (0.5)**(1-a)*(t**a)
f2 = lambda t: (1-f1(1-t))
return (t<.5)*f1(t) + (t>=.5)*f2(t)
return old_d*_f((t/new_d)**soonness)
def accel_decel(clip, new_duration=None, abruptness=1.0, soonness=1.0):
"""
new_duration
If None, will be that of the current clip.
abruptness
negative abruptness (>-1): speed up down up
zero abruptness : no effect
positive abruptness: speed down up down
soonness
for positive abruptness, determines how soon the
speedup occurs (0<soonness < inf)
"""
if new_duration is None:
new_duration = clip.duration
fl = lambda t : f_accel_decel(t, clip.duration, new_duration,
abruptness, soonness)
return clip.fl_time(fl).set_duration(new_duration)
duration = 30
main_clip = ImageClip(img, duration=30)
W,H = main_clip.size
print W,H
clip1 = (main_clip
.subclip(0,duration)
.set_pos(lambda t:(max((0), (int(W-0.5*W*t))), "center"))
)
modifiedClip1 = accel_decel(clip1, abruptness=5, soonness=1.3)
cc = CompositeVideoClip([modifiedClip1], size=(1920,1080), bg_color=(232,54,18)).resize(0.5)
cc.preview(fps=24)
#cc.write_videofile("mask.avi", fps=25, codec="libx264", bitrate="1000K", threads=3)
I think the best way of accelerating and decelerating clip objects is using easing functions.
Some reference sites:
http://easings.net
http://www.gizma.com/easing/
http://gsgd.co.uk/sandbox/jquery/easing/
Here's part of a script I made when trying to understand these functions.
Maybe you can use some of this concepts to solve your issue.
from __future__ import division
from moviepy.editor import TextClip, CompositeVideoClip
import math
def efunc(x0, x1, dur, func='linear', **kwargs):
# Return an easing function.
# It will control a single dimention of the clip movement.
# http://www.gizma.com/easing/
def linear(t):
return c*t/d + b
def out_quad(t):
t = t/d
return -c * t*(t-2) + b
def in_out_sine(t):
return -c/2 * (math.cos(math.pi*t/d) - 1) + b
def in_quint(t):
t = t/d
return c*t*t*t*t*t + b
def in_out_circ(t):
t /= d/2;
if t < 1:
return -c/2 * (math.sqrt(1 - t*t) - 1) + b
t -= 2;
return c/2 * (math.sqrt(1 - t*t) + 1) + b;
def out_bounce(t):
# http://gsgd.co.uk/sandbox/jquery/easing/jquery.easing.1.3.js
t = t/d
if t < 1/2.75:
return c*(7.5625*t*t) + b
elif t < 2/2.75:
t -= 1.5/2.75
return c*(7.5625*t*t + .75) + b
elif t < 2.5/2.75:
t -= 2.25/2.75
return c*(7.5625*t*t + .9375) + b
else:
t -= 2.625/2.75
return c*(7.5625*t*t + .984375) + b
# Kept the (t, b, c, d) notation found everywhere.
b = x0
c = x1 - x0
d = dur
return locals()[func]
def particle(x0, x1, y0, y1, d, func='linear', color='black', **kwargs):
# Dummy clip for testing.
def pos(t):
return efunc(x0, x1, d, func=func)(t), efunc(y0, y1, d, func=func)(t)
return (
TextClip('*', fontsize=80, color=color)
.set_position(pos)
.set_duration(d)
)
# Make a gif to visualize the behaviour of the functions:
easing_functions = [
('linear', 'red'),
('in_out_sine', 'green'),
('in_out_circ', 'violet'),
('out_quad', 'blue'),
('out_bounce', 'brown'),
('in_quint', 'black'),
]
d = 4
x0, x1 = 0, 370
clips = []
for i, (func, c) in enumerate(easing_functions):
y = 40*i
clips.append(particle(x0, x1, y, y, d=d, func=func, color=c))
clips.append(particle(x1, x0, y, y, d=d, func=func, color=c).set_start(d))
clip = CompositeVideoClip(clips, size=(400,250), bg_color=(255,255,255))
clip.write_gif('easing.gif', fps=12)
The output of the script:
I have been using matplotlib from python to show the animation of 1D wave equation.But I got a problem of making the animation.I want the image of the wave to change with time.It means that I may need a loop to form many different pictures of the wave equation.But it seems that the time cannot be put into the wave functions ,so the images do not change at all.Please help me with the mistake that I made.
Here are the codes that I wrote:(Part of the codes comes from the book "Python Scripting for Computational Science")
from numpy import zeros,linspace,sin,pi
import matplotlib.pyplot as mpl
def I(x):
return sin(2*x*pi/L)
def f(x,t):
return sin(x*t)
def solver0(I,f,c,L,n,dt,tstop):
# f is a function of x and t, I is a function of x
x = linspace(0,L,n+1)
dx = L/float(n)
if dt <= 0:
dt = dx/float(c)
C2 = (c*dt/dx)**2
dt2 = dt*dt
up = zeros(n+1)
u = up.copy()
um = up.copy()
t = 0.0
for i in range(0,n):
u[i] = I(x[i])
for i in range(1,n-1):
um[i] = u[i]+0.5*C2*(u[i-1] - 2*u[i] + u[i+1]) + dt2*f(x[i],t)
um[0] = 0
um[n] = 0
while t <= tstop:
t_old = t
t += dt
#update all inner points:
for i in range(1,n-1):
up[i] = -um[i] + 2*u[i] + C2*(u[i-1] - 2*u[i] + u[i+1]) + dt2*f(x[i],t_old)
#insert boundary conditions:
up[0] = 0
up[n] = 0
#update data structures for next step
um = u.copy()
u = up.copy()
return u
c = 3.0 #given by myself
L = 10
n = 100
dt = 0
tstart = 0
tstop = 6
x = linspace(0,L,n+1)
t_values = linspace(tstart,tstop,31)
mpl.ion()
y = solver0(I, f, c, L, n, dt, tstop)
lines = mpl.plot(x,y)
mpl.axis([x[0], x[-1], -1.0, 1.0])
mpl.xlabel('x')
mpl.ylabel('y')
counter = 0
for t in t_values:
y = solver0(I,f,c,L,n,dt,tstop)
lines[0].set_ydata(y)
mpl.draw()
mpl.legend(['t=%4.1f' % t])
mpl.savefig('sea_%04d.png' %counter)
counter += 1
Maybe that's what you need?
y = solver0(I,f,c,L,n,dt,t)