Shadowrun: Awakened 29 September 2011 - Build 871
SeismicSimulation.cpp
Go to the documentation of this file.
00001 /*
00002     Copyright 2005-2010 Intel Corporation.  All Rights Reserved.
00003 
00004     This file is part of Threading Building Blocks.
00005 
00006     Threading Building Blocks is free software; you can redistribute it
00007     and/or modify it under the terms of the GNU General Public License
00008     version 2 as published by the Free Software Foundation.
00009 
00010     Threading Building Blocks is distributed in the hope that it will be
00011     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00012     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with Threading Building Blocks; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019     As a special exception, you may use this file as part of a free software
00020     library without restriction.  Specifically, if other files instantiate
00021     templates or use macros or inline functions from this file, or you compile
00022     this file and link it with other files to produce an executable, this
00023     file does not by itself cause the resulting executable to be covered by
00024     the GNU General Public License.  This exception does not however
00025     invalidate any other reasons why the executable file might be covered by
00026     the GNU General Public License.
00027 */
00028 
00029 //#define _CRT_SECURE_NO_DEPRECATE
00030 #define VIDEO_WINMAIN_ARGS
00031 #include "../../common/gui/video.h"
00032 #include <cstdlib>
00033 #include <cstdio>
00034 #include <cstring>
00035 #include <cctype>
00036 #include <cassert>
00037 #include <math.h>
00038 #include "tbb/task_scheduler_init.h"
00039 #include "tbb/blocked_range.h"
00040 #include "tbb/parallel_for.h"
00041 #include "tbb/tick_count.h"
00042 
00043 using namespace std;
00044 
00045 #ifdef _MSC_VER
00046 // warning C4068: unknown pragma
00047 #pragma warning(disable: 4068)
00048 #endif
00049 
00050 #define DEFAULT_NUMBER_OF_FRAMES 100
00051 int number_of_frames = -1;
00052 const size_t MAX_WIDTH = 1024;
00053 const size_t MAX_HEIGHT = 512;
00054 
00055 int UniverseHeight=MAX_HEIGHT;
00056 int UniverseWidth=MAX_WIDTH;
00057 
00058 typedef float value;
00059 
00061 static value V[MAX_HEIGHT][MAX_WIDTH];
00062 
00064 static value S[MAX_HEIGHT][MAX_WIDTH];
00065 
00067 static value T[MAX_HEIGHT][MAX_WIDTH];
00068 
00070 static value M[MAX_HEIGHT][MAX_WIDTH];
00071 
00073 static value L[MAX_HEIGHT][MAX_WIDTH];
00074 
00076 static value D[MAX_HEIGHT][MAX_WIDTH];
00077 
00082 static tbb::affinity_partitioner Affinity;
00083 
00084 enum MaterialType {
00085     WATER=0,
00086     SANDSTONE=1,
00087     SHALE=2
00088 };
00089 
00091 static unsigned char Material[MAX_HEIGHT][MAX_WIDTH];
00092 
00093 static const colorcomp_t MaterialColor[4][3] = { // BGR
00094     {96,0,0},     // WATER
00095     {0,48,48},    // SANDSTONE
00096     {32,32,23}    // SHALE
00097 };
00098 
00099 static const int DamperSize = 32;
00100 
00101 static const int ColorMapSize = 1024;
00102 static color_t ColorMap[4][ColorMapSize];
00103 
00104 static int PulseTime = 100;
00105 static int PulseCounter;
00106 static int PulseX = UniverseWidth/3;
00107 static int PulseY = UniverseHeight/4;
00108 
00109 static bool InitIsParallel = true;
00110 const char *titles[2] = {"Seismic Simulation: Serial", "Seismic Simulation: Parallel"};
00114 int threads_low = 0, threads_high = tbb::task_scheduler_init::automatic;
00115 
00116 static void UpdatePulse() {
00117     if( PulseCounter>0 ) {
00118         value t = (PulseCounter-PulseTime/2)*0.05f;
00119         V[PulseY][PulseX] += 64*sqrt(M[PulseY][PulseX])*exp(-t*t);
00120         --PulseCounter;
00121     }
00122 }
00123 
00124 static void SerialUpdateStress() {
00125     drawing_area drawing(0, 0, UniverseWidth, UniverseHeight);
00126     for( int i=1; i<UniverseHeight-1; ++i ) {
00127         drawing.set_pos(1, i);
00128 #pragma ivdep
00129         for( int j=1; j<UniverseWidth-1; ++j ) {
00130             S[i][j] += M[i][j]*(V[i][j+1]-V[i][j]);
00131             T[i][j] += M[i][j]*(V[i+1][j]-V[i][j]);
00132             int index = (int)(V[i][j]*(ColorMapSize/2)) + ColorMapSize/2;
00133             if( index<0 ) index = 0;
00134             if( index>=ColorMapSize ) index = ColorMapSize-1;
00135             color_t* c = ColorMap[Material[i][j]];
00136             drawing.put_pixel(c[index]);
00137         }
00138     }
00139 }
00140 
00141 struct UpdateStressBody {
00142     void operator()( const tbb::blocked_range<int>& range ) const {
00143         drawing_area drawing(0, range.begin(), UniverseWidth, range.end()-range.begin());
00144         int i_end = range.end();
00145         for( int y = 0, i=range.begin(); i!=i_end; ++i,y++ ) {
00146             drawing.set_pos(1, y);
00147 #pragma ivdep
00148             for( int j=1; j<UniverseWidth-1; ++j ) {
00149                 S[i][j] += M[i][j]*(V[i][j+1]-V[i][j]);
00150                 T[i][j] += M[i][j]*(V[i+1][j]-V[i][j]);
00151                 int index = (int)(V[i][j]*(ColorMapSize/2)) + ColorMapSize/2;
00152                 if( index<0 ) index = 0;
00153                 if( index>=ColorMapSize ) index = ColorMapSize-1;
00154                 color_t* c = ColorMap[Material[i][j]];
00155                 drawing.put_pixel(c[index]);
00156             }
00157         }
00158     }
00159 };
00160 
00161 static void ParallelUpdateStress() {
00162     tbb::parallel_for( tbb::blocked_range<int>( 1, UniverseHeight-1 ), // Index space for loop
00163                        UpdateStressBody(),                             // Body of loop
00164                        Affinity );                                     // Affinity hint
00165 }
00166 
00167 static void SerialUpdateVelocity() {
00168     for( int i=1; i<UniverseHeight-1; ++i ) 
00169 #pragma ivdep
00170         for( int j=1; j<UniverseWidth-1; ++j ) 
00171             V[i][j] = D[i][j]*(V[i][j] + L[i][j]*(S[i][j] - S[i][j-1] + T[i][j] - T[i-1][j]));
00172 }
00173 
00174 struct UpdateVelocityBody {
00175     void operator()( const tbb::blocked_range<int>& range ) const {
00176         int i_end = range.end();
00177         for( int i=range.begin(); i!=i_end; ++i ) 
00178 #pragma ivdep
00179             for( int j=1; j<UniverseWidth-1; ++j ) 
00180                 V[i][j] = D[i][j]*(V[i][j] + L[i][j]*(S[i][j] - S[i][j-1] + T[i][j] - T[i-1][j]));
00181     }
00182 };
00183 
00184 static void ParallelUpdateVelocity() {
00185     tbb::parallel_for( tbb::blocked_range<int>( 1, UniverseHeight-1 ), // Index space for loop
00186                        UpdateVelocityBody(),                           // Body of loop
00187                        Affinity );                                     // Affinity hint
00188 }
00189 
00190 void SerialUpdateUniverse() {
00191     UpdatePulse();
00192     SerialUpdateStress();
00193     SerialUpdateVelocity();
00194 }
00195 
00196 void ParallelUpdateUniverse() {
00197     UpdatePulse();
00198     ParallelUpdateStress();
00199     ParallelUpdateVelocity();
00200 }
00201 
00202 class seismic_video : public video
00203 {
00204     void on_mouse(int x, int y, int key) {
00205         if(key == 1 && PulseCounter == 0) {
00206             PulseCounter = PulseTime;
00207             PulseX = x; PulseY = y;
00208         }
00209     }
00210     void on_key(int key) {
00211         key &= 0xff;
00212         if(char(key) == ' ') InitIsParallel = !InitIsParallel;
00213         else if(char(key) == 'p') InitIsParallel = true;
00214         else if(char(key) == 's') InitIsParallel = false;
00215         else if(char(key) == 'e') updating = true;
00216         else if(char(key) == 'd') updating = false;
00217         else if(key == 27) running = false;
00218         title = InitIsParallel?titles[1]:titles[0];
00219     }
00220     void on_process() {
00221         tbb::task_scheduler_init Init(threads_high);
00222         do {
00223             if( InitIsParallel )
00224                 ParallelUpdateUniverse();
00225             else
00226                 SerialUpdateUniverse();
00227             if( number_of_frames > 0 ) --number_of_frames;
00228         } while(next_frame() && number_of_frames);
00229     }
00230 } video;
00231 
00232 void InitializeUniverse() {
00233     PulseCounter = PulseTime;
00234     // Initialize V, S, and T to slightly non-zero values, in order to avoid denormal waves.
00235     for( int i=0; i<UniverseHeight; ++i ) 
00236 #pragma ivdep
00237         for( int j=0; j<UniverseWidth; ++j ) {
00238             T[i][j] = S[i][j] = V[i][j] = value(1.0E-6);
00239         }
00240     for( int i=1; i<UniverseHeight-1; ++i ) {
00241         for( int j=1; j<UniverseWidth-1; ++j ) {
00242             float x = float(j-UniverseWidth/2)/(UniverseWidth/2);
00243             value t = (value)i/UniverseHeight;
00244             MaterialType m;
00245             D[i][j] = 1.0;
00246             // Coefficient values are fictitious, and chosen to visually exaggerate 
00247             // physical effects such as Rayleigh waves.  The fabs/exp line generates
00248             // a shale layer with a gentle upwards slope and an anticline.
00249             if( t<0.3f ) {
00250                 m = WATER;
00251                 M[i][j] = 0.125;
00252                 L[i][j] = 0.125;
00253             } else if( fabs(t-0.7+0.2*exp(-8*x*x)+0.025*x)<=0.1 ) {
00254                 m = SHALE;
00255                 M[i][j] = 0.5;
00256                 L[i][j] = 0.6;
00257             } else {
00258                 m = SANDSTONE;
00259                 M[i][j] = 0.3;
00260                 L[i][j] = 0.4;
00261             } 
00262             Material[i][j] = m;
00263         }
00264     }
00265     value scale = 2.0f/ColorMapSize;
00266     for( int k=0; k<4; ++k ) {
00267         for( int i=0; i<ColorMapSize; ++i ) {
00268             colorcomp_t c[3];
00269             value t = (i-ColorMapSize/2)*scale;
00270             value r = t>0 ? t : 0;
00271             value b = t<0 ? -t : 0;
00272             value g = 0.5f*fabs(t);
00273             memcpy(c, MaterialColor[k], sizeof(c));
00274             c[2] = colorcomp_t(r*(255-c[2])+c[2]);
00275             c[1] = colorcomp_t(g*(255-c[1])+c[1]);
00276             c[0] = colorcomp_t(b*(255-c[0])+c[0]);
00277             ColorMap[k][i] = video.get_color(c[2], c[1], c[0]);
00278         }
00279     }
00280     // Set damping coefficients around border to reduce reflections from boundaries.
00281     value d = 1.0;
00282     for( int k=DamperSize-1; k>0; --k ) {
00283         d *= 1-1.0f/(DamperSize*DamperSize);
00284         for( int j=1; j<UniverseWidth-1; ++j ) {
00285             D[k][j] *= d;
00286             D[UniverseHeight-1-k][j] *= d;
00287         }
00288         for( int i=1; i<UniverseHeight-1; ++i ) {
00289             D[i][k] *= d;
00290             D[i][UniverseWidth-1-k] *= d;
00291         }
00292     }
00293 }
00294 
00296 #ifdef _WINDOWS
00297 #include "msvs/resource.h"
00298 #endif
00299 
00300 int main(int argc, char *argv[])
00301 {
00302     // threads number init
00303     if(argc > 1 && isdigit(argv[1][0])) {
00304         char* end; threads_high = threads_low = (int)strtol(argv[1],&end,0);
00305         switch( *end ) {
00306             case ':': threads_high = (int)strtol(end+1,0,0); break;
00307             case '\0': break;
00308             default: printf("unexpected character = %c\n",*end);
00309         }
00310     }
00311     if (argc > 2 && isdigit(argv[2][0])){
00312         number_of_frames = (int)strtol(argv[2],0,0);
00313     }
00314     // video layer init
00315     video.title = InitIsParallel?titles[1]:titles[0];
00316 #ifdef _WINDOWS
00317     #define MAX_LOADSTRING 100
00318     TCHAR szWindowClass[MAX_LOADSTRING];    // the main window class name
00319     LoadStringA(video::win_hInstance, IDC_SEISMICSIMULATION, szWindowClass, MAX_LOADSTRING);
00320     LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
00321     WNDCLASSEX wcex; memset(&wcex, 0, sizeof(wcex));
00322     wcex.lpfnWndProc    = (WNDPROC)WndProc;
00323     wcex.hIcon          = LoadIcon(video::win_hInstance, MAKEINTRESOURCE(IDI_SEISMICSIMULATION));
00324     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
00325     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
00326     wcex.lpszMenuName   = LPCTSTR(IDC_SEISMICSIMULATION);
00327     wcex.lpszClassName  = szWindowClass;
00328     wcex.hIconSm        = LoadIcon(video::win_hInstance, MAKEINTRESOURCE(IDI_SMALL));
00329     video.win_set_class(wcex); // ascii convention here
00330     video.win_load_accelerators(IDC_SEISMICSIMULATION);
00331 #endif
00332     if(video.init_window(UniverseWidth, UniverseHeight)) {
00333         video.calc_fps = true;
00334         video.threaded = threads_low > 0;
00335         // video is ok, init universe
00336         InitializeUniverse();
00337         // main loop
00338         video.main_loop();
00339     }
00340     else if(video.init_console()) {
00341         // do console mode
00342         if(number_of_frames <= 0) number_of_frames = DEFAULT_NUMBER_OF_FRAMES;
00343         if(threads_high == tbb::task_scheduler_init::automatic) threads_high = 4;
00344         if(threads_high < threads_low) threads_high = threads_low;
00345         for( int p = threads_low; p <= threads_high; ++p ) {
00346             InitializeUniverse();
00347             tbb::task_scheduler_init init(tbb::task_scheduler_init::deferred);
00348             if( p > 0 )
00349                 init.initialize( p );
00350             tbb::tick_count t0 = tbb::tick_count::now();
00351             if( p > 0 )
00352                 for( int i=0; i<number_of_frames; ++i )
00353                     ParallelUpdateUniverse();
00354             else
00355                 for( int i=0; i<number_of_frames; ++i )
00356                     SerialUpdateUniverse();
00357             tbb::tick_count t1 = tbb::tick_count::now();
00358             printf("%.1f frame per sec", number_of_frames/(t1-t0).seconds());
00359             if( p > 0 ) 
00360                 printf(" with %d way parallelism\n",p);
00361             else
00362                 printf(" with serial version\n"); 
00363         }
00364     }
00365     video.terminate();
00366     return 0;
00367 }
00368 
00369 #ifdef _WINDOWS
00370 //
00371 //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
00372 //
00373 //  PURPOSE:  Processes messages for the main window.
00374 //
00375 //  WM_COMMAND  - process the application menu
00376 //  WM_PAINT    - Paint the main window
00377 //  WM_DESTROY  - post a quit message and return
00378 //
00379 //
00380 LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
00381 {
00382     switch (message)
00383     {
00384     case WM_INITDIALOG: return TRUE;
00385     case WM_COMMAND:
00386         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
00387             EndDialog(hDlg, LOWORD(wParam));
00388             return TRUE;
00389         }
00390         break;
00391     }
00392     return FALSE;
00393 }
00394 
00395 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
00396 {
00397     int wmId, wmEvent;
00398     switch (message) {
00399     case WM_COMMAND:
00400         wmId    = LOWORD(wParam); 
00401         wmEvent = HIWORD(wParam); 
00402         // Parse the menu selections:
00403         switch (wmId)
00404         {
00405         case IDM_ABOUT:
00406             DialogBox(video::win_hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, (DLGPROC)About);
00407             break;
00408         case IDM_EXIT:
00409             PostQuitMessage(0);
00410             break;
00411         case ID_FILE_PARALLEL:
00412             if( !InitIsParallel ) {
00413                 InitIsParallel = true;
00414                 video.title = titles[1];
00415             }
00416             break;
00417         case ID_FILE_SERIAL:
00418             if( InitIsParallel ) {
00419                 InitIsParallel = false;
00420                 video.title = titles[0];
00421             }
00422             break;
00423         case ID_FILE_ENABLEGUI:
00424             video.updating = true;
00425             break;
00426         case ID_FILE_DISABLEGUI:
00427             video.updating = false;
00428             break;
00429         default:
00430             return DefWindowProc(hWnd, message, wParam, lParam);
00431         }
00432         break;
00433     default:
00434         return DefWindowProc(hWnd, message, wParam, lParam);
00435     }
00436     return 0;
00437 }
00438 
00439 #endif

Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.

GNU Lesser General Public License 3 Sourceforge.net