@@ -1243,13 +1243,17 @@ def _build_euler_timeseries(self, return_timestamps=None, final_time=None):
1243
1243
except IndexError :
1244
1244
# return_timestamps is an empty list
1245
1245
# model default final time or passed argument value
1246
- t_f = self .final_time
1246
+ t_f = self .components . final_time ()
1247
1247
1248
1248
if final_time is not None :
1249
1249
t_f = max (final_time , t_f )
1250
1250
1251
1251
ts = np .arange (
1252
- t_0 , t_f + self .time_step / 2 , self .time_step , dtype = np .float64 )
1252
+ t_0 ,
1253
+ t_f + self .components .time_step ()/ 2 ,
1254
+ self .components .time_step (),
1255
+ dtype = np .float64
1256
+ )
1253
1257
1254
1258
# Add the returned time series into the integration array.
1255
1259
# Best we can do for now. This does change the integration ever
@@ -1278,11 +1282,10 @@ def _format_return_timestamps(self, return_timestamps=None):
1278
1282
# Vensim's standard is to expect that the data set includes
1279
1283
# the `final time`, so we have to add an extra period to
1280
1284
# make sure we get that value in what numpy's `arange` gives us.
1281
-
1282
1285
return np .arange (
1283
1286
self .time (),
1284
- self .final_time + self .saveper / 2 ,
1285
- self .saveper , dtype = float
1287
+ self .components . final_time () + self .components . saveper () / 2 ,
1288
+ self .components . saveper () , dtype = float
1286
1289
)
1287
1290
1288
1291
try :
@@ -1377,23 +1380,35 @@ def run(self, params=None, return_columns=None, return_timestamps=None,
1377
1380
1378
1381
self .progress = progress
1379
1382
1383
+ # TODO move control variables to a class
1384
+ if params is None :
1385
+ params = {}
1386
+ if final_time :
1387
+ params ['final_time' ] = final_time
1388
+ elif return_timestamps is not None :
1389
+ params ['final_time' ] = \
1390
+ self ._format_return_timestamps (return_timestamps )[- 1 ]
1391
+ if time_step :
1392
+ params ['time_step' ] = time_step
1393
+ if saveper :
1394
+ params ['saveper' ] = saveper
1395
+ # END TODO
1396
+
1380
1397
if params :
1381
1398
self .set_components (params )
1382
1399
1383
1400
self .set_initial_condition (initial_condition )
1384
1401
1402
+ # TODO move control variables to a class
1385
1403
# save control variables
1386
- self .initial_time = self .time ()
1387
- self .final_time = final_time or self .components .final_time ()
1388
- self .time_step = time_step or self .components .time_step ()
1389
- self .saveper = saveper or max (self .time_step ,
1390
- self .components .saveper ())
1391
- # need to take bigger saveper if time_step is > saveper
1404
+ replace = {
1405
+ 'initial_time' : self .time ()
1406
+ }
1407
+ # END TODO
1392
1408
1393
1409
return_timestamps = self ._format_return_timestamps (return_timestamps )
1394
1410
1395
1411
t_series = self ._build_euler_timeseries (return_timestamps , final_time )
1396
- self .final_time = t_series [- 1 ]
1397
1412
1398
1413
if return_columns is None or isinstance (return_columns , str ):
1399
1414
return_columns = self ._default_return_columns (return_columns )
@@ -1410,10 +1425,9 @@ def run(self, params=None, return_columns=None, return_timestamps=None,
1410
1425
res = self ._integrate (t_series , capture_elements ['step' ],
1411
1426
return_timestamps )
1412
1427
1413
- self ._add_run_elements (res , capture_elements ['run' ])
1428
+ self ._add_run_elements (res , capture_elements ['run' ], replace = replace )
1414
1429
1415
1430
return_df = utils .make_flat_df (res , return_addresses , flatten_output )
1416
- return_df .index = return_timestamps
1417
1431
1418
1432
return return_df
1419
1433
@@ -1562,8 +1576,7 @@ def _integrate(self, time_steps, capture_elements, return_timestamps):
1562
1576
outputs: list of dictionaries
1563
1577
1564
1578
"""
1565
- outputs = pd .DataFrame (index = return_timestamps ,
1566
- columns = capture_elements )
1579
+ outputs = pd .DataFrame (columns = capture_elements )
1567
1580
1568
1581
if self .progress :
1569
1582
# initialize progress bar
@@ -1580,6 +1593,10 @@ def _integrate(self, time_steps, capture_elements, return_timestamps):
1580
1593
self .time .update (t2 ) # this will clear the stepwise caches
1581
1594
self .components .cache .reset (t2 )
1582
1595
progressbar .update ()
1596
+ # TODO move control variables to a class and automatically stop
1597
+ # when updating time
1598
+ if self .time () >= self .components .final_time ():
1599
+ break
1583
1600
1584
1601
# need to add one more time step, because we run only the state
1585
1602
# updates in the previous loop and thus may be one short.
@@ -1591,7 +1608,7 @@ def _integrate(self, time_steps, capture_elements, return_timestamps):
1591
1608
1592
1609
return outputs
1593
1610
1594
- def _add_run_elements (self , df , capture_elements ):
1611
+ def _add_run_elements (self , df , capture_elements , replace = {} ):
1595
1612
"""
1596
1613
Adds constant elements to a dataframe.
1597
1614
@@ -1603,6 +1620,10 @@ def _add_run_elements(self, df, capture_elements):
1603
1620
capture_elements: list
1604
1621
List of constant elements
1605
1622
1623
+ replace: dict
1624
+ Ouputs values to replace.
1625
+ TODO: move control variables to a class and avoid this.
1626
+
1606
1627
Returns
1607
1628
-------
1608
1629
None
@@ -1612,16 +1633,17 @@ def _add_run_elements(self, df, capture_elements):
1612
1633
for element in capture_elements :
1613
1634
df [element ] = [getattr (self .components , element )()] * nt
1614
1635
1636
+ # TODO: move control variables to a class and avoid this.
1615
1637
# update initial time values in df (necessary if initial_conditions)
1616
- for it in [ 'initial_time' , 'final_time' , 'saveper' , 'time_step' ] :
1638
+ for it , value in replace . items () :
1617
1639
if it in df :
1618
- df [it ] = getattr ( self , it )
1640
+ df [it ] = value
1619
1641
elif it .upper () in df :
1620
- df [it .upper ()] = getattr ( self , it )
1642
+ df [it .upper ()] = value
1621
1643
elif it .replace ('_' , ' ' ) in df :
1622
- df [it .replace ('_' , ' ' )] = getattr ( self , it )
1644
+ df [it .replace ('_' , ' ' )] = value
1623
1645
elif it .replace ('_' , ' ' ).upper () in df :
1624
- df [it .replace ('_' , ' ' ).upper ()] = getattr ( self , it )
1646
+ df [it .replace ('_' , ' ' ).upper ()] = value
1625
1647
1626
1648
1627
1649
def ramp (time , slope , start , finish = 0 ):
0 commit comments