Source code for Water.pumps

'''Pumps Module:

    This module calculates and produces pump curves based on mfg's data points
'''
from __future__ import print_function, division
import matplotlib.pyplot as plt
from numpy import linspace, any, interp, array
import sqlite3
from os import path

BASE_DIR = path.dirname(path.abspath(__file__))
db_path = path.join(BASE_DIR, "water.db")

[docs]class Pump: '''Defines Pump object to plot and/or affinitized pump curve and performance :param target_flow: target flow (gpm), *default None* :type target_flow: int :param target_head: target head (feet of water) *default None* :type target_head: int :Example: >>> from Water import Pump >>> pump_1 = Pump(target_flow=100, target_head=250) ''' def __init__(self, target_flow=None, target_head=None): self.target_flow = target_flow self.target_head = target_head self.flow = [] self.head = [] self.eff = [] self.bep = [None, None] self.model = None self.mfg = None self.rpm = None self.impeller = None self.fig = None self.ax = None self.affinity_data = []
[docs] def search_pump(self, pump_model, impeller=None): '''Checks sqlite database for existing pump record :param pump_model: pump model :param impeller: impeller diameter in inches, *default None* :type pump_model: string :type impeller: float :return: pump record if one exists :rtype: list ''' conn = sqlite3.connect(db_path) c = conn.cursor() existing_params = {'model' : pump_model, 'impeller' : impeller} if impeller: sqlquery='''SELECT * FROM pumps WHERE model=:model AND impeller=:impeller''' else: sqlquery='''SELECT * FROM pumps WHERE model=:model''' c.execute(sqlquery, existing_params) exists = c.fetchall() conn.commit() conn.close() if exists: return exists else: print("Pump could not be found in database") return None
[docs] def add_pump(self, **kwargs): '''Add a pump to the sqlite3 database :param \**kwargs: Use dictionary to specify parameters :type \**kwargs: dictionary :keyword Arguments: :model: (*string*) - pump model :mfg: (*string*) - pump manufacturer :flow: (*list*) - pump flows in acending order (gpm) :mfg: (*string*) - pump manufacturer :flow: (*list*) - pump flows in acending order (gpm) :head: (*list*) - pump head in respective to flow (ft) :eff: (*list*) - pump efficiencies respective to flow and head :bep: (*list*) - [flow, head] for best efficiency point :rpm: (*int*) - motor rpm :impeller: (*float*) - impeller diameter (inches) :Example: .. code-block:: python kwargs = { 'model' : 'abc123', 'mfg' : 'Acme', 'flow' : [0, 10, 20 ,30, 40, 50, 60, 70], 'head' : [300, 280, 275, 270, 250, 240, 220, 200], 'eff' : [0.50, 0.53, 0.58, 0.61, 0.66, 0.70, 0.68, 0.63], 'bep' : [220, 0.70], 'rpm' : 1800, 'impeller' : 5.125 } pump_1.add_pump(**kwargs) ''' self.flow = kwargs.get('flow', []) self.head = kwargs.get('head', []) self.eff = kwargs.get('eff', []) self.bep = kwargs.get('bep', [None, None]) self.model = kwargs.get('model', None) self.mfg = kwargs.get('mfg', None) self.rpm = kwargs.get('rpm', None) self.impeller = kwargs.get('impeller', None) conn = sqlite3.connect(db_path) c = conn.cursor() # check if pump currently exists in database exists = self.search_pump(self.model, self.impeller) if len(exists) == 0: sqlinsert = '''INSERT INTO pumps( manufacturer, model, maxFlow, minFlow, bestFlow, maxHead, minHead, bestHead, bestEff, rmp, impeller, flowArray, headArray, effArray) values( :mfg, :model, :maxFlow, :minFlow, :bestFlow, :maxHead, :minHead, :bestHead, :bestEff, :rpm, :impeller, :flowArray, :headArray, :effArray)''' params = {'mfg' : self.mfg, 'model': self.model, 'maxFlow' : max(self.flow), 'minFlow' : min(self.flow), 'bestFlow' : self.bep[0], 'maxHead' : max(self.head), 'minHead' : min(self.head), 'bestHead' : self.bep[1], 'bestEff': max(self.eff), 'rpm' : self.rpm, 'impeller': self.impeller, 'flowArray' : str(self.flow), 'headArray' : str(self.head), 'effArray' : str(self.eff)} print('Pump added to database') c.execute(sqlinsert, params) conn.commit() conn.close() else: print('Pump Model exists in the database, check below for specific parameters:') for each_pump in exists: print(each_pump[:12])
[docs] def available_pumps(self): '''returns pump table from pumps.db''' conn = sqlite3.connect(db_path) c = conn.cursor() c.execute('''SELECT pumpID, manufacturer, model, bestFlow, bestHead FROM pumps''') for eachPump in c.fetchall(): print(eachPump) conn.commit() conn.close()
[docs] def load_pump(self, mfg, model, impeller=None): '''Loads pump data from sqlite3 database into pump object :param mfg: pump manufacturer :type mfg: string :param model: pump model :type model: string :param impeller: pump impeller size in inches, *default None* :type impeller: float :Example: >>> pump_2 = Pump() >>> pump_2.load_pump('Goulds', '3657 1.5x2 -6: 3SS') ''' multiples = self.search_pump(model, impeller) print(multiples) if len(multiples) == 0: print('Pump does not exist in database.') elif len(multiples) > 1: print('Multiple pump models found in database, please include impeller diameter to select pump.') else: conn = sqlite3.connect(db_path) c = conn.cursor() params = {'mfg' : mfg, 'model' : model, 'impeller' : impeller} if impeller == None: sqlquery = '''SELECT * FROM pumps WHERE manufacturer=:mfg AND model=:model; ''' else: sqlquery = '''SELECT * FROM pumps WHERE manufacturer=:mfg AND model=:model AND impeller=:impeller ''' c.execute(sqlquery, params) pump = c.fetchall() if len(pump) > 0: pump = pump[0] self.mfg = pump[1] self.model = pump[2] self.bep = (pump[5], pump[8]) self.rpm = pump[10] self.impeller = pump[11] fstring = pump[12].strip('[]').split(',') hstring = pump[13].strip('[]').split(',') estring = pump[14].strip('[]').split(',') for f,h,e in zip(fstring, hstring, estring): self.flow.append(int(f)) self.head.append(int(h)) self.eff.append(float(e)) print('Pump loaded from database')
[docs] def delete_pump(self, pump_id): '''deletes a pump record from the database enter pump_id of pump to be deleted :param pump_id: pump id from pump table in database :type pump_id: int ''' conn = sqlite3.connect(db_path) c = conn.cursor() params = {'pumpID' : pump_id} c.execute('''SELECT * FROM pumps WHERE pumpID=:pumpID''',params) if len(c.fetchall()) > 0: c.execute('''DELETE FROM pumps WHERE pumpID=:pumpID''',params) print('pumpID', pump_id, 'was deleted from the database.') else: print('No pumps with pumpID', pump_id, 'was found in the database') conn.commit() conn.close()
@property def vfd_flow(self): '''affinitized array of pump flows property''' return self._affinitize(self.flow, 1) @property def vfd_head(self): '''affinitized array of heads property''' return self._affinitize(self.head, 2) @property def vfd_eff(self): '''affinitized array of efficiencies property''' return self._affinitize(self.eff, 3) def _affinitize(self, pump_data, pwr): '''creates affinitized curves for flow, head and efficiency for motor speeds at: Frequency =\n - 60 hz - 50 hz - 40 hz - 30 hz - 20 hz - 10 hz ''' percent_speed = (linspace(60,10,6)/60)**pwr for percent in percent_speed: self.affinity_data.append([data * percent for data in pump_data]) return self.affinity_data
[docs] def plot_curve(self, target_flow=None, tdh=None, vfd=True, eff=False, num_pumps=1, show=False, **kwargs): '''creates a matplotlib plot of the pump curve. Default is to plot affinitized curves with full speed curve. User has option to add parallel pumps, system curve and efficiency curve. Parallel pump curves only work when vfd=False. :param target_flow: flow point to plot (gpm), *default None* :type target_flow: int/float :param tdh: Total Dynamic Head (ft), *default None* :type tdh: int/float :param vfd: turn on/off affinitized pump curves, *default True* :type vfd: boolean :param eff: turn on/off pump efficiency curve, *default False* :type eff: boolean :param num_pumps: number of pumps in parallel *default 1* :type num_pumps: int :param show: show plot (keep false if using in an .ipynb file), *default False* :type show: boolean :param \**kwargs: matplotlib.pyplot.plot keyword arguments :return: pump curve for pump object :rtype: matplotlib.pyplot plot :Example: Plotting a pump curve with one design point with efficiency curve .. code-block:: python # design parameters FLOW = 100 # gpm TDH = 111 # ft head # define pump object and load pump data pump_1 = Pump() pump_1.load_pump('Goulds', '3657 1.5x2 -6: 3SS') # plot curve without affinitized curves and with efficiency curve pump_1.plot_curve(target_flow=FLOW, tdh=TDH, vfd=False, eff=True, show=True) .. image:: ./images/pump_ex1.png See :doc:`Pump Class Example <tutorial>` for affinitize curve functionality and how to plot a system curve along with the pump curve. ''' if self.impeller: title_str = 'Pump: ' + self.model + ' - ' + str(self.rpm) + ' RPM - ' + str(self.impeller) + '" impeller' else: title_str = 'Pump: ' + self.model + ' - ' + str(self.rpm) + ' RPM' self.fig, self.ax = plt.subplots(2,1,figsize=(8,4.95)) plt.style.use('seaborn-whitegrid') if eff: self.ax[0] = plt.subplot2grid((3,1), (0,0), rowspan=2) self.ax[1] = plt.subplot2grid((3,1), (2,0)) self.ax[1].plot(self.flow, self.eff, label='efficiency', color='grey') self.ax[1].set_ylabel('efficiency') self.ax[1].set_xlabel('flow (gpm)') self.ax[1].grid(True, alpha=0.5, which='both') else: self.ax[0] = plt.subplot2grid((2,1), (0,0), rowspan=2) self.ax[0].set_xlabel('flow (gpm)') if vfd: labels = ['60Hz', '50Hz', '40Hz', '30Hz', '20Hz', '10Hz'] for h, l in zip(self.vfd_head, labels): self.ax[0].plot(self.flow, h, label=l, **kwargs) else: for n in range(1,num_pumps+1): self.ax[0].plot(array(self.flow)*n, self.head, label='pump # ' + str(n), **kwargs) if any(target_flow) and any(tdh): self.ax[0].plot(target_flow, tdh, '.-.', color="red", label='system', markersize=5, lw=0.75) self.ax[0].grid(True, alpha=0.5, which='both',) self.ax[0].set_title(title_str) self.ax[0].set_ylabel('head (ft)') self.ax[0].legend() self.ax[1].legend() self.fig.tight_layout() plt.draw() if show: plt.show()
[docs] def find_head(self, flow): ''' Returns head value from pump curve based on flow input. If flow is not a known value it will interprolate between the two closest points on the curve. :param flow: pump flow (gpm) :type flow: int/float :return: head value from curve data :rtype: float :Example: >>> Q = 125 >>> h = pump_1.find_head(Q) >>> print(h, 'ft') 100.125 ft ''' try: if flow in self.flow: head = self.head[self.flow.index(flow)] else: head = interp(flow, self.flow, self.head) except ValueError: print("Value not found, check you numbers") return head
######################################## if __name__=="__main__": from numpy import exp print('test script:') pump = Pump() pump2 = Pump() pump.load_pump('Goulds', '3657 1.5x2 -6: 3SS') pump2.load_pump('Grundfos', 'CM10-2-A-S-G-V-AQQV') system_flow = linspace(1, 150, 30) system_head = [] for flow in system_flow: system_head.append(100 + 20*exp(-1/(flow*.005))) design_x = 50 design_y = 60 pump.plot_curve(system_flow, system_head, vfd=False, eff=True, num_pumps=2) pump2.plot_curve(design_x, design_y, eff=True) plt.show() ## example of pump database use new_pump_data = { 'model' : 'test pump', 'mfg' : 'Acme', 'flow' : [1,2,3,4,5,6,7,8], 'head' : [8,7,6,5,4,3,2,1], 'eff' : [.1,.2,.3,.4,.5,.6,.7,.8], 'bep' : [5,5], 'rpm' : 1800, 'impeller' : '5.5' } pump.add_pump(**new_pump_data) pump.available_pumps() conn = sqlite3.connect(db_path) c = conn.cursor() c.execute('''Select pumpID From pumps Where model='test pump' ''') pump_id = c.fetchall() pump.delete_pump(pump_id=pump_id[0][0]) pump.available_pumps() conn.commit() conn.close()