Водопьян А.О. Хабибуллин Р.А. 2019 г.

## Газосодержание

### Газосодержание, корреляция Стендинга

Для расчета газосодержания используется корреляция, обратная корреляции Стендинга для давления насыщения нефти газом.

$$ R_s =  \gamma_g  \left( \frac{1.92 p}{\ 10^{y_g}}\right)^{1.204} $$

где:

$R_s$ - газосодержание, $м^3/м^3 $

$P$ - давление, $МПа$

$\gamma_g$ - относительная плотность газа, безразмерная величина

$y_g$ - мольная доля газа, $ y_g = 1.225 +0.00164 T - \frac{ 1.769}{\gamma_o}$

$\gamma_o$ - относительная плотность нефти, безразмерная величина

$ T $ - температура, $ ^{\circ}\mathrm{K}$

Газосодержание является одним из ключевых свойств нефти при расчётах производительности скважин и работы скважинного оборудования. Динамика изменения газосодержания во многом определяет количество свободного газа в потоке и должна учитываться при проведении расчётов.

Если известно газосодержание при давлении насыщения, то газосодержание при давлениях ниже давления насыщения может быть получено из пропорции:

$$ R_s =  \ R_{sb}\left( \frac{p}{\ P_b}\right)^{1.204} $$

где:

$R_s$ - газосодержание, $м^3/м^3 $

$P$ - давление, $МПа$

$P_b$ - давление насыщения, $МПа$

$R_{sb}$ - газосодержание при давлении насыщения, $м^3/м^3 $

Корреляции Standing базируются на 105 экспериментально определенных давлениях насыщения нефтяных систем Калифорнии. Диапазоны значений основных свойств, использованных для разработки данной корреляции, приведены в таблице ниже.

|
 Параметр  | Диапазон |
| :--- | :--- |
|
 давление насыщения,$P_b$ , $ МПа $  | 0.896…48.263  |
|
 температура, $^{\circ}\mathrm{K} $ | 310…400 |
|
 газосодержание при давлении насыщения, $R_{sb}$ , $м^3/м^3 $ | 3.6…254 |
|
 относительная плотность нефти по воде, $\gamma_o$ | 0.725…0.956  |
|
 относительная плотность газа, $\gamma_g$  | 0.59…0.95  |

ref "A Pressure-Volume-Temperature Correlation for Mixtures of California Oil and Gases", M.B. Standing, Drill. & Prod. Prac., API, 1947.

```python
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
from sympy import *
init_printing()
import sys
sys.path.append('../')
import uniflocpy.uPVT.PVT_correlations as PVT
```

```python
# Корреляция Стендинга для газосодержания реализована
# в виде функции unf_Rs_Standing_m3m3 в модуле PVT_correlations.
# Подробные данные по функции включая исходный код приведены ниже

PVT.unf_rs_Standing_m3m3??
```

```python
# параметры определяющие диапазоны значений для построения графиков
p_set=np.arange(1,300,10)
t_set=np.arange(273,380,30)
t_set_def=np.array([313])
gg_set=np.arange(0.6,1,0.1)
gg_set_def=np.array([0.8])
go_set=np.arange(0.8,1,0.05)
go_set_def=np.array([0.86])
# функция для автоматизации построения графиков по давлению насыщения
def prep_plot(func,tset,goset,ggset,plot_title,plot_xlab,plot_ylab):
    for t in tset:
        for gg in ggset:
            for go in goset:
                Rs_set=[]
                for p in p_set:
                    Rs_set.append(func(p,t_K = t,gamma_gas = gg,gamma_oil = go))
                plt.plot(p_set, Rs_set, label='t = %1.0f $ ^{\circ}\mathrm{K}$'%t +
                                                 ' $\gamma_g$ = %1.2f'%gg +
                                                 ' $\gamma_o$ = %1.2f'%go)
    plt.title(plot_title)
    plt.ylabel(plot_ylab, color = 'black')
    plt.xlabel(plot_xlab, color = 'black')
    plt.legend()
```

```python
# код для построения графиков
plt.figure(figsize=(15,8))
f = PVT.unf_rs_Standing_m3m3
# рисуем первый график
plt.subplot(221)
prep_plot(f,t_set,go_set_def,gg_set_def,
              'Газосодержание от давления',
               '$P, MPa$',
               '$R_s, м^3/м^3$')
plt.grid()
# рисуем второй график
plt.subplot(222)
prep_plot(f,t_set_def,go_set,gg_set_def,
              'Газосодержание от давления',
               '$P, MPa$',
               '$R_s, м^3/м^3$')
plt.grid()
# рисуем третий график
plt.subplot(223)
prep_plot(f,t_set_def,go_set_def,gg_set,
              'Газосодержание от давления',
               '$P, MPa$',
               '$R_s, м^3/м^3$')

plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25, wspace=0.35)
# рисуем все
plt.grid()
plt.show()
```

### Газосодержание, корреляция Веларде-Маккейна

Корреляция Веларде-Маккейна (1999) для газосодержания базируется на 718 лабораторных исследованиях разгазирования различных нефтей со всего мира.

$$ R_s = R_{sb}R_{sr}   $$

где:

$R_s$ - газосодержание, $м^3/м^3$

$R_{sb}$ - газосодержание при давлении насыщения, $м^3/м^3$

$R_{sr}=a_1p_r^{a_2} + (1-a_1)p_r^{a_3}$ - приведенное газосодержание

$p_r=\frac{(p-14,7)}{(p_b-14,7)}$ - степень превышения давления, $psig/psig$

$a_1=9.73 \cdot 10^{-7}\gamma_{gSP}^{1.672608}API^{0.929870}T^{0.247235}(p_b-14.7)^{1.056052}$

$a_2=0.022339 \gamma_{gSP}^{-1.004750}API^{0.337711}T^{0.132795}(p_b-14.7)^{0.302065}$

$a_3=0.725167 \gamma_{gSP}^{-1.485480}API^{-0.164741}T^{-0.091330}(p_b-14.7)^{0.047094}$

В приведенной таблице представлены диапазоны значений использованных для создания корреляции:

|
 Параметр  | Мин|Среднее|Макс|
| :--- | :---: |:---:|:---:|
|
 давление насыщения,$P_b$ , $ МПа $  | 2.861  |15.706|53.434|
|
 температура, $^{\circ}\mathrm{С} $ | 21 |86|160|
|
 относительная плотность газа на сепараторе, $\gamma_g$  | 0.555  |0.793|1.472|
|
 объемный коэффициент нефти при давлении насыщения, $B_{ob}$ , $ м^3/м^3 $ | 1.012  |1.358|2.042|

```python
# Корреляция Веларде для газосодержания реализована
# в виде функции unf_Rs_Velarde_m3m3 в модуле PVT_correlations.
# Подробные данные по функции включая исходный код приведены ниже

PVT.unf_rs_Velarde_m3m3??
```

```python
# параметры определяющие диапазоны значений для построения графиков
p_set=np.arange(1,11,0.25)
t_set=np.arange(294,400,30)
t_set_def=np.array([313])
gg_set=np.arange(0.6,1,0.1)
gg_set_def=np.array([0.8])
go_set=np.arange(0.8,1,0.05)
go_set_def=np.array([0.86])
# функция для автоматизации построения графиков по давлению насыщения
def prep_plot(func,tset,goset,ggset,plot_title,plot_xlab,plot_ylab):
    for t in tset:
        for gg in ggset:
            for go in goset:
                Rs_set=[]
                for p in p_set:
                    Rs_set.append(func(p,t_K = t,gamma_gas = gg,gamma_oil = go))
                plt.plot(p_set, Rs_set, label='t = %1.0f $ ^{\circ}\mathrm{K}$'%t +
                                                 ' $\gamma_g$ = %1.2f'%gg +
                                                 ' $\gamma_o$ = %1.2f'%go)
    plt.title(plot_title)
    plt.ylabel(plot_ylab, color = 'black')
    plt.xlabel(plot_xlab, color = 'black')
    plt.legend()
```

```python
# код для построения графиков
plt.figure(figsize=(15,8))
f = PVT.unf_rs_Velarde_m3m3
# рисуем первый график
plt.subplot(221)
plt.grid()
prep_plot(f,t_set,go_set_def,gg_set_def,
              'Газосодержание от давления',
               '$P, MPa$',
               '$R_s, м^3/м^3$')
# рисуем второй график
plt.subplot(222)
plt.grid()
prep_plot(f,t_set_def,go_set,gg_set_def,
              'Газосодержание от давления',
               '$P, MPa$',
               '$R_s, м^3/м^3$')
# рисуем третий график
plt.subplot(223)
prep_plot(f,t_set_def,go_set_def,gg_set,
              'Газосодержание от давления',
               '$P, MPa$',
               '$R_s, м^3/м^3$')

plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25, wspace=0.35)
# рисуем все
plt.grid()
plt.show()
```

###  Газосодержание при давлении насыщения, Корреляция Маккейна если известны данные в сепараторе и резервуаре

Во многих корреляциях используется в качестве исходного параметра - газосодержание при давлении насыщения. Значение этого параметра может быть получено с помощью полевых данных как сумма отделяемого газового фактора в сепараторе и резервуаре для товарной нефти.

$$ R_{sb} = R_{sp} + R_{st}   $$

где:

$R_{sb}$ - газосодержание при давлении насыщения, $м^3/м^3$

$R_{sp}$ - газовый фактор, отделяемый в сепараторе, $м^3/м^3$

$R_{st}$ -  газовый фактор в резервуаре для товарной нефти, $м^3/м^3$

Данное уравнение справедливо только если пластовое давление выше давления насыщения

---

Расход газа и дебит нефти в сепараторе обычно измеряются, когда как в резервуаре газ обычно выпускается и не замеряется. Поэтому для более точной оценки газосодержания пластовой нефти при давлении насыщения необходимо оценить газовый фактор в резервуаре.
Таким образом, был разработана формула на основе GRACE-алгоритма на базе 898 исследований пластового флюида. В таблице приведены набор данных для исследования.

$$ ln R_{st} = 3.955 + 0.83z - 0.024z^2 + 0.075z^3 $$

$$ z =\sum_{n=1}^3 z_n $$

$$ z_n = C0_n + C1_nVAR_n + C2_nVAR_n^2 $$

|
 $$n$$  | $$VAR$$|$$CO$$|$$C1$$|$$C2$$|
| :--- | :---: |:---:|:---:|:---:|
|
 $$1$$  | $$ln p_{sp} $$ |$$-8.005$$|$$2.7$$|$$-0.161$$|
|
 $$2$$  | $$ln T_{sp}$$  |$$1.224$$|$$-0.5$$|$$0$$|
|
 $$3$$ | $$API$$  |$$-1.587$$|$$0.0441$$|$$-2.29 \cdot  10 ^{-5}$$|

$$T_{sp} - °F, p_{sp} - psia $$

Выражение для вычисления газового фактора в резервуаре требует знать температуру и давление в сепараторе, которые обычно не всегда бывают известны. Поэтому в этом случае можно использовать следующее уравнение.

$$ R_{sb} = 1.1618 R_{sp}   $$

```python
# Корреляция Маккейна для газосодержания при давлении насыщения реализована
# в виде функции unf_Rsb_Mccain_m3m3 в модуле PVT_correlations.
# Подробные данные по функции включая исходный код приведены ниже

PVT.unf_rsb_Mccain_m3m3??
```

```python
# параметры определяющие диапазоны значений для построения графиков
p_set=np.arange(1,11,0.25)
t_set=np.arange(294,400,30)
t_set_def=np.array([313])
go_set=np.arange(0.8,1,0.05)
go_set_def=np.array([0.86])
r_sp = 50
# функция для автоматизации построения графиков по давлению насыщения
def prep_plot(func,tset,goset,plot_title,plot_xlab,plot_ylab):
    for t in tset:
            for go in goset:
                Rs_set=[]
                for p in p_set:
                    Rs_set.append(func(r_sp,go,p,t))
                plt.plot(p_set, Rs_set, label='t = %1.0f $ ^{\circ}\mathrm{K}$'%t +
                                                  ' $\gamma_o$ = %1.2f'%go)
    plt.title(plot_title)
    plt.ylabel(plot_ylab, color = 'black')
    plt.xlabel(plot_xlab, color = 'black')
    plt.legend()
```

```python
# код для построения графиков
plt.figure(figsize=(15,8))
f = PVT.unf_rsb_Mccain_m3m3
# рисуем первый график
plt.subplot(221)
plt.grid()
prep_plot(f,t_set,go_set_def,
              'Газосодержание от давления в сепараторе',
               '$P, MPa$',
               '$R_s, м^3/м^3$')
# рисуем второй график
plt.subplot(222)
plt.grid()
prep_plot(f,t_set_def,go_set,
              'Газосодержание от давления в сепараторе',
               '$P, MPa$',
               '$R_s, м^3/м^3$')

plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25, wspace=0.35)
# рисуем все
plt.show()
```

notebooks/uPVT. Solution Gas-oil ratio.ipynb


# Find worst cases

\begin{equation}
\begin{array}{rl}
    \mathcal{F}_L =& \dfrac{4 K I H r}{Q_{in}(1+f)}\\
    u_{c} =& \dfrac{-KI\mathcal{F}_L}{\theta \left(\mathcal{F}_L+1\right)}\\
    \tau =& -\dfrac{r}{|u_{c}|}\\
    C_{\tau,{\rm decay}}=& C_0 \exp{\left(-\lambda \tau \right)}\\
    C_{\tau,{\rm filtr}}=& C_0 \exp{\left(-k_{\rm att} \tau \right)}\\
    C_{\tau,{\rm dilut}} =& C_{in} \left( \dfrac{Q_{in}}{u_c \Delta y \Delta z} \right)\\
    C_{\tau,{\rm both}} =& \dfrac{C_{\rm in}Q_{\rm in}}{u_c \Delta y H \theta} \exp{\left(-\lambda\dfrac{r}{|u_c|}\right)}
\end{array}
\end{equation}

```python
%reset -f
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from os import system
import os
from matplotlib.gridspec import GridSpec
from drawStuff import *

import jupypft.attachmentRateCFT as CFT
import jupypft.plotBTC as BTC

''' GLOBAL CONSTANTS '''
PI = 3.141592
THETA = 0.35
```

```python
def flowNumber():
    return (4.0*K*I*H*r) / (Qin*(1+f))

def uChar():
    '''Interstitial water velocity'''
    return -(K*I*flowNumber())/(THETA*(flowNumber() + 1))

def tChar():
    return -r/uChar()

def cDecay():
    return C0 * np.exp(-decayRate * tChar())

def cAttach():
    return C0 * np.exp(-attchRate * tChar())

def cDilut():
    return (C0 * Qin) / (-uChar() * delY * delZ * THETA)

def cBoth():
    return (C0 * Qin) / (-uChar() * delY * delZ * THETA) * np.exp(-decayRate * tChar())

def cTrice():
    return (C0 * Qin) / (-uChar() * delY * delZ * THETA) * np.exp(-(decayRate+attchRate) * tChar())

def findSweet():
    deltaConc = np.abs(cBoth() - np.max(cBoth()))
    return np.argmin(deltaConc)
```

```python
K = 10**-2
Qin = 0.24/86400
f = 10
H = 20
r = 40
I = 0.001
C0 = 1.0
qabs = np.abs(uChar()*THETA)

kattDict = dict(
    dp = 1.0E-7,
    dc = 2.0E-3,
    q = qabs,
    theta = THETA,
    visco = 0.0008891,
    rho_f = 999.79,
    rho_p = 1050.0,
    A = 5.0E-21,
    T = 10. + 273.15,
    alpha = 0.01)

decayRate = 3.5353E-06
attchRate,_ = CFT.attachmentRate(**kattDict)
delY,delZ = 1.35,H
```

```python
print("Nondim Flow  = {:.2E}".format(flowNumber()))
print("Charac. Vel  = {:.2E} m/s".format(uChar()))
print("Charac. time = {:.2E} s".format(tChar()))
```

    Nondim Flow  = 1.05E+03
    Charac. Vel  = -2.85E-05 m/s
    Charac. time = 1.40E+06 s

```python
print("Rel concenc. due decay = {:.2E}".format(cDecay()))
print("Rel conc. due dilution = {:.2E}".format(cDilut()))
print("Rel conc. due attachmt = {:.2E}".format(cAttach()))
print("Rel conc. due both eff = {:.2E}".format(cBoth()))
print("Rel conc. due three ef = {:.2E}".format(cTrice()))
```

    Rel concenc. due decay = 7.05E-03
    Rel conc. due dilution = 1.03E-02
    Rel conc. due attachmt = 4.42E-05
    Rel conc. due both eff = 7.26E-05
    Rel conc. due three ef = 3.21E-09

# Plot v. 1
I = 10**np.linspace(-5,0,num=100)

cDec = cDecay()
cDil = cDilut()
cAtt = cAttach()
cBot = cBoth()
cAll = cTrice()

i = findSweet()

worstC = cBot[i]
worstI = I[i]

fig, axs = plt.subplots(2,2,sharex=True, sharey=False,\
              figsize=(12,8),gridspec_kw={"height_ratios":[1,4],"hspace":0.04,"wspace":0.35})

bbox = dict(boxstyle='round', facecolor='mintcream', alpha=0.90)

arrowprops = dict(
    arrowstyle="->",
    connectionstyle="angle,angleA=90,angleB=40,rad=5")

fontdict = dict(size=12)

annotation = \
    r"$\bf{-\log(C/C_0)} = $" + "{:.1f}".format(-np.log10(worstC)) + \
    "\n@" + r" $\bf{I} = $" + "{:.1E}".format(worstI)

information = \
    r"$\bf{K}$" + " = {:.1E} m/s".format(K) + "\n"\
    r"$\bf{H}$" + " = {:.1f} m".format(H) + "\n"\
    r"$\bf{r}$" + " = {:.1f} m".format(r) + "\n"\
    r"$\bf{Q_{in}}$" + " = {:.2f} m³/d".format(Qin*86400) + "\n"\
    r"$\bf{f}$" + " = {:.1f}".format(f) + "\n"\
    r"$\bf{\lambda}$" + " = {:.2E} 1/s".format(decayRate)

#########################################
# Ax1 - Relative concentration
ax = axs[1,0]
ax.plot(I,cDec,label="Due decay",lw=3,ls="dashed",alpha=0.8)
ax.plot(I,cDil,label="Due dilution",lw=3,ls="dashed",alpha=0.8)
ax.plot(I,cAtt,label="Due attachment",lw=2,ls="dashed",alpha=0.6)
ax.plot(I,cBot,label="Decay + dilution",lw=3,c='k',alpha=0.9)
ax.plot(I,cAll,label="Overall effect",lw=3,c='gray',alpha=0.9)

ax.set(xscale="log",yscale="log")
ax.set(xlim=(1.0E-4,1.0E-1),ylim=(1.0E-10,1))
ax.legend(loc="lower left",shadow=True)

ax.annotate(annotation,(worstI,worstC),
    xytext=(0.05,0.85), textcoords='axes fraction',
    bbox=bbox, arrowprops=arrowprops)

ax.text(0.65,0.05,information,bbox=bbox,transform=ax.transAxes)

ax.set_xlabel("Water table gradient\n$I$ [m/m]",fontdict=fontdict)
ax.set_ylabel("Relative Concentration\n$C/C_0$ [-]",fontdict=fontdict)
####################################
# Ax2 - log-removals
ax = axs[1,1]
ax.plot(I,-np.log10(cDec),label="Due decay",lw=3,ls="dashed",alpha=0.8)
ax.plot(I,-np.log10(cDil),label="Due dilution",lw=3,ls="dashed",alpha=0.8)
ax.plot(I,-np.log10(cAtt),label="Due attachment",lw=2,ls="dashed",alpha=0.6)
ax.plot(I,-np.log10(cBot),label="Decay + dilution",lw=3,c='k',alpha=0.9)
ax.plot(I,-np.log10(cAll),label="Overall effect",lw=3,c='gray',alpha=0.9)

ax.set(xscale="log")
ax.set(xlim=(1.0E-4,1.0E-1),ylim=(0,10))
ax.legend(loc="upper left",shadow=True)

ax.annotate(annotation,(worstI,-np.log10(worstC)),
    xytext=(0.65,0.55), textcoords='axes fraction',
    bbox=bbox, arrowprops=arrowprops)

ax.text(0.65,0.70,information,bbox=bbox,transform=ax.transAxes)

ax.set_xlabel("Water table gradient\n$I$ [m/m]",fontdict=fontdict)
ax.set_ylabel("log-reductions\n$-\log(C/C_0)$ [-]",fontdict=fontdict)

####################################
#Flow number
for ax in axs[0,:]:
    ax.plot(I,flowNumber(),label="flowNumber",lw=3,c="gray")
    ax.axhline(y=1.0)
    ax.set_xscale("log")
    ax.set_yscale("log")
    ax.xaxis.set_tick_params(which="both",labeltop='on',top=True,bottom=False)
    ax.set_ylabel("Nondim. flow number\n$\mathcal{F}_L$ [-]")

####################################<
#Line worst case scenario
for axc in axs:
    for ax in axc:
        ax.axvline(x=I[i], lw=1, ls="dashed", c="red",alpha=0.5)

plt.show()
# v.2 With PFLOTRAN result

```python
listOfFiles = os.listdir("LittleValidation_MASSBALANCES")
listOfFiles.sort()

IPFLO = [float(s[9:16]) for s in listOfFiles]
CPFLO = BTC.get_endConcentrations(
            "LittleValidation_MASSBALANCES",
            indices={'t':"Time [d]",\
                     'q':"ExtractWell Water Mass [kg/d]",\
                     'm':"ExtractWell Vaq [mol/d]"
                    },
            normalizeWith=dict(t=1.0,q=kattDict['rho_f']/1000.,m=1.0))
```

    NumExpr defaulting to 8 threads.

```python
listOfFiles = os.listdir("LittleValidation_MASSBALANCES_Att")
listOfFiles.sort()

IPFLO2 = [float(s[8:15]) for s in listOfFiles]
CPFLO2 = BTC.get_endConcentrations(
            "LittleValidation_MASSBALANCES_Att",
            indices={'t':"Time [d]",\
                     'q':"ExtractWell Water Mass [kg/d]",\
                     'm':"ExtractWell Vaq [mol/d]"
                    },
            normalizeWith=dict(t=1.0,q=kattDict['rho_f']/1000.,m=1.0))
```

```python
# Theoretical stuff
I = 10**np.linspace(-5,0,num=100)
cDec = cDecay()
cDil = cDilut()
cAtt = cAttach()
cBot = cBoth()
cAll = cTrice()
i = findSweet()
worstC = cBot[i]
worstI = I[i]
```
fig, axs = plt.subplots(2,2,sharex=True, sharey=False,\
              figsize=(10,8),gridspec_kw={"height_ratios":[1,10],"hspace":0.04,"wspace":0.02})

bbox = dict(boxstyle='round', facecolor='mintcream', alpha=0.90)

arrowprops = dict(
    arrowstyle="->",
    connectionstyle="angle,angleA=90,angleB=40,rad=5")

fontdict = dict(size=12)

annotation = \
    r"$\bf{-\log(C/C_0)} = $" + "{:.1f}".format(-np.log10(worstC)) + \
    "\n@" + r" $\bf{I} = $" + BTC.sci_notation(worstI)

information = \
    r"$\bf{K} = $" + BTC.sci_notation(K) + " m/s\n"\
    r"$\bf{H}$" + " = {:.1f} m".format(H) + "\n"\
    r"$\bf{r}$" + " = {:.1f} m".format(r) + "\n"\
    r"$\bf{Q_{in}}$" + " = {:.2f} m³/d".format(Qin*86400) + "\n"\
    r"$\bf{f}$" + " = {:.1f}".format(f) + "\n"\
    r"$\bf{\lambda_{\rm aq}} = $" + BTC.sci_notation(decayRate) + " s⁻¹\n"\
    r"$\bf{k_{\rm att}} = $" + BTC.sci_notation(attchRate) + " s⁻¹"

####################################
# Ax2 - log-removals
ax = axs[1,0]

symbols=dict(dil="\u25A2",dec="\u25B3",att="\u25CE")

ax.plot(I,-np.log10(cDil),\
        label="Due dilution  " + symbols['dil'],\
        lw=3,ls="dashed",alpha=0.6,c='crimson')
ax.plot(I,-np.log10(cDec),\
        label="Due decay  " + symbols['dec'],\
        lw=3,ls="dashed",alpha=0.6,c='indigo')
ax.plot(I,-np.log10(cAtt),\
        label="Due attachment " + symbols['att'],\
        lw=2,ls="dashed",alpha=0.5,c='olive')
ax.plot(I,-np.log10(cBot),\
        label=symbols['dil'] + " + " + symbols['dec'],\
        lw=3,c='k',alpha=0.9,zorder=2)
ax.plot(I,-np.log10(cAll),\
        label=symbols['dil'] + " + " + symbols['dec'] + " + " + symbols['att'],\
        lw=2,c='gray',alpha=0.9,zorder=2)

ax.set(xscale="log")
ax.set(xlim=(1.0E-4,1.0E-1),ylim=(0,9.9))
ax.legend(loc="upper right",shadow=True,ncol=1,\
          title="Potential flow prediction",title_fontsize=11)

ax.annotate(annotation,(worstI,-np.log10(worstC)),
    xytext=(0.65,0.55), textcoords='axes fraction',
    bbox=bbox, arrowprops=arrowprops)

ax.set_xlabel("Water table gradient\n$I$ [m/m]",fontdict=fontdict)
ax.set_ylabel("log-reductions\n$-\log(C/C_0)$ [-]",fontdict=fontdict)

####################################
# Ax2 - log-removals
ax = axs[1,1]
ax.plot(I,-np.log10(cBot),
        lw=3,c='k',alpha=0.9)
ax.plot(IPFLO,-np.log10(CPFLO),zorder=2,\
        label= symbols['dil'] + " + " + symbols['dec'],\
        lw=0,ls='dotted',c='k',alpha=0.9,\
        marker="$\u25CA$",mec='k',mfc='k',ms=10)

ax.plot(I,-np.log10(cAll),\
        lw=2,c='gray',alpha=0.9)
ax.plot(IPFLO2,-np.log10(CPFLO2),zorder=2,\
        label= symbols['dil'] + " + " + symbols['dec'] + " + " + symbols['att'],\
        lw=0,ls='dotted',c='gray',alpha=0.9,\
        marker="$\u2217$",mec='gray',mfc='gray',ms=10)
#####

ax.set(xscale="log")
ax.set(xlim=(1.0E-4,9.0E-2),ylim=(0,9.9))
ax.legend(loc="lower left",shadow=True,ncol=1,\
          labelspacing=0.4,mode=None,\
          title="PFLOTRAN run",title_fontsize=11)
ax.set_xlabel("Water table gradient\n$I$ [m/m]",fontdict=fontdict)
ax.yaxis.tick_right()

ax.text(0.60,0.70,information,bbox=bbox,transform=ax.transAxes)
ax.text(I[i],0.5,"Worst\ncase",\
        ha='center',va='center',weight='semibold',\
        bbox=dict(boxstyle='square', fc='white', ec='red'))

####################################
#Flow number
ax = axs[0,0]
ax.plot(I,flowNumber(),label="flowNumber",lw=3,c="gray")
#ax.axhline(y=1.0)
ax.set_xscale("log")
ax.set_yscale("log")
ax.xaxis.set_tick_params(which="both",labeltop='on',top=False,bottom=False)
#ax.set_ylabel("Nondim. flow number\n$\mathcal{F}_L$ [-]")

####################################<
#Line worst case scenario
axs[0,0].axvline(x=I[i], lw=2, ls="dotted", c="red",alpha=0.5)
axs[1,0].axvline(x=I[i], lw=2, ls="dotted", c="red",alpha=0.5)
axs[1,1].axvline(x=I[i], lw=2, ls="dotted", c="red",alpha=0.5)

###############################
# Information box
ax = axs[0,1]
ax.axis('off')

plt.show()

```python
fig, axs = plt.subplots(1,1,figsize=(5,5))
fontdict = dict(size=12)
lines = {}
information = \
    r"$\bf{K} = $" + BTC.sci_notation(K) + " m/s\n"\
    r"$\bf{H}$" + " = {:.1f} m".format(H) + "\n"\
    r"$\bf{r}$" + " = {:.1f} m".format(r) + "\n"\
    r"$\bf{Q_{in}}$" + " = {:.2f} m³/d".format(Qin*86400) + "\n"\
    r"$\bf{f}$" + " = {:.1f}".format(f) + "\n"\
    r"$\bf{\lambda_{\rm aq}} = $" + BTC.sci_notation(decayRate) + " s⁻¹"\

####################################
# Ax2 - log-removals
ax = axs

lines['Dilution'] = ax.plot(I,-np.log10(cDil),\
        label="Due dilution",\
        lw=3,ls="dashed",alpha=0.99,c='#f1a340')
lines['Decay'] = ax.plot(I,-np.log10(cDec),\
        label="Due decay",\
        lw=3,ls="dashdot",alpha=0.99,c='#998ec3')
#ax.plot(I,-np.log10(cAtt),\
#        label="Due attachment " + symbols['att'],\
#        lw=2,ls="dashed",alpha=0.5,c='olive')
lines['Both'] = ax.plot(I,-np.log10(cBot),\
        label="Combined effect",\
        lw=3,c='k',alpha=0.9,zorder=2)
#ax.plot(I,-np.log10(cAll),\
#        label=symbols['dil'] + " + " + symbols['dec'] + " + " + symbols['att'],\
#        lw=2,c='gray',alpha=0.9,zorder=2)
lines['PFLOT'] = ax.plot(IPFLO,-np.log10(CPFLO),zorder=2,\
        label= "BIOPARTICLE model",\
        lw=0,ls='dotted',c='k',alpha=0.9,\
        marker="$\u25CA$",mec='k',mfc='k',ms=10)

ax.set(xscale="log")
ax.set(xlim=(5.0E-5,5.0E-1),ylim=(-0.5,9.9))
ax.set_xlabel("Water table gradient\n$I$ [m/m]",fontdict=fontdict)
ax.set_ylabel("log-reductions\n$-\log(C/C_0)$ [-]",fontdict=fontdict)

## Legend
whitebox = ax.scatter([1],[1],c="white",marker="o",s=1,alpha=0)

handles = [lines['PFLOT'][0],
           lines['Both'][0]]

labels = [lines['PFLOT'][0].get_label(),
          "PF model"]

plt.legend(handles, labels,
           loc="upper right",ncol=1,\
          edgecolor='gray',facecolor='mintcream',labelspacing=1)

##aNNOTATIONS
rotang = -1.0
bbox = dict(boxstyle='square', fc='w', ec='#998ec3',lw=1.5)
ax.text(0.85,0.10,'Inactivation',ha='center',va='center',
         fontsize=11,rotation=rotang,bbox=bbox,transform=ax.transAxes)

rotang = 21.0
bbox = dict(boxstyle='square', fc='w', ec='#f1a340',lw=1.5)
ax.text(0.12,0.21,'Dilution',ha='center',va='center',
         fontsize=11,rotation=rotang,bbox=bbox,transform=ax.transAxes)

rotang = -0.0
bbox = dict(boxstyle='square', fc='k', ec=None,lw=0.0)
ax.text(0.55,0.45,'Combined',c='w',ha='center',va='center',weight='bold',
         fontsize=11,rotation=rotang,bbox=bbox,transform=ax.transAxes)

bbox = dict(boxstyle='round,pad=0.5,rounding_size=0.3', fc='whitesmoke', alpha=0.90,ec='whitesmoke')
#ax.text(0.60,0.64,information,bbox=bbox,transform=ax.transAxes,fontsize=10)

fig.savefig(fname="SweetpointOnlyDecay.png",transparent=False,dpi=300,bbox_inches="tight")
#plt.show()
```

```python
fig, axs = plt.subplots(1,1,figsize=(5,5))
fontdict = dict(size=12)
lines = {}
information = \
    r"$\bf{K} = $" + BTC.sci_notation(K) + " m/s\n"\
    r"$\bf{H}$" + " = {:.1f} m".format(H) + "\n"\
    r"$\bf{r}$" + " = {:.1f} m".format(r) + "\n"\
    r"$\bf{Q_{in}}$" + " = {:.2f} m³/d".format(Qin*86400) + "\n"\
    r"$\bf{f}$" + " = {:.1f}".format(f) + "\n"\
    r"$\bf{\lambda_{\rm aq}} = $" + BTC.sci_notation(decayRate) + " s⁻¹\n"\
    r"$\bf{k_{\rm att}} = $" + BTC.sci_notation(attchRate) + " s⁻¹"

####################################
# Ax2 - log-removals
ax = axs

lines['Dilution'] = ax.plot(I,-np.log10(cDil),\
        label="Due dilution",\
        lw=3,ls="dashed",alpha=0.99,c='#f1a340')
lines['Decay'] = ax.plot(I,-np.log10(cDec),\
        label="Due decay",\
        lw=3,ls="dashdot",alpha=0.99,c='#998ec3')
lines['Attach'] = ax.plot(I,-np.log10(cAtt),\
        label="Due attachment",\
        lw=3,ls="dotted",alpha=0.95,c='#4dac26')
#lines['Both'] = ax.plot(I,-np.log10(cBot),\
#        label="Combined effect",\
#        lw=3,c='k',alpha=0.9,zorder=2)
lines['Both'] = ax.plot(I,-np.log10(cAll),\
        label="Combined\neffect",\
        lw=3,c='#101613',alpha=0.99,zorder=2)

lines['PFLOT'] = ax.plot(IPFLO2,-np.log10(CPFLO2),zorder=2,\
        label= "BIOPARTICLE model",\
        lw=0,ls='dotted',c='k',alpha=0.9,\
        marker="$\u2217$",mec='gray',mfc='k',ms=10)

ax.set(xscale="log")
ax.set(xlim=(5.0E-5,5.0E-1),ylim=(-0.5,9.9))
ax.set_xlabel("Water table gradient\n$I$ [m/m]",fontdict=fontdict)
ax.set_ylabel("log-reductions\n$-\log(C/C_0)$ [-]",fontdict=fontdict)

## Legend
whitebox = ax.scatter([1],[1],c="white",marker="o",s=1,alpha=0)

handles = [lines['PFLOT'][0],
           lines['Both'][0]]

labels = [lines['PFLOT'][0].get_label(),
          "PF model"]

plt.legend(handles, labels,
           loc="upper right",ncol=1,\
          edgecolor='gray',facecolor='mintcream',labelspacing=1)

##aNNOTATIONS
rotang = -82.0
bbox = dict(boxstyle='square', fc='w', ec='#998ec3',lw=1.5)
ax.text(0.12,0.85,'Inactivation',c='k',fontweight='normal',ha='center',va='center',
         fontsize=11,rotation=rotang,bbox=bbox,transform=ax.transAxes)

rotang = 21.0
bbox = dict(boxstyle='square', fc='w', ec='#f1a340',lw=1.5)
ax.text(0.12,0.21,'Dilution',ha='center',va='center',
         fontsize=11,rotation=rotang,bbox=bbox,transform=ax.transAxes)

rotang = -1.5
bbox = dict(boxstyle='square', fc='w', ec='#4dac26',ls='-',lw=1.5)
ax.text(0.85,0.10,'Filtration',ha='center',va='center',
         fontsize=11,rotation=rotang,bbox=bbox,transform=ax.transAxes)

rotang = -0.0
bbox = dict(boxstyle='square', fc='#101613', ec='#101613')
ax.text(0.65,0.52,'Combined',c='w',ha='center',va='center',weight='bold',
         fontsize=11,rotation=rotang,bbox=bbox,transform=ax.transAxes)

bbox = dict(boxstyle='round,pad=0.5,rounding_size=0.3', fc='whitesmoke', alpha=0.90,ec='whitesmoke')
#ax.text(0.60,0.58,information,bbox=bbox,transform=ax.transAxes,fontsize=10)

fig.savefig(fname="SweetpointAllConsidered.png",transparent=False,dpi=300,bbox_inches="tight")
plt.show()
```

# v.3 Together as filtration is assumed
fig, axs = plt.subplots(1,2,figsize=(10,5))
bbox = dict(boxstyle='round,pad=0.5,rounding_size=0.3', facecolor='mintcream', alpha=0.90)
fontdict = dict(size=12)
lines = {}
information = \
    "Parameters:\n" + \
    r"$\bf{K} = $" + BTC.sci_notation(K) + " m/s\n"\
    r"$\bf{H}$" + " = {:.1f} m".format(H) + "\n"\
    r"$\bf{r}$" + " = {:.1f} m".format(r) + "\n"\
    r"$\bf{Q_{in}}$" + " = {:.2f} m³/d".format(Qin*86400) + "\n"\
    r"$\bf{f}$" + " = {:.1f}".format(f) + "\n"\
    r"$\bf{\lambda_{\rm aq}} = $" + BTC.sci_notation(decayRate) + " s⁻¹"\

####################################
# Ax2 - log-removals
ax = axs[0]

lines['Dilution'] = ax.plot(I,-np.log10(cDil),\
        label="Due dilution",\
        lw=3,ls="dashed",alpha=0.99,c='#f1a340')
lines['Decay'] = ax.plot(I,-np.log10(cDec),\
        label="Due decay",\
        lw=3,ls="dashdot",alpha=0.99,c='#998ec3')
#ax.plot(I,-np.log10(cAtt),\
#        label="Due attachment " + symbols['att'],\
#        lw=2,ls="dashed",alpha=0.5,c='olive')
lines['Both'] = ax.plot(I,-np.log10(cBot),\
        label="Combined effect",\
        lw=3,c='k',alpha=0.9,zorder=2)
#ax.plot(I,-np.log10(cAll),\
#        label=symbols['dil'] + " + " + symbols['dec'] + " + " + symbols['att'],\
#        lw=2,c='gray',alpha=0.9,zorder=2)
lines['PFLOT'] = ax.plot(IPFLO,-np.log10(CPFLO),zorder=2,\
        label= "PFLOTRAN results",\
        lw=0,ls='dotted',c='k',alpha=0.9,\
        marker="$\u25CA$",mec='k',mfc='k',ms=10)

ax.set(xscale="log")
ax.set(xlim=(5.0E-5,5.0E-1),ylim=(0,9.9))
ax.text(1.04,0.55,information,bbox=bbox,transform=ax.transAxes)

ax.set_xlabel("Water table gradient\n$I$ [m/m]",fontdict=fontdict)
ax.set_ylabel("log-reductions\n$-\log(C/C_0)$ [-]",fontdict=fontdict)

## Legend
whitebox = ax.scatter([1],[1],c="white",marker="o",s=1,alpha=0)

handles = [whitebox,
           lines['Dilution'][0],
           lines['Decay'][0],
           lines['Both'][0],
           whitebox,
           lines['PFLOT'][0]]

labels = ['PF model',
          lines['Dilution'][0].get_label(),
          lines['Decay'][0].get_label(),
          lines['Both'][0].get_label(),
          '',
          lines['PFLOT'][0].get_label(),]

plt.legend(handles, labels,
           loc="center left",ncol=1,bbox_to_anchor=(1.01,0.25),\
          edgecolor='k',facecolor='mintcream',labelspacing=1)

bbox = dict(boxstyle='round,pad=0.5,rounding_size=0.3', facecolor='mintcream', alpha=0.90)
fontdict = dict(size=12)
lines = {}
information = \
    "Parameters:\n" + \
    r"$\bf{K} = $" + BTC.sci_notation(K) + " m/s\n"\
    r"$\bf{H}$" + " = {:.1f} m".format(H) + "\n"\
    r"$\bf{r}$" + " = {:.1f} m".format(r) + "\n"\
    r"$\bf{Q_{in}}$" + " = {:.2f} m³/d".format(Qin*86400) + "\n"\
    r"$\bf{f}$" + " = {:.1f}".format(f) + "\n"\
    r"$\bf{\lambda_{\rm aq}} = $" + BTC.sci_notation(decayRate) + " s⁻¹\n"\
    r"$\bf{k_{\rm att}} = $" + BTC.sci_notation(attchRate) + " s⁻¹"

####################################
# Ax2 - log-removals
ax = axs[1]

lines['Dilution'] = ax.plot(I,-np.log10(cDil),\
        label="Due dilution",\
        lw=3,ls="dashed",alpha=0.99,c='#f1a340')
lines['Decay'] = ax.plot(I,-np.log10(cDec),\
        label="Due decay",\
        lw=3,ls="dashdot",alpha=0.99,c='#998ec3')
lines['Attach'] = ax.plot(I,-np.log10(cAtt),\
        label="Due attachment",\
        lw=3,ls="dotted",alpha=0.95,c='#4dac26')
#lines['Both'] = ax.plot(I,-np.log10(cBot),\
#        label="Combined effect",\
#        lw=3,c='k',alpha=0.9,zorder=2)
lines['Both'] = ax.plot(I,-np.log10(cAll),\
        label="Combined effect",\
        lw=3,c='k',alpha=0.99,zorder=2)

lines['PFLOT'] = ax.plot(IPFLO2,-np.log10(CPFLO2),zorder=2,\
        label= "PFLOTRAN results",\
        lw=0,ls='dotted',c='k',alpha=0.9,\
        marker="$\u2217$",mec='gray',mfc='k',ms=10)

ax.set(xscale="log")
ax.set(xlim=(5.0E-5,5.0E-1),ylim=(0,9.9))
ax.text(1.04,0.55,information,bbox=bbox,transform=ax.transAxes)

ax.set_xlabel("Water table gradient\n$I$ [m/m]",fontdict=fontdict)
ax.set_ylabel("log-reductions\n$-\log(C/C_0)$ [-]",fontdict=fontdict)

## Legend
whitebox = ax.scatter([1],[1],c="white",marker="o",s=1,alpha=0)

handles = [whitebox,
           lines['Dilution'][0],
           lines['Decay'][0],
           lines['Attach'][0],
           lines['Both'][0],
           whitebox,
           lines['PFLOT'][0]]

labels = ['PF model',
          lines['Dilution'][0].get_label(),
          lines['Decay'][0].get_label(),
          lines['Attach'][0].get_label(),
          lines['Both'][0].get_label(),
          '',
          lines['PFLOT'][0].get_label(),]

plt.legend(handles, labels,
           loc="center left",ncol=1,bbox_to_anchor=(1.01,0.25),\
          edgecolor='k',facecolor='mintcream',labelspacing=1)

plt.show()
____
# Find the worst case
## >> Geometric parameters $H$ and $r$
K = 10**-2
Qin = 0.24/86400
f = 10
C0 = 1.0
decayRate = 3.5353E-06

Harray = np.array([2.,5.,10.,20.,50.])
rarray = np.array([5.,10.,40.,100.])
Iarray = 10**np.linspace(-5,0,num=100)

Ci = np.zeros([len(rarray),len(Harray)])
Ii = np.zeros([len(rarray),len(Harray)])
FLi = np.zeros([len(rarray),len(Harray)])

for hi,H in enumerate(Harray):
    for ri,r in enumerate(rarray):
        i = findSweet()

        worstC = -np.log10(cBoth()[i])
        worstGradient = Iarray[i]
        worstFlowNumber = flowNumber()[i]

        Ci[ri,hi]  = worstC
        Ii[ri,hi]  = worstGradient
        FLi[ri,hi] = worstFlowNumbermyLabels={"Title": { 0: r"$\bf{-\log (C_{\tau}/C_0)}$",
                     1: r"$\bf{I}$ (%)",
                     2: r"$\log(\mathcal{F}_L)$"},
          "Y": "Aquifer thickness\n$\\bf{H}$ (m)",
          "X": "Setback distance\n$\\bf{r}$ (m)"}

threeHeatplots(data={"I":Ii.T,"C":Ci.T,"FL":FLi.T},\
               xlabel=Harray,ylabel=rarray,myLabels=myLabels);
## >>Well parameters
K = 10**-2
H = 20
r = 40
C0 = 1.0
decayRate = 3.5353E-06

Qin_array = np.array([0.24,1.0,10.0,100.])/86400.
f_array = np.array([1,10.,100.,1000.,10000.])
Iarray = 10**np.linspace(-5,0,num=100)

Ci = np.zeros([len(Qin_array),len(f_array)])
Ii = np.zeros([len(Qin_array),len(f_array)])
FLi = np.zeros([len(Qin_array),len(f_array)])

for fi,f in enumerate(f_array):
    for qi,Qin in enumerate(Qin_array):
        i = findSweet()
        worstC = -np.log10(cBoth()[i])
        worstGradient = Iarray[i]
        worstFlowNumber = flowNumber()[i]

        Ci[qi,fi] = worstC
        Ii[qi,fi] = worstGradient
        FLi[qi,fi] = worstFlowNumber

### Plot heatmap
myLabels={"Title": { 0: r"$\bf{-\log (C_{\tau}/C_0)}$",
                     1: r"$\bf{I}$ (%)",
                     2: r"$\log(\mathcal{F}_L)$"},
          "Y": "Extraction to injection ratio\n$\\bf{f}$ (-)",
          "X": "Injection flow rate\n$\\bf{Q_{in}}$ (m³/d)"}

threeHeatplots(data={"I":Ii.T,"C":Ci.T,"FL":FLi.T},\
               xlabel=f_array,ylabel=np.round(Qin_array*86400,decimals=2),myLabels=myLabels);
## Hydraulic conductivity
Qin = 0.24/86400
f = 10
C0 = 1.0
decayRate = 3.5353E-06

Karray = 10.**np.array([-1.,-2.,-3.,-4.,-5.])
rarray = np.array([5.,10.,40.,100.])
Iarray = 10**np.linspace(-5,0,num=100)

Ci = np.zeros([len(rarray),len(Karray)])
Ii = np.zeros([len(rarray),len(Karray)])
FLi = np.zeros([len(rarray),len(Karray)])

for ki,K in enumerate(Karray):
    for ri,r in enumerate(rarray):
        i = findSweet()

        worstC = -np.log10(cBoth()[i])
        worstGradient = Iarray[i]
        worstFlowNumber = flowNumber()[i]

        Ci[ri,ki] = worstC
        Ii[ri,ki] = worstGradient
        FLi[ri,ki] = worstFlowNumber

### Plot heatmap
myLabels={"Title": { 0: r"$\bf{-\log (C_{\tau}/C_0)}$",
                     1: r"$\bf{I}$ (%)",
                     2: r"$\log(\mathcal{F}_L)$"},
          "Y": "Hydraulic conductivity\n$\\bf{K}$ (m/s)",
          "X": "Setback distance\n$\\bf{r}$ (m)"}

threeHeatplots(data={"I":Ii.T,"C":Ci.T,"FL":FLi.T},\
               xlabel=Karray,ylabel=rarray,myLabels=myLabels);K = 10**-2
H = 20
f = 10
C0 = 1.0
decayRate = 3.5353E-06

Qin_array = np.array([0.24,1.0,10.0,100.])/86400.
rarray = np.array([5.,10.,40.,100.])
Iarray = 10**np.linspace(-5,0,num=100)

Ci = np.zeros([len(rarray),len(Qin_array)])
Ii = np.zeros([len(rarray),len(Qin_array)])
FLi = np.zeros([len(rarray),len(Qin_array)])

for qi,Qin in enumerate(Qin_array):
    for ri,r in enumerate(rarray):
        i = findSweet()

        worstC = -np.log10(cBoth()[i])
        worstGradient = Iarray[i]
        worstFlowNumber = flowNumber()[i]

        Ci[ri,qi] = worstC
        Ii[ri,qi] = worstGradient
        FLi[ri,qi] = worstFlowNumber

myLabels={"Title": { 0: r"$\bf{-\log (C_{\tau}/C_0)}$",
                     1: r"$\bf{I}$ (%)",
                     2: r"$\log(\mathcal{F}_L)$"},
          "Y": "Injection flow rate\n$\\bf{Q_{in}}$ (m³/d)",
          "X": "Setback distance\n$\\bf{r}$ (m)"}

threeHeatplots(data={"I":Ii.T,"C":Ci.T,"FL":FLi.T},\
               ylabel=rarray,xlabel=np.round(Qin_array*86400,decimals=2),myLabels=myLabels);K = 10**-2
H = 20
f = 10
C0 = 1.0
decayRate = 1.119E-5

Qin_array = np.array([0.24,1.0,10.0,100.])/86400.
rarray = np.array([5.,10.,40.,100.])
Iarray = 10**np.linspace(-5,0,num=100)

Ci = np.zeros([len(rarray),len(Qin_array)])
Ii = np.zeros([len(rarray),len(Qin_array)])
FLi = np.zeros([len(rarray),len(Qin_array)])

for qi,Qin in enumerate(Qin_array):
    for ri,r in enumerate(rarray):
        i = findSweet()

        worstC = -np.log10(cBoth()[i])
        worstGradient = Iarray[i]
        worstFlowNumber = flowNumber()[i]

        Ci[ri,qi] = worstC
        Ii[ri,qi] = worstGradient
        FLi[ri,qi] = worstFlowNumber

myLabels={"Title": { 0: r"$\bf{-\log (C_{\tau}/C_0)}$",
                     1: r"$\bf{I}$ (%)",
                     2: r"$\log(\mathcal{F}_L)$"},
          "Y": "Injection flow rate\n$\\bf{Q_{in}}$ (m³/d)",
          "X": "Setback distance\n$\\bf{r}$ (m)"}

threeHeatplots(data={"I":Ii.T,"C":Ci.T,"FL":FLi.T},\
               ylabel=rarray,xlabel=np.round(Qin_array*86400,decimals=2),myLabels=myLabels);
## PLOTRAN SIMULATION RESULTS
minI = np.array([0.00046667, 0.0013    , 0.0048    , 0.012     , 0.00046667,
       0.0013    , 0.0048    , 0.012     , 0.00053333, 0.0013    ,
       0.0048    , 0.012     , 0.00056667, 0.0021    , 0.0053    ,
       0.012     ])

minC = np.array([2.2514572 , 2.62298917, 3.14213329, 3.51421485, 1.64182175,
       2.00913676, 2.52461269, 2.89537637, 0.74130696, 1.0754177 ,
       1.55071976, 1.90646243, 0.18705258, 0.39222131, 0.73428991,
       1.00387133])Qin_array = np.array([0.24,1.0,10.0,100.])/86400.
rarray = np.array([5.,10.,40.,100.])
Iarray = 10**np.linspace(-5,0,num=100)

Ci = np.zeros([len(rarray),len(Qin_array)])
Ii = np.zeros([len(rarray),len(Qin_array)])
FLi = np.zeros([len(rarray),len(Qin_array)])

i = 0
for qi,Qin in enumerate(Qin_array):
    for ri,r in enumerate(rarray):
        worstC = minC[i]
        worstGradient = minI[i]

        Ci[ri,qi] = worstC
        Ii[ri,qi] = worstGradient

        i += 1

myLabels={"Title": { 0: r"$\bf{-\log (C_{\tau}/C_0)}$",
                     1: r"$\bf{I}$ (%)",
                     2: r"$\log(\mathcal{F}_L)$"},
          "Y": "Injection flow rate\n$\\bf{Q_{in}}$ (m³/d)",
          "X": "Setback distance\n$\\bf{r}$ (m)"}

threeHeatplots(data={"I":Ii.T,"C":Ci.T,"FL":Ii.T},\
               ylabel=rarray,xlabel=np.round(Qin_array*86400,decimals=2),myLabels=myLabels);

```python

```

notebooks/Concepts/Find worst case (1).ipynb


```python
"""
================================
        Data pre-processing
         Angle correction
================================

(See the project documentation for more info)

The goal is to process data before using it to train ML algorithms :
1. Extraction of accelerations for activity 1 (rest activity)
2. Transitory regime suppression on activity 1
3. Calculation of theta angle between Z' and Z (ground's normal axis)
4. System rotation towards Z earth axis
5. Offset removal

Note that the solver fails to find a solution at step 3
"""
print(__doc__)
```

    ================================
            Data pre-processing
             Angle correction
    ================================

    (See the project documentation for more info)

    The goal is to process data before using it to train ML algorithms :
    1. Extraction of accelerations for activity 1 (rest activity)
    2. Transitory regime suppression on activity 1
    3. Calculation of theta angle between Z' and Z (ground's normal axis)
    4. System rotation towards Z earth axis
    5. Offset removal

    Note that the solver fails to find a solution at step 3

```python
# Imports statements

import pandas as pd
import numpy as np
# from math import cos, sin
from utils.colorpalette import black, red, blue, green, yellow, pink, brown, violet
from utils.activities import activities_labels
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
```

```python
# Import data into memory

raw_data = pd.read_csv('../data/1.csv',header=None,delimiter=',').astype(int)
raw_data.head()
```

      0
      1
      2
      3
      4

      0
      0.0
      1502
      2215
      2153
      1

      1
      1.0
      1667
      2072
      2047
      1

      2
      2.0
      1611
      1957
      1906
      1

      3
      3.0
      1601
      1939
      1831
      1

      4
      4.0
      1643
      1965
      1879
      1

```python
# Prepare further plotting activities
color_map = np.array([black, red, blue, green, yellow, pink, brown, violet])
axe_name = ['X', 'Y', 'Z']
activities = np.array(raw_data[4]-1) # -1 is here to shift the table correctly to work with the color_map
x_min, x_max = raw_data[0].min() - 1, raw_data[0].max() + 1
```

```python
# Show data before processing
y_min, y_max, xx, yy, fig, subplot  = [], [], [], [], [], []
legend = []
for activity, color in zip(activities_labels, color_map):
    legend.append(Line2D([0], [0], marker='o', label=activity, ls='None', markerfacecolor=color, markeredgecolor='k'))
for k in range(0,3):
    y_min.append(raw_data[k+1].min() - 1)
    y_max.append(raw_data[k+1].max() + 1)
    xx_tmp, yy_tmp = np.meshgrid(np.arange(x_min, x_max, 1000),np.arange(y_min[k], y_max[k], 100))
    xx.append(xx_tmp)
    yy.append(yy_tmp)
    fig.append(plt.figure())
    subplot.append(fig[k].add_subplot(111))
    subplot[k].scatter(raw_data[0], raw_data[k+1], s=1,c=color_map[activities])
    subplot[k].set_title('Acceleration on ' + axe_name[k])
legend = plt.legend(handles=legend, loc='upper center', bbox_to_anchor=(1, 2), title='Activities')
plt.show()
```

```python
#Prepare for processing
clean_data = []
clean_data.append(raw_data[0])
```

```python
# Transitory regime suppression on activity 1
np_raw_data = np.array(raw_data, dtype=object)
bool_mask_on_act_1 = np_raw_data[:, 4] == 1 # Boolean mask to only select rows concerning activity 1
bool_mask_on_permanent_regime = (np_raw_data[:, 0] >= 3200) & (np_raw_data[:, 0] <= 16000)
act_1_data_permanent_regime = np_raw_data[bool_mask_on_act_1 & bool_mask_on_permanent_regime]
```

```python
# Show activity 1 data after transitory regime suppression on activity 1
activities = np.array(act_1_data_permanent_regime[:,4]-1, dtype=int) # -1 is here to shift the table correctly to work with the color_map

x_min, x_max = act_1_data_permanent_regime[0].min() - 1, act_1_data_permanent_regime[0].max() + 1
y_min, y_max, xx, yy, fig, subplot  = [], [], [], [], [], []
legend = []
for activity, color in zip(activities_labels, color_map):
    legend.append(Line2D([0], [0], marker='o', label=activity, ls='None', markerfacecolor=color, markeredgecolor='k'))
for k in range(0,3):
    y_min.append(act_1_data_permanent_regime[k+1].min() - 1)
    y_max.append(act_1_data_permanent_regime[k+1].max() + 1)
    xx_tmp, yy_tmp = np.meshgrid(np.arange(x_min, x_max, 1000),np.arange(y_min[k], y_max[k], 100))
    xx.append(xx_tmp)
    yy.append(yy_tmp)
    fig.append(plt.figure())
    subplot.append(fig[k].add_subplot(111))
    subplot[k].scatter(act_1_data_permanent_regime[:,0], act_1_data_permanent_regime[:,k+1], s=1,c=color_map[activities])
    subplot[k].set_title('Acceleration on ' + axe_name[k])
legend = plt.legend(handles=legend, loc='upper center', bbox_to_anchor=(1, 2), title='Activities')
plt.show()
```

```python
index_mean, xp_mean, yp_mean, zp_mean, activity_mean = act_1_data_permanent_regime.mean(axis=0)
```

```python
# Look for theta value :
from sympy.solvers import solve
from sympy import Symbol, sin, cos
from math import sqrt

index_mean, xp_mean, yp_mean, zp_mean, activity_mean = act_1_data_permanent_regime.mean(axis=0)
abs_gamma_mean = sqrt(xp_mean**2+yp_mean**2+zp_mean**2)
theta = Symbol('theta')
index_mean, xp_mean, yp_mean, zp_mean, activity_mean = act_1_data_permanent_regime.mean(axis=0)
theta = solve(sin(theta)*yp_mean+cos(theta)*zp_mean, abs_gamma_mean, dict=True)
# TODO : Find a way that this equation returns results !
```

```python
# System rotation towards Z earth axis - see the report for documentation
rotation_matrix = np.array([[1, 0, 0],
                            [0, cos(theta), -sin(theta)]
                            [0, sin(theta), cos(theta)]])

for row_index in clean_data:
    Gamma_xp_yp_zp = clean_data.iloc[row_index][1, 2, 3]
    Gamma_x_y_z = np.matmul(rotation_matrix, Gamma_xp_yp_zp)
    clean_data.iloc[row_index][1, 2, 3] = Gamma_x_y_z
```

```python
# Offset suppression

# TODO :
# Should we really delete the offset though? Maybe it just corresponds to gravity, so change of system first !
# At rest, Gamma is expected to be 1g, but is calculated to be around 3,7g.
# So there might be offsets, indeed, but in which direction?

mean_acc_by_act = raw_data[[1, 2, 3, 4]].groupby([4], as_index=False).mean().sort_values(by=4, ascending=True)
mean_acc_at_act_1 = mean_acc_by_act.iloc[0] # Offset is calculated at rest (activity 1)

for k in range(1,4):
    clean_data.append(raw_data[k] - mean_acc_at_act_1[k])
```

```python
# Show changes after offset suppression
legend = []
for activity, color in zip(activities_labels, color_map):
    legend.append(Line2D([0], [0], marker='o', label=activity, ls='None', markerfacecolor=color, markeredgecolor='k'))

y_min, y_max, xx, yy, fig, subplot  = [], [], [], [], [], []
for k in range(0,3):
    y_min.append(clean_data[k+1].min() - 1)
    y_max.append(clean_data[k+1].max() + 1)
    xx_tmp, yy_tmp = np.meshgrid(np.arange(x_min, x_max, 1000),np.arange(y_min[k], y_max[k], 100))
    xx.append(xx_tmp)
    yy.append(yy_tmp)
    fig.append(plt.figure())
    subplot.append(fig[k].add_subplot(111))
    subplot[k].scatter(clean_data[0], clean_data[k+1], s=1,c=color_map[activities])
    subplot[k].set_title('Acceleration on ' + axe_name[k])
legend = plt.legend(handles=legend, loc='upper center', bbox_to_anchor=(1, 2), title='Activities')
plt.show()
```

```python
# Push data changes into new csv file
df = pd.DataFrame(clean_data)
df.to_csv("../../data/cleaned_data/projected_on_z_axis_1.csv",index=False)
```