Operations Taking It Further
There’s plenty of scope for further refinements with either the Using Timetables With Diagrams or the Using Scripting As An Alternative To Diagrams of our demo layout. The scripted version is the easiest one to mess around with, if you’re reasonably comfortable with writing scripts. As we saw, you can make a radical revision of the timetable with a couple of quick changes to the script and the timetable dump file. If the script is well thought through, it should be reasonably robust in the face of unexpected changes, e.g. if the user reverses a train somewhere or advances the clock.
Some things you could try:
- increase the frequency of trains for part of the day — you could double the frequency on route H/L by adding three extra trains, which could be sent back to the depot at the end of the rush hour
- change over from fixed route names to reporting numbers/headcodes — see if you can write a script that calculates the headcodes and departure times on the fly, without using a timetable at all
- build another route — how about extending south from Alfaton, so that some trains continue to reverse there and others run through? Or build another branch to the East. There’s at least half the nato alphabet left for station names…
- mix in goods trains and long-distance passenger trains from beyond Limathorpe — life gets much more interesting when you have trains with different speeds following each other
- throw the whole thing away and get hold of a working timetable for a real line you want to model!
1 Here’s one I prepared earlier…
This script will set up automatic headcode working, without either diagrams or timetables.
I’m not going to explain it in detail — it’s probably too complicated to call it a tutorial — but the general idea is that the “working timetable” is defined by a few constants in the Init()
function. A persistent counter remembers the last departure set for that route. When a train arrives at a reverse, the next departure time is generated based on the counter, and compared with the current sim time. If it is already past, the counter is incremented until it catches up with the clock. Thus the timetable should be able to keep up, even if the user advances the clock.
Up trains on route L get headcodes 2L01, 2L03, 2L05, etc.; when they get to 2L99, they loop back to 2L01. Down trains get corresponding even numbers. Route H gets 2Hnn, route E 2Enn. Empty stock workings are the same, but with a “5″ instead of a “2″.
If you want to use this, you will have to change the route names in switches and stops to match. Remember that you can use wildcards, e.g. “2L*” for all 2Lnn workings, or “5*” for all empty stock workings.
The version here is set up for ten-minute interval working with eight trains. I haven’t put in any code to reduce this off-peak yet, apart from taking Route E out of service in the evening as before.
// layout route management
//Mark Hodson Aug 2008
//Modfied to use headcodes
Init()
{
string Location;
persistent int Duty=1; //counter for depot duty assignment
//counters for headcodes and departure times
persistent int AHDep=0; //to H from A
persistent int AEDep=0;
persistent int ALDep=0;
persistent int HADep=0; //to A from H
persistent int EADep=0;
persistent int LADep=0;
persistent int DDDep=0; //empty stock
int TTstart=6*60+0; //start time in minutes
int TTint=10; //basic interval in minutes
int Day=24*60; //minutes in a day
//offset in minutes from the hour of 1st departure
int AHoff=0;
int AEoff=6;
int ALoff=5;
int HAoff=8;
int EAoff=9;
int LAoff=8;
}
OnReverse()
{
int DepTime;
int CodeSuffix;
int DH;
int DM;
string NewRoute;
string route=Train.GetRoute();
int L=Len(route);
if(L>2)
{
route=Left(route,2);
}
int Hour=Document.GetHour();
int Min=Document.GetMin();
int SimTime=Hour*60+Min;
if(Hour<5)
{
SimTime=SimTime+Day;
//make times between midnight and 5 a.m. bigger than times before midnight
}
if(Hour==12)
{
//reset duty cycle at midday, in case it's got out of sync
Duty=1;
}
//Deal with depot arrivals
if((Location=="Depot")&&(route=="5D"))
{
//allocate duties to arriving trains in order
int NDuties=8;
if(Duty==8)
{
Train.SetRoute("5E01");
Train.SetStartTime(5,49);
}
if(Duty==7)
{
Train.SetRoute("5L01");
Train.SetStartTime(5,54);
}
if(Duty==6)
{
Train.SetRoute("5H01");
Train.SetStartTime(5,59);
}
if(Duty==5)
{
Train.SetRoute("5L03");
Train.SetStartTime(6,14);
}
if(Duty==4)
{
Train.SetRoute("5E03");
Train.SetStartTime(6,19);
}
if(Duty==3)
{
Train.SetRoute("5L05");
Train.SetStartTime(6,24);
}
if(Duty==2)
{
Train.SetRoute("5H03");
Train.SetStartTime(6,29);
}
if(Duty==1)
{
Train.SetRoute("5L07");
Train.SetStartTime(6,34);
}
Duty++; //increment Duty counter
if(Duty>NDuties)
{
//reset if we've reached the end of the list
Duty=1;
Document.SetTime(5,45); //set clock to just before first departure
//Alert("Simulation time has been advanced to next morning");
//reset counters to zero for new day
AHDep=0; //to H from A
AEDep=0;
ALDep=0;
HADep=0; //to A from H
EADep=0;
LADep=0;
}
}
//Deal with Alfaton arrivals
if(Location=="Alfaton")
{
if((route=="2L")||(route=="5H"))
{
//Trains from A to H
DepTime=(TTint*AHDep)+TTstart+AHoff;
while(DepTime18)
{
DepTime=SimTime+5;
DepTime=DepTime%Day;
DH=DepTime/60;
DM=DepTime%60;
CodeSuffix=(2*DDDep)+1;
CodeSuffix=CodeSuffix%100;
DDDep++;
if(CodeSuffix<10)
{
NewRoute="5D"+"0"+CodeSuffix;
}
else
{
NewRoute="5D"+CodeSuffix;
}
Train.SetRoute(NewRoute);
Train.SetStartTime(DH,DM);
Train.SetDestinationIndicator("Do not board");
}
}
if((Location=="Hauttel")||(Location=="Limathorpe"))
{
if(Hour<5)
{
DepTime=SimTime+5;
DepTime=DepTime%Day;
DH=DepTime/60;
DM=DepTime%60;
CodeSuffix=(2*DDDep)+1;
CodeSuffix=CodeSuffix%100;
DDDep++;
if(CodeSuffix<10)
{
NewRoute="5D"+"0"+CodeSuffix;
}
else
{
NewRoute="5D"+CodeSuffix;
}
Train.SetRoute(NewRoute);
Train.SetStartTime(DH,DM);
Train.SetDestinationIndicator("Do not board");
}
}
}
3 Download
You can find the completed layout for this part of the tutorial at: http://www.markhodson.nl/rail3d/2kdlayouts/ops_layout_06.trp
import