问题
I want to do in python what this guy did in MATLAB.
I have installed anaconda, so i have numpy and sympy libraries. So far I have tried with numpy nsolve, but that doesn't work. I should say I'm new with python, and also that I konw how to do it in MATLAB :P.
The equation:
-2*log(( 2.51/(331428*sqrt(x)) ) + ( 0.0002 /(3.71*0.26)) ) = 1/sqrt(x)
Normally, I would solve this iteratively, simply guessing x on the left and than solving for the x on the right. Put solution on the left, solve again. Repeat until left x is close to right. I have an idea what solution should be.
So I could do that, but that's not very cool. I want to do it numerically. My 15€ Casio calculator can solve it as is, so I think it shouldn't be to complicated?
Thank you for your help,
edit: so I have tried the following:
from scipy.optimize import brentq
w=10;
d=0.22;
rho=1.18;
ni=18.2e-6;
Re=(w*d*rho)/ni
k=0.2e-3;
d=0.26;
def f(x,Re,k,d):
return (
-2*log((2.51/(Re*sqrt(x)))+(k/(3.71*d)),10)*sqrt(x)+1
);
print(
scipy.optimize.brentq
(
f,0.0,1.0,xtol=4.44e-12,maxiter=100,args=(),full_output=True,disp=True
)
);
And i get this result:
r = _zeros._brentq(f,a,b,xtol,maxiter,args,full_output,disp)
TypeError: f() takes exactly 4 arguments (1 given)
Is it because I'm solving also solving for constants?
edit2: so I think I have to assign constants via args=() keyword, so I changed:
f,0.0,1.0,xtol=4.44e-12,maxiter=100,args=(Re,k,d),full_output=True,disp=True
but now I get this:
-2*log((2.51/(Re*sqrt(x)))+(k/(3.71*d)),10)*sqrt(x)+1
TypeError: return arrays must be of ArrayType
Anyway, when I put in a different equation; lets say 2*x*Re+(k*d)/(x+5)
it works, so I guess I have to transform the equation.
so it dies here: log(x,10)..
edit4: correct syntax is log10(x)... Now it works but I get zero as a result
回答1:
This works fine. I've done a few things here. First, I've used a simpler definition of the function using the global variables you've defined anyway. I find this a little nicer than passing the args= to the solvers, it also enables easier use of your own custom solvers if you ever need something like that. I've used the generic root
function as an entry point rather than using a particular algorithm - this is nice because you can simply pass a different method later. I've also fixed up your spacing to be as recommended by PEP 8 and fixed your erronious rewriting of the equation. I find it more intuitive simply to write LHS - RHS rather than manipulate as you did. Also, notice that I've replaced all the integer literals with 1.0 or whatever to avoid problems with integer division. 0.02 is regarded as a pretty standard starting point for the friction factor.
import numpy
from scipy.optimize import root
w = 10.0
d = 0.22
rho = 1.18
ni = 18.2e-6
Re = w*d*rho/ni
k = 0.2e-3
def f(x):
return (-2*numpy.log10((2.51/(Re*numpy.sqrt(x))) + (k/(3.71*d))) - 1.0/numpy.sqrt(x))
print root(f, 0.02)
I must also mention that fixed point iteration is actually faster than even Newton's method for this problem. You can use the built-in fixed point iteration routine by defining f2
as follows:
def f2(x):
LHS = -2*numpy.log10((2.51/(Re*numpy.sqrt(x))) + (k/(3.71*d)))
return 1/LHS**2
Timings (starting further from the root to show speed of convergence):
%timeit root(f, 0.2)
1000 loops, best of 3: 428 µs per loop
%timeit fixed_point(f2, 0.2)
10000 loops, best of 3: 148 µs per loop
回答2:
Your tags are a little off: you're tagging it as sympy
which is a library for symbolic computations, but say that you want to solve it numerically. In case the latter is your actual intention, here are relevant scipy docs:
http://docs.scipy.org/doc/scipy/reference/tutorial/optimize.html#root-finding
来源:https://stackoverflow.com/questions/18880134/solving-colebrook-nonlinear-equation-in-python