Blender V2.61 - r43446

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