0

I am basically building a general tool for solving for the operating point of a pump in a system - i.e., two equations and two unknowns - pump curve/system curve and head (H) and flowrate (Q).

My posted example is not purely MWE, but is grouped in 3 sections and is easy to follow.

First is the imports and symbols.

Second is the pump curve fit (in case it is relevant to being one of the 'equations').

Third is the class and its use (where the problem is I believe).


import pint
u = pint.UnitRegistry()

from sympy import *
from sympy.solvers import solve
from sympy import Symbol, symbols, Eq

m, n = symbols('m n')
Q, H = symbols('Q H')
m = m*u.foot
n = n*u.foot**2

import numpy as np
globalPi = np.pi

import os

import pandas as pd
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit


# =========================================
# =========================================



# https://www.askpython.com/python/examples/curve-fitting-in-python
# Red Lion RL-SWJ100 @ 5' lift
x_data = np.array([ 17.3, 17, 12.9, 8.5, 4.4 ])
y_data = np.array([ 20, 30, 40, 50, 60])
 
plt.scatter(x_data , y_data)
plt.show()

#Defining our function
#def fit_f(x,a,b,c,d):
def fit_f(x,a,b,c):
#  return a*(x-b)**2+c+d*0.0001*np.cos(x)
  return a*(x-b)**2+c

#using our curve_fit() function
#popt, pcov = curve_fit(fit_f,x_data,y_data,p0=[1,2,-16,1])
popt, pcov = curve_fit(fit_f,x_data,y_data,p0=[1,2,6])
print(popt)
print(pcov)

#a_opt, b_opt, c_opt, d_opt = popt
a_opt, b_opt, c_opt = popt
x_model = np.linspace(min(x_data), max(y_data), 100)
#y_model = fit_f(x_model, a_opt, b_opt, c_opt,d_opt) 
y_model = fit_f(x_model, a_opt, b_opt, c_opt) 
 
plt.scatter(x_data, y_data)
plt.plot(x_model, y_model, color='r')
plt.title("title")
plt.xlabel('Q')
plt.ylabel('H')
plt.xlim(0,30)
plt.ylim(0,80)

fit_f(10,a_opt,b_opt,c_opt)

fit_f(Q,a_opt,b_opt,c_opt)



# =========================================
# =========================================



class Problem:
    name = "system_curve"
    
    def __init__(self, e):
        self.e = e
        
    def pumpHeadNeededWithExtraHead(self):
        def pumpHeadNeeded():
            print("Extra head (loss or gain) is: ", self.e)

#            eq1 = Eq(Q**2 - 3*H,0)
#            eq2 = Eq(Q - 2*H**2,4)
            eq1 = Eq( m**2 , n )
            eq2 = Eq(-m**2 - n , 3*u.foot**2)
#            tmp = solve([eq1, eq2],Q,H)
            tmp = solve([eq1, eq2],m,n)
            
            print(  N(  tmp[1][0]  ,4) )
            self.height = tmp[0]*u.foot
            return self.height
        self.pumpHeadNeeded = pumpHeadNeeded
        return pumpHeadNeeded
    

a = Problem(0*u.foot)

a.pumpHeadNeededWithExtraHead()()

The equations with Q & H have no units and can be solved easily.

The equations that are commented (x has units ft, y has units of ft**2) have each term dimensionally consistent.

The output from Spyder (though I am using Jupyter too) is;

runfile('C:/untitled0.py', wdir='C:/')
[-0.07771575 -6.6559499  69.03248368]
[[ 1.41000834e-02 -3.23123342e+00  4.11231816e+00]
 [-3.23123342e+00  7.47431731e+02 -9.62567370e+02]
 [ 4.11231816e+00 -9.62567370e+02  1.26208086e+03]]
Extra head (loss or gain) is:  0 foot
Traceback (most recent call last):

  File "C:\Users\name\Anaconda3\Libsite-packages\sympy\multipledispatch\dispatcher.py", line 234, in __call__
    func = self._cache[types]

KeyError: (<class 'pint.quantity.build_quantity_class.<locals>.Quantity'>, <class 'pint.quantity.build_quantity_class.<locals>.Quantity'>)


During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File "C:\untitled0.py", line 104, in <module>
    a.pumpHeadNeededWithExtraHead()()

  File "C:\untitled0.py", line 90, in pumpHeadNeeded
    eq1 = Eq( m**2 , n )

  File "C:\Users\name\Anaconda3\Lib\site-packages\sympy\core\relational.py", line 506, in __new__
    val = is_eq(lhs, rhs)

  File "C:\Users\name\Anaconda3\Lib\site-packages\sympy\core\relational.py", line 1362, in is_eq
    retval = _eval_is_eq(lhs, rhs)

  File "C:\Users\name\Anaconda3\Lib\site-packages\sympy\multipledispatch\dispatcher.py", line 238, in __call__
    raise NotImplementedError(

NotImplementedError: Could not find signature for _eval_is_eq: <Quantity, Quantity>

If the three hash marks are traded to the other equations, it runs just fine on my laptop.

Thanks!

nate
  • 269
  • 2
  • 11
  • Since your update basically answers your question, you should remove it from your question and post it as an _answer_. If you feel your question has been satisfactorily answered by your own answer, you can even accept it. – Pranav Hosangadi Nov 06 '22 at 02:06
  • Okay, I was going to work on finishing the whole thing, but can append that to the above answer. Thanks, will do – nate Nov 06 '22 at 02:07

1 Answers1

0

I commented out the module Pint stuff at the very top, and the m and n defined there, and replaced it with sympy units,

from sympy.physics import units as u
from sympy.abc import m, n
m = m*u.feet
n = n*u.feet**2

and now I can solve Eq() equations with units...

class Problem:
    name = "system_curve"
    
    def __init__(self, e):
        self.e = e
        
    def pumpHeadNeededWithExtraHead(self):
        def pumpHeadNeeded():
            print("Extra head (loss or gain) is: ", self.e)

            eq1 = Eq( m**2 - n, 0*u.foot**2)
            eq2 = Eq(-m**2 - n + 3*u.foot**2 , 0*u.foot**2)
            tmp = solve([eq1, eq2],[m,n])
            print(tmp)
            print(type(tmp))
            print("length of list is: ",len(tmp))
            print(tmp[1])
            print(tmp[1][1])
            self.height = tmp[len(tmp)-1]
            return self.height
        self.pumpHeadNeeded = pumpHeadNeeded
        return pumpHeadNeeded
    

a = Problem(0*u.foot)

a.pumpHeadNeededWithExtraHead()()

a1 = a.pumpHeadNeededWithExtraHead()()
print(a1)
print(list(map(lambda s: N(s,4), a1)))

whose output is,

[-0.07771575 -6.6559499  69.03248368]
[[ 1.41000834e-02 -3.23123342e+00  4.11231816e+00]
 [-3.23123342e+00  7.47431731e+02 -9.62567370e+02]
 [ 4.11231816e+00 -9.62567370e+02  1.26208086e+03]]
Extra head (loss or gain) is:  0
[(-sqrt(6)*foot/2, 3*foot**2/2), (sqrt(6)*foot/2, 3*foot**2/2)]
<class 'list'>
length of list is:  2
(sqrt(6)*foot/2, 3*foot**2/2)
3*foot**2/2
Extra head (loss or gain) is:  0
[(-sqrt(6)*foot/2, 3*foot**2/2), (sqrt(6)*foot/2, 3*foot**2/2)]
<class 'list'>
length of list is:  2
(sqrt(6)*foot/2, 3*foot**2/2)
3*foot**2/2
(sqrt(6)*foot/2, 3*foot**2/2)
[1.225*foot, 1.5*foot**2]

(Further refinements coming, probably)

nate
  • 269
  • 2
  • 11