I have two questions about the Gekko library in Python.
Is there any way to increase the below code's performance (Input1, Input2)? The code was solved fast, and the results were correct when lines 170~195 were excluded (commented). However, when I executed the entire code (including lines 170-195), the performance decreased dramatically, and I didn't obtain the results after waiting more than 30 mins. I presumed it was because of the if3 functions in lines 170 and 171 because as soon as I included these lines, the code couldn't be solved.
Even though I defined the days_to_consider variable in lines 61 to 1, I will increase the variable value to 365 days after the code can be executed successfully, which means it is essential for me to solve this code performance problem.
import numpy as np
from gekko import GEKKO
np.set_printoptions(linewidth=2000)
np.set_printoptions(formatter={'float': '{: 0.2f}'.format})
# Given parameters (Please ignore, this is just given input parameters)
left_numeric = np.zeros((14,1))
tempo = [3738.0, 8.5, 1, 1, 1, 2.25, 3.28, 0, 0.6, 1, 0.5, 4, 285000, 0]
for i in range(14):
left_numeric[i,0] = tempo[i]
left_string = ['Urban / City', 'Light : 110,000 * Af', 'Yes', '23. Variable air volume / Water or Water&Air / Air / Yes', '1. Mechanical system only; no provision for natural ventilation', 'Slowly rotating or intermittent heat exchangers (0.7)', 'No exhaust air recirculation', 'Automatic control more than 50%', 'Automatic control more than 50%', 'Taps More Than 3m from Heat Generation', 'Co-Generation (0.9)', '20', '', 'Electricity', 'Electricity', 'Electricity']
weatherData = np.load("Atlanta_TMY3_climate.npy")
weatherData = np.insert(weatherData, 0, np.zeros((1,15)), 0)
Info_Array = np.load("Info_Array.npy")
vsite = 0.8
totalAppliance = 12.0
totalOccupants = 8.39748075577327
hs_unoccupied = 16.0
Cm = 30.55555555
Htr_ms = 22.75
Htr_w = 1.5824055209225467
Htr_is = 15.525
Htr_em = 1.0723552727080168
f_BAC_hc = 0.7
f_BAC_e = 0.87
fcntrl_heat = 0.5
fcntrl_cool = 0.5
dist_heat = 0.9259259
dist_cool = 1.00
totalArea = 877.4
total_DHW_system = 76.40691666666666
effi_gen_DHW = 0.9
occu_equi_hours = 3093.5
Prs = 0.40580206298113436
Prm = 0.5555555555555556
HR_efficiency = 0.7
T_supply_h = 28.0
T_supply_c = 17.0
ventSupply = 2.519244226731981
ventRecirculation = 1
ventilation_cooling_type = 1
dist_heat = 0.9259259
dist_cool = 1.00000
# Create GEKKO model
m = GEKKO(remote=False)
#m.open_folder()
print(m.path)
days_to_consider = 1
m.time = np.linspace(0, 24*days_to_consider, 24*days_to_consider+1)
# Define MVs
fDim = m.MV(lb=1, ub=1, name="fDim") # dummy MV just for testing. In the future more MVs will be added and the interval will also be modified.
fDim.STATUS = 1
f_VT = 1 # this will be an MV, but for now, it is just a constant
# 2D numppy array manipulation (add zero row in the first row of the "Info_Array" and "weatherData")
T_heating_set = m.Param(value = Info_Array[0:24*days_to_consider+1,9], name="T_heating_set")
T_cooling_set = m.Param(value = Info_Array[0:24*days_to_consider+1,10], name="T_cooling_set")
# Define parameters
Te = m.Param(value = weatherData[0:24*days_to_consider+1,0], name="Te")
Wind_speed = m.Param(value = weatherData[0:24*days_to_consider+1,1], name="Wind_speed")
fapp = m.Param(value = Info_Array[0:24*days_to_consider+1,6], name="fapp")
Qapp = totalAppliance
focc = m.Param(value = Info_Array[0:24*days_to_consider+1,5], name="focc")
Qocc = totalOccupants
Qlight = m.Param(value = Info_Array[0:24*days_to_consider+1,8], name="Qlight")
Qsol = m.Param(value = Info_Array[0:24*days_to_consider+1,11], name="Qsol")
qv_infil_wind = m.Param(value = 0.0769*left_numeric[8,0]*(0.75*vsite*weatherData[0:24*days_to_consider+1,1]**2)**0.667, name="qv_infil_wind")
# Define variables
qv_infil_stack = m.Var(0, name="qv_infil_stack")
T_m0_t = m.Var(name="T_m0_t")
T_m10_t = m.Var(name="T_m10_t")
T_m0 = m.Var(name="T_m0")
T_m10 = m.Var(name="T_m10")
T_s0 = m.Var(name="T_s0")
T_s10 = m.Var(name="T_s10")
T_air0 = m.Var(value=hs_unoccupied, name="T_air0")
T_air10 = m.Var(name="T_air10")
T_m_ac_t = m.Var(value=hs_unoccupied, name="T_m_ac_t")
T_m_ac = m.Var(value=hs_unoccupied, name="T_m_ac")
T_s_ac = m.Var(name="T_s_ac")
T_air_ac = m.Var(name="T_air_ac")
T_air_set = m.Var(name="T_air_set")
T_air_set_prev = m.Var(name="T_air_set_prev")
m.delay(T_m_ac_t, T_air_set_prev, 1)
Q_HC_nd = m.Var(value=0, name="Q_HC_nd")
# Define delivered energy
E_heating = m.Var(name="E_heating")
E_cooling = m.Var(name="E_cooling")
E_lighting = m.Var(name="E_lighting")
E_fan = m.Var(name="E_fan")
E_pump = m.Var(name="E_pump")
E_equip = m.Var(name="E_equip")
E_dhw = m.Var(name="E_dhw")
V_heating_sup_air = m.Var(name="V_heating_sup_air")
V_cooling_sup_air = m.Var(name="V_cooling_sup_air")
q_v_sup = m.Var(name="q_v_sup")
# Build building Equations
# 0) Internal heat gains
Qint = m.Intermediate(fapp*Qapp + focc*Qocc + fDim*Qlight, name="Qint")
Qia = m.Intermediate(0.5*Qint, name="Qia")
Qst = m.Intermediate(Prs*(Qia + Qsol), name="Qst")
Qm = m.Intermediate(Prm*(Qia + Qsol), name="Qm")
# 1) Airflow
qv_mech_sup = m.Intermediate(ventSupply*ventRecirculation*focc, name="qv_mech_sup")
m.Equation(qv_infil_stack == 0.0146*left_numeric[8,0]*(0.7*left_numeric[1,0]*m.abs(Te-T_air_set))**0.667)
##qv_infil_stack = m.Intermediate(0.0146*left_numeric[8,0]*(0.7*left_numeric[1,0]*m.abs(Te-T_air_set))**0.667, name="qv_infil_stack")
qv_infil_sw = m.Intermediate(m.max3(qv_infil_stack,qv_infil_wind) + 0.14*qv_infil_stack*qv_infil_wind/left_numeric[8,0], name="qv_infil_sw")
Hve = m.Intermediate((qv_mech_sup*(1-HR_efficiency) + qv_infil_sw)*0.3333, name="Hve")
Htr_1 = m.Intermediate(Hve*Htr_is/(Hve + Htr_is), name="Htr_1")
# 2) Temperature
Tm_denom = m.Intermediate(Htr_ms + Htr_w + Htr_1, name="Tm_denom")
T_m_intermediate = m.Intermediate(0.5*((Htr_1+Htr_w)*Htr_ms/Tm_denom+Htr_em), name="T_m_intermediate")
m.Equations([\
T_m0_t == (1/(Cm+T_m_intermediate))*((Cm-T_m_intermediate)*T_air_set_prev+(Htr_ms*(Htr_w+Htr_1)/Tm_denom+Htr_em)*Te+(Htr_ms/Tm_denom)*Qst+(Htr_ms*Htr_1)/Hve/Tm_denom*(Qia)+Qm),\
T_m10_t == (1/(Cm+T_m_intermediate))*((Cm-T_m_intermediate)*T_air_set_prev+(Htr_ms*(Htr_w+Htr_1)/Tm_denom+Htr_em)*Te+(Htr_ms/Tm_denom)*Qst+(Htr_ms*Htr_1)/Hve/Tm_denom*(Qia+10)+Qm),\
T_m0 == 0.5*(T_air_set_prev+T_m0_t),\
T_m10 == 0.5*(T_air_set_prev+T_m10_t),\
T_s0 == (Htr_ms*T_m0 +(Htr_w+Htr_1)*Te+Qst+Htr_1*Qia/Hve)/Tm_denom,\
T_s10 == (Htr_ms*T_m10+(Htr_w+Htr_1)*Te+Htr_1*10/Hve+Qst+Htr_1*Qia/Hve)/Tm_denom,\
T_air0 == (Htr_is*T_s0 +Hve*Te+Qia)/(Htr_is+Hve),\
T_air10 == (Htr_is*T_s10+Hve*Te+10+Qia)/(Htr_is+Hve)])
# 3. Heating/Cooling need
# Tair set & Q_HC_nd
m.Equations([T_air_set == m.if3(T_air0-T_heating_set, T_heating_set, m.if3(T_cooling_set-T_air0, T_cooling_set, T_air0)),\
Q_HC_nd == 10*(T_air_set-T_air0)/(T_air10-T_air0)])
# 4. Tac & Q_nd
m.Equations([\
T_m_ac_t == (1/(Cm+T_m_intermediate))*((Cm-T_m_intermediate)*T_air_set_prev+(Htr_ms*(Htr_w+Htr_1)/Tm_denom+Htr_em)*Te+(Htr_ms/Tm_denom)*Qst+(Htr_ms*Htr_1)/Hve/Tm_denom*(Qia+Q_HC_nd)+Qm),\
T_m_ac == 0.5*(T_air_set_prev+T_m_ac_t),\
T_s_ac == (Htr_ms*T_m_ac+(Htr_w+Htr_1)*Te+Htr_1*Q_HC_nd/Hve+Qst+Htr_1*Qia/Hve)/Tm_denom,\
T_air_ac == (Htr_is*T_s_ac+Hve*Te+Q_HC_nd+Qia)/(Htr_is+Hve)])
m.Minimize(Q_HC_nd) # please use (uncomment) this line when the upper part of the code (line 1-163) is executed.
#_________________________When below code is included, the solver couldn't solve________________________#
##Q_heat_nd = m.Intermediate(m.if3(Q_HC_nd, 0, Q_HC_nd), name="Q_heat_nd") # suspect that this line slows down the code performance
##Q_cool_nd = m.Intermediate(m.if3(Q_HC_nd, -Q_HC_nd, 0), name="Q_cool_nd")
##
### 5. System delivered energy use (Unit: kW)
##m.Equations([E_heating == Q_heat_nd*f_BAC_hc/(dist_heat*left_numeric[5,0])*totalArea/1000,\
## E_cooling == f_VT*Q_cool_nd*f_BAC_hc/(dist_cool*left_numeric[6,0])*totalArea/1000,\
## E_lighting == fDim*Qlight*totalArea/1000,\
## E_equip == fapp*Qapp*totalArea/1000,\
## E_pump == 8*(fcntrl_heat+fcntrl_cool)/3.6/occu_equi_hours*totalArea,\
## E_dhw == total_DHW_system/effi_gen_DHW/occu_equi_hours*totalArea/1000,\
## V_heating_sup_air == Q_heat_nd*0.0036/(T_supply_h-T_air_ac)/0.001239913,\
## V_cooling_sup_air == Q_cool_nd*0.0036/(T_air_ac-T_supply_c)/0.001239913])
##
##
##if ventilation_cooling_type == 3 and left_numeric[7,0] == 0:
## m.Equation(E_fan == (m.max3(V_heating_sup_air, V_cooling_sup_air))*left_numeric[9,0]*left_numeric[10,0]*f_BAC_e*totalArea/1000)
##
##elif ventilation_cooling_type == 3 and left_numeric[7,0] != 0:
## m.Equation(E_fan == (m.max3(V_heating_sup_air, V_cooling_sup_air)+left_numeric[7,0]*3.6/totalArea*focc)*left_numeric[9,0]*left_numeric[10,0]*f_BAC_e)
##
##elif ventilation_cooling_type != 3 and left_numeric[7,0] == 0:
## m.Equation(E_fan == (m.max3(m.max3(V_heating_sup_air, V_cooling_sup_air),qv_mech_sup*(1-HR_efficiency)))*left_numeric[9,0]*left_numeric[10,0]*f_BAC_e*totalArea/1000)
##
##elif ventilation_cooling_type != 3 and left_numeric[7,0] != 0:
## m.Equation(E_fan == (m.max3(m.max3(V_heating_sup_air, V_cooling_sup_air),qv_mech_sup*(1-HR_efficiency))+left_numeric[7,0]*3.6/totalArea*focc)*left_numeric[9,0]*left_numeric[10,0]*f_BAC_e)
##m.Minimize(E_heating + E_cooling + E_lighting + E_fan + E_equip + E_pump + E_dhw) # please use (uncomment) this line when the entire code is executed.
#_______________________________________________________________________________________________________#
m.options.IMODE = 6
m.options.DIAGLEVEL = 4
m.options.SOLVER = 1
m.options.MAX_ITER = 1000000
m.solve(disp=True, GUI=False, debug=False)
I plan to conduct dynamic optimal control problems, which will be comprised of a total of ~45 MVs from ~10 buildings (the code is shown above, each building has 4-5 MVs) and 1 community PV (1 MV, the model is shown here) for 8,760-time steps(= 365 days x 24 hrs). Do you think this size of the problem is solvable from the IPOPT solver within a few hours on a normal personal laptop (or if the complexity of the IPOPT solver algorithm is available, I would appreciate it)? I think this would be challenging to solve because the number of the MVs becomes about ~400,000 (=~45 MVs x 8,760 hours), and I wonder if the IPOPT solver can handle this size of the optimization problem.
The commented code has 6 max3() functions and 2 if3() functions. Those add one binary variable for each time point so a total of 25 x 8 = 200 binary variables for 1 day and (24*365 + 1) x 8 = 70,088 binary variables for 365 days. The year-long solution would likely take too much time. Here are some suggestions to improve the solution time:
Use m.options.DIAGLEVEL=0 instead of 4. The additional diagnostics take longer with pre-processing.
Try m.options.REDUCE=3 to perform pre-processing to reduce the number of equations, if possible.
Initialize with m.options.SOLVER=3 (IPOPT) and then switch to m.options.SOLVER=1 (APOPT) with to obtain an integer solution. Use m.options.TIME_SHIFT=0 when solving again to keep the initial conditions from changing on the second solve.
Try if2() and max2() as MPCC forms that can solve faster than if3() and max3(), especially for large problems. They sometimes have problems if the solution is at the switch conditions.
Turn off degrees of freedom with .STATUS=0 to first solve without decision variables to obtain an initial feasible solution.
The augmented problem with the lines uncommented appear to be infeasible. Both APOPT and IPOPT reported that the problem is infeasible.
EXIT: Converged to a point of local infeasibility. Problem may be infeasible.
An error occured.
The error code is 2
---------------------------------------------------
Solver : IPOPT (v3.12)
Solution time : 86.0874 sec
Objective : 165.28211287911208
Unsuccessful with error code 0
---------------------------------------------------
The file infeasibilities.txt will have additional insights.
Related
I'm trying to label BUY, SELL, and HOLD values to the closing stock prices based on the algorithm I found in a paper. I'm not quite able to figure out the error I'm getting. I'd very much appreciate your help. Thank you.
Algorigthm:
[EDITED]
My implementation:
window_size = 11
counter = 0
result = []
window_begin_idx=0; window_end_idx=0; window_middle_idx=0; min_idx=0; max_idx=0;
while counter < len(closing_price):
if counter > window_size:
window_begin_idx = counter - window_size
window_end_idx = window_begin_idx + window_size - 1
window_middle_idx = (window_begin_idx + window_end_idx)//2
for i in range(window_begin_idx, window_end_idx+1):
rng = closing_price[window_begin_idx:window_end_idx+1]
number = closing_price[i]
mins = rng.min()
maxs = rng.max()
if number < mins:
mins=number
min_idx = np.argmin(rng)
if number > maxs:
maxs=number
max_idx = np.argmax(rng)
if max_idx == window_middle_idx:
result.append("SELL")
elif min_idx == window_middle_idx:
result.append("BUY")
else:
result.append("HOLD")
mins = 0.0
maxs = 10000.0
counter+=1
After the edit based on the author's JAVA code, I'm only getting the HOLD label. The author's implementation is here.
You need to initialize mins, maxs, min_idx and max_idx with appropriate values before the main loop.
In your case if max_idx == occurs earlier than any max_idx assignment
Edit after questing change:
Seems in Python you can make similar behavior replacing the whole for-loop with:
rng = closing_price[window_begin_idx:window_end_idx+1]
mins = rng.min()
maxs = rng.max()
min_idx = rng.index(mins)
max_idx = rng.index(maxs)
After reading through the author's implementation and following the suggestions provided by MBo, I have managed to solve this issue. So, now anyone who wants this algorithm in python, below is the code:
window_size = 11
counter = 0
result = []
window_begin_idx=0; window_end_idx=0; window_middle_idx=0; min_idx=0; max_idx=0;
number=0.0; mins=10000.0; maxs=0.0
while counter < len(closing_price):
if counter > window_size:
window_begin_idx = counter - window_size
window_end_idx = window_begin_idx + window_size - 1
window_middle_idx = (window_begin_idx + window_end_idx)//2
for i in range(window_begin_idx, window_end_idx+1):
number = closing_price[i]
if number < mins:
mins=number
min_idx = np.where(closing_price==mins)[0][0]
if number > maxs:
maxs=number
max_idx = np.where(closing_price==maxs)[0][0]
if max_idx == window_middle_idx:
result.append("SELL")
elif min_idx == window_middle_idx:
result.append("BUY")
else:
result.append("HOLD")
mins = 10000.0
maxs = 0.0
counter+=1
I am trying to track multiple set-points in the case of interacting quadruple tank system process. Here, the upper limits of tanks are 25 and lower limits are 0. I want to track the set-point values of 5,12,7 and 5. Although, I am able to track the initial 3 set-points (i.e. 5,12 and 7), I am not able to track the last set-point due to solver exceeding max. iterations. I have attached the code below->
#MHE+MPC model
#to measure computational time of the code
start=time.time()
#Process Model
p = GEKKO(remote=False)
process=0
p.time = [0,0.5]
noise = 0.25
#Constants
g = 981
g1 = .9
g2 = .9
A1=32
A3=32
A2=32
A4=32
a1=0.057
a3=0.057
a2=0.057
a4=0.057
init_h=5
#Controlled process variables
p.h1=p.SV(lb=0,ub=25)
p.h2=p.SV(lb=0,ub=25)
p.h3=p.SV(lb=0,ub=25)
p.h4=p.SV(lb=0,ub=25)
#Manipulated process variables
p.v1=p.MV(value=3.15,lb=0.1,ub=8)
p.v2=p.MV(value=3.15,lb=0.1,ub=8)
#Parameters of process
p.k1=p.Param(value=3.14,lb=0,ub=10)
p.k2=p.Param(value=3.14,lb=0,ub=10)
#Equations process
p.Equation(A1*p.h1.dt()==a3*((2*g*p.h3)**0.5)-(a1*((2*g*p.h1)**0.5))+(g1*p.k1*p.v1))
p.Equation(A2*p.h2.dt()==a4*((2*g*p.h4)**0.5)-(a2*((2*g*p.h2)**0.5))+(g2*p.k2*p.v2))
p.Equation(A3*p.h3.dt()==-a3*((2*g*p.h3)**0.5)+((1-g2)*p.k2*p.v2))
p.Equation(A4*p.h4.dt()==-a4*((2*g*p.h4)**0.5)+((1-g1)*p.k1*p.v1))
#options
p.options.IMODE = 4
#p.h1.TAU=-10^10
#p.h2.TAU=-10^10
#%% MHE Model
m = GEKKO(remote=False)
#prediction horizon
m.time = np.linspace(0,40,41) #0-20 by 0.5 -- discretization must match simulation
#MHE control, manipulated variables and parameters
m.h1=m.CV(lb=0,ub=25)
m.h2=m.CV(lb=0,ub=25)
m.h3=m.SV(lb=0,ub=25)
m.h4=m.SV(lb=0,ub=25)
m.v1=m.MV(value=3.15,lb=0.10,ub=8)
m.v2=m.MV(value=3.15,lb=0.10,ub=8)
m.k1=m.FV(value=3.14,lb=0,ub=10)
m.k2=m.FV(value=3.14,lb=0,ub=10)
#m.h1.TAU=0
#m.h2.TAU=0
#Equations
m.Equation(A1*m.h1.dt()==a3*((2*g*m.h3)**0.5)-(a1*((2*g*m.h1)**0.5))+(g1*m.k1*m.v1))
m.Equation(A2*m.h2.dt()==a4*((2*g*m.h4)**0.5)-(a2*((2*g*m.h2)**0.5))+(g2*m.k2*m.v2))
m.Equation(A3*m.h3.dt()==-a3*((2*g*m.h3)**0.5)+((1-g2)*m.k2*m.v2))
m.Equation(A4*m.h4.dt()==-a4*((2*g*m.h4)**0.5)+((1-g1)*m.k1*m.v1))
#Options
m.options.IMODE = 5 #MHE
m.options.EV_TYPE = 2
# STATUS = 0, optimizer doesn't adjust value
# STATUS = 1, optimizer can adjust
m.v1.STATUS = 0
m.v2.STATUS = 0
m.k1.STATUS=1
m.k2.STATUS=1
m.h1.STATUS = 1
m.h2.STATUS = 1
#m.h3.STATUS = 0
#m.h4.STATUS = 0
# FSTATUS = 0, no measurement
# FSTATUS = 1, measurement used to update model
m.v1.FSTATUS = 1
m.v2.FSTATUS = 1
m.k1.FSTATUS=0
m.k2.FSTATUS=0
m.h1.FSTATUS = 1
m.h2.FSTATUS = 1
m.h3.FSTATUS = 1
m.h4.FSTATUS = 1
#m.options.MAX_ITER=1000
m.options.SOLVER=3
m.options.NODES=3
#%% MPC Model
c = GEKKO(remote=False)
c.time = np.linspace(0,10,11) #0-5 by 0.5 -- discretization must match simulation
c.v1=c.MV(value=3.15,lb=0.10,ub=8)
c.v2=c.MV(value=3.15,lb=0.10,ub=8)
c.k1=c.FV(value=3.14,lb=0,ub=10)
c.k2=c.FV(value=3.14,lb=0,ub=10)
#Variables
c.h1=c.CV(lb=0,ub=25)
c.h2=c.CV(lb=0,ub=25)
c.h3=c.SV(lb=0,ub=25)
c.h4=c.SV(lb=0,ub=25)
#Equations
c.Equation(A1*c.h1.dt()==a3*((2*g*c.h3)**0.5)-(a1*((2*g*c.h1)**0.5))+(g1*c.k1*c.v1))
c.Equation(A2*c.h2.dt()==a4*((2*g*c.h4)**0.5)-(a2*((2*g*c.h2)**0.5))+(g2*c.k2*c.v2))
c.Equation(A3*c.h3.dt()==-a3*((2*g*c.h3)**0.5)+((1-g2)*c.k2*c.v2))
c.Equation(A4*c.h4.dt()==-a4*((2*g*c.h4)**0.5)+((1-g1)*c.k1*c.v1))
#Options
c.options.IMODE = 6 #MPC
c.options.CV_TYPE = 2
# STATUS = 0, optimizer doesn't adjust value
# STATUS = 1, optimizer can adjust
c.v1.STATUS = 1
c.v2.STATUS = 1
c.k1.STATUS=0
c.k2.STATUS=0
c.h1.STATUS = 1
c.h2.STATUS = 1
#c.h3.STATUS = 0
#c.h4.STATUS = 0
# FSTATUS = 0, no measurement
# FSTATUS = 1, measurement used to update model
c.v1.FSTATUS = 0
c.v2.FSTATUS = 0
c.k1.FSTATUS=1
c.k2.FSTATUS=1
c.h1.FSTATUS = 1
c.h2.FSTATUS = 1
c.h3.FSTATUS = 1
c.h4.FSTATUS = 1
sp=5
c.h1.SP=sp
c.h2.SP=sp
p1 = GEKKO(remote=False)
p1.time = [0,0.5]
#Parameters
p1.h1=p1.CV(lb=0,ub=25)
p1.h2=p1.CV(lb=0,ub=25)
p1.h3=p1.CV(lb=0,ub=25)
p1.h4=p1.CV(lb=0,ub=25)
p1.v1=p1.MV(value=3.15,lb=0.1,ub=8)
p1.v2=p1.MV(value=3.15,lb=0.1,ub=8)
p1.k1=p1.Param(lb=0,ub=10,value=3.14)
p1.k2=p1.Param(lb=0,ub=10,value=3.14)
#Equations
p1.Equation(A1*p1.h1.dt()==a3*((2*g*p1.h3)**0.5)-a1*((2*g*p1.h1)**0.5)+g1*p1.k1*p1.v1)
p1.Equation(A2*p1.h2.dt()==a4*((2*g*p1.h4)**0.5)-a2*((2*g*p1.h2)**0.5)+g2*p1.k2*p1.v2)
p1.Equation(A3*p1.h3.dt()==-a3*((2*g*p1.h3)**0.5)+(1-g2)*p1.k2*p1.v2)
p1.Equation(A4*p1.h4.dt()==-a4*((2*g*p1.h4)**0.5)+(1-g1)*p1.k1*p1.v1)
#options
p1.options.IMODE = 4
#%% problem configuration
# number of cycles
cycles = 480
# noise level
#%% run process, estimator and control for cycles
h1_meas = np.empty(cycles)
h2_meas =np.empty(cycles)
h3_meas =np.empty(cycles)
h4_meas=np.empty(cycles)
h1_est = np.empty(cycles)
h2_est = np.empty(cycles)
h3_est = np.empty(cycles)
h4_est = np.empty(cycles)
h1_plant=np.empty(cycles)
h2_plant=np.empty(cycles)
h3_plant=np.empty(cycles)
h4_plant=np.empty(cycles)
h1_measured=np.empty(cycles)
h2_measured=np.empty(cycles)
h3_measured=np.empty(cycles)
h4_measured=np.empty(cycles)
v1_est = np.empty(cycles)
v2_est = np.empty(cycles)
k1_est = np.empty(cycles)
k2_est = np.empty(cycles)
u_cont_k1 = np.empty(cycles)
u_cont_k2 = np.empty(cycles)
sp_store = np.empty(cycles)
sum_est=np.empty(cycles)
sum_model=np.empty(cycles)
# Create plot
plt.figure(figsize=(10,7))
plt.ion()
plt.show()
p.MAX_ITER=20
c.MAX_ITER=20
m.MAX_ITER=20
p1.MAX_ITER=20
for i in range(cycles):
print(i)
# set point changes
if i==cycles/4:
sp = 12
elif i==2*cycles/4:
sp = 7
elif i==3*cycles/4:
sp = 5
sp_store[i] = sp
c.h1.SP=sp
c.h2.SP=sp
c.k1.MEAS = m.k1.NEWVAL
c.k2.MEAS = m.k2.NEWVAL
if p.options.SOLVESTATUS == 1:
# print("going:",i)
c.h1.MEAS = p.h1.MODEL
c.h2.MEAS = p.h2.MODEL
c.h3.MEAS = p.h3.MODEL
c.h4.MEAS = p.h4.MODEL
print(i,'Plant Model:',p.h1.MODEL,p.h2.MODEL,p.h3.MODEL,p.h4.MODEL)
c.solve(disp=False,debug=0)
#print("NEWVAL:",i,c.u,c.u.NEWVAL)
u_cont_k1[i] = c.v1.NEWVAL
u_cont_k2[i] = c.v2.NEWVAL
#print("Horizon:",i,c.h1[0:],c.h2[0:])
#print("Move:",i,c.v1.NEWVAL,c.v2.NEWVAL)
## process simulator
#load control move
p.v1.MEAS = u_cont_k1[i]
p.v2.MEAS = u_cont_k2[i]
#simulate
p.solve(disp=False,debug=0)
#plant model
p1.k1=3.14
p1.k2=3.14
p1.v1.MEAS = u_cont_k1[i]
p1.v2.MEAS = u_cont_k2[i]
p1.solve(disp=False,debug=0)
h1_plant[i]=p1.h1.MODEL
h2_plant[i]=p1.h2.MODEL
h3_plant[i]=p1.h3.MODEL
h4_plant[i]=p1.h4.MODEL
h1_measured[i]=p1.h1.MODEL+(random()*2)*noise
h2_measured[i]=p1.h2.MODEL+(random()*2)*noise
h3_measured[i]=p1.h3.MODEL+(random()*2)*noise
h4_measured[i]=p1.h4.MODEL+(random()*2)*noise
#print("Model process output:",i,p.h1.MODEL,p.h2.MODEL,p.h3.MODEL,p.h4.MODEL)
#load output with white noise
h1_meas[i] = p.h1.MODEL+(random()-0.5)*noise
h2_meas[i] = p.h2.MODEL+(random()-0.5)*noise
h3_meas[i] = p.h3.MODEL+(random()-0.5)*noise
h4_meas[i] = p.h4.MODEL+(random()-0.5)*noise
#Only MPC
## estimator
#load input and measured output
m.v1.MEAS = u_cont_k1[i]
m.v2.MEAS = u_cont_k2[i]
#m.h1.MEAS = h1_meas[i]+(random()*2)*noise
#m.h2.MEAS = h2_meas[i]+(random()*2)*noise
#m.h3.MEAS = h3_meas[i]+(random()*2)*noise
#m.h4.MEAS = h4_meas[i]+(random()*2)*noise
m.h1.MEAS = h1_meas[i]
m.h2.MEAS = h2_meas[i]
m.h3.MEAS = h3_meas[i]
m.h4.MEAS = h4_meas[i]
#m.COLDSTART=2
#optimize parameters
m.solve(disp=False,debug=0)
#store results
if i>=process:
h1_est[i] = m.h1.MODEL
h2_est[i] = m.h2.MODEL
h3_est[i] = m.h3.MODEL
h4_est[i] = m.h4.MODEL
v1_est[i] = m.v1.NEWVAL
v2_est[i] = m.v2.NEWVAL
k1_est[i]= m.k1.NEWVAL
k2_est[i] = m.k2.NEWVAL
print("Estimated h:",i,h1_est[i],h2_est[i],h3_est[i],h4_est[i])
print("Estimated k:",i,k1_est[i],k2_est[i],p.k1[0],p.k2[0])
print("Estimated v:",i,v1_est[i],v2_est[i])
print("dh1/dt:",(a3*((2*g*h3_est[i])**0.5)-(a1*((2*g*h3_est[i])**0.5))+(g1*k1_est[i]*v1_est[i]))/A3)
print("dh2/dt:",(a4*((2*g*h4_est[i])**0.5)-(a2*((2*g*h2_est[i])**0.5))+(g2*k2_est[i]*v2_est[i]))/A2)
print("dh3/dt:",(-a3*((2*g*h3_est[i])**0.5)+((1-g2)*k2_est[i]*v2_est[i]))/A3)
print("dh4/dt:",(-a4*((2*g*h4_est[i])**0.5)+((1-g1)*k1_est[i]*v1_est[i]))/A4)
if i%1==0:
plt.clf()
plt.subplot(4,1,1)
#plt.plot(h1_meas[0:i])
#plt.plot(h2_meas[0:i])
#plt.plot(h3_meas[0:i])
#plt.plot(h4_meas[0:i])
plt.plot(h1_est[0:i])
plt.plot(h2_est[0:i])
plt.plot(sp_store[0:i])
plt.subplot(4,1,2)
plt.plot(h3_est[0:i])
plt.plot(h4_est[0:i])
#plt.legend(('h1_pred','h2_pred','h3_pred','h4_pred'))
plt.subplot(4,1,3)
plt.plot(k1_est[0:i])
plt.plot(k2_est[0:i])
plt.subplot(4,1,4)
plt.plot(v1_est[0:i])
plt.plot(v2_est[0:i])
plt.draw()
plt.pause(0.05)
end=time.time()
print("total time:",end-start)
I feel there is some issue with my MHE+MPC code. However, I am not able to realize the mistake?
Nice application. I needed a few imports to make the script work. These may be loaded automatically for you.
from gekko import GEKKO
import time
import numpy as np
import matplotlib.pyplot as plt
from random import random
The script solves successfully if a lower bound is included on all the level variables (1e-6). There is a problem when the level goes below zero or is at zero when using m.sqrt(). This small adjustment helps it solve successfully so it doesn't get into a region where it is undefined. Gekko solvers can't deal with imaginary numbers.
Although the solution is successful, it appears that the control performance oscillates. There may need to be some tuning of the application.
Premise
I am trying to solve a set of coupled PDEs that describes the diffusion of charged particles with different diffusion coefficients using FiPy. The ultimate goal is to obtain the concentration profile for both species and the electric field.
The geometry is an infinitely long cylinder with radius R. I want to use a non-uniform grid with more points close to the domain walls.
Charged particles diffuse from the center of the domain (left boundary) to the walls of the domain (right boundary). This translates to a Dirichlet boundary condition (B.C.) at the left boundary where both species concentration = 0, and a Neumann B.C. at the right boundary where species flux are 0 to describe radial symmetry. Because the charged species diffuse at different rates, there is an electric field that arises from the space charge. The electric field accelerates the slower species and decelerates the faster species proportional to the field magnitude.
P is the positively charged species concentration and N is negatively charged charged species concentration. E is the space charge electric field.
Issue
I can't seem to get a sensible solution from my code and I think it may be related on how I casted the gradient/divergence terms as a ConvectionTerm:
from fipy import *
import scipy.constants as constant
from fipy.tools import numerix
import numpy as np
## Defining physical constants
pi = constant.pi
m_argon = 6.6335e-26 # kg
k_b = constant.k # J/K
e_0 = constant.epsilon_0 # F/m
q_e = constant.elementary_charge # C
m_e = constant.electron_mass # kg
planck = constant.h
def char_diff_length(L,R):
"""Characteristic diffusion length in a cylinder.
Used for determining the ambipolar diffusion coefficient.
ref: https://doi.org/10.6028/jres.095.035"""
a = (pi/L)**2
b = (2.405/R)**2
c = (a+b)**(1/2)
return c
def L_Debye(ne,Te):
"""Electron Debye screening length given in m.
ne is in #/m3, Te is in K."""
if ne < 3.3e-5:
ne = 3.3e-5
return (((e_0*k_b*Te)/(ne*q_e**2)))**(1/2)
## Setting system parameters
# Operation parameters
Pressure = 1.e5 # ambient pressure Pa
T_g = 400. # background gas temperature K
n_g = Pressure/k_b/T_g # gas number density #/m3
Q_std = 300. # standard volumetric flowrate in sccm
T_e_0 = 11. # plasma temperature ratio T_e/T_g here assumed to be T_e = 0.5 eV and T_g = 500 K
n_e_0 = 1.e20 # electron density in bulk plasma #/m3
# Geometric parameters
R_b = 1.e-3 # radius cylinder m
L = 1.e-1 # length of cylinder m
# Transport parameters
D_ion = 4.16e-6 #m2/s ion diffusion, obtained from https://doi.org/10.1007/s12127-020-00258-z
mu_ion = D_ion*q_e/k_b/T_g # ion electrical mobility using Einstein relation
D_e = 100.68122*D_ion #m2/s electron diffusion
mu_e = D_e*q_e/k_b/T_g # electron electrical mobility using Einstein relation
Lambda = char_diff_length(L,R_b)
debyelength_e = L_Debye(n_e_0,T_g)
gamma = (Lambda/debyelength_e)**2
delta = D_ion/D_e
def d_j(rb,n): #sets the desired spatial steps for mesh
dj = np.zeros(n)
for j in range(n):
dj[j] = 2*rb*(1 - j/n)/n
return dj
#Initializing mesh
dj = d_j(1.,100) # 100 points
mesh = CylindricalGrid1D(dr = dj)
#Declaring cell variables
N = CellVariable(mesh=mesh, value = 1., hasOld = True, name = "electron density")
P = CellVariable(mesh=mesh, value = 1., hasOld = True, name = "ion density")
H = CellVariable(mesh=mesh, value = 0., hasOld = True, name = "electric field")
#Setting boundary conditions
N.constrain(0.,mesh.facesRight) # electron density = 0 at walls
P.constrain(0.,mesh.facesRight)# ion density = 0 at walls
H.constrain(0.,mesh.facesLeft) # electric field = 0 in the center
N.faceGrad.constrain([0.],mesh.facesLeft) # flux of electron = 0 in the center
P.faceGrad.constrain([0.],mesh.facesLeft) # flux of ion = 0 in the center
if __name__ == '__main__':
viewer = Viewer(vars=(P,N))
viewer.plot()
eqn1 = (TransientTerm(var=P) == DiffusionTerm(coeff=delta,var=P)
- ConvectionTerm(coeff=[H.cellVolumeAverage,],var=P)
- ConvectionTerm(coeff=[P.cellVolumeAverage,],var=H))
eqn2 = (TransientTerm(var=N) == DiffusionTerm(var=N)
+ (1/delta)*(ConvectionTerm(coeff=[H.cellVolumeAverage,],var=N)
+ConvectionTerm(coeff=[N.cellVolumeAverage,],var=H)))
eqn3 = (TransientTerm(var=H) == gamma*(ConvectionTerm(coeff=[delta**2,],var=P)
- ConvectionTerm(coeff=[delta,],var=N)
- H*(delta*P.cellVolumeAverage + N.cellVolumeAverage)))
P.setValue(1.)
N.setValue(1.)
H.setValue(0.)
eqn1d = eqn1 & eqn2 & eqn3
timesteps = 1e-5
steps = 100
for i in range(steps):
P.updateOld()
N.updateOld()
H.updateOld()
res = 1e10
sweep = 0
while res > 1e-3 and sweep < 20:
res = eqn1d.sweep(dt=timesteps)
sweep += 1
if __name__ == '__main__':
viewer.plot()
Electric field is a vector, not a scalar.
H = CellVariable(rank=1, mesh=mesh, value = 0., hasOld = True, name = "electric field")
Correcting that should make converting the terms to FiPy clearer:
There's no reason to run the chain rule on the last term of eq1 or eq2; they're already in the canonical form for a FiPy ConvectionTerm. After the chain rule, they become, e.g., , neither of which is a form that FiPy likes. You could write those last two terms as explicit sources, but you shouldn't.
eqn1 = (TransientTerm(var=P) == DiffusionTerm(coeff=delta, var=P)
- ConvectionTerm(coeff=H, var=P))
eqn2 = (TransientTerm(var=N) == DiffusionTerm(var=N)
+ (1/delta)*ConvectionTerm(coeff=H, var=N))
I don't really understand eq3. It looks sort of like an integration of the continuity equation? I don't see it on a quick scan of the Phelps paper you cite. Regardless, it's not in a form that FiPy is amenable to; you can write it, but it won't solve well. The terms on the right aren't ConvectionTerms, they're just gradients.
If you're going to be allowing charge separation and worrying about the Debye length, I think you should be solving Poisson's equation. Can you share where this equation comes from? We might be able to put it in a form that FiPy will be happier with.
eq3 is a modified Poisson's equation. I tried to follow the procedure outlined by Freeman where a time derivative is performed on the Poisson equation to substitute the species continuity equations. Freeman solved these equations using the Gear package which I can only assume is a package on Fortran. I followed his steps out of naivite because I am out of my depth with numerical methods.
I will try solving again with the Poisson equation in its standard form.
edit: I have changed the electric field H to a rank 1 tensor and I have modified eq3 as well as slightly changed the definition of gamma. Everything else is unchanged.
H = CellVariable(rank = 1, mesh=mesh, value = 0., hasOld = True, name = "electric field")
charlength = char_diff_length(L,R_b)
debyelength_e = L_Debye(n_e_0,T_g)
gamma = (debyelength_e/charlength)**2
delta = D_ion/D_e
eqn1 = (TransientTerm(var=P) == DiffusionTerm(coeff=delta,var=P)
- ConvectionTerm(coeff=H,var=P))
eqn2 = (TransientTerm(var=N) == DiffusionTerm(var=N)
+ (1/delta)*ConvectionTerm(coeff=H,var=N))
eqn3 = (ConvectionTerm(coeff = gamma/delta, var=H) == ImplicitSourceTerm(var=P)
- ImplicitSourceTerm(var=N))
P.setValue(1.)
N.setValue(1.)
H.setValue(0.)
eqn1d = eqn1 & eqn2 & eqn3
timesteps = 1e-8
steps = 100
for i in range(steps):
P.updateOld()
N.updateOld()
H.updateOld()
res = 1e10
sweep = 0
while res > 1e-3 and sweep < 20:
res = eqn1d.sweep(dt=timesteps)
sweep += 1
if __name__ == '__main__':
viewer.plot()
It does not give me the same errors as before which is some indication of progress. However, it is spitting out a new error:
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 1 dimension(s) and the array at index 2 has 2 dimension(s)
I'm trying to extract the orientation of a wiimote using cwiid in python. I've managed to get the accelerometer values but there doesn't seem to be any object attributes relating to the purely gyroscopic data.
This guy managed to do it in python, but to the best of my knowledge there's no python code online with an example.
https://www.youtube.com/watch?v=cUjh0xQO6eY
There is information on wiibrew about the controller data but again this seems to be excluded from any python library.
Has anyone got any suggestions? This link has an example of getting gyro data but the packages used don't seem available.
I was actually looking for this a few days ago, found this post: https://ofalcao.pt/blog/2014/controlling-the-sbrick-with-a-wiimote. More specifically, I think the code you're looking for is:
# roll = accelerometer[0], standby ~125
# pitch = accelerometer[1], standby ~125
...
roll=(wm.state['acc'][0]-125)
pitch=(wm.state['acc'][1]-125)
I'm assuming you can use the z-axis (index 2) for the yaw
So this question has a few parts, firstly how to extract the gyro data from the motion plus sensor. To do this, the motion plus will first need to be enabled.
The gyro provides the angular rotation vectors, but due to drift caused by integration errors you can't simply use a combination of these two things to get Eular angles. The second part of the question is how to use this data to give position, and that is done by using a Kalman filter, a highly complex matrix sequence, or a complementary filter, a less complex mathematical operation. Both of these filters are essentially combining the gyro and accelerometer data, so as mentioned in a comment above, resulting in more stable measurements, less drift and a system not prone to breaking when the remote is shaken.
Kalman filter:
http://blog.tkjelectronics.dk/2012/09/a-practical-approach-to-kalman-filter-and-how-to-implement-it/
Using PyKalman on Raw Acceleration Data to Calculate Position
Complementary filter
https://www.instructables.com/Angle-measurement-using-gyro-accelerometer-and-Ar/
Still currently developing the core but will post when I'm finished, hopefully tomorrow.
The foundation code I am using to test the measurements is found here:
http://andrew-j-norman.blogspot.com/2010/12/more-code.html. Very handy, as it plots the sensor readings automatically after recording. You can see by doing this that even when still, the position estimate by using simple integration of the angular velocities results in a drift in the position vector.
EDIT:
Testing this allows for the gyro sensor to accurately calculate the angle changed over time, however there remains drift in the acceleration - which I believe is unavoidable.
Here is an image demonstrating the gyro motion sensor:
Just finished up the code:
#!/usr/bin/python
import cwiid
from time import time, asctime, sleep, perf_counter
from numpy import *
from pylab import *
import math
import numpy as np
from operator import add
HPF = 0.98
LPF = 0.02
def calibrate(wiimote):
print("Keep the remote still")
sleep(3)
print("Calibrating")
messages = wiimote.get_mesg()
i=0
accel_init = []
angle_init = []
while (i<1000):
sleep(0.01)
messages = wiimote.get_mesg()
for mesg in messages:
# Motion plus:
if mesg[0] == cwiid.MESG_MOTIONPLUS:
if record:
angle_init.append(mesg[1]['angle_rate'])
# Accelerometer:
elif mesg[0] == cwiid.MESG_ACC:
if record:
accel_init.append(list(mesg[1]))
i+=1
accel_init_avg = list(np.mean(np.array(accel_init), axis=0))
print(accel_init_avg)
angle_init_avg = sum(angle_init)/len(angle_init)
print("Finished Calibrating")
return (accel_init_avg, angle_init_avg)
def plotter(plot_title, timevector, data, position, n_graphs):
subplot(n_graphs, 1, position)
plot(timevector, data[0], "r",
timevector, data[1], "g",
timevector, data[2], "b")
xlabel("time (s)")
ylabel(plot_title)
print("Press 1+2 on the Wiimote now")
wiimote = cwiid.Wiimote()
# Rumble to indicate a connection
wiimote.rumble = 1
print("Connection established - release buttons")
sleep(0.2)
wiimote.rumble = 0
sleep(1.0)
wiimote.enable(cwiid.FLAG_MESG_IFC | cwiid.FLAG_MOTIONPLUS)
wiimote.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC | cwiid.RPT_MOTIONPLUS
accel_init, angle_init = calibrate(wiimote)
str = ""
print("Press plus to start recording, minus to end recording")
loop = True
record = False
accel_data = []
angle_data = []
messages = wiimote.get_mesg()
while (loop):
sleep(0.01)
messages = wiimote.get_mesg()
for mesg in messages:
# Motion plus:
if mesg[0] == cwiid.MESG_MOTIONPLUS:
if record:
angle_data.append({"Time" : perf_counter(), \
"Rate" : mesg[1]['angle_rate']})
# Accelerometer:
elif mesg[0] == cwiid.MESG_ACC:
if record:
accel_data.append({"Time" : perf_counter(), "Acc" : [mesg[1][i] - accel_init[i] for i in range(len(accel_init))]})
# Button:
elif mesg[0] == cwiid.MESG_BTN:
if mesg[1] & cwiid.BTN_PLUS and not record:
print("Recording - press minus button to stop")
record = True
start_time = perf_counter()
if mesg[1] & cwiid.BTN_MINUS and record:
if len(accel_data) == 0:
print("No data recorded")
else:
print("End recording")
print("{0} data points in {1} seconds".format(
len(accel_data), perf_counter() - accel_data[0]["Time"]))
record = False
loop = False
else:
pass
wiimote.disable(cwiid.FLAG_MESG_IFC | cwiid.FLAG_MOTIONPLUS)
if len(accel_data) == 0:
sys.exit()
timevector = []
a = [[],[],[]]
v = [[],[],[]]
p = [[],[],[]]
last_time = 0
velocity = [0,0,0]
position = [0,0,0]
for n, x in enumerate(accel_data):
if (n == 0):
origin = x
else:
elapsed = x["Time"] - origin["Time"]
delta_t = x["Time"] - last_time
timevector.append(elapsed)
for i in range(3):
acceleration = x["Acc"][i] - origin["Acc"][i]
velocity[i] = velocity[i] + delta_t * acceleration
position[i] = position[i] + delta_t * velocity[i]
a[i].append(acceleration)
v[i].append(velocity[i])
p[i].append(position[i])
last_time = x["Time"]
n_graphs = 3
if len(angle_data) == len(accel_data):
n_graphs = 5
angle_accel = [(math.pi)/2 if (j**2 + k**2)==0 else math.atan(i/math.sqrt(j**2 + k**2)) for i,j,k in zip(a[0],a[1],a[2])]
ar = [[],[],[]] # Angle rates
aa = [[],[],[]] # Angles
angle = [0,0,0]
for n, x in enumerate(angle_data):
if (n == 0):
origin = x
else:
delta_t = x["Time"] - last_time
for i in range(3):
rate = x["Rate"][i] - origin["Rate"][i]
angle[i] = HPF*(np.array(angle[i]) + delta_t * rate) + LPF*np.array(angle_accel)
ar[i].append(rate)
aa[i].append(angle[i])
last_time = x["Time"]
plotter("Acceleration", timevector, a, 1, n_graphs)
if n_graphs == 5:
plotter("Angle Rate", timevector, ar, 4, n_graphs)
plotter("Angle", timevector, aa, 5, n_graphs)
show()
I built a grid that generates random obstacles for pathfinding algorithm, but with fixed starting and ending points as shown in my snippet below:
import random
import numpy as np
#grid format
# 0 = navigable space
# 1 = occupied space
x = [[random.uniform(0,1) for i in range(50)]for j in range(50)]
grid = np.array([[0 for i in range(len(x[0]))]for j in range(len(x))])
for i in range(len(x)):
for j in range(len(x[0])):
if x[i][j] <= 0.7:
grid[i][j] = 0
else:
grid[i][j] = 1
init = [5,5] #Start location
goal = [45,45] #Our goal
# clear starting and end point of potential obstacles
def clear_grid(grid, x, y):
if x != 0 and y != 0:
grid[x-1:x+2,y-1:y+2]=0
elif x == 0 and y != 0:
grid[x:x+2,y-1:y+2]=0
elif x != 0 and y == 0:
grid[x-1:x+2,y:y+2]=0
elif x ==0 and y == 0:
grid[x:x+2,y:y+2]=0
clear_grid(grid, init[0], init[1])
clear_grid(grid, goal[0], goal[1])
I need to generate also the starting and ending points randomly every time I run the code instead of making them fixed. How could I make it? Any assistance, please?.
Replace,
init = [5,5] #Start location
goal = [45,45] #Our goal
with,
init = np.random.randint(0, high = 49, size = 2)
goal = np.random.randint(0, high = 49, size = 2)
Assuming your grid goes from 0-49 on each axis. Personally I would add grid size variables, i_length & j_length
EDIT #1
i_length = 50
j_length = 50
x = [[random.uniform(0,1) for i in range(i_length)]for j in range(j_length)]
grid = np.array([[0 for i in range(i_length)]for j in range(j_length)])