Changing the code to Boundary Value Problem for ODE Python - python

I am struggling to change my code to solve a system of (Ordinary Differential Equation)ODE from initial value problem to boundary value problem. I have tried myself many times but I think i am making mistakes which are logically incorrect. So instead of pasting the change code, I am pasting below my original code which works fine.
Below mention code is used to solve a system of ODE with function odeint and then I am using Particle Swarm Optimiation(PSO) algorithm for optimisation process. I want to use the same equations with function solve_bvp with boundary conditions t(0) =1 and t(1) = 2. Below mention is the code. Thanks
from scipy import *
from scipy.integrate import odeint
from operator import itemgetter
import matplotlib
matplotlib.use('Agg')
from matplotlib.ticker import FormatStrFormatter
from pylab import *
from itertools import product
import itertools
from numpy import zeros_like
import operator
from pyswarm import pso
modelsOne = []
modelsTwo = []
modelsThree = []
#step 1 start## To build model structure library. HIV model is a three-variable model, so we need three model structure liararys: modelsOne, modelsTwo, modelsThree.
# the model structure library contains all possible structures of the model to be sought.
def ModelsProduct(modelsOne, modelsTwo, modelsThree):
modelsStepOne = list(product("+-",repeat = 4))
modelsStepThree = [('a','a'),('a','b'),('a','c'),('b','b'),('b','c'),('c','c')]
#produce modelsOne
modelsStepTwo = [('b',),('c',)]
for one in modelsStepOne:
for two in modelsStepTwo:
for three in modelsStepThree:
modelsOne.append(one+two+three)
#produce modelsTwo
modelsStepTwo = [('a',),('c',)]
for one in modelsStepOne:
for two in modelsStepTwo:
for three in modelsStepThree:
modelsTwo.append(one+two+three)
#produce modelsThree
modelsStepTwo = [('a',),('b',)]
for one in modelsStepOne:
for two in modelsStepTwo:
for three in modelsStepThree:
modelsThree.append(one+two+three)
return modelsOne, modelsTwo, modelsThree
modelsOne, modelsTwo,modelsThree = ModelsProduct(modelsOne, modelsTwo, modelsThree)
#step 1 end##
VarList = ["a","b","c"]
initial_condi = [100, 150, 50000]
dictVar = {'a':0, 'b': 1, 'c': 2}
ops = { "+": operator.add, "-": operator.sub }
t_range = arange(0.0,60.0,1.0)
def odeFunc(Y, t, x,dictVar):
if x[-3] == 192:
temp1 = 191
else:
temp1 = int(x[-3])
if x[-2] == 192:
temp2 = 191
else:
temp2 = int(x[-2])
if x[-1] == 192:
temp3 = 191
else:
temp3 = int(x[-1])
modelOne = modelsOne[temp1]
modelTwo = modelsTwo[temp2]
modelThree = modelsThree[temp3]
return GenModel(Y, x, modelOne,modelTwo,modelThree, dictVar)
def GenModel(Y,x,modelOne,modelTwo,modelThree, dictVar):
dydt = zeros_like(Y)
dydt[0] = ops[modelOne[0]](dydt[0],x[0]*Y[0])
dydt[0] = ops[modelOne[1]](dydt[0],x[1]*Y[dictVar[modelOne[-3]]])
dydt[0] = ops[modelOne[2]](dydt[0],x[2]*Y[dictVar[modelOne[-2]]]*Y[dictVar[modelOne[-1]]])
dydt[0] = ops[modelOne[3]](dydt[0],x[3])
dydt[1] = ops[modelTwo[0]](dydt[1],x[4]*Y[1])
dydt[1] = ops[modelTwo[1]](dydt[1],x[5]*Y[dictVar[modelTwo[-3]]])
dydt[1] = ops[modelTwo[2]](dydt[1],x[6]*Y[dictVar[modelTwo[-2]]]*Y[dictVar[modelTwo[-1]]])
dydt[1] = ops[modelTwo[3]](dydt[1],x[7])
dydt[2] = ops[modelThree[0]](dydt[2],x[8]*Y[2])
dydt[2] = ops[modelThree[1]](dydt[2],x[9]*Y[dictVar[modelThree[-3]]])
dydt[2] = ops[modelThree[2]](dydt[2],x[10]*Y[dictVar[modelThree[-2]]]*Y[dictVar[modelThree[-1]]])
dydt[2] = ops[modelThree[3]](dydt[2],x[11])
return dydt
## equations
def pendulum_equations(w, t):
T, I, V = w
dT = 80 - 0.15*T - 0.00002*T*V
dI = 0.00002*T*V - 0.55*I
dV = 900*0.55*I - 5.5*V - 0.00002*T*V
return dT, dI, dV
result_init = odeint(pendulum_equations, initial_condi, t_range)
result_init[:,2] = result_init[:,2]/100
def myfunc(xRand):
result_new = odeint(odeFunc, initial_condi, t_range, args=(xRand,dictVar))
result_new[:,2] = result_new[:,2]/100
result_sub = result_new - result_init
return sum(result_sub*result_sub)
x = (0.15,0,0.00002,80,0.55,0,0.00002,0,5.5,495,0.00002,0,122,98,128)
lb = [0]*15
ub = [1,1,0.5,200,1,1,0.5,200,10,1000,0.5,200,192,192,192]
xopt1, fopt1 = pso(myfunc, lb, ub,omega= 0.7298,phip=1.49618,phig=1.49618,maxiter=1000,swarmsize= 1000,minstep=1e-20,minfunc=1e-20,debug = True)

If you have an ODE like
def f_ode(t,u): return [ u[1], -u[0] ]
which you can solve as
tspan = np.linspace(0,1,51);
u_init = [1.0, 0.0]
u = odeint(f_ode, u_init, tspan, tfirst=True)
or as
res = solve_ivp(f_ode, tspan[[0,-1]], u_init, t_eval=tspan)
if res.success:
u=res.y
you can switch to a boundary problem by encoding the necessary functions and initial guess
def f_bc(u0, u1): return [u0[0]-1, u1[0]-2]
t = np.linspace(0,1,11);
u = [ 1+t, 1+0*t]
res = solve_bvp(f_ode,f_bc,t,u)
if res.success:
u = res.sol(tspan)
Note that you have to try out if your version of the new solver functions supports the passing of parameters the same way as odeint. If that is not possible, use lambda constructs as wrappers, or explicitly defined functions.

Related

Using dictionary entries as parameters in scipy solve_ivp

Can I somehow pass variables from dictionaries into the functions inside of solve_ivp,
such that I can call them directly, i.e. offFSH instead of para_dict["offFSH"] ?
I think that this would be better for readability, but please let me know if my current/another version would be preferable.
Please don't pay attention to the model/equations itself, I took it from a much larger model I want to simulate, hence my desire to organize variables with dictionaries.
Thanks!
from scipy.integrate import solve_ivp
def simulate_model(simu_dict, para_dict):
tspan = [0, simu_dict["simulationLength"]]
InitialValues = [simu_dict["FSHR_init"], simu_dict["FSHR_complex_init"], simu_dict["LHR_init"], simu_dict["LHR_complex_init"]]
result = solve_ivp(fun = lambda t, y: func(t,y, para_dict), t_span = tspan, y0 = InitialValues, method = "RK45", dense_output = True)
return result
def func(t, y, para_dict):
FSHR = 0
FSHR_complex = 1
LHR = 2
LHR_complex = 3
dFSHR = para_dict["offFSH"] * y[FSHR_complex] - para_dict["onFSH"] * y[FSHR_complex]
dFSHR_complex = para_dict["onFSH"] * y[FSHR] - para_dict["offFSH"] * y[FSHR_complex]
dLHR = para_dict["offLH"] * y[LHR_complex] - para_dict["onLH"] * y[LHR]
dLHR_complex = para_dict["onLH"] - para_dict["offLH"] * y[LHR_complex]
dy = [dFSHR,dFSHR_complex,dLHR, dLHR_complex]
return dy
###########################################################################################
simu_dict = {
"FSHR_init": 0.7,
"FSHR_complex_init": 0.9,
"LHR_init": 1.8,
"LHR_complex_init": 6.2,
"simulationLength": 2
}
para_dict = {
"onFSH": 1,
"offFSH": 5,
"onLH": 1,
"offLH": 1,
}
test = simulate_model(simu_dict, para_dict)

How to solve non-numeric type in numeric context error in pyomo python

This is the code. I think the solver could be glpk instead of gurobi. I got the error before it tries to solve the problem.
from pyomo.environ import *
from pyomo.opt import SolverFactory, SolverStatus
PrintSolverOutput = False ###
model = ConcreteModel()
model.dual = Suffix(direction =Suffix.IMPORT)
model.X = Var(I,T, within = NonNegativeReals)
model.In = Var(I,T, within = NonNegativeReals)
model.S = Var(T, within = NonNegativeReals)
def Objetivo(model):
return (sum(C[i]*model.X[i,t]*((1+tau[i])**(t-1))+Ch[i]*model.In[i,t]
for i in I for t in T)
+sum(Cs*model.S[t]
for t in T)
)
model.Total_Cost = Objective(rule = Objetivo, sense= minimize)
def Balance(model,i,t):
if t==1:
return model.X[i,t]+I0[i]-model.In[i,t]==D[i,t]
elif t>=2:
return model.X[i,t]+model.IN[i,t-1]-model.In[i,t]==D[i,t]
def Horas(model, t):
return sum(r[i]*model.X[i,t] for i in I) <= H+model.S[t]
def Limite(model,t):
return model.S[T]<=LS
model.RBalance = Constraint(I,T,rule=Balance)
model.RHoras = Constraint(T,rule=Horas)
model.RLimiteoras = Constraint(T,rule=Limite)
opt = SolverFactory("gurobi")
This is the data
I forgot to put the data before.
T = [1,2,3,4,5,6]
I = ['A','B']
D = {('A',1):300,
('A',2):400,
('A',3):500,
('A',4):600,
('A',5):800,
('A',6):700,
('B',1):700,
('B',2):600,
('B',3):500,
('B',4):400,
('B',5):300,
('B',6):400}
tau = {'A':0.02,'B':0.01}
r = {'A':5,'B':3}
H = 3520
LS = 800
C = {'A':150,'B':120}
Ch = {'A':8,'B':4}
Cs = 6
I0 = {'A':100,'B':250}
error
The code is from a youtube tutorial and it worked for him but not for me. Why?
Aside from fixing two typos in your code, this model computes and solves for me without that error. Make these fixes, run it again, re-post the exact error with line number and the exact code that produces the error if stuck...

no speedup when using numba jit

I am trying to run a NEAT algorithm using this python implementation. This is the original file from the library that is relevant for my question:
from neat.graphs import feed_forward_layers
class FeedForwardNetwork(object):
def __init__(self, inputs, outputs, node_evals):
self.input_nodes = inputs
self.output_nodes = outputs
self.node_evals = node_evals
self.values = dict((key, 0.0) for key in inputs + outputs)
def activate(self, inputs):
if len(self.input_nodes) != len(inputs):
raise RuntimeError("Expected {0:n} inputs, got {1:n}".format(len(self.input_nodes), len(inputs)))
for k, v in zip(self.input_nodes, inputs):
self.values[k] = v
for node, act_func, agg_func, bias, response, links in self.node_evals:
node_inputs = []
for i, w in links:
node_inputs.append(self.values[i] * w)
s = agg_func(node_inputs)
self.values[node] = act_func(bias + response * s)
return [self.values[i] for i in self.output_nodes]
#staticmethod
def create(genome, config):
""" Receives a genome and returns its phenotype (a FeedForwardNetwork). """
# Gather expressed connections.
connections = [cg.key for cg in genome.connections.values() if cg.enabled]
layers = feed_forward_layers(config.genome_config.input_keys, config.genome_config.output_keys, connections)
node_evals = []
for layer in layers:
for node in layer:
inputs = []
node_expr = [] # currently unused
for conn_key in connections:
inode, onode = conn_key
if onode == node:
cg = genome.connections[conn_key]
inputs.append((inode, cg.weight))
node_expr.append("v[{}] * {:.7e}".format(inode, cg.weight))
ng = genome.nodes[node]
aggregation_function = config.genome_config.aggregation_function_defs.get(ng.aggregation)
activation_function = config.genome_config.activation_defs.get(ng.activation)
node_evals.append((node, activation_function, aggregation_function, ng.bias, ng.response, inputs))
return FeedForwardNetwork(config.genome_config.input_keys, config.genome_config.output_keys, node_evals)
Since I evaluate the performance of my neural networks on a large dataset, I wanted to speed up the activate method using numba jit. In order to not fall back into numbas object mode I had to update the implementation of the activate method (and hence also the fields of the FeedForwardNetwork class) using only datatypes supported by numba. This is what I came up with (create is the same as before):
from neat.graphs import feed_forward_layers
from neat.six_util import itervalues
import numba
from numba import jit, njit
from numba.typed import List, Dict
import numpy as np
import math
#jit(nopython=True)
def activate(input_nodes, output_nodes, node_evals_node, node_evals_bias, node_evals_resp, node_evals_ins_nodes, node_evals_ins_conns, values, inputs):
for i in range(input_nodes.size):
values[input_nodes[i]] = inputs[i]
for node in range(len(node_evals_node)):
s = 0
for pred in range(len(node_evals_ins_nodes[node])):
s += values[node_evals_ins_nodes[node][pred]] * node_evals_ins_conns[node][pred]
values[node_evals_node[node]] = math.tanh(node_evals_bias[node] + node_evals_resp[node] * s)
return [values[output_nodes[i]] for i in range(output_nodes.size)]
class FeedForwardNetwork(object):
def __init__(self, inputs, outputs, node_evals):
self.input_nodes = np.array(inputs)
self.output_nodes = np.array(outputs)
# NODE_EVALS decomposition
self.node_evals_node = np.reshape(np.array(node_evals)[:, 0:1], (len(node_evals),)).astype(np.int64)
self.node_evals_bias = np.reshape(np.array(node_evals)[:, 3:4], (len(node_evals),)).astype(np.float64)
self.node_evals_resp = np.reshape(np.array(node_evals)[:, 4:5], (len(node_evals),)).astype(np.float64)
temp = np.array(node_evals)[:, 5:6]
self.node_evals_ins_nodes = List()
self.node_evals_ins_conns = List()
for node in range(temp.size):
l = List()
m = List()
for predecessor in range(len(temp[node])):
l.append(temp[0][node][predecessor][0])
m.append(temp[0][node][predecessor][1])
self.node_evals_ins_nodes.append(l)
self.node_evals_ins_conns.append(m)
self.values = Dict()
# Set types of dict
self.values[0] = float(1)
self.values.pop(0)
This is the code I call the create and activate method in:
def eval_single_genome(genome, config, thread_id, result):
net = neat.nn.FeedForwardNetwork.create(genome, config)
error_sum = 0
for i, row in PRICES.iterrows():
prediction = feed_forward.activate(net.input_nodes, net.output_nodes, net.node_evals_node, net.node_evals_bias, net.node_evals_resp, net.node_evals_ins_nodes, net.node_evals_ins_conns, net.values, np.array([0]))
error_sum += (prediction - PRICES.iloc[i]['open']) ** 2
result[thread_id] = error_sum
The code compiles and runs without errors or warnings which (as far as I've understood) indicates that numba should be able to optimize my implementation. But adding/removing the #jit(nopython=True)decorator doesn't change the runtime at all.
Did I overlook something? Or is there just nothing that numba can improve in my case?

If else statement returning TypeError:object of type 'int' has no len() - Not sure why

So, I am trying to solve an optimization problem. What I am trying to figure out is that when I run the code, my function call "to_fp_Cx" throws an error and I don't understand why.
The traceback keeps pointing to the functions I have defined. I tested these functions independently by calling it with different values and that worked as expected. So, I am not sure what is happening.
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-41-3f717a4f07e1> in <module>
37 # intermediate variables with explicit equations
38
---> 39 if(fload_c3_1 < 0.1):
40 alt_fload_c3_1 = m.Intermediate(0)
41 else:
~\AppData\Local\Continuum\anaconda3\lib\site-packages\gekko\gk_operators.py in __len__(self)
23 return self.name
24 def __len__(self):
---> 25 return len(self.value)
26 def __getitem__(self,key):
27 return self.value[key]
~\AppData\Local\Continuum\anaconda3\lib\site-packages\gekko\gk_operators.py in __len__(self)
142
143 def __len__(self):
--> 144 return len(self.value)
145
146 def __getitem__(self,key):
TypeError: object of type 'int' has no len()
As the name suggests, I am a python noob and I am bamboozled. Any help would be appreciated. Thanks
import numpy as np
# import gekko, pip install if needed
from gekko import GEKKO
# Compressor Performance curves
# Fraction capacity to Fractional power conversion
# Compressor C3
def to_fp_c3(fc):
a = 5.16102738
b = -16.25992208
c = 18.52731113
d = -8.859480201
e = 2.096698885
f = 0.334319989
if (fc < 0.1):
fp = 0.0
else:
fp = (a*fc**5)+(b*fc**4)+(c*fc**3)+(d*fc**2)+(e*fc**1)+(f*fc**0)
return fp
...
### Optimization Model ####
# create new model
m = GEKKO(remote = False)
# Solver option - 1: APOPT, 2: BPOPT, 3: IPOPT 0:Benchmark all available
m.options.SOLVER = 3
# declare model parameters
maxcap_c3_1 = m.Param(value = 900)
maxcap_c3_2 = m.Param(value = 900)
load = m.Param(value = 1500)
## Model variables
# load distribution
fload_c3_1 = m.Var(value=0.50,lb=0.0,ub=1.0, integer = False)
fload_c3_2 = m.Var(value=0.50,lb=0.0,ub=1.0, integer = False)
# declare variables and initial guesses
#totalpowerdraw = m.Var()
# intermediate variables with explicit equations
if(fload_c3_1 < 0.1):
alt_fload_c3_1 = m.Intermediate(0)
else:
alt_fload_c3_1 = m.Intermediate(fload_c3_1)
if(fload_c3_2 < 0.1):
alt_fload_c3_2 = m.Intermediate(0)
else:
alt_fload_c3_2 = m.Intermediate(fload_c3_2)
assignedload_c3_1 = m.Intermediate(alt_fload_c3_1 * maxcap_c3_1)
assignedload_c3_2 = m.Intermediate(alt_fload_c3_2 * maxcap_c3_2)
powerdraw_c3_1 = m.Intermediate(to_fp_c3(alt_fload_c3_1) * maxcap_c3_1)
powerdraw_c3_2 = m.Intermediate(to_fp_c3(alt_fload_c3_2) * maxcap_c3_2)
totalpowerdraw = m.Intermediate(powerdraw_c3_1 + powerdraw_c3_2)
# implicit equations
m.Equation(load == assignedload_c3_1 + assignedload_c3_2 )
# minimize weight1
m.Obj(totalpowerdraw)
# solve optimization
m.solve() # remote=False for local solve
print ('')
print ('--- Results of the Optimization Problem ---')
print (alt_fload_c3_1.value, powerdraw_c3_1.value)
print (alt_fload_c3_1.value, powerdraw_c3_2.value)
Try the m.if3() (or m.if2()) function from Gekko to make the conditional statement switch based on a Gekko variable. There is more information on conditional statements in Question about the conditional statement ('m.if3') in the GEKKO
# use gekko if3 (or if2)
alt_fload_c3_1 = m.if3(fload_c3_1-0.1,0,fload_c3_1)
alt_fload_c3_2 = m.if3(fload_c3_2-0.1,0,fload_c3_2)
Here is a version of your program that gives a successful solution.
import numpy as np
from gekko import GEKKO
# Compressor Performance curves
# Fraction capacity to Fractional power conversion
# Compressor C3
def to_fp_c3(fc):
a = 5.16102738
b = -16.25992208
c = 18.52731113
d = -8.859480201
e = 2.096698885
f = 0.334319989
fp = m.if3(fc-0.1,0,(a*fc**5)+(b*fc**4)+(c*fc**3)\
+(d*fc**2)+(e*fc**1)+(f*fc**0))
return fp
### Optimization Model ####
# create new model
m = GEKKO(remote = False)
# declare model parameters
maxcap_c3_1 = m.Param(value = 900)
maxcap_c3_2 = m.Param(value = 900)
load = m.Param(value = 1500)
## Model variables
# load distribution
fload_c3_1 = m.Var(value=0.50,lb=0.0,ub=1.0, integer = False)
fload_c3_2 = m.Var(value=0.50,lb=0.0,ub=1.0, integer = False)
# use gekko if3 (or if2)
alt_fload_c3_1 = m.if3(fload_c3_1-0.1,0,fload_c3_1)
alt_fload_c3_2 = m.if3(fload_c3_2-0.1,0,fload_c3_2)
assignedload_c3_1 = m.Intermediate(alt_fload_c3_1 * maxcap_c3_1)
assignedload_c3_2 = m.Intermediate(alt_fload_c3_2 * maxcap_c3_2)
powerdraw_c3_1 = m.Intermediate(to_fp_c3(alt_fload_c3_1) * maxcap_c3_1)
powerdraw_c3_2 = m.Intermediate(to_fp_c3(alt_fload_c3_2) * maxcap_c3_2)
totalpowerdraw = m.Intermediate(powerdraw_c3_1 + powerdraw_c3_2)
# implicit equations
m.Equation(load == assignedload_c3_1 + assignedload_c3_2 )
# minimize weight1
m.Obj(totalpowerdraw)
# solve optimization
m.solve() # remote=False for local solve
print ('')
print ('--- Results of the Optimization Problem ---')
print (alt_fload_c3_1.value, powerdraw_c3_1.value)
print (alt_fload_c3_1.value, powerdraw_c3_2.value)
with the solution:
---------------------------------------------------
Solver : APOPT (v1.0)
Solution time : 0.0313 sec
Objective : 1576.7914326000025
Successful solution
---------------------------------------------------
--- Results of the Optimization Problem ---
[0.66761123885] [677.4476587]
[0.66761123885] [899.3437739]
You have to use this
If(fload_c3_1.value < 0.1):

Using PyMC3 to compute ODE parameter posterior: Bad initial energy error

I am trying to sample the parameter posterior of an ODE's parameters using a Likelihood that has mean equal to the logarithm of those ODE solutions for a particular choice of parameter and initial value. This is based on the tutorial found here. I can replicate the tutorial, but can't make my model work. My model's ODE is:
dQ(t)/dt = (1/K)*(R(t) - Q(t))
where R(t) is based on rainfall data that I input.
I am assigning priors to the noise standard deviation \sigma, the initial value Q(0) and parameter K.
Any help on how to overcome the error would be much appreciated :)
This is my code:
from scipy.integrate import odeint
from scipy.interpolate import interp1d
import numpy as np
import pandas as pd
import theano
from theano import *
import pymc3 as pm
import theano.tensor as tt
THEANO_FLAGS='optimizer=fast_compile'
theano.config.exception_verbosity= 'high'
theano.config.floatX = 'float64'
n_states = 1
n_odeparams = 1
n_ivs = 1
class LinearReservoirModel(object):
def __init__(self, n_states, n_odeparams, n_ivs,net_rainfall_data, y0=None):
self._n_states = n_states
self._n_odeparams = n_odeparams
self._n_ivs = n_ivs
self._y0 = y0
self._nr = net_rainfall_data
def simulate(self, parameters, times):
return self._simulate(parameters, times, self._nr, False)
def simulate_with_sensitivities(self, parameters, times):
return self._simulate(parameters, times, self._nr, True)
def _simulate(self, parameters, times, net_rainfall_data, sensitivities):
k, q0 = [x for x in parameters]
# Interpolate net_rainfall
nr_int = interp1d(times, net_rainfall_data,fill_value="extrapolate",kind='slinear')
def r(q,time,k,nrint):
return (nrint(time) - q) * (1./k)
if sensitivities:
def jac(k):
ret = np.zeros((self._n_states, self._n_states))
ret[0, 0] = (-1./k)
return ret
def dfdp(x,t,k,nrint):
ret = np.zeros((self._n_states,
self._n_odeparams + self._n_ivs))
ret[0, 0] = (-1./(k**2)) * (nrint(t) - x)
return ret
def rhs(q_and_dqdp, t, k, nrint):
q = q_and_dqdp[0:self._n_states]
dqdp = q_and_dqdp[self._n_states:].reshape((self._n_states,
self._n_odeparams + self._n_ivs))
dqdt = r(q, t, k, nrint)
# print('jacobian',jac(q))
# print('dqdp',dqdp)
# print('dfdp',dfdp(q,t,nrint))
d_dqdp_dt = jac(k)*dqdp + dfdp(q,t,k,nrint) # CHANGED CODE HERE np.matmul(jac(q), dqdp) + dfdp(q,t,nrint)
return np.concatenate((dqdt, d_dqdp_dt.reshape(-1)))
y0 = np.zeros( (n_states*(n_odeparams+n_ivs)) + n_states ) # CHANGED CODE HERE 2*
y0[2] = 1. #\frac{\partial [X]}{\partial Xt0} at t==0, and same below for Y
y0[0:n_states] = q0
result = odeint(rhs, y0, times, (k,nr_int),rtol=1e-6,atol=1e-5)
values = result[:, 0:self._n_states]
dvalues_dp = result[:, self._n_states:].reshape((len(times),
self._n_states,
self._n_odeparams + self._n_ivs))
return values, dvalues_dp
else:
q = odeint(r,q0,times,args=(k,nr_int),rtol=1e-6,atol=1e-5)
q_flat = [item for sublist in q for item in sublist]
return q_flat
q = [0.01, 0.084788051,0.289827287,0.487426902,0.623592162,0.855202214,0.901709887,0.87936577,0.857067839,0.775516564,0.701725939,0.675138958,0.68101658,0.64644605,0.701305112,0.747128907,0.676039744,0.668502137,0.731464651,0.766588801]
nr = [1.618666063,0.0001,4.405308823,0.394073731,3.392555321,2.733285785,0.0001,1.31186209,0.0001,0.0001,0.0001,0.83074128,0.646141131,0.0001,2.405660466,0.0001,0.0001,1.174002978,1.481146447,0.73244669]
ode_model = LinearReservoirModel(n_states, n_odeparams, n_ivs, nr)
class ODEGradop(theano.Op):
def __init__(self, numpy_vsp):
self._numpy_vsp = numpy_vsp
def make_node(self, x, g):
x = theano.tensor.as_tensor_variable(x)
g = theano.tensor.as_tensor_variable(g)
node = theano.Apply(self, [x, g], [g.type()])
return node
def perform(self, node, inputs_storage, output_storage):
x = inputs_storage[0]
g = inputs_storage[1]
out = output_storage[0]
out[0] = self._numpy_vsp(x, g) # get the numerical VSP
class ODEop(theano.Op):
def __init__(self, state, numpy_vsp):
self._state = state
self._numpy_vsp = numpy_vsp
def make_node(self, x):
x = theano.tensor.as_tensor_variable(x)
return theano.Apply(self, [x], [x.type()])
def perform(self, node, inputs_storage, output_storage):
x = inputs_storage[0]
out = output_storage[0]
out[0] = self._state(x) # get the numerical solution of ODE states
def grad(self, inputs, output_grads):
x = inputs[0]
g = output_grads[0]
grad_op = ODEGradop(self._numpy_vsp) # pass the VSP when asked for gradient
grad_op_apply = grad_op(x, g)
return [grad_op_apply]
class solveCached(object):
def __init__(self, times, n_params, n_outputs):
self._times = times
self._n_params = n_params
self._n_outputs = n_outputs
self._cachedParam = np.zeros(n_params)
self._cachedSens = np.zeros((len(times), n_outputs, n_params))
self._cachedState = np.zeros((len(times),n_outputs))
def __call__(self, x):
if np.all(x==self._cachedParam):
state, sens = self._cachedState, self._cachedSens
else:
state, sens = ode_model.simulate_with_sensitivities(x, times)
return state, sens
times = np.arange(0, len(q)) # number of measurement points (see below)
cached_solver=solveCached(times, n_odeparams + n_ivs, n_states)
def state(x):
State, Sens = cached_solver(np.array(x,dtype=np.float64))
cached_solver._cachedState, cached_solver._cachedSens, cached_solver._cachedParam = State, Sens, x
return State.reshape((len(State),))
def numpy_vsp(x, g):
numpy_sens = cached_solver(np.array(x,dtype=np.float64))[1].reshape((n_states*len(times),len(x)))
return numpy_sens.T.dot(g)
# Define the data matrix
Q = np.vstack((q))
# Now instantiate the theano custom ODE op
my_ODEop = ODEop(state,numpy_vsp)
# The probabilistic model
with pm.Model() as LR_model:
# Priors for unknown model parameters
k = pm.Uniform('k', lower=0.01, upper=10)
# Priors for initial conditions and noise level
q0 = pm.Lognormal('q0', mu=np.log(1.2), sd=1)
sigma = pm.Lognormal('sigma', mu=-1, sd=1, shape=1)
# Forward model
all_params = pm.math.stack([k,q0],axis=0)
ode_sol = my_ODEop(all_params)
forward = ode_sol.reshape(Q.shape)
# log_forward = pm.math.log(forward)
# log_forward_print = tt.printing.Print('log_forward')(log_forward.shape)
# tt.printing.Print('sigma')(sigma.shape)
# Likelihood
Q_obs = pm.Lognormal('Q_obs', mu=pm.math.log(forward), sd=sigma, observed=Q)
print(LR_model.check_test_point())
# Y_obs_print = tt.printing.Print('Y_obs')(Y_obs)
trace = pm.sample(n_init=1500, tune=1000, chains=1, init='adapt_diag')
trace['diverging'].sum()
If you run the code above you should be able to reproduce the following error:
Traceback (most recent call last):
File "examples/myexample.py", line 195, in <module>
trace = pm.sample(1500, tune=1000, chains=1, init='adapt_diag')
File "/Users/Yannis/.pyenv/versions/mini-project/lib/python3.6/site-packages/pymc3/sampling.py", line 457, in sample
trace = _sample_many(**sample_args)
File "/Users/Yannis/.pyenv/versions/mini-project/lib/python3.6/site-packages/pymc3/sampling.py", line 503, in _sample_many
step=step, random_seed=random_seed[i], **kwargs)
File "/Users/Yannis/.pyenv/versions/mini-project/lib/python3.6/site-packages/pymc3/sampling.py", line 544, in _sample
for it, strace in enumerate(sampling):
File "/Users/Yannis/.pyenv/versions/mini-project/lib/python3.6/site-packages/tqdm/std.py", line 1091, in __iter__
for obj in iterable:
File "/Users/Yannis/.pyenv/versions/mini-project/lib/python3.6/site-packages/pymc3/sampling.py", line 633, in _iter_sample
point, states = step.step(point)
File "/Users/Yannis/.pyenv/versions/mini-project/lib/python3.6/site-packages/pymc3/step_methods/arraystep.py", line 247, in step
apoint, stats = self.astep(array)
File "/Users/Yannis/.pyenv/versions/mini-project/lib/python3.6/site-packages/pymc3/step_methods/hmc/base_hmc.py", line 144, in astep
raise SamplingError("Bad initial energy")
pymc3.exceptions.SamplingError: Bad initial energy
PyMC3 Version: 3.7
Theano Version: 1.0.4
Python Version: 3.6.5
Operating system: macOS Catalina (v10.15.1)
How did you install PyMC3: pip (managed in a pyenv virtualenv)

Categories

Resources