I have quite a big project I want to solve with GEKKO. It consists of quite a large number of partial differential equations, and I have a function that uses an iterative process to calculate steady state "leak". However, GEKKO runs the function only during initialization. I want GEKKO to solve this task by taking into account that function. It would be really hard to write this function in GEKKOs equations. But without GEKKO it would be really hard to solve the Partial Differential Equations. So I am stuck, I would appreciate any help.
Here is a simple example I want to implement
a = 0.01
def CalculateLeak(P,a):
a = a - P*0.1
print("Leak is calculated")
return a
m = GEKKO(remote = False)
tf = 10
nt = int(tf/1) + 1
m.time = np.linspace(0,tf,nt)
P = m.Var(0.1)
m.Equation(P.dt() == P*0.1 - CalculateLeak(P,a))
m.options.IMODE = 7
m.solve(disp = False)
print("Finished")
print(a)
Below is the function I actually want to add to my project. It calculates the adsorption amount based on P (pressure), T (temperature), y1,y2,y3,y4,y5,y6 are molar fractions. All these variables should come from the partial differential equations solved in time by GEKKO (probably except temperature which can be assumed constant some time). Every time iteration this function would calculate the amount of gas adsorbed and return to Partial Diff. Eq. as a source term.
import numpy as np
import matplotlib.pyplot as plt
def FastIAST(P_gas,T,y1,y2,y3,y4,y5,y6):
IP1_CH4 = 0.0016 #kmol/kg
IP2_CH4 = 0 #1/bar
IP3_CH4 = 4.2E-05 #1/bar
IP4_CH4 = 2922.78 #K
IP1_C2H6 = 0.0027 #kmol/kg
IP2_C2H6 = 0.0 #1/bar
IP3_C2H6 = 2.66E-04 #1/bar
IP4_C2H6 = 2833.77 # K
IP1_C3H8 = 0.0062 #kmol/kg
IP2_C3H8 = 0.0 #1/bar
IP3_C3H8 = 3.75E-04 #1/bar
IP4_C3H8 = 2795.28 #K
IP1_C4H10 = 0.007 #kmol/kg
IP2_C4H10 = 0.0 #1/bar
IP3_C4H10 = 0.0015 #1/bar
IP4_C4H10 = 2600 #K
IP1_CO2 = 0.0028 #kmol/kg
IP2_CO2 = 0.0 #(kmol/kg)/bar
IP3_CO2 = 0.000748 #1/bar
IP4_CO2 = 2084.44 #K
IP1_N2 = 0.0075 #kmol/kg
IP2_N2 = 0.0 #(kmol/kg)/bar
IP3_N2 = 0.00099 #1/bar
IP4_N2 = 935.77 #K
Q1 = IP1_CH4 - IP2_CH4*T # Isotherm max capacity CH4
Q2 = IP1_C2H6 - IP2_C2H6*T # Isotherm max capacity C2H6
Q3 = IP1_C3H8 - IP2_C3H8*T # Isotherm max capacity C3H8
Q4 = IP1_C4H10 - IP2_C4H10*T # Isotherm max capacity C4H10
Q5 = IP1_CO2 - IP2_CO2*T # Isotherm max capacity CO2
Q6 = IP1_N2 - IP2_N2*T # Isotherm max capacity N2
b1 = IP3_CH4*np.exp(IP4_CH4/T) # Isotherm affinity coeff. CH4
b2 = IP3_C2H6*np.exp(IP4_C2H6/T) # Isotherm affinity coeff. C2H6
b3 = IP3_C3H8*np.exp(IP4_C3H8/T) # Isotherm affinity coeff. C3H8
b4 = IP3_C4H10*np.exp(IP4_C4H10/T) # Isotherm affinity coeff. C4H10
b5 = IP3_CO2*np.exp(IP4_CO2/T) # Isotherm affinity coeff. CO2
b6 = IP3_N2*np.exp(IP4_N2/T) # Isotherm affinity coeff. N2
error = 0 # 1 - there was an error in the programm, 0 - OK
N = 6 # Number of components
#Langmuir Isotherm
SingleComponentCapacity = np.array([Q1,Q2,Q3,Q4,Q5,Q6]) #Langmuir Isotherm capacity of every component
AffinityCoefficient = np.array([b1,b2,b3,b4,b5,b6]) #Langmuir Affinity Coefficient of every component
fractionGas = np.array([y1,y2,y3,y4,y5,y6]) #Gas fraction of every component
#Initialization
fastiastGraphConcentration = np.zeros(N)
fastiastGraphFraction = np.zeros(N)
fastiastPressure = 0
adsorbedFraction = np.zeros(N)
adsorbedConcentration = np.zeros(N)
#Checking..
if (len(fractionGas) < N or len(SingleComponentCapacity) < N or len(AffinityCoefficient) < N):
print("You have the incorrect number of components")
error = 1
if np.sum(fractionGas) < 0.95 or np.sum(fractionGas) > 1.05:
error = 1
print("The molar fractions sum is not equal to 1")
###Calculation###
kappa_old = np.zeros(N)
delta_kappa = np.ones(N)
kappa = np.zeros(N)
CmuT = 0
partialPressureComponents = fractionGas*P_gas
for k in range(N):
CmuT += SingleComponentCapacity[k]*AffinityCoefficient[k]*partialPressureComponents[k]
for k in range(N):
kappa[k] = CmuT/(SingleComponentCapacity[k])
i = 0
while np.any((delta_kappa) > 1e-4):
f = np.zeros(N)
fDerivative = np.zeros(N)
g = np.zeros(N)
sigma = np.zeros(N)
phi = np.zeros((N,N))
phi = np.matrix(phi)
for k in range(N):
f[k] = SingleComponentCapacity[k]*(np.log(1+kappa[k]))
fDerivative[k] = SingleComponentCapacity[k]*(1/(1+kappa[k]))
for k in range(N-1):
g[k] = f[k] - f[k+1]
for k in range(N):
g[N-1] += AffinityCoefficient[k]*partialPressureComponents[k]/kappa[k]
g[N-1] = g[N-1] - 1
for k in range(N-1):
phi[k,k] = fDerivative[k]
phi[k,k+1] = -fDerivative[k+1]
for k in range(0,N):
phi[N-1,k] = - (AffinityCoefficient[k]*partialPressureComponents[k]/(kappa[k]**2))
sigma = np.linalg.solve(phi, g)
kappa_old = kappa
kappa = kappa_old - sigma
delta_kappa = np.abs(kappa-kappa_old)
i += 1
if i > 20 or np.any(kappa<0):
print("No convergence")
error = 1
break
if np.any(kappa < 0):
print("No convergence")
error = 1
break
adsorbedFraction = partialPressureComponents*AffinityCoefficient/kappa
adsorbedConcentrationPure = SingleComponentCapacity*(kappa
/(1+kappa))
C_total = 0
for k in range(0,N):
C_total += ( (adsorbedFraction[k]) / adsorbedConcentrationPure[k])
C_total = 1/C_total
adsorbedConcentration = C_total*adsorbedFraction
fastiastGraphConcentration=np.vstack((fastiastGraphConcentration, adsorbedConcentration))
fastiastGraphFraction=np.vstack((fastiastGraphFraction, adsorbedFraction))
fastiastPressure=np.vstack((fastiastPressure, P_gas))
if error == 0:
###Result###
return(fastiastGraphConcentration[1,:])
else:
return(0)
FastIAST(2,298,1,0,0,0,0,0)
There is no current method to call external "black-box" functions with Gekko. One of the reasons that Gekko performs well is that it compiles the functions to byte-code as if they were written in FORTRAN or C++ and it uses automatic differentiation to provide sparse 1st and 2nd derivatives to the solvers. One work-around is to use a c-spline (1D) or b-spline (2D) to approximate the function if there are only one or two independent variables. The simple problem would qualify but the FastIAST has 8 independent variables so that approach wouldn't work. There is also the deep learning library in Gekko to approximate functions of any dimension, but it may be more difficult to control the approximation error. There are new developments coming that may allow external function calls and interfaces to other machine learning libraries that would allow function approximations. As of Gekko v1.0.4, external black-box function calls aren't possible. Python function calls are allowed such as:
from gekko import GEKKO
m = GEKKO()
def f(x,c):
y = m.sum([(xi-c)**2 for xi in x])
return y
x1 = m.Array(m.Var,5)
p = 2.1
m.Minimize(f(x1,p))
m.Equation(f(x1,0)<=10)
m.solve()
print(x1)
Related
I am currently using Python.
However, I am struggling with one error.
This is the tool I have made so far.
from gekko import GEKKO
import numpy as np
m = GEKKO(remote=False)
m.options.SOLVER = 1
hour = 24
Num_EV = 1
p_i =m.Array(m.Var,(hour,Num_EV))
TOU = [64.9,64.9,64.9,64.9,64.9,64.9,64.9,64.9,152.6,239.8,
239.8,152.6,239.8,239.8,239.8,239.8,152.6,152.6,
152.6,152.6,152.6,152.6,152.6,64.9]
n=len(TOU)
inp = m.Array(m.Var, (n), value=0.0, lb=0.0, ub=7.0, integer=True)
# EV min/Max setting
for tt in range(0,hour):
p_i[tt,0].lower = 30
p_i[tt,0].upper = 70
# EV Charger min/Max setting
Num_EV_C = 1
p_j = m.Array(m.Var, (hour, Num_EV_C))
for tt in range(0,hour):
p_j[tt,0].lower = 0
p_j[tt,0].upper = 7
# s.t : EV SOC
p_i[0,0] = 30 # inital EV SOC
eq_EV_SOC = np.zeros((hour,1))
eq_EV_SOC = list(eq_EV_SOC)
for tt in range(0,hour):
for i in range(0,Num_EV):
eq_EV_SOC[tt] = p_i[tt-1,i] + p_i[tt,i] == p_i[tt,0]
m.Equation(eq_EV_SOC)
# s.t : EV charging rate
p_j[0,0] = 0
eq_EV_C = np.zeros((hour,1))
eq_EV_C = list(eq_EV_C)
for tt in range(0,hour):
for i in range(0,Num_EV_C):
eq_EV_C[tt] = p_j[tt,0] >= p_j[tt,i]
m.Equation(eq_EV_C)
# Object Function : sum[i=n]*sum[t=T]()
F = np.zeros((hour*Num_EV))
F = F.tolist()
for tt in range(0,hour):
for i in range(0,Num_EV):
F[i+tt*Num_EV] = p_i[tt,i] * p_j[tt,i]
F_Obj = m.sum(F)
m.Minimize(F_Obj)
m.solve(disp=True)
Exception: #error: Equation Definition
Equation without an equality (=) or inequality (>,<) true STOPPING...
I want to know this problem.
Below is a description of constraints and objective functions.
s.t is constraint. First constraint is EV SOC range. EV SOC minimum is 30 and Maxmium is 70. EV SOC form is (inital SOC + time by EV SOC). Second constraint is EV Charging range. EV Charging range is from 0 to 7.
Finally, Object function is to minimize the product of tou and charging rate.
There are a few problems with the model that can be observed by opening the model file in the run directory. Use m.open_folder() and open the gk_model0.apm file with a text editor. Here are some of the equations that indicate that there is a problem with the formulation:
True
v50>=v50
v51>=v51
v52>=v52
v53>=v53
The True expression is because a constant is evaluated with another constant in the first cycle of:
for tt in range(0,hour):
for i in range(0,Num_EV_C):
eq_EV_C[tt] = p_j[tt,0] >= p_j[tt,i]
This gives a Boolean True result.
The initial EV SOC should either be changed to fixed or else include a simple equation:
# s.t : EV SOC
m.Equation(p_i[0,0]== 30) # inital EV SOC
# s.t : EV charging rate
m.Equation(p_j[0,0]==0)
It appears that the charging rate should decrease over time with this constraint:
m.Equation(p_j[0,0]==0)
for tt in range(0,hour):
for i in range(1,Num_EV_C):
m.Equation(p_j[tt,0] >= p_j[tt,i])
The index is changed to p_j[tt,0] >= p_j[tt,i] so that p_j[tt,0] >= p_j[tt,0] is not included as an equation. Should the range for time also be adjusted here to start at 1?
for tt in range(1,hour):
for i in range(0,Num_EV):
m.Equation(p_i[tt-1,i] + p_i[tt,i] == p_i[tt,0])
The problem is currently infeasible, even with these corrections. Maybe this problem can help:
from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
m = GEKKO()
m.options.SOLVER = 1
m.options.IMODE = 3
Num_car = 1
TOU = [64.9,64.9,64.9,64.9,64.9,64.9,64.9,64.9,152.6,239.8,
239.8,152.6,239.8,239.8,239.8,239.8,152.6,152.6,
152.6,152.6,152.6,152.6,152.6,64.9]
n=len(TOU)
inp = m.Array(m.Var, (n), value = 0.0,
lb = 0.0, ub = 7.0, integer = True)
SOC_Min = 30; SOC_Max = 90
# set bounds 30-90
SOC_t = m.Array(m.Var,(n, Num_car),lb=SOC_Min,ub=SOC_Max)
# set new bounds 30-70
for tt in range(0,n):
for j in range(Num_car):
SOC_t[tt,j].lower = 30
SOC_t[tt,j].upper = 70
for j in range(Num_car):
# initial SOC
m.Equation(SOC_t[0,j]==30) # initial charge at start
m.Equation(SOC_t[n-1,j]==70) # desired charge at end
for tt in range(1,n):
m.Equation(SOC_t[tt,j] == SOC_t[tt-1,j] + inp[tt])
for tt in range(n):
m.Minimize(TOU[tt]*inp[tt])
m.options.IMODE = 3
m.options.SOLVER = 1
m.solve(disp=True)
plt.figure(figsize=(8,5))
plt.subplot(3,1,1)
for j in range(Num_car):
p = np.empty(n)
for tt in range(n):
p[tt] = SOC_t[tt,j].value[0]
plt.plot(p,'r.-',label='vehicle '+str(j+1))
plt.legend(); plt.ylabel('SOC'); plt.grid()
plt.subplot(3,1,2)
p = np.empty(n)
for tt in range(n):
p[tt] = inp[tt].value[0]
plt.plot(p,'ko-',label='charge rate')
plt.legend(); plt.ylabel('charge'); plt.grid()
plt.subplot(3,1,3)
plt.plot(TOU,'bs-',label='electricity price')
plt.ylabel('price'); plt.grid()
plt.legend(); plt.xlabel('Time (hr)')
plt.tight_layout()
plt.savefig('soc_results.png',dpi=300)
plt.show()
This is a solution to this question: How to optimize the electric vehicle charging cost using Gekko? It looks like you may be working on a similar problem.
Here are additional similar questions:
How to model a time-dependent constraint in Gekko?
GEKKO RTO vs MPC MODES
Mixed-Integer Model Predictive Control using Gekko
Variable bounds in MPC with GEKKO
I am trying to minimize the average root mean squared error of the following form in a class file using Gekko:
objective = np.sqrt((np.sum((ym-np.array(y))**2))/N/
(np.sum((ym-np.mean(ym))**2))/N)
Here is the code:
# Code
from math import ceil
import numpy as np
import pandas as pd
import os
from gekko import GEKKO
import sys
from demandlib.tools import add_weekdays2df
import matplotlib.pyplot as plt
class HeatBuilding_Personalized:
def __init__(self, df_index, **kwargs):
self.datapath = kwargs.get(
'datapath', os.path.join(os.path.dirname(__file__), 'bdew_data'))
self.df = pd.DataFrame(index=df_index)
self.df = add_weekdays2df(self.df, holiday_is_sunday=True,
holidays=kwargs.get('holidays'))
self.df['hour'] = self.df.index.hour + 1 # hour of the day
self.temperature = kwargs.get('temperature')
self.annual_heat_demand = kwargs.get('annual_heat_demand')
self.shlp_type = kwargs.get('shlp_type').upper()
self.wind_class = kwargs.get('wind_class')
self.building_class = kwargs.get('building_class', 0)
self.ww_incl = kwargs.get('ww_incl', True)
self.name = kwargs.get('name', self.shlp_type)
self.data_points = kwargs.get('data_points')
self.st_p= kwargs.get('st_p')
self.end= kwargs.get('end')
def get_bdew_profile(self):
""" Calculation of the normalized hourly heat demand
"""
self.df['temperature'] = self.temperature.values
self.df['temperature_geo'] = self.weighted_temperature(how='geometric_series')
sf = self.get_sf_values()
f = self.get_weekday_parameters()
# measurements
self.df['data_points']=self.data_points.values
self.df= self.df[self.st_p:self.end]
self.df=self.df.dropna()
self.annual_heat_demand= self.df['data_points'].sum()
self.temperature= pd.DataFrame(self.df['temperature'])
print(self.df)
ym = pd.DataFrame(self.df['data_points'])
print("amount of nan",str(ym.isnull().sum()))
ymeas_mean = np.mean(ym)
print(ym)
print('ymeas_mean:',ymeas_mean)
x1= np.array(self.df['temperature_geo'])
x2= np.array(self.get_weekday_parameters())
x3= np.int(self.annual_heat_demand)
x4= np.array(self.get_sf_values())
ym= np.array(ym)
# GEKKO model
m = GEKKO(remote=False)
a = m.FV( 3.7,lb=1,ub=4)
a.STATUS=1
b = m.FV(-35.1,lb=-40,ub=-30)
b.STATUS=1
c = m.FV(7.1,lb=5,ub=9)
c.STATUS=1
d = m.FV( 0.9,lb=0.1,ub=1.5)
d.STATUS=1
# variables
T_g= m.Param(value=x1)
f=m.Param(value=x2)
annual_demand=m.Param(value=x3)
sf=m.Param(value=x4)
ymeas = m.Param(value=ym)
N = len(ym)
print('index n:',N)
yest = m.CV(value=0)
yest.FSTATUS=1
# y=m.Var() # I am defining my state variabel
# y = m.Var()
# z.FSTATUS=1
# regression equation
k = m.Intermediate((a / (1 + (b / (T_g - 40)) ** c) + d))
s=m.Intermediate(np.sum(k*f))
kw=m.Intermediate( 1.0 / (s / 24))
m.Equation(yest == (k* kw * f * sf) * annual_demand)
# objectives
# m.Minimize(((yest-ymeas)/ymeas)**2)
m.Obj(m.sqrt((np.sum((ymeas-yest)**2))/N/(np.sum((ymeas-np.mean(ymeas))**2))/N))
# print('Obj init value = ' + str(object_af.value))
# regression mode
m.options.IMODE = 2
m.options.SOLVER = 1 # considering APOPT solver for 1 and IPOPT for 3
# optimize
m.options.MAX_ITER = 20
m.options.OTOL = 1.0e-10
m.options.RTOL = 1.0e-10
m.solve(disp=True)
# print parameters
# print('Obj after value = ' + str(vd.value))
print('Optimized, a = ' + str(a.value[0]))
print('Optimized, b = ' + str(b.value[0]))
print('Optimized, c = ' + str(c.value[0]))
print('Optimized, d = ' + str(d.value[0]))
# print('Optimized, h = ' + str(h.value))
# sys.exit()
print("optimization is ok")
sf = self.get_sf_values()
f = self.get_weekday_parameters()
h = (a.value[0] / (1 + (b.value[0] / (self.df['temperature_geo'] - 40)) ** c.value[0]) + d.value[0])
kw = 1.0 / (sum(h * f) / 24) #1.0 instead of annual heat demand because the #annual heat demand is already multiplied in get_bdew_profile and divide by 24 to get #daily value
y = (kw * h * f * sf) * self.annual_heat_demand
objective= np.sqrt((np.sum((ym-np.array(y))**2))/N/(np.sum((ym-np.mean(ym))**2))/N)
print('objective calculated without Gekko:',objective)
return y
It returns this output:
Outputs: Solver :
APOPT (v1.0) Solution time : 27.2771999999968 sec
Objective : 40884011.5968099
Successful solution --------------------------------------------------
Optimized, a = 3.8708321781 Optimized, b = -31.844822393
Optimized, c = 7.8648564579 Optimized, d = 1.0244814518
The objective value is high. Without Gekko the objective is calculated as 0.01904060781034217. Why is it different?
It is hard to diagnose the problem because it is missing the data to run and verify. Here are a couple things to change:
Set yest as a Variable instead of a CV. It is automatically adding squared error terms when you declare a CV with FSTATUS=1 as described in the Dynamic Optimization course and in the Estimator Tuning Lesson. Because you are defining a custom objective, there is no need to declare a CV.
#yest = m.CV(value=0)
#yest.FSTATUS=1
yest = m.Var(value=0)
For a direct comparison, try declaring Intermediate variables to inspect the parts of the objective. Also, use m.sum() instead of np.sum() for the Gekko version of summation. The den piece is a number so it can be pre-calculated before the objective function is defined with ym.
den = (np.sum((ym-np.mean(ym))**2)
m.Obj(m.sqrt((np.sum((ymeas-yest)**2))/(den*N*N)))
Please post complete minimal, verifiable code for more specific help.
so we corrected the code like said in the previous comment but we get problems when we try to take a sum of a gekko parameter and we don't understand why. s is the variable where we calculate a sum and try to use it in the next equation but it doesn't work. Even with numpy.sum() it doesn't sum it up. We get this error: TypeError: x must be a python list of GEKKO parameters, variables, or expressions
Any idea what we need to change on factor k or f so the sum can be achieved?
x1= np.array(self.df['temperature_geo'])
x2= np.array(self.get_weekday_parameters())
x3= np.int(self.annual_heat_demand)
x4= np.array(self.get_sf_values())
ym= np.array(ym)
# GEKKO model
m = GEKKO(remote=False)
# variables
T_g= m.Param(value=x1)
f=m.Param(value=x2)
annual_demand=m.Param(value=x3)
sf=m.Param(value=x4)
ymeas = m.Param(value=ym)
yest = m.Var(value=0)
# regression equation
k = m.Intermediate((a / (1 + (b / (T_g - 40)) ** c) + d))
s=m.Intermediate(m.sum(k*f))
kw=m.Intermediate( 1.0 / (s / 24))
m.Equation(yest == (k* kw * f * sf) * annual_demand)
den = (m.sum((ymeas-np.mean(ymeas))**2))
ben = m.sum((ymeas-yest)**2)
m.Obj(m.sqrt((ben)/N/(den)/N))
# print('Obj init value = ' + str(object_af.value))
# regression mode
m.options.IMODE = 2
m.options.SOLVER = 1 # considering APOPT solver for 1 and IPOPT for 3
# optimize
m.options.MAX_ITER = 20
m.options.OTOL = 1.0e-10
m.options.RTOL = 1.0e-10
m.solve(disp=True)
I tried to implement a weighted correlation function based on the article in the link, formula number 2:
http://staff.ustc.edu.cn/~lshao/papers/paper07.pdf
let suppose to have 3 vectors s, r and w each of n elements.
The vector w is obtained from the following formulas:
w = |r|/(1+D)
D = |s - k*r|
k = (r_Transpose * s)/(r_Transpose*r)
I would like to implement the formula for the weighted correlation function described on the article. It is correct my implementation?
I start from a matrix of dimension [224,640] which means that i have 640 vectors of 224 elements. I would like to calculated the weighted correlation coefficient between those 640 vector respect one other vector - r. Every one of those 640 vector is the vector s.
ref = reference
ref_mean = np.mean(ref) # calcolo il valore medio dello spettro di riferimento
sens = 190
frame_correlation = np.zeros((1,640))
img_correlation = np.zeros((nf,npixels))
for i in range(nf):
frame_test = dati_new[:,:,i] Selection of one matrix from a cell of matrices
for j in range(npixels):
spettro_test = frame_test[:,j] # is my vector s
spettro_test = np.reshape(spettro_test,(224,1))
spettro_test_mean = np.mean(spettro_test)
k = np.dot(np.transpose(ref),spettro_test)/np.dot(np.transpose(ref),ref)
k = k[0][0]
D = np.abs(spettro_test - k*ref)
W = np.abs(ref)/(1+D)
# NUMERATOR OF FORMULA IN THE ARTICLE
numeratore = np.sum(W*(spettro_test - spettro_test_mean)*(ref - ref_mean))
# DENOMINATOR
den1_ex = np.sqrt(np.sum(W*np.power(spettro_test - spettro_test_mean,2)))
den2_ex = np.sqrt(np.sum(W*np.power(ref - ref_mean,2)))
denominatore = den1_ex * den2_ex
rho = numeratore/denominatore
if rho < 0:
rho = 0
if rho > 1: # for safety reason
rho = 1
if rho >=0.99:
rho = (sens*rho)/100
frame_correlation[:,j]= rho
img_correlation[i,:] = frame_correlation
this is the code i wrote in order to implement the Weighted correlation function between two array, selected from a matrix.
ref = reference
ref_mean = np.mean(ref)
sens = 190
nf = n #number of matrices
frame_correlation = np.zeros((1,640))
img_correlation = np.zeros((nf,npixels))
for i in range(nf):
frame_test = dati_new[:,:,i] #dati_new is a 3D structure made of nf matrices
for j in range(npixels):
spettro_test = frame_test[:,j]
spettro_test = np.reshape(spettro_test,(224,1))
spettro_test_mean = np.mean(spettro_test)
# calcolo del peso per lo spettro selezionato
k = np.dot(np.transpose(ref),spettro_test)/np.dot(np.transpose(ref),ref)
k = k[0][0]
D = np.abs(spettro_test - k*ref)
W = np.abs(ref)/(1+D)
# Definizione del numeratore del coefficiente di correlazione
numeratore = np.sum(W*(spettro_test - spettro_test_mean)*(ref - ref_mean))
# Definizione del denominatore del coefficiente di correlazione
den1_ex = np.sqrt(np.sum(W*np.power(spettro_test - spettro_test_mean,2)))
den2_ex = np.sqrt(np.sum(W*np.power(ref - ref_mean,2)))
denominatore = den1_ex * den2_ex
rho = numeratore/denominatore
if rho < 0:
rho = 0
if rho > 1: # just in case
rho = 1
if rho >=0.998:
rho = (sens*rho)/100
frame_correlation[:,j]= rho
img_correlation[i,:] = frame_correlation
img_correlation = np.array(img_correlation)
fig, ax=plt.subplots()
ax.imshow(img_correlation,cmap="gray", origin="lower")
plt.title('correlation coefficient image')
plt.xlabel("Pixels")
plt.ylabel("Number of frames")
plt.show()
I want to solve a system of 4 ODE's, it all works however, I need 1 parameter in the system to change after a state variable reaches a certrain threshold value.
These are the equations to be solved. The parameterKIIaAP needs to be 0 before the state variable IIa reaches thethreshold, and change to 0.5 after the threshold is reached (IIath).
This was my code until now, only here I manually change KIIaAP outside the intregration and guessed when it should change to 0.5 instead of calculating IIa evefy time step and once the treshold is reachd it goes up to 0.5.
from math import *
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
plt.close("all")
IIath = 4e-8 #Thrombin concentration threshold for plat. activation. (kg/kg)
PL = 0.0016 #platelet concentration (kg/kg == 200e9pl/L) ik dacht 1.9
def model(x,t,kIIaAP):
IIa = x[0]
II = x[1]
AP = x[2]
RP = x[3]
kAPAP = 5.24e-2 #platelet activation by activated platelets (s-1)
kAPII = 0.73 #Thrombin generation by activated platelets (s-1)
ksurf = 7.3e-6
kin0 = 1.7e-2 #Inhibition of thrombin in interior cells
kinadd = 3e-3 #Enhanced inhibition of thrombin due to the presence of ATH III in boundary cells
# kIIaAP = 0.0
dIIadt = -(kin0+kinadd)*IIa+(ksurf+kAPII*AP)*II
dIIdt = -(ksurf + kAPII*AP)*II
dAPdt = kAPAP * AP * RP + kIIaAP*RP
dRPdt = -kAPAP*AP*RP - kIIaAP*RP
return [dIIadt,dIIdt,dAPdt,dRPdt]
#initial conditions
y0 = [0,9.51e-5,0,0.0016]
tend = 2000
nsteps = 4000
dt = tend/nsteps
t = np.linspace(0,tend,nsteps)
IIa = np.zeros(nsteps)
II = np.zeros(nsteps)
AP = np.zeros(nsteps)
RP = np.zeros(nsteps)
kIIaAP = np.zeros(nsteps)
kIIaAP[200:] = 0.5
#solve model
for i in range(1,nsteps):
tspan = [t[i-1],t[i]]
y = odeint(model,y0,t,args=(kIIaAP[i],)) #los systeem op voor 1 tijdstap
y0 = y[1] #oplossing van vorige tijdstap is nieuwe initial condition
IIa[i] = y0[0] #sla uitkomst van tijdstap op in array
II[i] = y0[1]
AP[i] = y0[2]
RP[i] = y0[3]
def kgkg2molL(value):
molmassIIa = 70e3 #molar mass IIa [Da]
M = (value * 1000 / molmassIIa) / 1.06 #1.06 derived that denisty of blood is 1060
nM = M*10**9
return nM
#thrombin list in nM
IIanM = [kgkg2molL(i) for i in IIa]
# plot the results
plt.subplot(4,1,1)
plt.plot(t,IIanM)
plt.ylabel('[IIa] nM')
plt.axhline(y=IIath,color="r")
plt.subplot(4,1,2)
plt.plot(t,II,'b--')
plt.ylabel('[II] kg/kg')
plt.subplot(4,1,3)
plt.plot(t,AP)
plt.ylabel('[AP] kg/kg')
plt.subplot(4,1,4)
plt.plot(t,RP)
plt.ylabel('[RP] kg/kg')
plt.xlabel('time (s)')
In short,
I need help making sure kIIaAP jumps from 0 to 0.5 after state variable IIa hits a threshold value, automatically mid integration , and not manually like I did by defining the array.
Thanks in advance.
i'm currently incredibly stuck on what isn't working in my code and have been staring at it for hours. I have created some functions to approximate the solution to the laplace equation adaptively using the finite element method then estimate it's error using the dual weighted residual. The error function should give a vector of errors (one error for each element), i then choose the biggest errors, add more elements around them, solve again and then recheck the error; however i have no idea why my error estimate isn't changing!
My first 4 functions are correct but i will include them incase someone wants to try the code:
def Poisson_Stiffness(x0):
"""Finds the Poisson equation stiffness matrix with any non uniform mesh x0"""
x0 = np.array(x0)
N = len(x0) - 1 # The amount of elements; x0, x1, ..., xN
h = x0[1:] - x0[:-1]
a = np.zeros(N+1)
a[0] = 1 #BOUNDARY CONDITIONS
a[1:-1] = 1/h[1:] + 1/h[:-1]
a[-1] = 1/h[-1]
a[N] = 1 #BOUNDARY CONDITIONS
b = -1/h
b[0] = 0 #BOUNDARY CONDITIONS
c = -1/h
c[N-1] = 0 #BOUNDARY CONDITIONS: DIRICHLET
data = [a.tolist(), b.tolist(), c.tolist()]
Positions = [0, 1, -1]
Stiffness_Matrix = diags(data, Positions, (N+1,N+1))
return Stiffness_Matrix
def NodalQuadrature(x0):
"""Finds the Nodal Quadrature Approximation of sin(pi x)"""
x0 = np.array(x0)
h = x0[1:] - x0[:-1]
N = len(x0) - 1
approx = np.zeros(len(x0))
approx[0] = 0 #BOUNDARY CONDITIONS
for i in range(1,N):
approx[i] = math.sin(math.pi*x0[i])
approx[i] = (approx[i]*h[i-1] + approx[i]*h[i])/2
approx[N] = 0 #BOUNDARY CONDITIONS
return approx
def Solver(x0):
Stiff_Matrix = Poisson_Stiffness(x0)
NodalApproximation = NodalQuadrature(x0)
NodalApproximation[0] = 0
U = scipy.sparse.linalg.spsolve(Stiff_Matrix, NodalApproximation)
return U
def Dualsolution(rich_mesh,qoi_rich_node): #BOUNDARY CONDITIONS?
"""Find Z from stiffness matrix Z = K^-1 Q over richer mesh"""
K = Poisson_Stiffness(rich_mesh)
Q = np.zeros(len(rich_mesh))
Q[qoi_rich_node] = 1.0
Z = scipy.sparse.linalg.spsolve(K,Q)
return Z
My error indicator function takes in an approximation Uh, with the mesh it is solved over, and finds eta = (f - Bu)z.
def Error_Indicators(Uh,U_mesh,Z,Z_mesh,f):
"""Take in U, Interpolate to same mesh as Z then solve for eta vector"""
u_inter = interp1d(U_mesh,Uh) #Interpolation of old mesh
U2 = u_inter(Z_mesh) #New function u for the new mesh to use in
Bz = Poisson_Stiffness(Z_mesh)
Bz = Bz.tocsr()
eta = np.empty(len(Z_mesh))
for i in range(len(Z_mesh)):
for j in range(len(Z_mesh)):
eta[i] += (f[i] - Bz[i,j]*U2[j])
for i in range(len(Z)):
eta[i] = eta[i]*Z[i]
return eta
My next function seems to adapt the mesh very well to the given error indicator! Just no idea why the indicator seems to stay the same regardless?
def Mesh_Refinement(base_mesh,tolerance,refinement,z_mesh,QOI_z_mesh):
"""Solve for U on a normal mesh, Take in Z, Find error indicators, adapt. OUTPUT NEW MESH"""
New_mesh = base_mesh
Z = Dualsolution(z_mesh,QOI_z_mesh) #Solve dual solution only once
f = np.empty(len(z_mesh))
for i in range(len(z_mesh)):
f[i] = math.sin(math.pi*z_mesh[i])
U = Solver(New_mesh)
eta = Error_Indicators(U,base_mesh,Z,z_mesh,f)
while max(abs(k) for k in eta) > tolerance:
orderedeta = np.sort(eta) #Sort error indicators LENGTH 40
biggest = np.flipud(orderedeta[int((1-refinement)*len(eta)):len(eta)])
position = np.empty(len(biggest))
ratio = float(len(New_mesh))/float(len(z_mesh))
for i in range(len(biggest)):
position[i] = eta.tolist().index(biggest[i])*ratio #GIVES WHAT NUMBER NODE TO REFINE
refine = np.zeros(len(position))
for i in range(len(position)):
refine[i] = math.floor(position[i])+0.5 #AT WHAT NODE TO PUT NEW ELEMENT 5.5 ETC
refine = np.flipud(sorted(set(refine)))
for i in range(len(refine)):
New_mesh = np.insert(New_mesh,refine[i]+0.5,(New_mesh[refine[i]+0.5]+New_mesh[refine[i]-0.5])/2)
U = Solver(New_mesh)
eta = Error_Indicators(U,New_mesh,Z,z_mesh,f)
print eta
An example input for this would be:
Mesh_Refinement(np.linspace(0,1,3),0.1,0.2,np.linspace(0,1,60),20)
I understand there is alot of code here but i am at a loss, i have no idea where to turn!
Please consider this piece of code from def Error_Indicators:
eta = np.empty(len(Z_mesh))
for i in range(len(Z_mesh)):
for j in range(len(Z_mesh)):
eta[i] = (f[i] - Bz[i,j]*U2[j])
Here you override eta[i] each j iteration, so the inner cycle proves useless and you can go directly to the last possible j. Did you mean to find a sum of the (f[i] - Bz[i,j]*U2[j]) series?
eta = np.empty(len(Z_mesh))
for i in range(len(Z_mesh)):
for j in range(len(Z_mesh)):
eta[i] += (f[i] - Bz[i,j]*U2[j])