Search All of the Math Forum:

Views expressed in these public forums are not endorsed by NCTM or The Math Forum.

Notice: We are no longer accepting new posts, but the forums will continue to be readable.

Topic: Fixed Typo in Code---> Re: updating a simulation within Manipulate.
Replies: 5   Last Post: Mar 9, 2013 5:25 AM

 Messages: [ Previous | Next ]
 Nasser Abbasi Posts: 6,677 Registered: 2/7/05
Re: Fixed Typo in Code---> Re: updating a simulation within Manipulate.
Posted: Mar 9, 2013 5:25 AM

On 3/7/2013 9:47 PM, W Craig Carter wrote:
> On previous message, there is a typo in the example code, please use this instead:
>
> randomStep[bias_, stepList_] :=
> Module[{angle = RandomVariate[NormalDistribution[bias, 1]]},
> Join[stepList, {Last[stepList] + {Cos[angle], Sin[angle]}}]]
>
> walkerGraphic[stepList_, range_] :=
> Graphics[GraphicsComplex[stepList, Disk /@ Range[Length[stepList]]],
> PlotRange -> range {{-1, 1}, {-1, 1}}]
>
> DynamicModule[{walkerPath = {{0, 0}}},
> Manipulate[
> If[keepWalking,(*kludge warning---testing for If[ True...] seems inefficient*)
> walkerPath = randomStep[bias, walkerPath]];
> If[reset, reset = False; keepWalking = False;
> walkerPath = {{0, 0}}];
> walkerGraphic[walkerPath,
> range], {{keepWalking, False}, {True, False}}, {{reset,
> False}, {True, False}}, Delimiter, {{range, 20}, 0, 100},
> {{bias, 0}, -Pi, Pi,
> AngularGauge[##, ImageSize -> 160,
> ScaleOrigin -> {{-4 Pi, 4 Pi}, 1}] &}]]
>
>
>
> W Craig Carter
> Professor of Materials Science, MIT

The best way that I found after to do all these things
in Mathematica is to use a finite state machine type setup
to control the overall state of simulation. There will be a
"running" state, "pause" state, "reset" state and so on.

Then the whole simulation will be controlled by one ticklish
dynamic, called `tick` which acts like the heart beat of the
simulation.

Only one TrackedSymbol in the whole simulation.

Next, we will use the second argument of Dynamic to act as
the callback. Each time a control is changed, in the callback
we adjust the state of simulation as needed, then tickle the
heart beat so that the main display is refreshed.

When the main display does not need to refresh, then the heart beat
is not updated in the callback. Other house keeping logic can
be there if needed.

So, this is the whole idea. This works now as traditional simulation
loops work and as traditional GUI callbacks work, but with the
advntage of having Dynamics as well.

No need now to worry about where to do what, and have the logic spread
in many different locations in the code. The logic of the simulation
now is more organized and it is possible to make the simulation as
complex as needed without losing track of things.

In the callback (i.e. second argument of Dynamic), only work
relating to this control is done.

In the main display area, is where the main logic of the
state machine is, which updates the display, and if needed
tickle the heart beat again, so that the loop continue again
and again. No trigers are needed, no clocks, etc... Just one
tickle when needed, and the use of the second argument of
Dynamics and adding TrackedSymbols on the tick.

I wrote a note on this method sometime ago here

http://12000.org/my_notes/event_driven_GUI_with_Manipulate/event_driven_manipulate.htm

Using this method of doing simulation, here is your simulation now.
I put the notebook here also in case the paste does not work:

http://12000.org/tmp/030813/

----------------------------------------------
DynamicModule[{walkerPath = {{0, 0}}, state = "running", tick = 0,
result, del = \$MachineEpsilon, range = 40, bias = 0, btnControls,
rangeControl, biasControl, stepSizeControl, stepSize = 0.21},

stepSizeControl =
Row[{Text@"step size", Spacer[5],
Manipulator[Dynamic[stepSize, {stepSize = #} &], {0.01, 1, 0.01},
ImageSize -> Tiny, ContinuousAction -> True], Spacer[5],
Dynamic[AccountingForm[stepSize, {3, 2}, NumberSigns -> {"", ""},

btnControls = Grid[{{
Button[Text[Style["run", 12]],
If[state == "running", walkerPath = {{0, 0}}];
state = "running"; tick += del, ImageSize -> {50, 35}],
Button[Text[Style["pause", 12]], state = "paused"; tick += del,
ImageSize -> {50, 35}],
Button[Text[Style["step", 12]], state = "step"; tick += del,
ImageSize -> {50, 35}],
Button[Text[Style["reset", 12]], state = "reset";
walkerPath = {{0, 0}};
result = walkerGraphic[walkerPath, range]; tick = 0,
ImageSize -> {50, 35}]
}}, Spacings -> {0.2, .1}
];

rangeControl =
Row[{Text@"range", Spacer[5],
Manipulator[Dynamic[range, {range = #} &], {0, 100, 1},
ImageSize -> Tiny, ContinuousAction -> True], Spacer[5],
Dynamic[range]}];

biasControl =
AngularGauge[Dynamic[bias, {bias = #; tick += del} &], {-Pi, Pi},
ImageSize -> {260, 100}, ScaleOrigin -> {{-4 Pi, 4 Pi}, 1}];

Labeled[Grid[{

{Grid[{{btnControls},
{stepSizeControl},
{rangeControl},
{biasControl}
}],

Dynamic[
tick;
Which[state == "running" || state == "step",
walkerPath = randomStep[bias, walkerPath, stepSize];
result = walkerGraphic[walkerPath, range];
If[state == "running", tick += del]
];
result,
TrackedSymbols :> {tick}
]
}
}, Frame -> All]
, Text[Style["version 3/8/2013", 10]]]
,
Initialization :>
{
randomStep[bias_, stepList_, stepSize_] :=
Module[{angle = RandomVariate[NormalDistribution[bias, 1]]},
Join[stepList, {Last[stepList] +
stepSize {Cos[angle], Sin[angle]}}]
];

walkerGraphic[stepList_, range_] :=
Graphics[{Gray, PointSize[.04], Point@Most@stepList, Blue,
Point@Last@stepList}, PlotRange -> range {{-1, 1}, {-1, 1}},
ImageSize -> 200];
}
]
--------------------------------------------------

--Nasser

Date Subject Author
3/7/13 W. Craig Carter
3/9/13 Nasser Abbasi
3/8/13 Bob Hanlon
3/8/13 W. Craig Carter