cloudy  trunk
cpu.cpp
Go to the documentation of this file.
1 /* This file is part of Cloudy and is copyright (C)1978-2013 by Gary J. Ferland and
2  * others. For conditions of distribution and use see copyright notice in license.txt */
5 #include "cdstd.h"
6 
7 #if defined(__HP_aCC)
8 /* this is for the HP compiler on the sdx */
9 extern "C" unsigned long fegettrapenable();
10 extern "C" void fesettrapenable(unsigned long);
11 #endif
12 
13 #if defined(__ia64) && defined(__INTEL_COMPILER)
14 extern "C" unsigned long fpgetmask();
15 extern "C" void fpsetmask(unsigned long);
16 #endif
17 
18 #if defined(__sun) || defined(__sgi)
19 #include <ieeefp.h>
20 #if defined(HAVE_SUNMATH) || defined(FLUSH_DENORM_TO_ZERO)
21 #include <sunmath.h>
22 #endif
23 #endif
24 
25 #if defined(__alpha) && defined(__linux__) && defined(__GNUC__)
26 #define __USE_GNU
27 #include <fenv.h>
28 #endif
29 
30 #if defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140
31 #include <fenv.h>
32 #endif
33 
34 #if defined(__unix) || defined(__APPLE__)
35 #include <unistd.h>
36 #endif
37 
38 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
39 #include <sys/types.h>
40 #include <sys/sysctl.h>
41 #endif
42 
43 /* the redefinition of float in cddefines.h can cause problems in system headers
44  * hence these includes MUST come after the system header includes above */
45 #include "cddefines.h"
46 #include "cpu.h"
47 #include "path.h"
48 #include "trace.h"
49 
50 STATIC NORETURN void AbortErrorMessage( const char* fname, vector<string>& PathList, access_scheme scheme );
51 
52 // Use Schwartz/nifty counter to ensure that global policy class
53 // is set up before other globals/statics, and deleted last.
55 static int cpu_count = 0;
57 {
58  if (0 == cpu_count++)
59  {
60  m_i = new t_cpu_i;
61  }
62 }
64 {
65  if (0 == --cpu_count)
66  {
67  delete m_i;
68  }
69 }
70 
71 /* NB NB - this constructor needs to be called before any of the user code is executed !! */
73 {
74  DEBUG_ENTRY( "t_cpu_i()" );
75 
76  // set up signal handlers so that we can control what happens...
78 
79  p_exit_status.resize( ES_TOP, "--undefined--" );
80  p_exit_status[ES_SUCCESS] = "ok";
81  p_exit_status[ES_FAILURE] = "early termination";
82  p_exit_status[ES_WARNINGS] = "warnings";
83  p_exit_status[ES_BOTCHES] = "botched monitors";
84  p_exit_status[ES_CLOUDY_ABORT] = "cloudy abort";
85  p_exit_status[ES_BAD_ASSERT] = "failed assert";
86  p_exit_status[ES_BAD_ALLOC] = "failed memory alloc";
87  p_exit_status[ES_OUT_OF_RANGE] = "array bound exceeded";
88  p_exit_status[ES_USER_INTERRUPT] = "user interrupt";
89  p_exit_status[ES_TERMINATION_REQUEST] = "process killed";
90  p_exit_status[ES_ILLEGAL_INSTRUCTION] = "illegal instruction";
91  p_exit_status[ES_FP_EXCEPTION] = "fp exception";
92  p_exit_status[ES_SEGFAULT] = "segmentation fault";
93  p_exit_status[ES_BUS_ERROR] = "bus error";
94  p_exit_status[ES_UNKNOWN_SIGNAL] = "unknown signal";
95  p_exit_status[ES_UNKNOWN_EXCEPTION] = "unknown exception";
96 
97  /* >>chng 05 dec 14, add test of endianness of the CPU, PvH */
98  endian.c[0] = 0x12;
99  endian.c[1] = 0x34;
100  endian.c[2] = 0x56;
101  endian.c[3] = 0x78;
102 
103  /* >>chng 05 dec 15, add signaling NaN for float and double to cpu struct, PvH */
104  /* in C++ this should be replaced by numeric_limits<TYPE>::signaling_NaN() */
105  if( sizeof(sys_float) == 4 )
106  {
107 # ifdef __mips
108  /* definition of signaling and quiet NaN is reversed on MIPS */
109  Float_SNaN_Value = 0xffffffff;
110 # else
111  if( big_endian() || little_endian() )
112  {
113  /* this should work on most modern CPU's */
114  Float_SNaN_Value = 0xffbfffff;
115  }
116  else
117  {
118  /* this is an unusual CPU -> bit pattern for SNaN is unknown */
119  Float_SNaN_Value = -1;
120  }
121 # endif
122  }
123  else
124  {
125  /* this is an unusual CPU -> bit pattern for SNaN is unknown */
126  Float_SNaN_Value = -1;
127  }
128 
129 # ifdef HAVE_INT64
130 
131  if( sizeof(double) == 8 )
132  {
133 # ifdef __mips
134  /* definition of signaling and quiet NaN is reversed on MIPS */
135  Double_SNaN_Value = 0xffffffffffffffff;
136 # else
137  /* this should work on most modern CPU's */
138  Double_SNaN_Value = 0xfff7ffffffbfffff;
139 # endif
140  }
141  else
142  {
143  /* this is an unusual CPU -> bit pattern for SNaN is unknown */
144  Double_SNaN_Value = -1;
145  }
146 
147 # else
148 
149  if( sizeof(double) == 8 )
150  {
151 # ifdef __mips
152  /* definition of signaling and quiet NaN is reversed on MIPS */
153  Double_SNaN_Value[0] = 0xffffffff;
154  Double_SNaN_Value[1] = 0xffffffff;
155 # else
156  if( big_endian() )
157  {
158  /* this should work on most modern CPU's */
159  Double_SNaN_Value[0] = 0xfff7ffff;
160  Double_SNaN_Value[1] = 0xffbfffff;
161  }
162  else if( little_endian() )
163  {
164  /* this should work on most modern CPU's */
165  Double_SNaN_Value[0] = 0xffbfffff;
166  Double_SNaN_Value[1] = 0xfff7ffff;
167  }
168  else
169  {
170  /* this is an unusual CPU -> bit pattern for SNaN is unknown */
171  Double_SNaN_Value[0] = -1;
172  Double_SNaN_Value[1] = -1;
173  }
174 # endif
175  }
176  else
177  {
178  /* this is an unusual CPU -> bit pattern for SNaN is unknown */
179  Double_SNaN_Value[0] = -1;
180  Double_SNaN_Value[1] = -1;
181  }
182 
183 # endif
184 
185  /* set FP environment to trap FP exceptions */
186  enable_traps();
187 
188  ioStdin = stdin;
189  ioQQQ = stdout;
190  ioPrnErr = stderr;
191  lgPrnErr = false;
192 
193  test_float = FLT_MIN;
194  test_double = DBL_MIN;
195 
196  /* default is for failed asserts not to abort */
197  p_lgAssertAbort = false;
198 
199  const char *str;
200 
201  /* determine the no. of CPUs on this machine; used by PHYMIR, grid command, .... */
202 # if defined(_SC_NPROCESSORS_ONLN) /* Linux, Sun Sparc, DEC Alpha, MacOS (OS releases >= 10.4) */
203  n_avail_CPU = sysconf(_SC_NPROCESSORS_ONLN);
204 # elif defined(_SC_NPROC_ONLN) /* SGI Iris */
205  n_avail_CPU = sysconf(_SC_NPROC_ONLN);
206 # elif defined(_SC_CRAY_NCPU) /* Cray */
207  n_avail_CPU = sysconf(_SC_CRAY_NCPU);
208 # elif defined(_WIN32) /* Microsoft Windows */
209  str = getenv( "NUMBER_OF_PROCESSORS" );
210  if( str != NULL )
211  {
212  int found = sscanf( str, "%ld", &n_avail_CPU );
213  if( found != 1 )
214  n_avail_CPU = 1;
215  }
216  else
217  {
218  n_avail_CPU = 1;
219  }
220 # elif defined(HW_AVAILCPU) /* MacOS, BSD variants */
221  int mib[2];
222  size_t len = sizeof(n_avail_CPU);
223  mib[0] = CTL_HW;
224  mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
225  sysctl(mib, 2, &n_avail_CPU, &len, NULL, 0);
226  if( n_avail_CPU < 1 )
227  {
228  mib[1] = HW_NCPU;
229  sysctl(mib, 2, &n_avail_CPU, &len, NULL, 0);
230  if( n_avail_CPU < 1 )
231  n_avail_CPU = 1;
232  }
233 # else
234  /* Other systems, supply no. of CPUs on OPTIMIZE PHYMIR command line */
235  n_avail_CPU = 1;
236 # endif
237  /* the constructor is run before MPI starts, so the rank is not available yet */
238 # ifdef MPI_ENABLED
239  p_lgMPI = true;
240 # else
241  p_lgMPI = false;
242 # endif
243  /* the default is for all ranks to cooperate on the same sim */
244  p_lgMPISingleRankMode = false;
245  n_rank = 0;
246 
247 # ifdef _WIN32
248  str = getenv( "COMPUTERNAME" );
249 # else
250  str = getenv( "HOSTNAME" );
251 # endif
252 
253  if( str != NULL )
254  strncpy( HostName, str, STDLEN );
255  else
256  strncpy( HostName, "unknown", STDLEN );
257  HostName[STDLEN-1] = '\0';
258 
259  /* pick up the path from the environment, if set by user */
260  const char *path = getenv( "CLOUDY_DATA_PATH" );
261 
262  /* if the environment variable was not set, the default set in path.h takes effect */
263  string chSearchPathRaw = ( path != NULL ) ? string( path ) : string( CLOUDY_DATA_PATH );
264 
265 # ifdef _WIN32
266  string separator( ";" );
267  p_chDirSeparator = '\\';
268 # else
269  string separator( ":" );
270  p_chDirSeparator = '/';
271 # endif
272 
273  chSearchPath.push_back( "" ); // the current working directory should be first and last
274  Split( chSearchPathRaw, separator, chSearchPath, SPM_RELAX );
275  chSearchPath.push_back( "" );
276 
277  for( vector<string>::size_type i=0; i < chSearchPath.size(); ++i )
278  {
279  if( chSearchPath[i].length() > 0 )
280  {
281  /* get last valid char */
282  char chEnd = *chSearchPath[i].rbegin();
283 
284  /* make sure path ends with directory separator */
285  if( chEnd != p_chDirSeparator )
287  }
288  }
289 
290  nFileDone = 0;
291 }
292 
294 {
295  /* >>chng 01 aug 07, added code to circumvent math library bug with g++ on
296  * alpha-linux machines, see bug report 51072 on http://bugzilla.redhat.com, PvH */
297  /* >>chng 01 apr 17, added code for Solaris and SGI operating systems, PvH */
298  /* this routine contains no code for alphas or crays, they do not need
299  * special code to enable FP exceptions since they are enabled by default */
300 
301  /* there is no command line option on MS Visual Studio to force crash */
302 # if defined(_MSC_VER)
303  volatile unsigned int NewMask;
304 
305  /* | is a bitwise inclusive or, turns on bits
306  * 0|0 = 0
307  * 0|1 = 1|0 = 1|1 = 1 */
308  NewMask = _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_INVALID;
309  /* ~ is the unary bitwise complement - all bits flip */
310  NewMask = ~NewMask;
311  _controlfp( NewMask , _MCW_EM );
312 
313  /* this is the code for Linux PC (but not Linux alpha) to force crash */
314  /* >>chng 04 apr 26, added support for AMD64, enable FPE traps for SSE/SSE2, PvH */
315  /* >>chng 06 aug 12, added support for Apple MacOSX, and hopefully also Solaris x86, PvH */
316  // do not enable trapping FPEs for Clang compiler since it is not supported in v3.4 and later
317 # elif defined(__GNUC__) && ( defined(__i386) || defined(__amd64) ) && !defined(__clang__)
318  volatile unsigned int Old_Mask, New_Mask;
319 # if defined(__SSE__) || defined(__SSE2__)
320  volatile unsigned int SSE_Mask;
321 # endif
322 
323 # define _FPU_MASK_IM 0x01 /* Invalid */
324 # define _FPU_MASK_DM 0x02 /* Denormalized */
325 # define _FPU_MASK_ZM 0x04 /* Division-by-zero */
326 # define _FPU_MASK_OM 0x08 /* Overflow */
327 # define _FPU_MASK_UM 0x10 /* Underflow */
328 # define _FPU_MASK_PM 0x20 /* Inexact */
329 
330  /* | is a bitwise inclusive or, turns on bits */
331  /* 0|0 = 0 */
332  /* 0|1 = 1|0 = 1|1 = 1 */
333 
334  /* ~ is the unary bitwise complement - all bits flip */
335 
336  /* this enables FPE traps for regular i387 FP instructions */
337 
338  volatile unsigned int UnMask = ~((unsigned int)( _FPU_MASK_ZM | _FPU_MASK_IM | _FPU_MASK_OM ));
339 
340  __asm__ volatile("fnstcw %0" : "=m" (*&Old_Mask));
341 
342  New_Mask = Old_Mask & UnMask;
343 
344  __asm__ volatile("fldcw %0" : : "m" (*&New_Mask));
345 
346 # if defined(__SSE__) || defined(__SSE2__)
347 
348 # if defined(FLUSH_DENORM_TO_ZERO)
349  /* using this causes denormalized numbers to be flushed to zero,
350  * which will speed up the code on Pentium 4 processors */
351  SSE_Mask = 0x9900;
352 # else
353  /* this version allows denormalized numbers to be retained */
354  SSE_Mask = 0x1900;
355 # endif
356 
357  /* this enables FPE traps for SSE/SSE2 instructions */
358 
359  __asm__ volatile( "ldmxcsr %0" : : "m" (*&SSE_Mask) );
360 
361 # endif
362 
363  /* this is for IA64 systems running g++ or icc (e.g. SGI, HP, ...) */
364 # elif defined(__ia64)
365 
366 # define FPSR_TRAP_VD (1 << 0) /* invalid op trap disabled */
367 # define FPSR_TRAP_DD (1 << 1) /* denormal trap disabled */
368 # define FPSR_TRAP_ZD (1 << 2) /* zero-divide trap disabled */
369 # define FPSR_TRAP_OD (1 << 3) /* overflow trap disabled */
370 # define FPSR_TRAP_UD (1 << 4) /* underflow trap disabled */
371 # define FPSR_TRAP_ID (1 << 5) /* inexact trap disabled */
372 
373 # define FPSR_SF0_FTZ (1 << 6) /* flush denormalized numbers to zero */
374 
375 # if defined(__GNUC_EXCL__)
376  /* __asm__ instructions are not supported by icc as of v9.0 */
377 # define _IA64_REG_AR_FPSR 40
378 
379 # define ia64_getreg( regnum ) __asm__ volatile( "mov %0=ar%1" : "=r" (fpsr) : "i"(regnum) )
380 # define ia64_setreg( regnum, val ) __asm__ volatile( "mov ar%0=%1" :: "i" (regnum), "r"(val): "memory" )
381 # define ia64_serialize __asm__ volatile( "srlz.i" );
382 
383  volatile unsigned long fpsr, flags = FPSR_TRAP_VD | FPSR_TRAP_ZD | FPSR_TRAP_OD;
384 
385  ia64_getreg( _IA64_REG_AR_FPSR );
386  fpsr &= ~flags;
387 # if defined(FLUSH_DENORM_TO_ZERO)
388  fpsr |= FPSR_SF0_FTZ;
389 # endif
390  ia64_setreg( _IA64_REG_AR_FPSR, fpsr );
391  /* this prevents RAW and WAW dependency violations in case this ever gets inlined... */
392  ia64_serialize;
393 
394 # elif defined(__INTEL_COMPILER)
395  /* this is for icc on IA64 SGI machines */
396  unsigned long fpsr = fpgetmask();
397  fpsr |= FPSR_TRAP_VD | FPSR_TRAP_ZD | FPSR_TRAP_OD;
398  fpsetmask( fpsr );
399 # elif defined(__HP_aCC)
400  /* this is for the HP compiler on the sdx */
401  unsigned long fpsr = fegettrapenable();
402  fpsr |= FPSR_TRAP_VD | FPSR_TRAP_ZD | FPSR_TRAP_OD;
403  fesettrapenable( fpsr );
404 # endif /* defined(__GNUC_EXCL__) */
405 
406  /* this is for Solaris and SGI to force crash */
407 # elif defined(__sun) || defined(__sgi)
408 
409  fp_except mask;
410 
411  /* >>chng 05 dec 30, accept FLUSH_DENORM_TO_ZERO as a synonym for HAVE_SUNMATH, PvH */
412 # if defined(HAVE_SUNMATH) || defined(FLUSH_DENORM_TO_ZERO)
413 
414  /* >>chng 01 oct 09, disable gradual underflow on ultrasparc whith g++
415  * (only needed for versions < 3.1 or >= 4.3.0, see Note 1).
416  *
417  * compile this module with:
418  * g++ [ other options... ] -I<include-dir> -DHAVE_SUNMATH -c cpu.cpp
419  * link the program with:
420  * g++ -L<library-dir> -o cloudy.exe *.o -lsunmath
421  *
422  * you probably need to use -I<include-dir> and -L<library-dir> to point the
423  * compiler/linker to the location of the sunmath.h header file and libsunmath.so
424  * library (e.g., -I/opt/SUNWspro/prod/include/cc -L/opt/SUNWspro/lib; note that
425  * the actual location may vary from one installation to another).
426  * See also bug report 4487 on http://gcc.gnu.org/bugzilla/
427  *
428  * Note 1: Starting with g++ 3.1, bug 4487 has been solved: -funsafe-math-optimizations
429  * will automatically disable gradual underflow. Hence using nonstandard_arithmetic()
430  * is no longer necessary. The option -funsafe-math-optimizations should be included
431  * both when compiling and linking:
432  *
433  * g++ [ other options... ] -funsafe-math-optimizations -c *.c
434  * g++ [ other options... ] -funsafe-math-optimizations -o cloudy.exe *.o
435  *
436  * Starting with g++ 4.3.0 the -funsafe-math-optimizations option can no longer be
437  * used as it implicitly enables -fno-trapping-math, which is unsafe for Cloudy
438  * because we do trap floating point exceptions.
439  *
440  * Note 2: Don't use nonstandard_arithmetic() with CC (the SunWorks/Forte compiler);
441  * use the -fast commandline option instead to disable gradual underflow (or use
442  * -fnonstd if you don't want all the other options enabled by -fast). The option
443  * -fast (or -fnonstd) should be included both when compiling and linking:
444  *
445  * CC [ other options... ] -fast -c *.c
446  * CC -fast -o cloudy.exe *.o
447  *
448  * PvH */
449  nonstandard_arithmetic();
450 # endif
451 
452  /* enable floating point exceptions on sun and sgi */
453  mask = fpgetmask();
454  mask = mask | FP_X_INV | FP_X_OFL | FP_X_DZ;
455  fpsetmask(mask);
456 
457 # elif defined(__alpha) && defined(__linux__) && defined(__GNUC__)
458 
459  /* the following is not supported on all hardware platforms, but certainly for EV56
460  * and later. earlier versions may work as well, but that has not been tested.
461  * for details see https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=51072 */
462 # ifdef FE_NONIEEE_ENV
463  /* this prevents the infamous math library bug when compiling with gcc on alpha-linux
464  * machines. if this doesn't work on your system, the only alternative is to link
465  * against the Compaq math library: gcc *.o -lcpml -lm, or use ccc itself, PvH */
466  fesetenv(FE_NONIEEE_ENV);
467 # endif
468 
469 # elif defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140
470 
471  // from Oracle Developer Studio 12.5 onwards, FP traps are not enebled by default
472  feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
473 
474 # endif
475 }
476 
478 {
479  DEBUG_ENTRY( "set_signal_handlers()" );
480 
481 #ifdef CATCH_SIGNAL
482 # ifdef __unix
483  p_action.sa_handler = &signal_handler;
484  sigemptyset( &p_action.sa_mask );
485  p_action.sa_flags = SA_NODEFER;
486 
487  p_default.sa_handler = SIG_DFL;
488  sigemptyset( &p_default.sa_mask );
489  p_default.sa_flags = SA_NODEFER;
490 
491  for( int sig=1; sig <= 31; sig++ )
492  {
493  // is the signal valid?
494  if( sigaction( sig, NULL, NULL ) == 0 )
495  // these two are for suspending and resuming a job
496  if( sig != SIGSTOP && sig != SIGCONT )
497  sigaction( sig, action(), NULL );
498  }
499 # endif
500 
501 # ifdef _MSC_VER
502  signal( SIGABRT, &signal_handler );
503  signal( SIGFPE, &signal_handler );
504  signal( SIGILL, &signal_handler );
505  signal( SIGINT, &signal_handler );
506  signal( SIGSEGV, &signal_handler );
507  signal( SIGTERM, &signal_handler );
508 # endif
509 #endif
510 }
511 
513 {
514  // when an FPE is caught, the mask is reset...
515  cpu.i().enable_traps();
516 # ifdef _MSC_VER
517  // at this point the signal handler has reverted to the default handler
518  signal( sig, &signal_handler );
519 # endif
520  throw bad_signal( sig );
521 }
522 
523 
525 {
526  fprintf(ioQQQ, "The path is:\n");
527  for( vector<string>::size_type i=1; i < chSearchPath.size()-1; ++i )
528  fprintf( ioQQQ, " ==%s==\n", chSearchPath[i].c_str() );
529 }
530 
531 // this routine generates a list of all full paths to the locations where we should look for the file
532 void t_cpu_i::getPathList( const char* fname, vector<string>& PathList, access_scheme scheme ) const
533 {
534  DEBUG_ENTRY( "getPathList()" );
535 
536  vector<string>::size_type begin, end;
537 
538  switch( scheme )
539  {
540  case AS_DATA_ONLY:
541  case AS_DATA_ONLY_TRY:
542  case AS_DATA_OPTIONAL:
543  begin = 1;
544  end = cpu.i().chSearchPath.size()-1;
545  break;
546  case AS_DATA_LOCAL:
547  case AS_DATA_LOCAL_TRY:
548  begin = 1;
549  end = cpu.i().chSearchPath.size();
550  break;
551  case AS_LOCAL_DATA:
552  case AS_LOCAL_DATA_TRY:
553  begin = 0;
554  end = cpu.i().chSearchPath.size()-1;
555  break;
556  case AS_LOCAL_ONLY:
557  case AS_LOCAL_ONLY_TRY:
558  case AS_SILENT_TRY:
559  begin = 0;
560  end = 1;
561  break;
562  default:
563  TotalInsanity();
564  }
565 
566  PathList.clear();
567  string FileName( fname );
568  for( vector<string>::size_type i=begin; i < end; ++i )
569  PathList.push_back( cpu.i().chSearchPath[i] + FileName );
570 }
571 
572 STATIC NORETURN void AbortErrorMessage( const char* fname, vector<string>& PathList, access_scheme scheme )
573 {
574  DEBUG_ENTRY( "AbortErrorMessage()" );
575 
576  if( scheme == AS_DATA_OPTIONAL )
577  // presence is optional -> make warning less scary...
578  fprintf( ioQQQ, "\nI could not open the data file %s\n\n", fname );
579  else
580  fprintf( ioQQQ, "\nPROBLEM DISASTER I could not open the data file %s\n\n", fname );
581  if( cpu.i().firstOpen() || scheme == AS_DATA_ONLY )
582  {
583  // failed on very first open -> most likely path is not correct
584  // failed on AS_DATA_ONLY -> CLOUDY_DATA_PATH may point to obsolete data dir
585  fprintf( ioQQQ, "Although there may be other reasons you have received this error,\n");
586  fprintf( ioQQQ, "the most likely are that the path has not been properly set\n");
587  fprintf( ioQQQ, "or that the path points to an old version of the data.\n\n");
588  fprintf( ioQQQ, "Please have a look at the file path.h in the source directory\n");
589  fprintf( ioQQQ, "to check how the variable CLOUDY_DATA_PATH is set - \n");
590  fprintf( ioQQQ, "it should give the location of the data files I need.\n");
591  fprintf( ioQQQ, "These are the files in the data download from the web site.\n\n");
592  fprintf( ioQQQ, "Recompile the code with the correct data path set in path.h\n");
593  fprintf( ioQQQ, "or use the shell command \nexport CLOUDY_DATA_PATH=\"/path/to/data\"\n to set the\n");
594  fprintf( ioQQQ, "path from a bash command prompt.\n\n");
595  cpu.i().printDataPath();
596  }
597  else
598  {
599  // failed on search including local directory -> most likely the file name
600  // was mistyped on a compile command, or Cloudy is run in the wrong directory
601  // if scheme == AS_DATA_OPTIONAL, this most likely is a stellar grid that is not installed.
602  fprintf( ioQQQ, "These are all the paths I tried:\n" );
603  for( vector<string>::const_iterator ptr=PathList.begin(); ptr != PathList.end(); ++ptr )
604  fprintf( ioQQQ, " ==%s==\n", ptr->c_str() );
605  // AS_DATA_OPTIONAL files should provide their own message (currently only stellar grids)
606  if( scheme != AS_DATA_OPTIONAL )
607  {
608  fprintf( ioQQQ, "\nAlthough there may be other reasons you have received this error,\n");
609  fprintf( ioQQQ, "the most likely are that you mistyped the file name, or that you\n");
610  fprintf( ioQQQ, "are running Cloudy in the wrong directory. If you are running a\n");
611  fprintf( ioQQQ, "COMPILE command, this needs to be done in the data directory.\n\n");
612  fprintf( ioQQQ, "Otherwise, please have a look at the file path.h in the source\n");
613  fprintf( ioQQQ, "directory to check how the variable CLOUDY_DATA_PATH is set - \n");
614  fprintf( ioQQQ, "it should give the location of the data files I need.\n");
615  fprintf( ioQQQ, "These are the files in the data download from the web site.\n\n");
616  fprintf( ioQQQ, "Recompile the code with the correct data path set in path.h\n");
617  fprintf( ioQQQ, "or use the shell command \nexport CLOUDY_DATA_PATH=\"/path/to/data\"\n to set the\n");
618  fprintf( ioQQQ, "path from a bash command prompt.\n\n");
619  }
620  }
621  fprintf(ioQQQ, "Sorry.\n\n\n");
623 }
624 
625 FILE* open_data( const char* fname, const char* mode, access_scheme scheme )
626 {
627  DEBUG_ENTRY( "open_data()" );
628 
629  bool lgAbort = ( scheme == AS_DATA_ONLY || scheme == AS_DATA_OPTIONAL || scheme == AS_DATA_LOCAL ||
630  scheme == AS_LOCAL_DATA || scheme == AS_LOCAL_ONLY );
631 
632  vector<string> PathList;
633  cpu.i().getPathList( fname, PathList, scheme );
634 
635  FILE* handle = NULL;
636  vector<string>::const_iterator ptr;
637  for( ptr=PathList.begin(); ptr != PathList.end() && handle == NULL; ++ptr )
638  {
639  handle = fopen( ptr->c_str(), mode );
640  if( trace.lgTrace && scheme != AS_SILENT_TRY )
641  fprintf( ioQQQ, " open_data trying %s mode %s handle %p\n", ptr->c_str(), mode, handle );
642  }
643 
644  if( handle == NULL && lgAbort )
645  AbortErrorMessage( fname, PathList, scheme );
646 
647  ++cpu.i().nFileDone;
648 
649  return handle;
650 }
651 
652 void open_data( fstream& stream, const char* fname, ios_base::openmode mode, access_scheme scheme )
653 {
654  DEBUG_ENTRY( "open_data()" );
655 
656  bool lgAbort = ( scheme == AS_DATA_ONLY || scheme == AS_DATA_OPTIONAL || scheme == AS_DATA_LOCAL ||
657  scheme == AS_LOCAL_DATA || scheme == AS_LOCAL_ONLY );
658 
659  vector<string> PathList;
660  cpu.i().getPathList( fname, PathList, scheme );
661 
662  ASSERT( !stream.is_open() );
663  vector<string>::const_iterator ptr;
664  for( ptr=PathList.begin(); ptr != PathList.end() && !stream.is_open(); ++ptr )
665  {
666  stream.open( ptr->c_str(), mode );
667  if( trace.lgTrace && scheme != AS_SILENT_TRY )
668  fprintf( ioQQQ, " open_data trying %s succes? %c\n", ptr->c_str(), TorF(stream.is_open()) );
669  }
670 
671  if( !stream.is_open() && lgAbort )
672  AbortErrorMessage( fname, PathList, scheme );
673 
674  ++cpu.i().nFileDone;
675 }
676 
683 {
684  if( sizeof(sys_float) == 4 )
685  *reinterpret_cast<int32*>(&x) = cpu.i().Float_SNaN_Value;
686  else
687  x = -FLT_MAX;
688 }
689 
690 void set_NaN(sys_float x[], /* x[n] */
691  long n)
692 {
693  long i;
694 
695  if( sizeof(sys_float) == 4 )
696  {
697  int32 *y = reinterpret_cast<int32*>(x);
698  for( i=0; i < n; i++ )
699  *y++ = cpu.i().Float_SNaN_Value;
700  }
701  else
702  {
703  for( i=0; i < n; i++ )
704  x[i] = -FLT_MAX;
705  }
706 }
707 
708 void set_NaN(double &x)
709 {
710  if( sizeof(double) == 8 )
711  {
712 # ifdef HAVE_INT64
713  *reinterpret_cast<int64*>(&x) = cpu.i().Double_SNaN_Value;
714 # else
715  int32 *y = reinterpret_cast<int32*>(&x);
716  *y++ = cpu.i().Double_SNaN_Value[0];
717  *y = cpu.i().Double_SNaN_Value[1];
718 # endif
719  }
720  else
721  x = -DBL_MAX;
722 }
723 
724 /* set_NaN - set NaN */
725 void set_NaN(double x[], /* x[n] */
726  long n)
727 {
728  long i;
729 
730  if( sizeof(double) == 8 )
731  {
732 # ifdef HAVE_INT64
733  int64 *y = reinterpret_cast<int64*>(x);
734  for( i=0; i < n; i++ )
735  *y++ = cpu.i().Double_SNaN_Value;
736 # else
737  int32 *y = reinterpret_cast<int32*>(x);
738  for( i=0; i < n; i++ )
739  {
740  *y++ = cpu.i().Double_SNaN_Value[0];
741  *y++ = cpu.i().Double_SNaN_Value[1];
742  }
743 # endif
744  }
745  else
746  {
747  for( i=0; i < n; i++ )
748  x[i] = -DBL_MAX;
749  }
750 }
751 
753 bool MyIsnan(const sys_float &x)
754 {
755  if( sizeof(sys_float) == 4 && FLT_MAX_EXP-FLT_MIN_EXP+3 == 256 )
756  {
757  const int32 *p = reinterpret_cast<const int32*>(&x);
758  int32 r = *p & 0x7f800000; r ^= 0x7f800000;
759  int32 s = *p & 0x007fffff;
760  return ( r == 0 && s != 0 );
761  }
762  else
763  /* we don't understand this CPU */
764  return false;
765 }
766 
768 bool MyIsnan(const double &x)
769 {
770  if( sizeof(double) == 8 && DBL_MAX_EXP-DBL_MIN_EXP+3 == 2048 )
771  {
772 # ifdef HAVE_INT64
773  const int64 *p = reinterpret_cast<const int64*>(&x);
774  int64 r = *p & 0x7ff0000000000000; r ^= 0x7ff0000000000000;
775  int64 s = *p & 0x000fffffffffffff;
776  return ( r == 0 && s != 0 );
777 # else
778  const int32 *p = reinterpret_cast<const int32*>(&x);
779  if( cpu.i().little_endian() )
780  {
781  int32 r = p[1] & 0x7ff00000; r ^= 0x7ff00000;
782  int32 s = p[1] & 0x000fffff; s |= p[0];
783  return ( r == 0 && s != 0 );
784  }
785  else if( cpu.i().big_endian() )
786  {
787  int32 r = p[0] & 0x7ff00000; r ^= 0x7ff00000;
788  int32 s = p[0] & 0x000fffff; s |= p[1];
789  return ( r == 0 && s != 0 );
790  }
791  else
792  /* we don't understand this CPU */
793  return false;
794 # endif
795  }
796  else
797  /* we don't understand this CPU */
798  return false;
799 }
ES_SEGFAULT
@ ES_SEGFAULT
Definition: cddefines.h:128
ES_FAILURE
@ ES_FAILURE
Definition: cddefines.h:117
path.h
TorF
char TorF(bool l)
Definition: cddefines.h:710
t_cpu_i::p_lgMPISingleRankMode
bool p_lgMPISingleRankMode
Definition: cpu.h:267
lgAbort
bool lgAbort
Definition: cddefines.cpp:10
t_cpu_i::getPathList
void getPathList(const char *fname, vector< string > &PathList, access_scheme scheme) const
Definition: cpu.cpp:532
open_data
FILE * open_data(const char *fname, const char *mode, access_scheme scheme)
Definition: cpu.cpp:625
ES_USER_INTERRUPT
@ ES_USER_INTERRUPT
Definition: cddefines.h:124
ES_BOTCHES
@ ES_BOTCHES
Definition: cddefines.h:119
t_cpu_i::enable_traps
void enable_traps() const
Definition: cpu.cpp:293
ES_CLOUDY_ABORT
@ ES_CLOUDY_ABORT
Definition: cddefines.h:120
t_cpu_i::p_chDirSeparator
char p_chDirSeparator
Definition: cpu.h:275
t_cpu_i::endian
union t_cpu_i::@3 endian
AS_DATA_ONLY
@ AS_DATA_ONLY
Definition: cpu.h:207
ioQQQ
FILE * ioQQQ
Definition: cddefines.cpp:7
bad_signal
Definition: cddefines.h:522
STATIC
#define STATIC
Definition: cddefines.h:97
AS_LOCAL_DATA_TRY
@ AS_LOCAL_DATA_TRY
Definition: cpu.h:207
ES_UNKNOWN_SIGNAL
@ ES_UNKNOWN_SIGNAL
Definition: cddefines.h:130
AS_DATA_ONLY_TRY
@ AS_DATA_ONLY_TRY
Definition: cpu.h:207
AS_LOCAL_ONLY
@ AS_LOCAL_ONLY
Definition: cpu.h:208
ioStdin
FILE * ioStdin
Definition: cddefines.cpp:8
ES_TERMINATION_REQUEST
@ ES_TERMINATION_REQUEST
Definition: cddefines.h:125
cpu
static t_cpu cpu
Definition: cpu.h:355
t_cpu::m_i
static t_cpu_i * m_i
Definition: cpu.h:345
trace.h
t_cpu_i::set_signal_handlers
void set_signal_handlers()
Definition: cpu.cpp:477
t_cpu_i::n_avail_CPU
long n_avail_CPU
Definition: cpu.h:260
AS_DATA_OPTIONAL
@ AS_DATA_OPTIONAL
Definition: cpu.h:208
lgPrnErr
bool lgPrnErr
Definition: cddefines.cpp:13
ASSERT
#define ASSERT(exp)
Definition: cddefines.h:578
t_cpu::~t_cpu
~t_cpu()
Definition: cpu.cpp:63
t_cpu_i::test_double
double test_double
Definition: cpu.h:242
t_cpu_i::t_cpu_i
t_cpu_i()
Definition: cpu.cpp:72
t_cpu_i::i
int32 i
Definition: cpu.h:238
t_cpu_i
Definition: cpu.h:231
cpu_count
static int cpu_count
Definition: cpu.cpp:55
t_cpu_i::little_endian
bool little_endian() const
Definition: cpu.h:288
t_cpu::i
t_cpu_i & i()
Definition: cpu.h:347
EXIT_FAILURE
#define EXIT_FAILURE
Definition: cddefines.h:140
t_cpu_i::big_endian
bool big_endian() const
Definition: cpu.h:287
t_cpu_i::p_lgAssertAbort
bool p_lgAssertAbort
Definition: cpu.h:257
t_cpu_i::p_exit_status
vector< string > p_exit_status
Definition: cpu.h:281
ioPrnErr
FILE * ioPrnErr
Definition: cddefines.cpp:9
ES_BUS_ERROR
@ ES_BUS_ERROR
Definition: cddefines.h:129
trace
t_trace trace
Definition: trace.cpp:5
cddefines.h
NORETURN
#define NORETURN
Definition: cpu.h:383
cdstd.h
ES_BAD_ALLOC
@ ES_BAD_ALLOC
Definition: cddefines.h:122
t_cpu_i::firstOpen
bool firstOpen() const
Definition: cpu.h:332
TotalInsanity
NORETURN void TotalInsanity(void)
Definition: service.cpp:886
ES_SUCCESS
@ ES_SUCCESS
Definition: cddefines.h:116
access_scheme
access_scheme
Definition: cpu.h:207
set_NaN
void set_NaN(sys_float &x)
Definition: cpu.cpp:682
ES_ILLEGAL_INSTRUCTION
@ ES_ILLEGAL_INSTRUCTION
Definition: cddefines.h:126
Split
void Split(const string &str, const string &sep, vector< string > &lst, split_mode mode)
Definition: service.cpp:106
cpu.h
ES_TOP
@ ES_TOP
Definition: cddefines.h:132
t_cpu_i::n_rank
long n_rank
Definition: cpu.h:269
cdEXIT
#define cdEXIT(FAIL)
Definition: cddefines.h:434
AS_SILENT_TRY
@ AS_SILENT_TRY
Definition: cpu.h:208
ES_WARNINGS
@ ES_WARNINGS
Definition: cddefines.h:118
t_cpu_i::Double_SNaN_Value
int32 Double_SNaN_Value[2]
Definition: cpu.h:248
t_cpu_i::test_float
sys_float test_float
Definition: cpu.h:241
AbortErrorMessage
STATIC NORETURN void AbortErrorMessage(const char *fname, vector< string > &PathList, access_scheme scheme)
Definition: cpu.cpp:572
ES_BAD_ASSERT
@ ES_BAD_ASSERT
Definition: cddefines.h:121
t_cpu_i::HostName
char HostName[STDLEN]
Definition: cpu.h:271
STDLEN
const int STDLEN
Definition: cpu.h:197
t_cpu_i::p_lgMPI
bool p_lgMPI
Definition: cpu.h:262
ES_OUT_OF_RANGE
@ ES_OUT_OF_RANGE
Definition: cddefines.h:123
ES_UNKNOWN_EXCEPTION
@ ES_UNKNOWN_EXCEPTION
Definition: cddefines.h:131
AS_DATA_LOCAL
@ AS_DATA_LOCAL
Definition: cpu.h:208
sys_float
float sys_float
Definition: cddefines.h:106
ES_FP_EXCEPTION
@ ES_FP_EXCEPTION
Definition: cddefines.h:127
MyIsnan
bool MyIsnan(const sys_float &x)
Definition: cpu.cpp:753
t_cpu_i::printDataPath
void printDataPath() const
Definition: cpu.cpp:524
t_cpu_i::nFileDone
int nFileDone
Definition: cpu.h:276
SPM_RELAX
@ SPM_RELAX
Definition: cddefines.h:1325
t_cpu_i::chSearchPath
vector< string > chSearchPath
Definition: cpu.h:273
t_cpu_i::Float_SNaN_Value
int32 Float_SNaN_Value
Definition: cpu.h:244
AS_LOCAL_DATA
@ AS_LOCAL_DATA
Definition: cpu.h:208
t_cpu::t_cpu
t_cpu()
Definition: cpu.cpp:56
DEBUG_ENTRY
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:684
AS_DATA_LOCAL_TRY
@ AS_DATA_LOCAL_TRY
Definition: cpu.h:207
t_trace::lgTrace
bool lgTrace
Definition: trace.h:12
AS_LOCAL_ONLY_TRY
@ AS_LOCAL_ONLY_TRY
Definition: cpu.h:207
t_cpu_i::signal_handler
static void signal_handler(int sig)
Definition: cpu.cpp:512