[This is preliminary documentation and is subject to change.]

How-tos Overview

Here are some how-tos that, due to the current lack of a more complete manual, will hopefully provide help building React.NET simulations.

Simulation

Tasks & Processes

Resources & Consumables

Random Numbers

Developer

Simulation

Back to top1. Create a Simulation

Creating a simulation involves two steps: (1) first you must instantiate a Simulation instance; and (2) you must supply the newly created Simulation with one or more generator tasks. Instantiating the simulation is simple...

Simulation sim = new Simulation();

Creating the generator tasks may be somewhat more involved as you need to write some code to get the generators tasks to actually do something when they're executed by the simulation. Once you have such a task, it may be activated prior to calling the Simulation.Run method or it may be passed to the Run method.

Method 1

Activate a single generator task of type MyTask prior to calling the Simulation.Run() method.

Task task = new MyTask(sim);
task.Activate();
sim.Run();

Method 2

Pass a single generator task of type MyTask to the Simulation.Run(Task) method.

Task task = new MyTask(sim);
sim.Run(task);

Method 3

Pass a multiple generator tasks of type MyTaskA and MyTaskB to the Simulation.Run(Task[]) method.

Task [] tasks = new Task [2];
tasks[0] = MyTaskA(sim);
tasks[1] = MyTaskB(sim);
sim.Run(tasks);

Note that Method 1 may be used in conjunction with Method 2 or Method 3. Method 2 and Method 3 cannot be used to run the same simulation.

Back to top2. Stop a Simulation

There are a few different ways to stop a running simulation. It mainly depends upon whether: you want to stop the simulation immediately; or want to have to option to cancel the stoppage if it's scheduled to occur at some time in the future.

If you don't need to be able to cancel the stoppage, the easiest way to stop the simulation is to use one of the Stop methods of the Simulation class.

public void Stop();
public virtual void Stop(long absTime);

The first version, Stop() simply stops the simulation immediately. The second version stops the simulation at some absolute simulation time. The first version simply calls the second version with an argument of Now (the current simulation time).

Note

The Stop(long) method is one of the few methods that takes an absolute time rather than a relative time.

Once a stop time is set by calling Stop is possible to issue a different stop time, but not to recind the stoppage alltogether. If you need to be able to cancel a stoppage, you can use a StopSimulation task.

Simulation sim = /* get the running Simulation instance. */
long stopTime = sim.Now + 1000L;
Task stopTask = new React.Tasking.StopSimulation(sim);
stopTask.Activate(stopTime);

To cancel stopTask simply invoke its Cancel() method prior to its execution.

stopTask.Cancel();

Tasks & Processes

IMPORTANT: Always bear in mind that a Process is a Task. Most of the tips below that apply to Task instances apply equally to Process instances.

Back to top1. Start a task running

To start a task running, it must be activated. The Task class contains a number of methods to activate an instance.

public void Activate(object activator);
public void Activate(object activator, long relTime);
public void Activate(object activator, long relTime, int priority);
public void Activate(object activator, long relTime, object data);
public virtual void Activate(object activator, long relTime, object data, int priority);

The meaning of the parameters are identical for each version of the Activate method. All versions delegate to the final version (the one marked virtual).

activator
The object that is activating the Task. This may be null in which case the activation is said to be anonymous.
relTime
The time, relative to the current simulation time, when the Task should be activated.
data
Client data to pass to the Task when it is activated. This object is available to Process instances as the ActivationData property. It is available to Task instances by querying the triggering ActivationEvent.
priority
The priority of the Task. This value is used to order task execution when two or more tasks occur at the exact same time. Higher values indicate higher priority. The default task priority is zero (0).

Back to top2. Immediately cancel a running task

If a Task is scheduled, that is, it has been activated using one of the methods described previously, it may be cancelled by invoking its Cancel() method.

task.Cancel();

Back to top3. Schedule a task cancellation at some future time

A Task can be cancelled at some future time in the running Simulation by using a CancellationTask.

Task target = /* get the Task to cancel */
Task cancelTask = new React.Tasking.CancellationTask(sim, target);
cancelTask.Activate(null, 5000L);

The above would cancel target in 5000 time units from the current simulation time.

Cancellation in this manner is one way to implement reneging; however using an interrupt is probably a better approach.

Back to top4. Have one task block (wait) on another task

One Task can be made to block on another using one of two techniques (Process instance offer one addition method). The technique to choose depends upon whether or not you want to immediately activate the blocking task.

In the following examples, let blocker be the blocking Task and waiting be the Task being blocked (i.e. that task that's waiting on blocker).

Block with immediate activation of blocker

If you want to activate blocker immediately, call waiting's WaitOnTask method.

waiting.WaitOnTask(blocker);

The task, waiting will block on blocker and blocker will be activated.

Block with deferred activation of blocker

If you want to defer activation of blocker use the Block(Task) method of blocker.

blocker.Activate(null, 500);
blocker.Block(waiting);

In the above example, blocker will activate 500 time units from the current time. It also is blocking the task, waiting.

Have a process block on a task

Process instances provide another means of blocking on other Tasks. They simply need to return the blocking Task from the GetProcessSteps method. Remember, GetProcessSteps is an iterator method so you must to a yield return.

// Block on the task 'blocker'
yield return blocker;

Note that blocker is activated immediately.

Back to top5. Re-activate one blocked task

A Task that is blocking one or more Tasks can re-activate one of the blocked Tasks by invoking the ResumeNext method. There are three versions of ResumeNext available.

	// Resume the next blocked task.  The blocked task is re-activated with the
	// blocking task as its activator.
	ResumeNext();
	
	// Resume the next blocked task specifying some activation data.  The blocked
	// task is re-activated with the blocking task as its activator.
	ResumeNext(thing);
	
	// Resume the next blocked task specifiying both the activator and activation
	// data.
	ResumeNext(activator, thing);

Back to top6. Re-activate all blocked tasks

A Task that is blocking one or more Tasks can re-activate all of the blocked Tasks by invoking the ResumeAll method. There are three versions of ResumeAll available. The arguments to ResumeAll are used identically to those of ResumeNext (see previous how-to).

Back to top7. Create a process using delegation

A Process can be created using a ProcessSteps delegate defined as follows

	public delegate IEnumerator<Task> ProcessSteps(Process process, object data);

To create a Process in this manner, you must first write the method to be used by the ProcessSteps delegate. Then pass the delegate to the appropriate constructor.

// The method usable as a ProcessSteps delegate.
private IEnumerator<Task> DoProcess(Process process, object data)
{
    // ... do your processing ...

    // Doesn't hurt to always include this at the end.
    yield break;
}

public static void Main(string [] args)
{
	Thing thing = new Thing();
    Simulation sim = new Simulation();
    
    // Create a new Process using the delegate method.
    Process p1 = new Process(sim, DoProcess);
    
    // Create a new Process using the delegate method and passing it
    // some initial data.
    Process p2 = new Process(sim, DoProcess, thing);
    
    // Run the simulation. p1 and p2 are the generator tasks.
    sim.Run(new Task[] {p1, p2});
}

Back to top8. Create a process using derivation

To create a Process using derivation, you must override the GetProcessSteps method.

public class MyProcess : Process
{
    public MyProcess(Simulation sim) : base(sim) {}

    protected override IEnumerator<Task>GetProcessSteps()
    {
        .
        .
        .

        yield break;
    }
}

When creating a new class this way, you do not need to invoke the base class version of GetProcessSteps.

Resources & Consumables

Back to top1. Create an anonymous resource

An anonymous resource, implemented by the AnonymousResource class, can be created by directly instantiating an AnonymousResource instance or by using a Resource factory method. Using direct instantiation allows you to supply a name for the resource at the time of its creation.

Direct Instantiation

Create a new AnonymousResource instance by using one of the three available constructors.

// Create with an capacity of one (1).
IResource r1 = new AnonymousResource();

// Create with the specified capacity (e.g. 5).
IResource r2 = new AnonymousResource(5);

// Create with specified name and capacity.
IResource r3 = new AnonymousResource("Printers", 4);

Factory Method

Create a new AnonymousResource instance by using the Resource.Create(int) or Resource.Create(int,int) factory methods.

// Create an AnonymousResource with a capacity of 10.
IResource r4 = Resource.Create(10);

// Create an AnonymousResource with a capacity of 10, 4 of which are
// out of service.
IResource r5 = Resource.Create(6, 4);

In the first Create call, all ten resource items are in-service. In the second Create call, six items are in-service and four items are out-of-service. Both result in an AnonymousResource with a capacity of ten (e.g. the resource's Count property equals 10).

Back to top2. Create a tracked resource

A tracked resource, implemented by the TrackedResource class, can be created by directly instantiating an TrackedResource instance or by using a Resource factory method. Using direct instantiation allows you to supply a name for the resource at the time of its creation.

Direct Instantiation

Create a new TrackedResource instance by using one of the two available constructors.

// Load an IEnumerable with the objects the TrackedResource will contain.
// In this example a simple array is used.
object [] things = new object [5];
things[0] = new Thing();
things[1] = new Thing();
    .
    .
    .
    
// Create an unnamed TrackedResource.
IResource r1 = new TrackedResource(things);

// Create an named TrackedResource.
IResource r2 = new TrackedResource("Stuff", things);

Note that while the above example shows the objects in the things array being placed into two different TrackedResource instance, this is not a good idea and should be avoided. An object should never be contained by more than one TrackedResource.

Factory Method

Create a new TrackedResource instance by using the Resource.Create(IEnumerable) factory method.

// Create and load an IEnumerable...
IList list = new ArrayList();
list.add(new Thing());
list.add(new Thing());

// Create an TrackedResource containing the elements of 'list'.
IResource r3 = Resource.Create(list);

All the resource items in a newly created TrackedResource are in-service.

Back to top3. Obtain the number of free and in-use items

To query an IResource for the number of items that are free and the number of items that are in-use, query the Free and InUse properties.

// Get the number of free (available) items in resource 'res'.
int nFree = res.Free;

// Get the number of in-use items in resource 'res'.
int nUsed = res.InUse;

Back to top4. Change the capacity of a resource

Once created, it's actually not possible to change the capacity of a resource. That is, the Count property remains fixed. It is, however, possible to alter the number of resource items are are out-of-service. An item that is out-of-service is considered unusable and therefore cannot be made available by the IResource.

To change the number of out-of-service items simply change the OutOfService property.

// Decrease the number of in-service items in the resource 'res' by two.
res.OutOfService += 2;

One major implication of the above is that you must remember to create your resources with a capacity that will accomodate the maximum desired in-service count.

Back to top5. Acquire a resource item from a resource pool

A Process can acquire a resource item from a IResource using the Acquire method.

IResource res = /* get the resource you want to acquire from */
yield return res.Acquire(this);
// When the process resumes, we have the resource item.

Note that this example applies only to Process instances. The above code is only valid in an overridden GetProcessSteps method or a ProcessSteps delegate method.

Back to top6. Release a resource item back into its resource pool

A Process can release a previously acquired resource item to a IResource using the Release method.

IResource res = /* get the resource you want to release to */
yield return res.Release(this);
// When the process resumes, we will have released the resource item.

Note that this example applies only to Process instances. The above code is only valid in an overridden GetProcessSteps method or a ProcessSteps delegate method.

Note

If you own multiple resource items from a TrackedResource you can use the Release(Task, object) method (defined on TrackedResource) to specify which resource item to release. If the IResource.Release(Task) method is used, the longest owned item is released.

Back to top7. Obtain the tracked resource item acquired (allocated)

When using a TrackedResource the acquiring Task is passed the allocated resource item as the data parameter of the ExecuteTask method.

For Process instances, obtaining the allocated resource item is a bit different because normally, you are not overriding ExecuteTask. In this case, the resource item is available in the ActivationData property.

Back to top8. Create a consumable

Create a new Consumable instance using one of four constructors. Two of the constructor create an empty consumable, while the other two create a consumable with a specified initial quantity of consumable items (units).

Create an empty consumable

The following two constructors create empty Consumable instances.

// Create an unnamed, empty consumable.
IConsumable c1 = new Consumable();

// Create a named, empty consumable.
IConsumable c2 = new Consumable("Fuel Tank");

Create a consumable with an initial quantity

The following two constructors create Consumable instances having the specified initial quantity of consumable items or units.

// Create an unnamed consumable with initial quantity of 2500 items/units.
IConsumable c3 = new Consumable(2500);

// Create an named consumable with initial quantity of 500 items/units.
IConsumable c4 = new Consumable("Water Tank", 500);

Back to top9. Add items/units to a consumable

Adding items or units to a IConsumable is called re-supplying. After it's initial creation a consumable can only be re-supplied during the simulation run. Re-supplying is accomplished by the Task returned by the Resupply(Task task, int quantity) blocking method of IConsumable.

The example code shown below illustrates performing a re-supply from a Process.

protected override IEnumerator<Task> GetProcessSteps()
{
	// ... perform some processing ...
	
	// Get ahold of an IConsumable instance
	IConsumable c = GetWaterTank();
	
	// Now resupply it with 1000 items/units.
	yield return c.Resupply(this, 1000);
	
	// ... perform some more processing ...
}

Random Numbers

Back to top1. Create a uniformly distributed random number generator

The React.Distribution.Uniform class includes two static methods that return a new Uniform instance.

public static Uniform Create();
public static Uniform Create(long seed);

In the first case, the resulting Uniform is seeded using the current system time. In the second case, the seed must be specified.

Both of the above Create methods, return a Uniform derivitive that uses System.Random to do the actual random number generation.

Back to top2. Configure a non-uniform variate to use a user-supplied uniform generator

Non-uniform random number generators or non-uniform variates can be created to use a uniform generator from the system-wide set of uniform random number streams or they can use a user-supplied random number generator.

All the React.NET non-uniform variates have constructors that take a IUniformSource interface. To specify the IUniformSource for non-uniform variate use one of the constructors that accept a IUniformSource parameter. For example, to create a Weibull instance that uses its own uniform generator, you can do the following.

// Create a new IUniformSource instance seeded from the system time.
IUniformSource rngSource = Uniform.Create();

// Create a new Weibull instance that obtains a uniform generator from rngSource.
Weibull weibull = new Weibull(rngSource);

Note that in the example above, weibull will use the Weibull class's default shape and scale.

Developer

Back to top1. Check out the latest sources

React.NET is currently developed using the Subversion version control system. SourceForge began supporting Subversion in February 2006. It is possible to check out the React.NET source code as follows (if you're using the Subversion command-line client).

svn co https://svn.sourceforge.net/svnroot/reactnet/trunk reactnet

The above will check out the main development line (the trunk) into a directory named reactnet.

For more infomation on using Subversion with SourceForge, see the documents