Preliminary, but functional, autotoolsification
[proto.git] / src / sim / customizations.cpp
blob298fd044975a0d152e7747f9f39777f04cca7da5
1 /* User plug-in point for simulator customizations
2 Copyright (C) 2005-2008, Jonathan Bachrach, Jacob Beal, and contributors
3 listed in the AUTHORS file in the MIT Proto distribution's top directory.
5 This file is part of MIT Proto, and is distributed under the terms of
6 the GNU General Public License, with a linking exception, as described
7 in the file LICENSE in the MIT Proto distribution's top directory. */
9 // This file is where to make all of the small changes to adapt
10 // a spatial computer to the needs of a particular user.
11 // It's a separate file so that the core files won't change often.
12 // In particular, it is the only place that should need to be
13 // modified in order to integrate a new layer with the body.
15 #include "config.h"
16 #include "spatialcomputer.h"
17 #include "customizations.h"
18 #include "basic-hardware.h"
19 #include "simpledynamics.h"
20 #include "unitdiscradio.h"
21 #ifdef WANT_ODE
22 #include "odedynamics.h"
23 #endif // WANT_ODE
25 /*****************************************************************************
26 * DEVICE DISTRIBUTIONS *
27 *****************************************************************************/
28 class UniformRandom : public Distribution {
29 public:
30 UniformRandom(int n, Rect* volume) : Distribution(n,volume) {}
31 virtual BOOL next_location(METERS *loc) {
32 loc[0] = urnd(volume->l,volume->r);
33 loc[1] = urnd(volume->b,volume->t);
34 if(volume->dimensions()==3) {
35 Rect3* r = (Rect3*)volume;
36 loc[2] = urnd(r->f,r->c);
37 } else loc[2]=0;
38 return TRUE;
42 // Y is random
43 class XGrid : public Distribution {
44 public:
45 int rows,columns,layers;
46 int i;
47 XGrid(int n, Rect* volume) : Distribution(n,volume) {
48 i=0;
49 if(volume->dimensions()==3) {
50 layers = (int)ceil(pow(n*depth*depth/(width*height), 1.0/3.0));
51 rows = (int)ceil(layers*width/depth);
52 columns = (int)ceil(n/rows/layers);
53 } else {
54 rows = (int)ceil(sqrt(n)*sqrt(width/height));
55 columns = (int)ceil(n/rows);
56 layers = 1;
59 BOOL next_location(METERS *loc) {
60 int l = (i%layers), r = (i/layers)%rows, c = (i/(layers*rows));
61 loc[0] = volume->l + c*width/columns;
62 loc[1] = urnd(volume->b,volume->t);
63 loc[2] = (volume->dimensions()==3)?(((Rect3*)volume)->f+l*depth/layers):0;
64 i++;
65 return TRUE;
69 class FixedPoint : public UniformRandom {
70 public:
71 int fixed; int n_fixes;
72 Population fixes;
73 FixedPoint(Args* args, int n, Rect* volume) : UniformRandom(n,volume) {
74 fixed=0; n_fixes=0;
75 do {
76 n_fixes++;
77 METERS* loc = (METERS*)calloc(3,sizeof(METERS));
78 loc[0]=args->pop_number(); loc[1]=args->pop_number();
79 loc[2]= (str_is_number(args->peek_next()) ? args->pop_number() : 0);
80 fixes.add(loc);
81 } while(args->extract_switch("-fixedpt",FALSE));
83 virtual ~FixedPoint() {
84 for(int i=0;i<n_fixes;i++) { free(fixes.get(i)); }
86 BOOL next_location(METERS *loc) {
87 if(fixed<n_fixes) {
88 METERS* src = (METERS*)fixes.get(fixed);
89 for(int i=0;i<3;i++) loc[i]=src[i];
90 fixed++;
91 return TRUE;
92 } else {
93 return UniformRandom::next_location(loc);
98 class Grid : public Distribution {
99 public:
100 int rows,columns,layers;
101 int i;
102 Grid(int n, Rect* volume) : Distribution(n,volume) {
103 i=0;
104 if(volume->dimensions()==3) {
105 layers = (int)ceil(pow(n*depth*depth/(width*height), 1.0/3.0));
106 rows = (int)ceil(layers*width/depth);
107 columns = (int)ceil(n/rows/layers);
108 } else {
109 rows = (int)ceil(sqrt(n)*sqrt(width/height));
110 columns = (int)ceil(n/rows);
111 layers = 1;
114 BOOL next_location(METERS *loc) {
115 int l = (i%layers), r = (i/layers)%rows, c = (i/(layers*rows));
116 loc[0] = volume->l + c*width/columns;
117 loc[1] = volume->b + r*height/rows;
118 loc[2] = (volume->dimensions()==3)?(((Rect3*)volume)->f+l*depth/layers):0;
119 i++;
120 return TRUE;
124 class GridRandom : public Grid {
125 public:
126 METERS epsilon;
127 GridRandom(Args* args, int n, Rect* volume) : Grid(n,volume) {
128 epsilon = args->pop_number();
130 BOOL next_location(METERS *loc) {
131 Grid::next_location(loc);
132 loc[0] += epsilon*((rand()%1000/1000.0) - 0.5);
133 loc[1] += epsilon*((rand()%1000/1000.0) - 0.5);
134 if(volume->dimensions()==3) loc[2] += epsilon*((rand()%1000/1000.0) - 0.5);
135 i++;
136 return TRUE;
140 class Cylinder : public Distribution {
141 public:
142 METERS r;
143 Cylinder(int n, Rect* volume) : Distribution(n,volume) {
144 r = MIN(width, height) / 2;
146 BOOL next_location(METERS *loc) {
147 loc[0] = urnd(volume->l,volume->r);
148 flo theta = urnd(0, 2 * 3.14159);
149 loc[1] = r * sin(theta);
150 loc[2] = r * cos(theta);
151 return TRUE;
156 /*****************************************************************************
157 * CHOICE OF DISTRIBUTION *
158 *****************************************************************************/
159 void SpatialComputer::choose_distribution(Args* args, int n) {
160 if(args->extract_switch("-grideps")) { // random grid
161 distribution = new GridRandom(args,n,volume);
162 args->extract_switch("-grid"); // with eps, -grid is a null operation
163 } else if(args->extract_switch("-grid")) { // plain grid
164 distribution = new Grid(n,volume);
165 } else if(args->extract_switch("-xgrid")) { // grid w. random y
166 distribution = new XGrid(n,volume);
167 } else if(args->extract_switch("-fixedpt")) {
168 distribution = new FixedPoint(args,n,volume);
169 } else if(args->extract_switch("-cylinder")) {
170 distribution = new Cylinder(n,volume);
171 } else { // default is random
172 distribution = new UniformRandom(n,volume);
177 /*****************************************************************************
178 * TIME MODELS *
179 *****************************************************************************/
180 class FixedTimer : public DeviceTimer {
181 SECONDS dt, half_dt, internal_dt, internal_half_dt;
182 flo ratio;
183 public:
184 FixedTimer(flo dt, flo ratio) {
185 this->dt=dt; half_dt=dt/2;
186 internal_dt = dt*ratio; internal_half_dt = dt*ratio/2;
187 this->ratio = ratio;
189 void next_transmit(SECONDS* d_true, SECONDS* d_internal) {
190 *d_true = half_dt; *d_internal = internal_half_dt;
192 void next_compute(SECONDS* d_true, SECONDS* d_internal) {
193 *d_true = dt; *d_internal = internal_dt;
195 DeviceTimer* clone_device() { return new FixedTimer(dt,internal_dt/dt); }
196 void set_internal_dt(SECONDS dt) {
197 internal_dt = dt;
198 internal_half_dt = dt/2;
199 this->dt = internal_dt/ratio;
200 half_dt = internal_dt/(ratio*2);
204 class FixedIntervalTime : public TimeModel, public HardwarePatch {
205 BOOL sync;
206 flo dt; flo var;
207 flo ratio; flo rvar; // ratio is internal/true time
208 public:
209 FixedIntervalTime(Args* args, SpatialComputer* p) {
210 sync = args->extract_switch("-sync");
211 dt = (args->extract_switch("-desired-period"))?args->pop_number():1;
212 var = (args->extract_switch("-desired-period-variance"))
213 ? args->pop_number() : 0;
214 ratio = (args->extract_switch("-desired-ratio"))?args->pop_number():1;
215 rvar = (args->extract_switch("-desired-ratio-variance"))
216 ? args->pop_number() : 0;
218 p->hardware.patch(this,SET_DT_FN);
221 DeviceTimer* next_timer(SECONDS* start_lag) {
222 if(sync) { *start_lag=0; return new FixedTimer(dt,ratio); }
223 *start_lag = urnd(0,dt);
224 flo p = urnd(dt-var,dt+var);
225 flo ip = urnd(ratio-rvar,ratio+rvar);
226 return new FixedTimer(MAX(0,p),MAX(0,ip));
228 SECONDS cycle_time() { return dt; }
229 NUM_VAL set_dt (NUM_VAL dt) {
230 ((FixedTimer*)device->timer)->set_internal_dt(dt);
231 return dt;
236 /*****************************************************************************
237 * CHOICE OF TIME MODELS *
238 *****************************************************************************/
239 void SpatialComputer::choose_time_model(Args* args, int n) {
240 time_model = new FixedIntervalTime(args,this);
244 /*****************************************************************************
245 * CHOICE OF LAYERS *
246 *****************************************************************************/
247 // boot_layers is the one function that needs to know about all possible layers
248 // A layer that is not added at this time cannot be added layer; it may be
249 // added but not executed, though.
250 void SpatialComputer::choose_layers(Args* args, int n) {
251 // select physics model
252 if(args->extract_switch("-ODE")) {
253 #ifndef WANT_ODE
254 uerror("Cannot use ODE: Compiled without ODE");
255 #else
256 physics = new ODEDynamics(args,this,n);
257 #endif
258 } else {
259 physics = new SimpleDynamics(args,this,n);
261 addLayer(new DebugLayer(args,this));
262 addLayer(new UnitDiscRadio(args,this,n)); // select network model
263 addLayer(new SimpleLifeCycle(args,this));
264 addLayer(new PerfectLocalizer(this));
265 // other layers
266 if(args->extract_switch("-mote-io")) addLayer(new MoteIO(args,this));