Blender  V2.59
utilities.cpp
Go to the documentation of this file.
00001 
00004 /******************************************************************************
00005  *
00006  * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
00007  * Copyright 2003-2006 Nils Thuerey
00008  *
00009  * Global C style utility funcions
00010  *
00011  *****************************************************************************/
00012 
00013 
00014 #include <iostream>
00015 #include <sstream>
00016 #ifdef WIN32
00017 // for timing
00018 #include <windows.h>
00019 #else
00020 #include <time.h>
00021 #include <sys/time.h>
00022 #include <sys/times.h>
00023 #endif
00024 
00025 #include "utilities.h"
00026 
00027 #ifndef NOPNG
00028 #ifdef WIN32
00029 #include "png.h"
00030 #else
00031 #include <png.h>
00032 #endif
00033 #endif // NOPNG
00034 #include <zlib.h>
00035 
00036 // global debug level
00037 #ifdef DEBUG 
00038 int gDebugLevel = DEBUG;
00039 #else // DEBUG 
00040 int gDebugLevel = 0;
00041 #endif // DEBUG 
00042 
00043 // global world state, acces with get/setElbeemState
00044 int gElbeemState = SIMWORLD_INVALID;
00045 
00046 // access global state of elbeem simulator
00047 void setElbeemState(int set) {
00048         gElbeemState = set;
00049 }
00050 int  getElbeemState(void) { 
00051         return gElbeemState;
00052 }
00053 int  isSimworldOk(void) {
00054         return (getElbeemState>=0);
00055 }
00056 
00057 // last error as string, acces with get/setElbeemErrorString
00058 char gElbeemErrorString[256] = {'-','\0' };
00059 
00060 // access elbeem simulator error string
00061 void setElbeemErrorString(const char* set) {
00062         strncpy(gElbeemErrorString, set, 256);
00063 }
00064 char* getElbeemErrorString(void) { return gElbeemErrorString; }
00065 
00066 
00068 myTime_t globalIntervalTime = 0;
00070 #ifdef WIN32
00071 // switch off first call
00072 #define DEF_globalColorSetting -1 
00073 #else // WIN32
00074 // linux etc., on by default
00075 #define DEF_globalColorSetting 1 
00076 #endif // WIN32
00077 int globalColorSetting = DEF_globalColorSetting; // linux etc., on by default
00078 int globalFirstEnvCheck = 0;
00079 void resetGlobalColorSetting() { globalColorSetting = DEF_globalColorSetting; }
00080 
00081 // global string for formatting vector output, TODO test!?
00082 const char *globVecFormatStr = "V[%f,%f,%f]";
00083 
00084 
00085 // global mp on/off switch
00086 bool glob_mpactive = false; 
00087 // global access to mpi index, for debugging (e.g. in utilities.cpp)
00088 int glob_mpnum = -1;
00089 int glob_mpindex = -1;
00090 int glob_mppn = -1;
00091 
00092 
00093 //-----------------------------------------------------------------------------
00094 // helper function that converts a string to integer, 
00095 // and returns an alternative value if the conversion fails
00096 int convertString2Int(const char *str, int alt)
00097 {
00098         int val;
00099         char *endptr;
00100         bool success=true;
00101 
00102         val = strtol(str, &endptr, 10);
00103         if( (str==endptr) ||
00104                         ((str!=endptr) && (*endptr != '\0')) ) success = false;
00105 
00106         if(!success) {
00107                 return alt;
00108         }
00109         return val;
00110 }
00111 
00112 //-----------------------------------------------------------------------------
00114 string convertFlags2String(int flags) {
00115         std::ostringstream ret;
00116         ret <<"(";
00117         int max = sizeof(int)*8;
00118         for(int i=0; i<max; i++) {
00119                 if(flags & (1<<31)) ret <<"1";
00120                 else ret<<"0";
00121                 if(i<max-1) {
00122                         //ret << ",";
00123                         if((i%8)==7) ret << " ";
00124                 }
00125                 flags = flags << 1;
00126         }       
00127         ret <<")";
00128         return ret.str();
00129 }
00130 
00131 #ifndef NOPNG
00132 //-----------------------------------------------------------------------------
00134 int writePng(const char *fileName, unsigned char **rowsp, int w, int h)
00135 {
00136         // defaults for elbeem
00137         const int colortype = PNG_COLOR_TYPE_RGBA;
00138         const int bitdepth = 8;
00139         png_structp png_ptr = NULL;
00140         png_infop info_ptr = NULL;
00141         png_bytep *rows = rowsp;
00142 
00143         //FILE *fp = fopen(fileName, "wb");
00144         FILE *fp = NULL;
00145         string doing = "open for writing";
00146         if (!(fp = fopen(fileName, "wb"))) goto fail;
00147 
00148         if(!png_ptr) {
00149                 doing = "create png write struct";
00150                 if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail;
00151         }
00152         if(!info_ptr) {
00153                 doing = "create png info struct";
00154                 if (!(info_ptr = png_create_info_struct(png_ptr))) goto fail;
00155         }
00156 
00157         if (setjmp(png_jmpbuf(png_ptr))) goto fail;
00158         doing = "init IO";
00159         png_init_io(png_ptr, fp);
00160         doing = "write header";
00161         png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE,
00162                         PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
00163         doing = "write info";
00164         png_write_info(png_ptr, info_ptr);
00165         doing = "write image";
00166         png_write_image(png_ptr, rows);
00167         doing = "write end";
00168         png_write_end(png_ptr, NULL);
00169         doing = "write destroy structs";
00170         png_destroy_write_struct(&png_ptr, &info_ptr);
00171 
00172         fclose( fp );
00173         return 0;
00174 
00175 fail:   
00176         errMsg("writePng","Write_png: could not "<<doing<<" !");
00177         if(fp) fclose( fp );
00178         if(png_ptr || info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
00179         return -1;
00180 }
00181 #else // NOPNG
00182 // fallback - write ppm
00183 int writePng(const char *fileName, unsigned char **rowsp, int w, int h)
00184 {
00185         gzFile gzf;
00186         string filentemp(fileName);
00187         // remove suffix
00188         if((filentemp.length()>4) && (filentemp[filentemp.length()-4]=='.')) {
00189                 filentemp[filentemp.length()-4] = '\0';
00190         }
00191         std::ostringstream filennew;
00192         filennew << filentemp.c_str();
00193         filennew << ".ppm.gz";
00194 
00195         gzf = gzopen(filennew.str().c_str(), "wb9");
00196         if(!gzf) goto fail;
00197 
00198         gzprintf(gzf,"P6\n%d %d\n255\n",w,h);
00199         // output binary pixels
00200         for(int j=0;j<h;j++) {
00201                 for(int i=0;i<h;i++) {
00202                         // remove alpha values
00203                         gzwrite(gzf,&rowsp[j][i*4],3);
00204                 }
00205         }
00206 
00207         gzclose( gzf );
00208         errMsg("writePng/ppm","Write_png/ppm: wrote to "<<filennew.str()<<".");
00209         return 0;
00210 
00211 fail:   
00212         errMsg("writePng/ppm","Write_png/ppm: could not write to "<<filennew.str()<<" !");
00213         return -1;
00214 }
00215 #endif // NOPNG
00216 
00217 
00218 //-----------------------------------------------------------------------------
00219 // helper function to determine current time
00220 myTime_t getTime()
00221 {
00222         myTime_t ret = 0;
00223 #ifdef WIN32
00224         LARGE_INTEGER liTimerFrequency;
00225         QueryPerformanceFrequency(&liTimerFrequency);
00226         LARGE_INTEGER liLastTime;
00227         QueryPerformanceCounter(&liLastTime);
00228         ret = (INT)( ((double)liLastTime.QuadPart / liTimerFrequency.QuadPart)*1000 ); // - mFirstTime;
00229 #else
00230         struct timeval tv;
00231         struct timezone tz;
00232         tz.tz_minuteswest = 0;
00233         tz.tz_dsttime = 0;
00234         gettimeofday(&tv,&tz);
00235         ret = (tv.tv_sec*1000)+(tv.tv_usec/1000); //-mFirstTime;
00236 #endif
00237         return (myTime_t)ret;
00238 }
00239 //-----------------------------------------------------------------------------
00240 // convert time to readable string
00241 string getTimeString(myTime_t usecs) {
00242         std::ostringstream ret;
00243         //myTime_t us = usecs % 1000;
00244         myTime_t ms = (myTime_t)(   (double)usecs / (60.0*1000.0)  );
00245         myTime_t ss = (myTime_t)(  ((double)usecs / 1000.0) - ((double)ms*60.0)  );
00246         int      ps = (int)(       ((double)usecs - (double)ss*1000.0)/10.0 );
00247 
00248         //ret.setf(ios::showpoint|ios::fixed);
00249         //ret.precision(5); ret.width(7);
00250 
00251         if(ms>0) {
00252                 ret << ms<<"m"<< ss<<"s" ;
00253         } else {
00254                 if(ps>0) {
00255                         ret << ss<<".";
00256                         if(ps<10) { ret <<"0"; }
00257                         ret <<ps<<"s" ;
00258                 } else {
00259                         ret << ss<<"s" ;
00260                 }
00261         }
00262         return ret.str();
00263 }
00264 
00266 bool checkBoundingBox(ntlVec3Gfx s, ntlVec3Gfx e, string checker) {
00267         if( (s[0]>e[0]) ||
00268                         (s[1]>e[1]) ||
00269                         (s[2]>e[2]) ) {
00270                 errFatal("checkBoundingBox","Check by '"<<checker<<"' for BB "<<s<<":"<<e<<" failed! Aborting...",SIMWORLD_INITERROR);
00271                 return 1;
00272         }
00273         return 0;
00274 }
00275 
00276 
00277 
00278 //-----------------------------------------------------------------------------
00279 // debug message output
00280 
00281 static string col_black ( "\033[0;30m");
00282 static string col_dark_gray ( "\033[1;30m");
00283 static string col_bright_gray ( "\033[0;37m");
00284 static string col_red ( "\033[0;31m");
00285 static string col_bright_red ( "\033[1;31m");
00286 static string col_green ( "\033[0;32m");
00287 static string col_bright_green ( "\033[1;32m");
00288 static string col_bright_yellow ( "\033[1;33m");
00289 static string col_yellow ( "\033[0;33m");
00290 static string col_cyan ( "\033[0;36m");
00291 static string col_bright_cyan ( "\033[1;36m");
00292 static string col_purple ( "\033[0;35m");
00293 static string col_bright_purple ( "\033[1;35m");
00294 static string col_neutral ( "\033[0m");
00295 static string col_std = col_bright_gray;
00296 
00297 std::ostringstream globOutstr;
00298 bool               globOutstrForce=false;
00299 #define DM_NONE      100
00300 void messageOutputForce(string from) {
00301         bool org = globOutstrForce;
00302         globOutstrForce = true;
00303         messageOutputFunc(from, DM_NONE, "\n", 0);
00304         globOutstrForce = org;
00305 }
00306 
00307 void messageOutputFunc(string from, int id, string msg, myTime_t interval) {
00308         // fast skip
00309         if((id!=DM_FATAL)&&(gDebugLevel<=0)) return;
00310 
00311         if(interval>0) {
00312                 myTime_t currTime = getTime();
00313                 if((currTime - globalIntervalTime)>interval) {
00314                         globalIntervalTime = getTime();
00315                 } else {
00316                         return;
00317                 }
00318         }
00319 
00320         // colors off?
00321         if( (globalColorSetting == -1) || // off for e.g. win32 
00322                   ((globalColorSetting==1) && ((id==DM_FATAL)||( getenv("ELBEEM_NOCOLOROUT") )) )
00323                 ) {
00324                 // only reset once
00325                 col_std = col_black = col_dark_gray = col_bright_gray =  
00326                 col_red =  col_bright_red =  col_green =  
00327                 col_bright_green =  col_bright_yellow =  
00328                 col_yellow =  col_cyan =  col_bright_cyan =  
00329                 col_purple =  col_bright_purple =  col_neutral =  "";
00330                 globalColorSetting = 0;
00331         }
00332 
00333         std::ostringstream sout;
00334         if(id==DM_DIRECT) {
00335                 sout << msg;
00336         } else {
00337                 sout << col_cyan<< from;
00338                 switch(id) {
00339                         case DM_MSG:
00340                                 sout << col_std << " message:";
00341                                 break;
00342                         case DM_NOTIFY:
00343                                 sout << col_bright_cyan << " note:" << col_std;
00344                                 break;
00345                         case DM_IMPORTANT:
00346                                 sout << col_yellow << " important:" << col_std;
00347                                 break;
00348                         case DM_WARNING:
00349                                 sout << col_bright_red << " warning:" << col_std;
00350                                 break;
00351                         case DM_ERROR:
00352                                 sout << col_red << " error:" << col_red;
00353                                 break;
00354                         case DM_FATAL:
00355                                 sout << col_red << " fatal("<<gElbeemState<<"):" << col_red;
00356                                 break;
00357                         case DM_NONE:
00358                                 // only internal debugging msgs
00359                                 break;
00360                         default:
00361                                 // this shouldnt happen...
00362                                 sout << col_red << " --- messageOutputFunc error: invalid id ("<<id<<") --- aborting... \n\n" << col_std;
00363                                 break;
00364                 }
00365                 sout <<" "<< msg << col_std;
00366         }
00367 
00368         if(id==DM_FATAL) {
00369                 strncpy(gElbeemErrorString,sout.str().c_str(), 256);
00370                 // dont print?
00371                 if(gDebugLevel==0) return;
00372                 sout << "\n"; // add newline for output
00373         }
00374 
00375         // determine output - file==1/stdout==0 / globstr==2
00376         char filen[256];
00377         strcpy(filen,"debug_unini.txt");
00378         int fileout = false;
00379 #if ELBEEM_MPI==1
00380         std::ostringstream mpin;
00381         if(glob_mpindex>=0) {
00382                 mpin << "elbeem_log_"<< glob_mpindex <<".txt";
00383         } else {
00384                 mpin << "elbeem_log_ini.txt";
00385         }
00386         fileout = 1;
00387         strncpy(filen, mpin.str().c_str(),255); filen[255]='\0';
00388 #else
00389         strncpy(filen, "elbeem_debug_log.txt",255);
00390 #endif
00391 
00392 #ifdef WIN32
00393         // windows causes trouble with direct output
00394         fileout = 1;
00395 #endif // WIN32
00396 
00397 #if PARALLEL==1
00398         fileout = 2;// buffer out, switch off again...
00399         if(globOutstrForce) fileout=1;
00400 #endif
00401         if(getenv("ELBEEM_FORCESTDOUT")) {
00402                 fileout = 0;// always direct out
00403         }
00404         //fprintf(stdout,"out deb %d, %d, '%s',l%d \n",globOutstrForce,fileout, filen, globOutstr.str().size() );
00405 
00406 #if PARALLEL==1
00407 #pragma omp critical 
00408 #endif // PARALLEL==1
00409         {
00410         if(fileout==1) {
00411                 // debug level is >0 anyway, so write to file...
00412                 FILE *logf = fopen(filen,"a+");
00413                 // dont complain anymore here...
00414                 if(logf) {
00415                         if(globOutstrForce) {
00416                                 fprintf(logf, "%s",globOutstr.str().c_str() );
00417                                 globOutstr.str(""); // reset
00418                         }
00419                         fprintf(logf, "%s",sout.str().c_str() );
00420                         fclose(logf);
00421                 }
00422         } else if(fileout==2) {
00423                         globOutstr << sout.str();
00424         } else {
00425                 // normal stdout output
00426                 fprintf(stdout, "%s",sout.str().c_str() );
00427                 if(id!=DM_DIRECT) fflush(stdout); 
00428         }
00429         } // omp crit
00430 }
00431 
00432 // helper functions from external program using elbeem lib (e.g. Blender)
00433 /* set gDebugLevel according to env. var */
00434 extern "C" 
00435 void elbeemCheckDebugEnv(void) {
00436         const char *strEnvName = "BLENDER_ELBEEMDEBUG";
00437         const char *strEnvName2 = "ELBEEM_DEBUGLEVEL";
00438         if(globalFirstEnvCheck) return;
00439 
00440         if(getenv(strEnvName)) {
00441                 gDebugLevel = atoi(getenv(strEnvName));
00442                 if(gDebugLevel>0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<<strEnvName<<"'='"<<getenv(strEnvName)<<"', debugLevel set to: "<<gDebugLevel<<"\n", 1);
00443         }
00444         if(getenv(strEnvName2)) {
00445                 gDebugLevel = atoi(getenv(strEnvName2));
00446                 if(gDebugLevel>0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<<strEnvName2<<"'='"<<getenv(strEnvName2)<<"', debugLevel set to: "<<gDebugLevel<<"\n", 1);
00447         }
00448         if(gDebugLevel< 0) gDebugLevel =  0;
00449         if(gDebugLevel>10) gDebugLevel =  0; // only use valid values
00450         globalFirstEnvCheck = 1;
00451 }
00452 
00453 /* elbeem debug output function */
00454 extern "C" 
00455 void elbeemDebugOut(char *msg) {
00456         elbeemCheckDebugEnv();
00457         // external messages default to debug level 5...
00458         if(gDebugLevel<5) return;
00459         // delegate to messageOutputFunc
00460         messageOutputFunc("[External]",DM_MSG,msg,0);
00461 }
00462 
00463 /* set elbeem debug output level (0=off to 10=full on) */
00464 extern "C" 
00465 void elbeemSetDebugLevel(int level) {
00466         if(level<0)  level=0;
00467         if(level>10) level=10;
00468         gDebugLevel=level;
00469 }
00470 
00471 
00472 /* estimate how much memory a given setup will require */
00473 #include "solver_interface.h"
00474 
00475 extern "C" 
00476 double elbeemEstimateMemreq(int res, 
00477                 float sx, float sy, float sz,
00478                 int refine, char *retstr) {
00479         int resx = res, resy = res, resz = res;
00480         // dont use real coords, just place from 0.0 to sizeXYZ
00481         ntlVec3Gfx vgs(0.0), vge(sx,sy,sz);
00482         initGridSizes( resx,resy,resz, vgs,vge, refine, 0);
00483 
00484         double memreq = -1.0;
00485         string memreqStr("");   
00486         // ignore farfield for now...
00487         calculateMemreqEstimate(resx,resy,resz, refine, 0., &memreq, NULL, &memreqStr );
00488 
00489         if(retstr) { 
00490                 // copy at max. 32 characters
00491                 strncpy(retstr, memreqStr.c_str(), 32 );
00492                 retstr[31] = '\0';
00493         }
00494         return memreq;
00495 }
00496 
00497 
00498