I am struggling on making constraints using for loop in Python Pyomo. My code concept is the following:
model.Q = Set()
model.sbase=Param(model.Q, within = PositiveReals)
My code can run properly with one Sbase. But if I get 3 different numbers of Sbase. And what I want to do is to output 3 different image by using these 3 numbers.
set Q := 1 2 3;
param sbase:=
1 800
2 1000
3 1200;
What i have done so far is that:(really don't know how to do this..)
from pyomo.environ import *
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.pyplot as plt
import random
# create a model
model = AbstractModel()
# declare decision variables
model.Q = Set()
model.J = Set()
model.A = Param(model.J, within = PositiveReals)
model.B = Param(model.J, within = PositiveReals)
model.C = Param(model.J, within = PositiveReals)
model.P_min = Param(model.J, within = PositiveReals)
model.P_max= Param(model.J, within = PositiveReals)
model.P = Var(model.J, within = NonNegativeReals)
model.sbase=Param(model.Q, within = PositiveReals)
# declare objective
def obj_expression(model):
return sum(model.A[j] * model.P[j]**2 + model.B[j] * model.P[j] + model.C[j] for j in model.J)
model.profit = Objective(rule = obj_expression, sense=minimize)
# declare constraints
def lower_bound(model,j):
return model.P_min[j] <= model.P[j]
model.laborA = Constraint(model.J, rule = lower_bound)
def upper_bound(model, j):
return model.P[j] <= model.P_max[j]
model.laborB = Constraint(model.J, rule = upper_bound)
for q in range(2): #from this line ,really confused about this
def sum_labor(model,i,q):???
if q==1:??
return sum(model.P[j] for j in model.J) >= (model.sbase[Q] for q in model.Q)??
elif q==2:??
reture sum(model.P[j] for j in model.J) > = (model.sbase[Q] for q in model.Q)
model.laborC = Constraint(model.sbase,rule = sum_labor)
instance = model.create_instance("E:\pycharm_project\PD\pd.dat")
opt = SolverFactory('Ipopt')
results = opt.solve(instance)
plt.figure(figsize=(8,6))
plt.subplot(121)
for i in instance.J:
plt.bar(i,value(instance.P[i]))
plt.xlabel('Generators')
plt.ylabel('Power')
plt.title('Power distribution')
plt.subplot(122)
x=[0.1]
plt.bar(x,value(instance.profit),alpha=0.7,width=0.015)
plt.xlim(0,0.2)
plt.xlabel('')
plt.ylabel('Cost')
plt.title('minimum cost')
plt.show()
print('\n\n---------------------------')
print('Cost: ',value(instance.profit))
#DATA
set Q := 1 2 3;
set J := g1 g2 g3 g4 g5 g6 g7 g8 g9 g10 ;
param : A B C P_min P_max:=
g1 0.0148 12.1 82 80 200
g2 0.0289 12.6 49 120 320
g3 0.0135 13.2 100 50 150
g4 0.0127 13.9 105 250 520
g5 0.0261 13.5 72 80 280
g6 0.0212 15.4 29 50 150
g7 0.0382 14.0 32 30 120
g8 0.0393 13.5 40 30 110
g9 0.0396 15.0 25 20 80
g10 0.0510 14.3 15 20 60
;
param sbase:=
1 800
2 1000
3 1200;
Do you have any suggestion on how to do it?
Thanks!
Here is a toy example that I think answers your question. You can use something like this or still read your sbase variable in from data and then just index it to set the value in a similar way within the loop.
from pyomo.environ import *
m = ConcreteModel()
m.I = Set(initialize=[1,]) # mixed type set for demo only.
m.sbase = Param(mutable=True) # for the purposes of each instantiation, sbase is FIXED, so no index reqd.
m.x = Var(m.I, domain=NonNegativeReals )
## constraint
m.C1 = Constraint(expr=sum(m.sbase*m.x[i] for i in m.I) <= 10 )
## objective
m.OBJ = Objective(expr=sum(m.sbase*m.x[i] for i in m.I), sense=maximize)
solver = SolverFactory('cbc')
sbase_values = {1, 2, 5}
for sbase in sbase_values:
m.sbase = sbase
results = solver.solve(m)
print(f'\n ***** solved for sbase = {sbase} *****')
m.display()
Related
I have a pandas dataframe with 10000 columns and 3000 rows. I want to call the below function for each column and this is taking me 1+ min. I would like to reduce it, say 10s since the same code in Rust is just taking 1 sec to complete. I know python will not match Rust performance but a reduction is welcome. Is there something I can do which can vectorize or improve performance?
def extract_cycles_v3(series: pd.Series):
from collections import deque
import numpy as np
points = deque()
result = []
def format_output(point1, point2, count):
x1 = point1
x2 = point2
rng = np.abs(x1 - x2)
mean = 0.5 * (x1 + x2)
return rng, mean, count
for point in series:
points.append(point)
while len(points) >= 3:
# Form ranges X and Y from the three most recent points
x1, x2, x3 = points[-3], points[-2], points[-1]
X = np.abs(x3 - x2)
Y = np.abs(x2 - x1)
if X < Y:
# Read the next point
break
elif len(points) == 3:
# Y contains the starting point
# Count Y as one-half cycle and discard the first point
result.append(format_output(points[0], points[1], 0.5))
points.popleft()
else:
# Count Y as one cycle and discard the peak and the valley of Y
result.append(format_output(points[-3], points[-2], 1.0))
last = points.pop()
points.pop()
points.pop()
points.append(last)
else:
# Count the remaining ranges as one-half cycles
while len(points) > 1:
result.append(format_output(points[0], points[1], 0.5))
points.popleft()
return result
Below is the time spent by profiler
Line # Hits Time Per Hit % Time Line Contents
==============================================================
9 def extract_cycles_v3(series):
10 5625 200287.0 35.6 0.0 from collections import deque
11 5625 31852.0 5.7 0.0 import numpy as np
12 5625 49075.0 8.7 0.0 points = deque()
13 5625 17245.0 3.1 0.0 result = []
14 5625 32680.0 5.8 0.0 def format_output(point1, point2, count):
15 x1 = point1
16 x2 = point2
17 rng = np.abs(x1 - x2)
18 mean = 0.5 * (x1 + x2)
19 return rng, mean, count
20 9241245 30028829.0 3.2 3.8 for point in series:
21 9241245 30075819.0 3.3 3.8 points.append(point)
22 13715870 49794814.0 3.6 6.3 while len(points) >= 3:
23 # Form ranges X and Y from the three most recent points
24 13715870 55754712.0 4.1 7.1 x1, x2, x3 = points[-3], points[-2], points[-1]
25 13715870 158680523.0 11.6 20.2 X = np.abs(x3 - x2)
26 13715870 143759753.0 10.5 18.3 Y = np.abs(x2 - x1)
27 9096216 25824510.0 2.8 3.3 if X < Y:
28 # Read the next point
29 9096216 20523135.0 2.3 2.6 break
30 4577013 15633704.0 3.4 2.0 elif len(points) == 3:
31 # Y contains the starting point
32 # Count Y as one-half cycle and discard the first point
33 42641 1982939.0 46.5 0.3 result.append(format_output(points[0], points[1], 0.5))
34 42641 182248.0 4.3 0.0 points.popleft()
35 else:
36 # Count Y as one cycle and discard the peak and the valley of Y
37 4577013 193884083.0 42.4 24.6 result.append(format_output(points[-3], points[-2], 1.0))
38 4577013 15812058.0 3.5 2.0 last = points.pop()
39 4577013 13912050.0 3.0 1.8 points.pop()
40 4577013 13846706.0 3.0 1.8 points.pop()
41 4577013 14957967.0 3.3 1.9 points.append(last)
42 else:
43 # Count the remaining ranges as one-half cycles
44 38953 155899.0 4.0 0.0 while len(points) > 1:
45 38953 1695531.0 43.5 0.2 result.append(format_output(points[0], points[1], 0.5))
46 38953 157556.0 4.0 0.0 points.popleft()
47 5625 14289.0 2.5 0.0 return result
source
Here I have modeled the Epidemic disease for which I am trying to optimize the parameters so that I can fit the model with the covid-19 data. The problem here is an I am not able to get the optimized parameters instead getting the same parameters. what should I fix here and get optimized parameters for my model? Please help me correcting the code.
library(deSolve)
library(reshape2)
library(ggplot2)
library(ggpubr)
# Model Input
N <- 1380004385
p <- .87 #0.88689
initial_state_values <- c(S = N - 1, E = 0, A = 0, I = 1, T = 0, F = 0, R = 0)
parameters <- c(pie = .6782, mu = 0.0000391, beta =.89768, alpha = 0.24757, phi = 0.08,
h = 1.08, mu_I = 0.06891, mu_T = 0.06891, gamma_I = 0.05090,
gamma_T = 0.07048) #67446.82054)
time <- seq(1, 164, .1)
# Input function: Differential equation
SEAITFR_fn <- function(time, initial_state_values, parameters) {
with(as.list(c(initial_state_values, parameters)), {
N <- S+E+A+I+T+F+R
lamda <- beta/N * (A + I)
dS <- pie - (lamda + mu) * S
dE <- lamda * S - (alpha + mu) * E
dA <- alpha * (1-p) * E - (mu + phi) * A
dI <- alpha * p * E + phi * A -(h + gamma_I + mu_I + mu) * I
dT <- h * I - (gamma_T + mu_T) * T
dF <- mu_I * I + mu_T * T
dR <- gamma_I * I + gamma_T * T - mu * R
return(list(c(dS, dE, dA, dI, dT, dF, dR)))
})
}
output <- as.data.frame(ode(y = initial_state_values,
times = time,
func = SEAITFR_fn,
parms = parameters)
)
#output
output$total_prevalence <- output$I + output$T
#output$total_prevalence
# Distance Function
SEAITFR_SSQ <- function(parameters, data) {
output <- as.data.frame(ode(y = initial_state_values, # vector of initial state
times = time, # vector of times
func = SEAITFR_fn,
parms = parameters)
)
data <- na.omit(data)
deltas_square <- (output$total_prevalence[output$time %in% data$time] -
data$new_cases)^2
SSQ <- sum(deltas_square)
return(SSQ)
}
# Real world data
covid_19_data <- read_excel("covid.xlsx")
covid_19_data
#Optimization
optimised <- optim(par = c(pie =.6782, mu = 0.0000391, beta = 0.88689, alpha = 0.24757, phi = 0.08,
h = 1.08, mu_I = 0.06891, mu_T = 0.06891, gamma_I = 0.05090,
gamma_T = 0.07048), # these are the starting beta
# and gamma that will be fed
# first, into SSQ_fn
fn = SEAITFR_SSQ,
data = covid_19_data # this argument comes under "..."
# "Further arguments to be passed to fn a
)
optimised
optimised_model <- as.data.frame(ode(y = initial_state_values,
times = time, func = SEAITFR_fn, parms = optimised$par))
# Optimised_model
optimised_model$prevalence <- optimised_model$I + optimised_model$T
#optimised_model$prevalence
# Plotting
plot2 <- ggplot() + geom_line(data = optimised_model,
aes(x = time, y = prevalence)) +
geom_point(data = covid_19_data, aes(x = time, y = new_cases), colour = "red" ) +
xlab("Times(days)") + ylab("No. of infection") + labs(title =
paste("Calibration of SIR model with optimised value ")) + ylim(0,30000)
plot2
I am able to get your model to run with different parameters based on the output. Also, I have used maximum likelihood estimation and it is working just fine with the covid data
require(deSolve)
SIR_fn <- function(time, state, parameters) {
with(as.list(c(state, parameters)), {
N <- S+I+R
dS <- -beta*S*I/N
dI <- beta*S*I/N-gamma*I
dR <- gamma*I
return(list(c(dS, dI, dR)))
})
}
SIR_SSQ <- function(parameters, dat) { # parameters must contain beta & gamma
# calculate model output using your SIR function with ode()
result <- as.data.frame(ode(y = initial_state_values # vector of initial state
# values, with named elements
, times = times # vector of times
, func = SIR_fn # your predefined SIR function
, parms = parameters) # the parameters argument
# entered with SIR_SSQ()
)
# SSQ calculation: needs the dat argument (the observed data you are fitting to)
# assumes the data you are fitting to has a column "I"
# select only complete cases, i.e. rows with no NAs, from the dataframe
dat <- na.omit(dat)
# select elements where results$time is in dat$time
deltas2 <- (result$I[result$time %in% dat$time] - dat$I)^2
SSQ <- sum(deltas2)
return(SSQ)
}
flu_dat <- read.csv("flu.csv")
head(flu_dat, 10)
# time I
# 1 1 16928
# 2 2 21389
# 3 3 20006
# 4 4 21368
# 5 5 25349
# 6 6 21405
# 7 7 17662
# 8 8 17492
# 9 9 18361
# 10 10 20951
initial_state_values <- c(S = 100000, I = 1, R = 0)
# choose values to start your optimisation
beta_start <- 0.1
gamma_start <- 0.1
# times - dense timesteps for a more detailed solution
times <- seq(from = 0, to = 107, by = 0.01)
# optim
# you will need to run the cells to assign your functions first
optimised <- optim(
par = c(beta = beta_start
, gamma = gamma_start) # these are the starting beta
# and gamma that will be fed
# first, into SSQ_fn
,
fn = SIR_SSQ
,
dat = flu_dat # this argument comes under "..."
# "Further arguments to be passed to fn and gr"
)
optimised #have a look at the model output
# $par
# beta gamma
# 0.40487383 0.01637813
#
# $value
# [1] 25002879441
#
# $counts
# function gradient
# 81 NA
#
# $convergence
# [1] 0
#
# $message
# NULL
#
#
# optimised$par
# beta gamma
# 0.40487383 0.01637813
opt_mod <- as.data.frame(ode(y = initial_state_values # named vector of initial
# state values
, times = times # vector of times
, func = SIR_fn # your predefined SIR function
, parms = optimised$par))
## plot your optimised model output, with the epidemic data using ggplot ##
require(ggplot2)
opt_plot <- ggplot()
opt_plot <- opt_plot + geom_point(aes(x = time, y = I)
, colour = "red"
,size = 3
, shape = "x"
, data = flu_dat)
opt_plot <- opt_plot + geom_line(aes(x = time, y = I)
, colour = "blue"
, data = opt_mod)
opt_plot
flu_dat
# time I
# 1 1 16928
# 2 2 21389
# 3 3 20006
# 4 4 21368
# 5 5 25349
# 6 6 21405
# 7 7 17662
# 8 8 17492
# 9 9 18361
# 10 10 20951
# 11 11 23042
# 12 12 24914
# 13 13 25268
# 14 14 19019
# 15 15 19456
# 16 16 23693
# 17 17 26499
# 18 18 27867
# 19 19 30981
# 20 20 31917
# 21 21 25968
# 22 22 30676
# 23 23 36208
# 24 24 34426
# 25 25 40356
# 26 26 45353
# 27 27 41359
# 28 28 40409
# 29 29 40057
# 30 30 45980
# 31 31 51488
# 32 32 55588
# 33 33 51841
# 34 34 45549
# 35 35 49580
# 36 36 44162
# 37 37 60755
# 38 38 59740
# 39 39 62567
# 40 40 67859
# 41 41 60038
# 42 42 59085
# 43 43 58793
# 44 44 67427
# 45 45 67635
# 46 46 77102
# 47 47 71672
# 48 48 62470
# 49 49 60716
# 50 50 61477
# 51 51 64239
# 52 52 71915
# 53 53 68511
# 54 54 73208
# 55 55 65375
# 56 56 54864
# 57 57 55947
# 58 58 65785
# 59 59 71832
# 60 60 67599
# 61 61 67911
# 62 62 57839
# 63 63 46269
# 64 64 44567
# 65 65 57283
# 66 66 54433
# 67 67 59481
# 68 68 58322
# 69 69 54449
# 70 70 46369
# 71 71 48733
# 72 72 46910
# 73 73 56811
# 74 74 51742
# 75 75 64764
# 76 76 46790
# 77 77 41181
# 78 78 36484
# 79 79 45034
# 80 80 47393
# 81 81 44087
# 82 82 48253
# 83 83 43653
# 84 84 34510
# 85 85 36432
# 86 86 39979
# 87 87 45520
# 88 88 45120
# 89 89 46929
# 90 90 45414
# 91 91 34787
# 92 92 35138
# 93 93 41677
# 94 94 40951
# 95 95 43781
# 96 96 50129
# 97 97 43192
# 98 98 31511
# 99 99 23545
# 100 100 26845
# 101 101 33895
# 102 102 36066
# 103 103 47439
# 104 104 41003
# 105 105 34305
# 106 106 33842
# 107 107 39385
I am trying to do optimization with Pyomo (solver Ipopt).
I have 2 sets (j for the numbers of generator and t for times),6 indexed parameters (A,B,C,Pmin,Pmax :indexed on model.J, Demand indexed on model.T)
What I want to do is generate 24 different costs base on 24 different demands.
After I ran the code, this error appeared:
TypeError: P_LoadgenBalance() takes 1 positional argument but 2 were given.
I don’t know why this error occurs,Hope you can help me with it. Thanks for your help!
Vivi
from pyomo.environ import *
import matplotlib.pyplot as plt
import numpy as np
# create a model
model = AbstractModel()
# There are ten generators with different values of ABC.
# Minimizing the costs and find the optimal dispatch for 24 different demands changed with time
# obj:Cost= sum(ap^2 +bp+c)
# constraints: sum_i P(i,t) >= load(t) , (Pmin =< P =< Pmax).
# declare decision variables
model.M = Param(mutable=True)
model.T = RangeSet(model.M)
model.N = Param(mutable=True)
model.J = RangeSet(model.N)
model.A = Param(model.J)
model.B = Param(model.J)
model.C = Param(model.J)
model.D = Param(model.J)
model.E = Param(model.J)
model.F = Param(model.J)
model.P_min = Param(model.J, within=PositiveReals)
model.P_max = Param(model.J, within=PositiveReals)
model.demand = Param(model.T)
model.emission_value = Param(initialize=1000000, mutable=True)
# declare constraints_Pbounds (Pmin =< P =< Pmax)
def Pbounds(model, j,t):
return (model.P_min[j], model.P_max[j])
model.P = Var(model.J, model.T, bounds=Pbounds, domain=NonNegativeReals)
# declare constraints_P_LoadgenBalance ( sum P >= demand)
def P_LoadgenBalance(model,t):
return sum(model.P[j,t] for j in model.J ) >= model.demand[t]
model.P_LoadgenBalance = Constraint(model.T, rule=P_LoadgenBalance)
# declare objective_cost
def obj_cost(model):
return sum(model.A[j]* model.P[j,t] ** 2 + model.B[j] * model.P[j,t] + model.C[j] for j in model.J for t in model.T)
model.cost= Objective(rule=obj_cost, sense=minimize)
# declare objective_emission
def obj_emission(model):
return sum(model.E[j]* model.P[j,t] ** 2 + model.D[j] * model.P[j,t] + model.F[j] for j in model.J for t in model.T)
model.emission= Objective(rule=obj_emission, sense=minimize)
model.emission.deactivate()
opt = SolverFactory('Ipopt')
instance = model.create_instance("E:\pycharm_project\END-10units.dat")
results = opt.solve(instance)
print(value(instance.cost)
Data file
param M:=24;
param N:=10;
# Creating Parameters A, B, C,D,E,F, P_min, P_max:
param : A B C D E F P_min P_max:=
1 0.0148 12.1 82 2.15 3.59 -11.4 80 200
2 0.0289 12.6 49 3.63 2.02 -3.65 120 320
3 0.0135 13.2 100 3.3 4.7 -4.04 50 150
4 0.0127 13.9 105 3.73 1.61 -13.44 250 520
5 0.0261 13.5 72 2.27 2.29 -4.41 80 280
6 0.0212 15.4 29 2.37 2.77 -8.61 50 150
7 0.0382 14 32 2.03 4.86 -8.91 30 120
8 0.0393 13.5 40 2.4 3.32 -31.74 30 110
9 0.0396 15 25 2.5 4.03 -19.14 20 80
10 0.051 14.3 15 3.43 3.27 -21.02 20 60
param demand:=
1 600
2 650
3 680
4 651
5 630
6 650
7 810
8 820
9 883
10 893
11 888
12 901
13 892
14 875
15 843
16 877
17 880
18 904
19 865
20 855
21 766
22 733
23 688
24 654;
You're not defining t in the function P_LoadgenBalance, so t is the other expected argument. Code should be like:
def P_LoadgenBalance(model ,t):
For storage the individual cost, you must create a variable for it as follows with the new objective function:
# Cost Variable to store individual cost per j through t
model.X = Var(model.J, model.T, domain=NonNegativeReals)
# Cost Function
def cost(model, j, t):
return model.X[j, t] == model.A[j] * model.P[j, t] ** 2 + model.B[j] * model.P[j, t] + model.C[j]
model.cost = Constraint(model.T, Model.J, rule=cost)
# Objective
def obj_cost(model):
return sum(model.X[j, t] for j in model.J for t in model.T)
model.total_cost = Objective(rule=obj_cost, sense=minimize)
This is the dataset that I have of some orders each week. I want to predict the orders for the rest of the year. I've tried building an ARIMA model and it doesn't work.
Is there any other model that I can try for such a small dataset? Maybe a HMM or try fitting a polynomial curve to it or build a time series LSTM?
FW Order
1 6
2 45
3 59
4 60
5 50
6 115
7 23
8 44
9 164
10 8
11 30
12 20
13 0
14 50
15 60
16 0
17 50
18 30
19 115
20 75
21 54
22 29
23 124
24 32
25 28
Here's a plot of your data. Your main problem is that there isn't really enough data for any model to give you meaningful predictions with statistical significance. Your data mostly just looks like white noise around a mean, so you'd represent it with:
x_t = mu + e
where e is an error term representing white noise.
There is a hint of mean reversion, so you could try an Ornstein Uhlenbeck model:
dx_t = theta * (mu - x_t-1) dt + sigma * dW_t
https://en.wikipedia.org/wiki/Ornstein%E2%80%93Uhlenbeck_process
Here's it coded up. Orange line is the prediction. Again, the prediction isn't great, but you probably won't find much better without more data.
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.api as sm
def least_squares_naive(s, delta=1.0):
y = s.diff().iloc[1:]
x = s.shift(1)[1:]
res = sm.OLS(y, sm.add_constant(x)).fit()
b, a = res.params
residual_df = y - (a * x + b)
se = residual_df.std(ddof=2)
lambda_ = -a / delta
mu_ = b / (lambda_ * delta)
sigma_ = se / (delta ** 0.5)
return mu_, lambda_, sigma_
list = [6,45,59,60,50,115,23,44,164,8,30,20,0,50,60,0,50,30,115,75,54,29,124,32,28]
s = pd.Series(list)
mu_, lambda_, sigma_ = least_squares_naive(s)
dx = -lambda_ * (s - mu_)
pred = (s + dx).shift()
diff = s.diff(1).dropna()
s.plot()
pred.plot()
plt.show()
I have an ODE system of 7 equations for explaining a particular set of microorganisms dynamics of the form:
Where the are the different chemical and microorganisms species involved (even sub-indexes for chemical compounds), the are the yield coefficients and the are the pseudo-reactions:
I am using Pyomo for the estimation of all my unknown parameters, which are basically all the yield coefficients and kinetic constants (15 in total).
The following code works perfectly when is used with complete experimental time series for each of the dynamical variables:
from pyomo.environ import *
from pyomo.dae import *
m = AbstractModel()
m.t = ContinuousSet()
m.MEAS_t = Set(within=m.t) # Measurement times, must be subset of t
m.x1_meas = Param(m.MEAS_t)
m.x2_meas = Param(m.MEAS_t)
m.x3_meas = Param(m.MEAS_t)
m.x4_meas = Param(m.MEAS_t)
m.x5_meas = Param(m.MEAS_t)
m.x6_meas = Param(m.MEAS_t)
m.x7_meas = Param(m.MEAS_t)
m.x1 = Var(m.t,within=PositiveReals)
m.x2 = Var(m.t,within=PositiveReals)
m.x3 = Var(m.t,within=PositiveReals)
m.x4 = Var(m.t,within=PositiveReals)
m.x5 = Var(m.t,within=PositiveReals)
m.x6 = Var(m.t,within=PositiveReals)
m.x7 = Var(m.t,within=PositiveReals)
m.k1 = Var(within=PositiveReals)
m.k2 = Var(within=PositiveReals)
m.k3 = Var(within=PositiveReals)
m.k4 = Var(within=PositiveReals)
m.k5 = Var(within=PositiveReals)
m.k6 = Var(within=PositiveReals)
m.k7 = Var(within=PositiveReals)
m.k8 = Var(within=PositiveReals)
m.k9 = Var(within=PositiveReals)
m.y1 = Var(within=PositiveReals)
m.y2 = Var(within=PositiveReals)
m.y3 = Var(within=PositiveReals)
m.y4 = Var(within=PositiveReals)
m.y5 = Var(within=PositiveReals)
m.y6 = Var(within=PositiveReals)
m.x1dot = DerivativeVar(m.x1,wrt=m.t)
m.x2dot = DerivativeVar(m.x2,wrt=m.t)
m.x3dot = DerivativeVar(m.x3,wrt=m.t)
m.x4dot = DerivativeVar(m.x4,wrt=m.t)
m.x5dot = DerivativeVar(m.x5,wrt=m.t)
m.x6dot = DerivativeVar(m.x6,wrt=m.t)
m.x7dot = DerivativeVar(m.x7,wrt=m.t)
def _init_conditions(m):
yield m.x1[0] == 51.963
yield m.x2[0] == 6.289
yield m.x3[0] == 0
yield m.x4[0] == 6.799
yield m.x5[0] == 0
yield m.x6[0] == 4.08
yield m.x7[0] == 0
m.init_conditions=ConstraintList(rule=_init_conditions)
def _x1dot(m,i):
if i==0:
return Constraint.Skip
return m.x1dot[i] == - m.y1*m.k1*m.x1[i]*m.x2[i]/(m.k2+m.x1[i]) - m.y2*m.k3*m.x1[i]*m.x4[i]/(m.k4+m.x1[i])
m.x1dotcon = Constraint(m.t, rule=_x1dot)
def _x2dot(m,i):
if i==0:
return Constraint.Skip
return m.x2dot[i] == m.k1*m.x1[i]*m.x2[i]/(m.k2+m.x1[i]) - m.k7*m.x2[i]*m.x3[i]
m.x2dotcon = Constraint(m.t, rule=_x2dot)
def _x3dot(m,i):
if i==0:
return Constraint.Skip
return m.x3dot[i] == m.y3*m.k1*m.x1[i]*m.x2[i]/(m.k2+m.x1[i]) - m.y4*m.k5*m.x3[i]*m.x6[i]/(m.k6+m.x3[i])
m.x3dotcon = Constraint(m.t, rule=_x3dot)
def _x4dot(m,i):
if i==0:
return Constraint.Skip
return m.x4dot[i] == m.k3*m.x1[i]*m.x4[i]/(m.k4+m.x1[i]) - m.k8*m.x4[i]*m.x3[i]
m.x4dotcon = Constraint(m.t, rule=_x4dot)
def _x5dot(m,i):
if i==0:
return Constraint.Skip
return m.x5dot[i] == m.y5*m.k3*m.x1[i]*m.x4[i]/(m.k4+m.x1[i])
m.x5dotcon = Constraint(m.t, rule=_x5dot)
def _x6dot(m,i):
if i==0:
return Constraint.Skip
return m.x6dot[i] == m.k5*m.x3[i]*m.x6[i]/(m.k6+m.x3[i]) - m.k9*m.x6[i]*m.x7[i]
m.x6dotcon = Constraint(m.t, rule=_x6dot)
def _x7dot(m,i):
if i==0:
return Constraint.Skip
return m.x7dot[i] == m.y6*m.k5*m.x3[i]*m.x6[i]/(m.k6+m.x3[i])
m.x7dotcon = Constraint(m.t, rule=_x7dot)
def _obj(m):
return sum((m.x1[i]-m.x1_meas[i])**2+(m.x2[i]-m.x2_meas[i])**2+(m.x3[i]-m.x3_meas[i])**2+(m.x4[i]-m.x4_meas[i])**2+(m.x5[i]-m.x5_meas[i])**2+(m.x6[i]-m.x6_meas[i])**2+(m.x7[i]-m.x7_meas[i])**2 for i in m.MEAS_t)
m.obj = Objective(rule=_obj)
m.pprint()
instance = m.create_instance('exp.dat')
instance.t.pprint()
discretizer = TransformationFactory('dae.collocation')
discretizer.apply_to(instance,nfe=30)#,ncp=3)
solver=SolverFactory('ipopt')
results = solver.solve(instance,tee=True)
However, I am trying to run the same estimation routine in another experimental data that have missing values at the end of one or maximum two time series of some of the dynamical variables.
In other words, these complete experimental data looks like (in the .dat file):
set t := 0 6 12 18 24 30 36 42 48 54 60 66 72 84 96 120 144;
set MEAS_t := 0 6 12 18 24 30 36 42 48 54 60 66 72 84 96 120 144;
param x1_meas :=
0 51.963
6 43.884
12 24.25
18 26.098
24 11.871
30 4.607
36 1.714
42 4.821
48 5.409
54 3.701
60 3.696
66 1.544
72 4.428
84 1.086
96 2.337
120 2.837
144 3.486
;
param x2_meas :=
0 6.289
6 6.242
12 7.804
18 7.202
24 6.48
30 5.833
36 6.644
42 5.741
48 4.568
54 4.252
60 5.603
66 5.167
72 4.399
84 4.773
96 4.801
120 3.866
144 3.847
;
param x3_meas :=
0 0
6 2.97
12 9.081
18 9.62
24 6.067
30 11.211
36 16.213
42 10.215
48 20.106
54 22.492
60 5.637
66 5.636
72 13.85
84 4.782
96 9.3
120 4.267
144 7.448
;
param x4_meas :=
0 6.799
6 7.73
12 7.804
18 8.299
24 8.208
30 8.523
36 8.507
42 8.656
48 8.49
54 8.474
60 8.203
66 8.127
72 8.111
84 8.064
96 6.845
120 6.721
144 6.162
;
param x5_meas :=
0 0
6 0.267
12 0.801
18 1.256
24 1.745
30 5.944
36 3.246
42 7.787
48 7.991
54 6.943
60 8.593
66 8.296
72 6.85
84 8.021
96 7.667
120 7.209
144 8.117
;
param x6_meas :=
0 4.08
6 4.545
12 4.784
18 4.888
24 5.293
30 5.577
36 5.802
42 5.967
48 6.386
54 6.115
60 6.625
66 6.835
72 6.383
84 6.605
96 5.928
120 5.354
144 4.975
;
param x7_meas :=
0 0
6 0.152
12 1.616
18 0.979
24 4.033
30 5.121
36 2.759
42 3.541
48 4.278
54 4.141
60 6.139
66 3.219
72 5.319
84 4.328
96 3.621
120 4.208
144 5.93
;
While one of my incomplete data sets could have all time series complete, but one like this:
param x6_meas :=
0 4.08
6 4.545
12 4.784
18 4.888
24 5.293
30 5.577
36 5.802
42 5.967
48 6.386
54 6.115
60 6.625
66 6.835
72 6.383
84 6.605
96 5.928
120 5.354
144 .
;
I have knowledge that one can specify to Pyomo to take the derivative of certain variables with respect to a different time serie. However, after tried it, it hadn't worked, and I guess that is because that these are coupled ODE. So basically my question is if there is a way to overcome this issue in Pyomo.
Thanks in advance.
I think all you need to do is slightly modify your objective function like this:
def _obj(m):
sum1 = sum((m.x1[i]-m.x1_meas[i])**2 for i in m.MEAS_t if i in m.x1_meas.keys())
sum2 = sum((m.x2[i]-m.x2_meas[i])**2 for i in m.MEAS_t if i in m.x2_meas.keys())
sum3 = sum((m.x3[i]-m.x3_meas[i])**2 for i in m.MEAS_t if i in m.x3_meas.keys())
sum4 = sum((m.x4[i]-m.x4_meas[i])**2 for i in m.MEAS_t if i in m.x4_meas.keys())
sum5 = sum((m.x5[i]-m.x5_meas[i])**2 for i in m.MEAS_t if i in m.x5_meas.keys())
sum6 = sum((m.x6[i]-m.x6_meas[i])**2 for i in m.MEAS_t if i in m.x6_meas.keys())
sum7 = sum((m.x7[i]-m.x7_meas[i])**2 for i in m.MEAS_t if i in m.x7_meas.keys())
return sum1+sum2+sum3+sum4+sum5+sum6+sum7
m.obj = Objective(rule=_obj)
This double checks that i is a valid index for each set of measurements before adding that index to the sum. If you knew apriori which measurement sets were missing data then you could simplify this function by only doing this check on those sets and summing over the others like you were before.