Python & SciPy - use fsolve with COM connection - python

I am trying to use scipy Optimize fsolve function to find the zero of a function defined using a COM object.
First, I create the COM object:
import win32com.client
os = win32com.client.Dispatch("PX32.OpenServer.1")
This COM object works as an interface to a program where I input variables, then make calculations, and obtain results, using the setvalue, docommand and getvalue methods/functions.
If I define a function like:
def fn(x):
os.setvalue("INPUT_VAR_STRING", x)
os.docommand("COMMAND_STRING")
return float(os.getvalue("RESULT_STRING"))
By changing the input value (passed into fn through x), I get different output values:
fn(100)
> 18.139818203
fn(190)
> -40.93182830
But, if I try to use fsolve to find the root of the fn function, I get an error:
from scipy.optimize import fsolve
fsolve(fn,150)
> TypeError
> (...)
> TypeError: Internal error - the buffer length is not the sequence length!
What does this mean? How can I try to solve this error that has appeared?

I found the problem. According to http://kitchingroup.cheme.cmu.edu/pycse/pycse.html,
12.11 Using an external solver with Aspen
(...)
flashT = float(flashT) # COM objects do not understand numpy types
That was the main thing. I had to change
os.setvalue("INPUT_VAR_STRING", x) for
os.setvalue("INPUT_VAR_STRING", float(x)) to get the expected results.

Related

Python - Tring to find the integral after knowing how to analytically solve it using Contour Integration

So, if the title is not clear, I am trying to take the function [sin(x)/(x3-2*x2+4x-8)] and find the integral. I know that the analytical solution is (-pi/(8e**2))+(pi/8)*cos(2) or ~ -0.2165...
The code that I can not seem create properly so far looks like
import numpy as np
from sympy import integrate
from sympy.abc import x
f = integrate(np.sin(x)/(x**3-2*x**2+4x-8), (x, -5, 2))
print(f)
I would like the code to eventually be drawn out which I plan on doing myself, however, this gives me the error
"TypeError: loop of ufunc does not support argument 0 of type Symbol which has no callable sin method"
How do I go about fixing this?

Problems regarding Pyomo-provided math functions

I am trying to solve a bilevel problem using Pyomo in Python. However, when I try to run the code, I am getting the following error:
"Implicit conversion of Pyomo NumericValue type `mon' to a float is disabled. This error is often the result of using Pyomo components as arguments to one of the Python built-in math module functions when
defining expressions. Avoid this error by using Pyomo-provided math functions."
In Pyomo's documentation there is no reference to Pyomo-provided functions. I want to know how I can modify the penultimate line of code shown so that model.rn[i,j] meet the integer requirement?
The following is my code:
import random
import matplotlib.pyplot as plt
import numpy as np
from pyomo.environ import *
from pyomo.bilevel import *
from pyomo.bilevel.components import SubModel
from pyomo.opt import SolverFactory
capacity =[150,80, 65]
model = ConcreteModel()
model.sub = SubModel()
model.M=RangeSet(1,3)
model.N=RangeSet(1,12)
model.f= Param(model.M,model.N,within=NonNegativeIntegers,initialize=20)
model.v= Param(model.M,model.N,within=NonNegativeIntegers)
model.sub.x = Param(within=Binary)
model.r= Var(model.M,model.N,within=PercentFraction)
model.rp= Var(model.M,model.N,within=NonNegativeReals,bounds=(0, 10))
model.rn = Var(model.M, model.N, within=NonNegativeIntegers)
model.un= Var(model.M,model.N,within=NonNegativeIntegers)
for j in range(1,13):
model.v[1,j] = capacity[0]-model.f[1,j]
model.v[2,j] = capacity[1]-model.f[2,j]
model.v[3,j] = capacity[2]-model.f[3,j]
for j in range(1,13):
for i in range(1,4):
model.rn[i,j]=floor(model.v[i,j]*model.r[i,j])
model.un[i,j]=model.v[i,j]-model.rn[i,j]
That's tricky to do. As far as I know, it may only work on the values of that pyomo object as model.r is a pyomo object. It is not a problem on a parameter but the variable.
You may want to write out constraints that models the python 'floor' function instead.

how to generate the values for the Q function

I am trying to apply the Q-function values for a problem. I don't know the function available for it in Python.
What is the python equivalent for the following code in octave?
>> f=0:0.01:1;
>> qfunc(f)
The Q-function can be expressed in terms of the error function. Check here for more info. "scipy" has the error function, special.erf(), that can be used to calculate the Q-function.
import numpy as np
from scipy import special
f = np.linspace(0,1,101)
0.5 - 0.5*special.erf(f/np.sqrt(2)) # Q(f) = 0.5 - 0.5 erf(f/sqrt(2))
Take a look at this https://docs.scipy.org/doc/scipy-0.19.1/reference/generated/scipy.stats.norm.html
Looks like the norm.sf method (survival function) might be what you're looking for.
I've used this Q function for my code and it worked perfectly well,
from scipy import special as sp
def qfunc(x):
return 0.5-0.5*sp.erf(x/sqrt(2))
I'vent used this one but I think it should work,
def invQfunc(x):
return sqrt(2)*sp.erfinv(1-2x)
references:
https://mail.python.org/pipermail/scipy-dev/2016-February/021252.html
Python equivalent of MATLAB's qfuncinv()
Thanks #Anton for letting me know how to write a good answer

How to use Sympys NumPyPrinter?

I am trying to print my Sympy-expression as a string ready to be used with Numpy. I just cannot figure out how to do it.
I found that there is sp.printing.pycode: https://docs.sympy.org/latest/_modules/sympy/printing/pycode.html
The web page states that "This module contains python code printers for plain python as well as NumPy & SciPy enabled code.", but I just cannot figure out how to get it to output the expression numpy format.
sp.printing.pycode(expr)
'math.cos((1/2)*alpha)*math.cos((1/2)*beta)'
That web page also contain class NumPyPrinter(PythonCodePrinter) but I do not know how to use it. def pycode(expr, **settings) just seems to use return PythonCodePrinter(settings).doprint(expr) as a default all the time.
The definition of pycode is almost trivial:
def pycode(expr, **settings):
# docstring skipped
return PythonCodePrinter(settings).doprint(expr)
It should be straight forward to run NumPyPrinter().doprint(expr) instead. The problem is that sympy.printing re-exports the pycode function which shadows the module with the same name. However, we can still import the class directly and use it:
import sympy as sy
from sympy.printing.pycode import NumPyPrinter
x = sy.Symbol('x')
y = x * sy.cos(x * sy.pi)
code = NumPyPrinter().doprint(y)
print(code)
# x*numpy.cos(numpy.pi*x)

How can I make a transfer function for an RC circuit in python

I'm fairly new to programming, but this problem happens in python and in excel as well.
I'm using the following formulas for the RC transfer function
s/(s+1) for High Pass
1/(s+1) for Low Pass
with s = jwRC
below is the code I used in python
from pylab import *
from numpy import *
from cmath import *
"""
Generating a transfer function for RC filters.
Importing modules for complex math and plotting.
"""
f = arange(1, 5000, 1)
w = 2.0j*pi*f
R=100
C=1E-5
hp_tf = (w*R*C)/(w*R*C+1) # High Pass Transfer function
lp_tf = 1/(w*R*C+1) # Low Pass Transfer function
plot(f, hp_tf) # plot high pass transfer function
plot(f, lp_tf, '-r') # plot low pass transfer function
xscale('log')
I can't post images yet so I can't show the plot. But the issue here is the cutoff frequency is different for each one. They should cross at y=0.707, but they actually cross at about 0.5.
I figure my formula or method is wrong somewhere, but I can't find the mistake can anyone help me out?
Also, on a related note, I tried to convert to dB scale and I get the following error:
TypeError: only length-1 arrays can be converted to Python scalars
I'm using the following
debl=20*log(hp_tf)
This is a classical example why you should avoid pylab and more generally imports of the form
from module import *
unless you know exactly what it does, since it hopelessly clutters the name space.
Using,
import matplotlib.pyplot as plt
import numpy as np
and then calling np.log and plt.plot etc. will solve your problem.
Furether explanations
What's happening here is that,
from pylab import *
defines a log function from numpy that operate on arrays (the one you want).
However, the later import,
from cmath import *
overwrites it with a version that only accepts scalars, hence your error.

Categories

Resources