00001
00002 #include <cassert>
00003 #include <climits>
00004 #include <stdlib.h>
00005 #include <stdio.h>
00006
00007
00008 #include <boost/multi_array.hpp>
00009 #include <boost/filesystem/operations.hpp>
00010
00011
00012 #include <dtUtil/log.h>
00013
00014
00015 #include <defines.h>
00016 #include <controllers/innerSpace/Space3D.h>
00017 #include <controllers/innerSpace/Space3DUnit.h>
00018 #include <controllers/innerSpace/Location3D.h>
00019
00020 #ifdef WITH_VISUALISATION
00021 #include <linda/gnuplot_i.h>
00022 #endif
00023
00024 namespace srAlmende
00025 {
00026
00033 Space3D::Space3D() {
00034 LOG_INFO("Construct Space3D");
00035 srand(time(NULL));
00036 diffusion_rate = 5;
00037 }
00038
00043 Space3D::~Space3D() {
00044 units.~multi_array();
00045 }
00046
00054 void Space3D::Init(int ldim) {
00055 LOG_INFO("Initialise Space3D");
00056 assert(ldim > 0);
00057 assert(ldim % 2);
00058 dimension = ldim;
00059 radius = dimension >> 1;
00060 std::ostringstream msg; msg.clear(); msg.str("");
00061 msg << "Grid dimension is " << dimension << ", while the radius is " << radius << ".";
00062 LOG_INFO(msg.str());
00063 units.resize(boost::extents[dimension][dimension][dimension]);
00064
00065
00066 for (array3D::index i = 0; i < dimension; i++) {
00067 for (array3D::index j = 0; j < dimension; j++) {
00068 for (array3D::index k = 0; k < dimension; k++) {
00069 units[i][j][k].Init();
00070 units[i][j][k].space = this;
00071 units[i][j][k].node = NULL;
00072 units[i][j][k].location = new Location3D(i-radius,j-radius,k-radius);
00073 }
00074 }
00075 }
00076 }
00077
00082 Space3DUnit *Space3D::getSpace3DUnit(Location3D *loc) {
00083 return &units[loc->getX()+radius][loc->getY()+radius][loc->getZ()+radius];
00084 }
00085
00096 Space3DUnit *Space3D::getSpace3DUnit(int x, int y, int z) {
00097
00098
00099
00100 return &units[x+radius][y+radius][z+radius];
00101 }
00102
00107 void Space3D::Tick() {
00108 Generate();
00109 Normalise(true);
00110 Diffuse();
00111
00112 Normalise(true);
00113 #ifdef WITH_VISUALISATION
00114 Visualise();
00115 #endif
00116
00117 }
00118
00123 void Space3D::Generate() {
00124 for (int i = 0; i < 20; i++) {
00125 unsigned int x = (rand() % dimension);
00126 unsigned int y = (rand() % dimension);
00127 unsigned int z = (rand() % dimension);
00128 unsigned int p = (rand() % 2);
00129 unsigned int v = 40 + (rand() % 60);
00130 units[x][y][z].products[p].quantity = v;
00131 }
00132 }
00133
00150 void Space3D::Diffuse() {
00151 #ifdef CHECK_CONSERVATION_OF_PRODUCT_QUANTITIES
00152 long long int sum_all_product_quantities = SumAllProductQuantities();
00153 #endif
00154 assert(diffusion_rate <= (100 / 6));
00155 LOG_DEBUG("Diffuse products");
00156
00157 SyncBefore();
00158
00159 std::list<Space3DUnit*> neighbours;
00160
00161 space_iterate(i,j,k) {
00162 neighbours = units[i][j][k].getNeighbours();
00163 while (!neighbours.empty()) {
00164 Space3DUnit *neighbour = neighbours.front();
00165 for (unsigned int p_i = 0; p_i < neighbour->products.size(); p_i++) {
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 unsigned char transfer_quantity =
00178 (units[i][j][k].products[p_i].quantity * diffusion_rate) / 100;
00179 neighbour->products[p_i].new_quantity += transfer_quantity;
00180 units[i][j][k].products[p_i].new_quantity -= transfer_quantity;
00181
00182 }
00183 neighbours.pop_front();
00184 }
00185
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 SyncAfter();
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 #ifdef CHECK_CONSERVATION_OF_PRODUCT_QUANTITIES
00232 assert(sum_all_product_quantities == SumAllProductQuantities());
00233 #endif
00234 }
00235
00239 void Space3D::SyncBefore() {
00240 space_iterate(i,j,k) {
00241 for (unsigned int p_i = 0; p_i < units[i][j][k].products.size(); p_i++) {
00242 Product *p = &units[i][j][k].products[p_i];
00243 p->new_quantity = p->quantity;
00244 }
00245 }
00246 }
00247
00251 void Space3D::SyncAfter() {
00252 space_iterate(i,j,k) {
00253 for (unsigned int p_i = 0; p_i < units[i][j][k].products.size(); p_i++) {
00254 Product *p = &units[i][j][k].products[p_i];
00255 p->quantity = p->new_quantity;
00256 }
00257 }
00258
00259 }
00260
00268 void Space3D::Normalise(bool error) {
00269 space_iterate(i,j,k) {
00270 for (unsigned int p_i = 0; p_i < units[i][j][k].products.size(); p_i++) {
00271 Product *p = &units[i][j][k].products[p_i];
00272 if (error) {
00273 assert (p->quantity <= 100);
00274 } else {
00275 if (p->quantity > 100) p->quantity = 100;
00276 }
00277 }
00278 }
00279 }
00280
00281 #ifdef WITH_VISUALISATION
00282
00288 void Space3D::DrawSpace(gnuplot_ctrl *handle) {
00289 gnuplot_setstyle(handle, (char*)"dots");
00290 int n = dimension*dimension*dimension, ii=0;
00291 double *x_axis = (double*) calloc(n, sizeof(double));
00292 double *y_axis = (double*) calloc(n, sizeof(double));
00293 double *z_axis = (double*) calloc(n, sizeof(double));
00294 for (array3D::index i = 0; i < dimension; i++) {
00295 for (array3D::index j = 0; j < dimension; j++) {
00296 for (array3D::index k = 0; k < dimension; k++) {
00297 x_axis[ii] = i;
00298 y_axis[ii] = j;
00299 z_axis[ii] = k;
00300 ii++;
00301 }
00302 }
00303 }
00304 gnuplot_splot(handle, x_axis, y_axis, z_axis, n, (char*)"Quantity in cube");
00305 LOG_DEBUG("Plotted borders!");
00306 free(x_axis);
00307 free(y_axis);
00308 free(z_axis);
00309 }
00310 #endif
00311
00312 #ifdef WITH_VISUALISATION
00313
00316 void Space3D::Visualise() {
00317 gnuplot_ctrl *handle = gnuplot_init();
00318
00319 #ifdef PLOT_TO_FILE
00320 gnuplot_cmd(handle, (char*)"set terminal png");
00321 #endif
00322 gnuplot_cmd(handle, (char*)"set view 60,30");
00323
00324 #ifdef PLOT_TO_FILE
00325 std::ostringstream msg;
00326 boost::filesystem::path dir_path = "output/pictures";
00327 if( !exists(dir_path) ) {
00328 msg.clear(); msg.str("");
00329 msg << "No such directory: " << dir_path.string() << " (it will be created).";
00330 LOG_INFO(msg.str());
00331 create_directory(dir_path);
00332 }
00333 #endif
00334
00335 #ifdef PLOT_TO_FILE
00336 int fileIndex = 0; char filecmd[64];
00337 sprintf(filecmd, (char*)"set output 'output/pictures/figure_%03i.png'", fileIndex);
00338 gnuplot_cmd(handle, filecmd);
00339 #endif
00340 gnuplot_cmd(handle, (char*)"set multiplot");
00341 gnuplot_cmd(handle, (char*)"set xrange [0:3]");
00342 gnuplot_cmd(handle, (char*)"set yrange [0:3]");
00343 gnuplot_cmd(handle, (char*)"set zrange [0:3]");
00344
00345
00346 gnuplot_cmd(handle, (char*)"set ticslevel 0");
00347
00348
00349 gnuplot_cmd(handle, (char*)"set xtic 0.5");
00350 gnuplot_cmd(handle, (char*)"set ytic 0.5");
00351 gnuplot_cmd(handle, (char*)"set ztic 0.5");
00352
00353 DrawSpace(handle);
00354
00355 gnuplot_cmd(handle, (char*)"unset xtics");
00356 gnuplot_cmd(handle, (char*)"unset ytics");
00357 gnuplot_cmd(handle, (char*)"unset ztics");
00358
00359 for (array3D::index i = 0; i < dimension; i++) {
00360 for (array3D::index j = 0; j < dimension; j++) {
00361 for (array3D::index k = 0; k < dimension; k++) {
00362 units[i][j][k].DrawCell(handle);
00363 }
00364 }
00365 }
00366
00367 #ifndef PLOT_TO_FILE
00368 sleep(10);
00369 #endif
00370 gnuplot_close(handle);
00371 }
00372 #endif
00373
00374 #ifdef CHECK_CONSERVATION_OF_PRODUCT_QUANTITIES
00375
00381 long long int Space3D::SumAllProductQuantities() {
00382 long long int result = 0;
00383 for (array3D::index i = 0; i < dimension; i++) {
00384 for (array3D::index j = 0; j < dimension; j++) {
00385 for (array3D::index k = 0; k < dimension; k++) {
00386 result += units[i][j][k].sumProductQuantities();
00387 #ifdef CHECK_PRODUCT_QUANTITY_LIMIT
00388 assert(result < (LLONG_MAX - INT_MAX));
00389 #endif
00390 }
00391 }
00392 }
00393 if (dtUtil::Log::GetInstance().IsLevelEnabled(dtUtil::Log::LOG_INFO)) {
00394 std::ostringstream msg; msg.clear(); msg.str("");
00395 msg << "Overall sum is " << result << ".";
00396 LOG_DEBUG(msg.str());
00397 }
00398 return result;
00399 }
00400 #endif
00401
00402 }