File indexing completed on 2026-04-09 07:49:33
0001 #pragma once
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <iomanip>
0018
0019 #include "sdirectory.h"
0020 #include "spath.h"
0021 #include "sstr.h"
0022 #include "ssys.h"
0023 #include "scurandref.h"
0024 #include "sdigest.h"
0025
0026 #include "SYSRAP_API_EXPORT.hh"
0027
0028 struct SYSRAP_API SCurandChunk
0029 {
0030 typedef unsigned long long ULL ;
0031 scurandref<curandStateXORWOW> ref = {} ;
0032
0033 std::string desc() const ;
0034 std::string meta() const ;
0035 std::string name() const ;
0036 const char* path(const char* _dir=nullptr) const ;
0037 bool path_exists(const char* _dir=nullptr) const ;
0038
0039 static constexpr const long STATE_SIZE = 44 ;
0040 static constexpr const char* RNGDIR = "${RNGDir:-$HOME/.opticks/rngcache/RNG}" ;
0041 static constexpr const ULL M = 1000000 ;
0042 static constexpr const char* PREFIX = "SCurandChunk_" ;
0043 static constexpr const char* EXT = ".bin" ;
0044 static constexpr char DELIM = '_' ;
0045 static constexpr const long NUM_ELEM = 5 ;
0046
0047 static const char* Dir( const char* _dir=nullptr );
0048 static std::string Desc(const SCurandChunk& chunk, const char* _dir=nullptr );
0049 static std::string Desc(const std::vector<SCurandChunk>& chunk, const char* _dir=nullptr );
0050 static int ParseDir( std::vector<SCurandChunk>& chunk, const char* _dir=nullptr );
0051
0052 static constexpr const char* ParseName_DEBUG = "SCurandChunk__ParseName_DEBUG" ;
0053 static int ParseName( SCurandChunk& chunk, const char* name );
0054 static long ParseNum(const char* num);
0055
0056 static std::string FormatIdx(ULL idx);
0057 static std::string FormatNum(ULL num);
0058 static std::string FormatMeta(const scurandref<curandStateXORWOW>& d );
0059 static std::string FormatName(const scurandref<curandStateXORWOW>& d );
0060
0061 static ULL NumFromFilesize(const char* name, const char* _dir=nullptr);
0062 static bool IsValid(const SCurandChunk& chunk, const char* _dir=nullptr);
0063 static int CountValid(const std::vector<SCurandChunk>& chunk, const char* _dir=nullptr );
0064 static scurandref<curandStateXORWOW>* Find(std::vector<SCurandChunk>& chunk, long idx );
0065 static ULL NumTotal_SpecCheck(const std::vector<SCurandChunk>& chunk, const std::vector<ULL>& spec );
0066 static ULL NumTotal_InRange( const std::vector<SCurandChunk>& chunk, ULL i0, ULL i1 );
0067
0068 scurandref<curandStateXORWOW> load(ULL read_num=0, const char* _dir=nullptr, sdigest* dig=nullptr ) const ;
0069 static int OldLoad( SCurandChunk& chunk, const char* name, ULL q_num=0, const char* _dir=nullptr );
0070 static curandStateXORWOW* Load_( ULL& file_num, const char* path, ULL read_num, sdigest* dig );
0071
0072 static int Save( curandStateXORWOW* states, unsigned num_states, const char* path ) ;
0073 int save( const char* _dir=nullptr ) const ;
0074 };
0075
0076 inline std::string SCurandChunk::desc() const
0077 {
0078 std::stringstream ss ;
0079 ss << Desc(*this) << "\n" ;
0080 std::string str = ss.str() ;
0081 return str ;
0082 }
0083
0084 inline std::string SCurandChunk::meta() const
0085 {
0086 return FormatMeta(ref);
0087 }
0088 inline std::string SCurandChunk::name() const
0089 {
0090 return FormatName(ref);
0091 }
0092 inline const char* SCurandChunk::path(const char* _dir) const
0093 {
0094 std::string n = name();
0095 const char* dir = _dir ? _dir : RNGDIR ;
0096 return spath::Resolve( dir, n.c_str() );
0097 }
0098
0099 inline bool SCurandChunk::path_exists(const char* _dir) const
0100 {
0101 const char* pth = path(_dir) ;
0102 return spath::Exists(pth);
0103 }
0104
0105 inline const char* SCurandChunk::Dir( const char* _dir )
0106 {
0107 const char* dir = _dir ? _dir : RNGDIR ;
0108 return spath::Resolve(dir);
0109 }
0110
0111 inline std::string SCurandChunk::Desc(const SCurandChunk& chunk, const char* _dir )
0112 {
0113 bool exists = chunk.path_exists(_dir);
0114 std::stringstream ss ;
0115 ss << chunk.path(_dir) << " exists " << ( exists ? "YES" : "NO " ) ;
0116 std::string str = ss.str() ;
0117 return str ;
0118 }
0119
0120 inline std::string SCurandChunk::Desc(const std::vector<SCurandChunk>& chunk, const char* _dir )
0121 {
0122 int num_chunk = chunk.size();
0123 std::stringstream ss ;
0124 ss << "SCurandChunk::Desc\n" ;
0125 for(int i=0 ; i < num_chunk ; i++) ss << Desc(chunk[i], _dir) << "\n" ;
0126 std::string str = ss.str() ;
0127 return str ;
0128 }
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139 inline int SCurandChunk::ParseDir(std::vector<SCurandChunk>& chunk, const char* _dir )
0140 {
0141 const char* dir = spath::Resolve(_dir ? _dir : RNGDIR) ;
0142 std::vector<std::string> names ;
0143 sdirectory::DirList( names, dir, PREFIX, EXT );
0144
0145 int num_names = names.size();
0146 int count = 0 ;
0147
0148 for(int i=0 ; i < num_names ; i++)
0149 {
0150 const std::string& n = names[i] ;
0151 SCurandChunk c = {} ;
0152 if(SCurandChunk::ParseName(c, n.c_str())==0)
0153 {
0154 ULL chunk_offset = NumTotal_InRange(chunk, 0, chunk.size() );
0155 assert( c.ref.chunk_offset == chunk_offset );
0156 assert( c.ref.chunk_idx == count );
0157 chunk.push_back(c);
0158 count += 1 ;
0159 }
0160 }
0161 return 0 ;
0162 }
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182 inline int SCurandChunk::ParseName( SCurandChunk& chunk, const char* name )
0183 {
0184 if(name == nullptr ) return 1 ;
0185 size_t other = strlen(PREFIX)+strlen(EXT) ;
0186 if( strlen(name) <= other ) return 2 ;
0187
0188 std::string n = name ;
0189 std::string meta = n.substr( strlen(PREFIX), strlen(name) - other );
0190
0191 std::vector<std::string> elem ;
0192 sstr::Split(meta.c_str(), DELIM, elem );
0193
0194 unsigned num_elem = elem.size();
0195 if( num_elem != NUM_ELEM ) return 3 ;
0196
0197 chunk.ref.chunk_idx = std::atoll(elem[0].c_str()) ;
0198 chunk.ref.chunk_offset = ParseNum(elem[1].c_str()) ;
0199 chunk.ref.num = ParseNum(elem[2].c_str()) ;
0200 chunk.ref.seed = std::atoll(elem[3].c_str()) ;
0201 chunk.ref.offset = std::atoll(elem[4].c_str()) ;
0202 chunk.ref.states = nullptr ;
0203
0204 int DEBUG = ssys::getenvint(ParseName_DEBUG,0);
0205
0206 if(DEBUG > 0) std::cout
0207 << ParseName_DEBUG
0208 << " " << std::setw(30) << n
0209 << " : [" << meta << "]["
0210 << chunk.name()
0211 << "]\n"
0212 ;
0213 return 0 ;
0214 }
0215
0216
0217
0218 inline long SCurandChunk::ParseNum(const char* num)
0219 {
0220 char* n = strdup(num);
0221 char last = n[strlen(n)-1] ;
0222 ULL scale = last == 'M' ? M : 1 ;
0223 if(scale > 1) n[strlen(n)-1] = '\0' ;
0224 ULL value = scale*std::atoll(num) ;
0225 return value ;
0226 }
0227
0228
0229
0230 inline std::string SCurandChunk::FormatMeta(const scurandref<curandStateXORWOW>& d)
0231 {
0232 std::stringstream ss ;
0233 ss
0234 << FormatIdx(d.chunk_idx)
0235 << DELIM
0236 << FormatNum(d.chunk_offset)
0237 << DELIM
0238 << FormatNum(d.num)
0239 << DELIM
0240 << d.seed
0241 << DELIM
0242 << d.offset
0243 ;
0244 std::string str = ss.str();
0245 return str ;
0246 }
0247 inline std::string SCurandChunk::FormatName(const scurandref<curandStateXORWOW>& d)
0248 {
0249 std::stringstream ss ;
0250 ss << PREFIX << FormatMeta(d) << EXT ;
0251 std::string str = ss.str();
0252 return str ;
0253 }
0254
0255 inline std::string SCurandChunk::FormatIdx(ULL idx)
0256 {
0257 std::stringstream ss;
0258 ss << std::setw(4) << std::setfill('0') << idx ;
0259 std::string str = ss.str();
0260 return str ;
0261 }
0262 inline std::string SCurandChunk::FormatNum(ULL num)
0263 {
0264 ULL scale = M ;
0265
0266 bool intmul = num % scale == 0 ;
0267 if(!intmul) std::cerr
0268 << "SCurandChunk::FormatNum"
0269 << " num [" << num << "]"
0270 << " intmul " << ( intmul ? "YES" : "NO " )
0271 << "\n"
0272 ;
0273 assert( intmul && "integer multiples of 1000000 are required" );
0274 ULL value = num/scale ;
0275
0276 std::stringstream ss;
0277 ss << std::setw(4) << std::setfill('0') << value << 'M' ;
0278 std::string str = ss.str();
0279 return str ;
0280 }
0281
0282 inline unsigned long long SCurandChunk::NumFromFilesize(const char* name, const char* _dir)
0283 {
0284 const char* dir = _dir ? _dir : RNGDIR ;
0285 ULL file_size = spath::Filesize(dir, name);
0286
0287 bool expected_file_size = file_size % STATE_SIZE == 0 ;
0288 ULL file_num = file_size/STATE_SIZE ;
0289
0290 if(0) std::cerr
0291 << "SCurandChunk::NumFromFilesize"
0292 << " dir " << ( dir ? dir : "-" )
0293 << " name " << ( name ? name : "-" )
0294 << " file_size " << file_size
0295 << " STATE_SIZE " << STATE_SIZE
0296 << " file_num " << file_num
0297 << " expected_file_size " << ( expected_file_size ? "YES" : "NO" )
0298 << "\n"
0299 ;
0300
0301 assert( expected_file_size );
0302 return file_num ;
0303 }
0304
0305 inline bool SCurandChunk::IsValid(const SCurandChunk& chunk, const char* _dir )
0306 {
0307 bool exists = chunk.path_exists(_dir) ;
0308 if(!exists) return false ;
0309
0310 std::string n = chunk.name();
0311
0312
0313 ULL chunk_num = chunk.ref.num ;
0314 ULL file_num = NumFromFilesize(n.c_str(), _dir) ;
0315 bool valid = chunk_num == file_num ;
0316
0317 if(!valid) std::cerr
0318 << "SCurandChunk::IsValid"
0319 << " chunk file exists [" << n << "]"
0320 << " but filesize does not match name metadata "
0321 << " chunk_num " << chunk_num
0322 << " file_num " << file_num
0323 << " valid " << ( valid ? "YES" : "NO " )
0324 << "\n"
0325 ;
0326 return valid ;
0327 }
0328
0329 inline int SCurandChunk::CountValid(const std::vector<SCurandChunk>& chunk, const char* _dir )
0330 {
0331 int num_chunk = chunk.size();
0332 int count = 0 ;
0333 for(int i=0 ; i < num_chunk ; i++)
0334 {
0335 const SCurandChunk& c = chunk[i];
0336 bool valid = IsValid(c, _dir);
0337 if(!valid) continue ;
0338 count += 1 ;
0339 }
0340 return count ;
0341 }
0342
0343 inline scurandref<curandStateXORWOW>* SCurandChunk::Find(std::vector<SCurandChunk>& chunk, long q_idx )
0344 {
0345 int num_chunk = chunk.size();
0346 int count = 0 ;
0347 scurandref<curandStateXORWOW>* p = nullptr ;
0348 for(int i=0 ; i < num_chunk ; i++)
0349 {
0350 SCurandChunk& c = chunk[i] ;
0351 if( c.ref.chunk_idx == q_idx )
0352 {
0353 p = &(c.ref) ;
0354 count += 1 ;
0355 }
0356 }
0357 assert( count == 0 || count == 1 );
0358 return count == 1 ? p : nullptr ;
0359 }
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371 inline unsigned long long SCurandChunk::NumTotal_SpecCheck(const std::vector<SCurandChunk>& chunk, const std::vector<ULL>& spec )
0372 {
0373 assert( chunk.size() == spec.size() ) ;
0374 ULL tot = 0 ;
0375 ULL num_chunk = chunk.size();
0376 for(ULL i=0 ; i < num_chunk ; i++)
0377 {
0378 const scurandref<curandStateXORWOW>& d = chunk[i].ref ;
0379 assert( d.chunk_idx == i );
0380 assert( d.num == spec[i] );
0381 tot += d.num ;
0382 }
0383 return tot ;
0384 }
0385
0386 inline unsigned long long SCurandChunk::NumTotal_InRange( const std::vector<SCurandChunk>& chunk, ULL i0, ULL i1 )
0387 {
0388 ULL num_chunk = chunk.size();
0389 assert( i0 <= num_chunk );
0390 assert( i1 <= num_chunk );
0391
0392 ULL num_tot = 0ull ;
0393 for(ULL i=i0 ; i < i1 ; i++)
0394 {
0395 const scurandref<curandStateXORWOW>& d = chunk[i].ref ;
0396 num_tot += d.num ;
0397 }
0398 return num_tot ;
0399 }
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409 inline scurandref<curandStateXORWOW> SCurandChunk::load( ULL read_num, const char* _dir, sdigest* dig ) const
0410 {
0411 scurandref<curandStateXORWOW> lref(ref);
0412 const char* p = path(_dir);
0413
0414 ULL file_num = 0 ;
0415 lref.states = Load_(file_num, p, read_num, dig );
0416 lref.num = read_num ;
0417
0418 return lref ;
0419 }
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429 inline int SCurandChunk::OldLoad( SCurandChunk& chunk, const char* name, ULL read_num, const char* _dir )
0430 {
0431 int prc = ParseName(chunk, name);
0432 if( prc > 0) std::cerr
0433 << "SCurandChunk::Load"
0434 << " chunk name not allowed "
0435 << "\n"
0436 ;
0437 if(prc > 0) return 1 ;
0438
0439 const char* dir = _dir ? _dir : RNGDIR ;
0440 const char* p = spath::Resolve(dir, name);
0441
0442 ULL name_num = chunk.ref.num ;
0443
0444 ULL file_num = 0 ;
0445 curandStateXORWOW* h_states = Load_( file_num, p, read_num, nullptr ) ;
0446
0447 if( h_states )
0448 {
0449 chunk.ref.num = read_num ;
0450 chunk.ref.states = h_states ;
0451 bool name_filesize_consistent = file_num == name_num ;
0452
0453 std::cerr
0454 << "SCurandChunk::Load"
0455 << " path " << p
0456 << " name_num " << FormatNum(name_num) << "(from parsing filename) "
0457 << " file_num " << FormatNum(file_num) << "(from file_size/STATE_SIZE) "
0458 << " name_filesize_consistent " << ( name_filesize_consistent ? "YES" : "NO " )
0459 << " read_num " << FormatNum(read_num)
0460 << "\n"
0461 ;
0462 }
0463 return h_states ? 0 : 2 ;
0464 }
0465
0466
0467 inline curandStateXORWOW* SCurandChunk::Load_( ULL& file_num, const char* path, ULL read_num, sdigest* dig )
0468 {
0469 FILE *fp = fopen(path,"rb");
0470
0471 bool open_failed = fp == nullptr ;
0472 if(open_failed) std::cerr
0473 << "SCurandChunk::Load_"
0474 << " unable to open file "
0475 << "[" << path << "]"
0476 << "\n"
0477 ;
0478
0479 if(open_failed) return nullptr ;
0480
0481 fseek(fp, 0L, SEEK_END);
0482 ULL file_size = ftell(fp);
0483 rewind(fp);
0484
0485 bool expected_size = file_size % STATE_SIZE == 0 ;
0486 if(!expected_size) std::cerr
0487 << "SCurandChunk::Load_"
0488 << " expected_size " << ( expected_size ? "YES" : "NO " )
0489 << "\n"
0490 ;
0491
0492 if(!expected_size) return nullptr ;
0493
0494 file_num = file_size/STATE_SIZE;
0495
0496 bool read_num_toobig = read_num > file_num ;
0497 if(read_num_toobig) std::cerr
0498 << "SCurandChunk::Load_"
0499 << " read_num_toobig " << ( read_num_toobig ? "YES" : "NO " )
0500 << "\n"
0501 ;
0502
0503 if(read_num_toobig) return nullptr ;
0504 if(read_num == 0) read_num = file_num ;
0505
0506 curandStateXORWOW* h_states = (curandStateXORWOW*)malloc(sizeof(curandStateXORWOW)*read_num);
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523 for(ULL i = 0 ; i < read_num ; ++i )
0524 {
0525 curandStateXORWOW& rng = h_states[i] ;
0526 fread(&rng.d, sizeof(unsigned),1,fp); if(dig) dig->add_<unsigned>(&rng.d, 1 );
0527 fread(&rng.v, sizeof(unsigned),5,fp); if(dig) dig->add_<unsigned>( rng.v, 5 );
0528 fread(&rng.boxmuller_flag, sizeof(int) ,1,fp); if(dig) dig->add_<int>(&rng.boxmuller_flag,1);
0529 fread(&rng.boxmuller_flag_double, sizeof(int) ,1,fp); if(dig) dig->add_<int>(&rng.boxmuller_flag_double,1);
0530 fread(&rng.boxmuller_extra, sizeof(float) ,1,fp); if(dig) dig->add_<float>(&rng.boxmuller_extra,1);
0531 fread(&rng.boxmuller_extra_double,sizeof(double) ,1,fp); if(dig) dig->add_<double>(&rng.boxmuller_extra_double,1);
0532 }
0533 fclose(fp);
0534 return h_states ;
0535 }
0536
0537
0538 inline int SCurandChunk::Save( curandStateXORWOW* states, unsigned num_states, const char* path )
0539 {
0540 sdirectory::MakeDirsForFile(path);
0541 FILE *fp = fopen(path,"wb");
0542 bool open_fail = fp == nullptr ;
0543
0544 if(open_fail) std::cerr
0545 << "SCurandChunk::Save"
0546 << " FAILED to open file for writing"
0547 << ( path ? path : "-" )
0548 << "\n"
0549 ;
0550
0551 if( open_fail ) return 3 ;
0552
0553 for(unsigned i = 0 ; i < num_states ; ++i )
0554 {
0555 curandStateXORWOW& rng = states[i] ;
0556 fwrite(&rng.d, sizeof(unsigned int),1,fp);
0557 fwrite(&rng.v, sizeof(unsigned int),5,fp);
0558 fwrite(&rng.boxmuller_flag, sizeof(int) ,1,fp);
0559 fwrite(&rng.boxmuller_flag_double, sizeof(int) ,1,fp);
0560 fwrite(&rng.boxmuller_extra, sizeof(float) ,1,fp);
0561 fwrite(&rng.boxmuller_extra_double,sizeof(double) ,1,fp);
0562 }
0563 fclose(fp);
0564 return 0 ;
0565 }
0566
0567 inline int SCurandChunk::save( const char* _dir ) const
0568 {
0569 const char* p = path(_dir);
0570 bool exists = spath::Exists(p);
0571 std::cerr
0572 << "SCurandChunk::save"
0573 << " p " << ( p ? p : "-" )
0574 << " exists " << ( exists ? "YES" : "NO " )
0575 << "\n"
0576 ;
0577
0578 if(exists) return 1 ;
0579
0580 int rc = Save( ref.states, ref.num, p );
0581 return rc ;
0582 }
0583