Search code examples
pythonarraysnumpygridatan

Performing a calculation over an x,y grid in Python


I'd like to perform a calculation over an X, Y data to produce a calculated Z. My code is below:

Example Data set for injection_wells.csv

Name X Y Q
MW-1 2517700 996400 5
MW-2 2517770 996420 5
import pandas as pd
import math
import numpy as np
import matplotlib.mlab as mlab
import matplotlib.tri as tri

IW = pd.read_csv (r'Injection_wells.csv')

`Note that - Injection wells is a table of three wells with names, X, Y, and Q (flow rate).`

#pull all the relevant well information by well into their own arrays

MW1 = IW[IW['Name'] == 'MW1']
MW2 = IW[IW['Name'] == 'MW2']
MW3 = IW[IW['Name'] == 'MW3']

#initiate grid
xi = np.linspace(2517675,2517800,625)
yi = np.linspace(996300,996375,375)

#make it so i can apply np.float to an array
vector = np.vectorize(np.float)

X,Y = np.meshgrid(xi,yi)

#perform calculation over every X and Y.
PSI = ((MW1['Q']/(2*math.pi))*(np.arctan(((vector(X[None,:]))-np.float(MW1['X']))/(vector(Y[:,None])-np.float(MW1['Y']))))+
      (MW2['Q']/(2*math.pi))*(np.arctan(((vector(X[None,:])-np.float(MW2['X']))/vector((Y[:,None])-np.float(MW2['Y'])))))+
      (MW3['Q']/(2*math.pi))*(np.arctan(((vector((X[None,:])-np.float(MW3['X']))/vector((Y[:,None])-np.float(MW3['Y'])))))))

I get the error:

ValueError                                Traceback (most recent call last)
<ipython-input-11-fd6ee058014f> in <module>
     17 X,Y = np.meshgrid(xi,yi)
     18 
---> 19 PSI = ((MW1['Q']/(2*math.pi))*(np.arctan(((vector(X[None,:]))-np.float(MW1['X']))/(vector(Y[:,None])-np.float(MW1['Y']))))+
     20       (MW2['Q']/(2*math.pi))*(np.arctan(((vector(X[None,:])-np.float(MW2['X']))/vector((Y[:,None])-np.float(MW2['Y'])))))+
     21       (MW3['Q']/(2*math.pi))*(np.arctan(((vector((X[None,:])-np.float(MW3['X']))/vector((Y[:,None])-np.float(MW3['Y'])))))))

~\Anaconda3\lib\site-packages\pandas\core\ops\common.py in new_method(self, other)
     63         other = item_from_zerodim(other)
     64 
---> 65         return method(self, other)
     66 
     67     return new_method

~\Anaconda3\lib\site-packages\pandas\core\ops\__init__.py in wrapper(left, right)
    343         result = arithmetic_op(lvalues, rvalues, op)
    344 
--> 345         return left._construct_result(result, name=res_name)
    346 
    347     wrapper.__name__ = op_name

~\Anaconda3\lib\site-packages\pandas\core\series.py in _construct_result(self, result, name)
   2755         # We do not pass dtype to ensure that the Series constructor
   2756         #  does inference in the case where `result` has object-dtype.
-> 2757         out = self._constructor(result, index=self.index)
   2758         out = out.__finalize__(self)
   2759 

~\Anaconda3\lib\site-packages\pandas\core\series.py in __init__(self, data, index, dtype, name, copy, fastpath)
    311                 try:
    312                     if len(index) != len(data):
--> 313                         raise ValueError(
    314                             f"Length of passed values is {len(data)}, "
    315                             f"index implies {len(index)}."

ValueError: Length of passed values is 375, index implies 1.

I know that this has something to do with me trying to apply a function to an array that only accepts one value. I am trying to overcome this issue and be able to perform this calculation as is on the entire gridded data set. Any help on this would be greatly appreciated.

The equation i'm trying to do is below. Note that the theta in the equation is the arc tan of distance from the grid node to the injection well (for each grid node) which is what i'm trying to replicate in the code.

Equation for the code below

Thanks


Solution

  • I'm gonna jump the gun here as I think I understand the problem now, after looking at it a bit more.

    So you've got a DataFrame of injection well data, with four columns:

    name    x    y    q
    str   int  int  int
    

    And you have a function f(x, y, q) -> z that you want to evaluate. I'm not sure I follow exactly what your function is doing because it's formatted in such a way that it's pretty hard to read, so I'll use a simplified example:

    def func(x, y, q):
        return (q / 2 * np.pi) * np.arctan(y, x)
    

    Now instead of breaking your well data into different arrays, simply apply the function over the entire dataframe row-wise:

    df["z"] = func(df.x, df.y, df.q)