Geant4 Cross Reference |
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #include "PoPs.h" 6 #include "PoPs_private.h" 7 8 /* 9 In PoPs_addParticleIfNeeded and unitsDB_addUnitIfNeeded, smr_malloc2 and not smr_realloc2 is used so that the current database is not 10 lost if more memory cannot be allocated (not sure that this is needed, maybe should crash). 11 */ 12 13 #if defined __cplusplus 14 namespace GIDI { 15 using namespace GIDI; 16 #endif 17 18 #define incrementalSize 1000 19 20 #define MeV2eV 1e6 21 #define MeV2keV 1e3 22 #define AMU2MeV 931.494028 23 #define AMU2eV ( MeV2eV * 931.494028 ) 24 #define K2MeV 8.6173856922566752e-11 25 #define K2eV ( MeV2eV * K2MeV ) 26 27 typedef struct unitConversions_s unitConversions; 28 29 struct unitConversions_s { 30 char const *_from; 31 char const *_to; 32 double ratio; 33 }; 34 35 int PoPs_smr_ID = smr_unknownID; 36 static int referenceCount = 0; 37 static char versionStr[64] = ""; 38 39 /* 40 * For MPI the following need to be broadcasted. 41 */ 42 static unitsDB unitsRoot = { 0, 0, NULL }; 43 static PoPs popsRoot = { 0, 0, NULL, NULL }; 44 /* 45 * End need to MPI broadcasted. 46 */ 47 48 static unitConversions conversions[] = { { "amu", "eV/c**2", AMU2eV }, { "amu", "MeV/c**2", AMU2MeV }, { "MeV/c**2", "eV/c**2", MeV2eV }, 49 { "MeV", "eV", MeV2eV }, { "MeV", "keV", MeV2keV }, { "K", "MeV", K2MeV }, { "K", "eV", K2eV } }; 50 51 static char const *PoPs_genreStrings[] = { "invalid", "unknown", "alias", "photon", "lepton", "quark", "meson", "baryon", "nucleus", "atom" }; 52 53 static int PoPs_particleProperIndex( int index ); 54 static int PoPs_sortedParticleIndex( char const *name ); 55 static int unitsDB_release( void ); 56 /* 57 ======================================================================== 58 */ 59 const char *PoPs_version( void ) { 60 61 if( versionStr[0] == 0 ) snprintf( versionStr, sizeof versionStr, "PoPs version %d.%d.%d", POPS_VERSION_MAJOR, POPS_VERSION_MINOR, POPS_VERSION_PATCHLEVEL ); 62 return( versionStr ); 63 } 64 /* 65 ======================================================================== 66 */ 67 int PoPs_versionMajor( void ) { return( POPS_VERSION_MAJOR ); } 68 int PoPs_versionMinor( void ) { return( POPS_VERSION_MINOR ); } 69 int PoPs_versionPatchLevel( void ) { return( POPS_VERSION_PATCHLEVEL ); } 70 /* 71 ======================================================================== 72 */ 73 int PoPs_register( void ) { 74 75 if( referenceCount < 0 ) return( -1 ); 76 return( ++referenceCount ); 77 } 78 /* 79 ======================================================================== 80 */ 81 int PoPs_readDatabase( statusMessageReporting *smr, char const *fileName ) { 82 83 return( PoPs_particleReadDatabase( smr, fileName ) ); 84 } 85 /* 86 ======================================================================== 87 */ 88 int PoPs_release( statusMessageReporting *smr ) { 89 90 referenceCount--; 91 if( referenceCount != 0 ) return( referenceCount ); 92 PoPs_releasePrivate( smr ); 93 return( 0 ); 94 } 95 /* 96 ======================================================================== 97 */ 98 int PoPs_releasePrivate( statusMessageReporting * /*smr*/ ) { 99 100 int i; 101 102 for( i = 0; i < popsRoot.numberOfParticles; i++ ) PoP_free( popsRoot.pops[i] ); 103 smr_freeMemory( (void **) &(popsRoot.pops) ); 104 popsRoot.sorted = NULL; 105 popsRoot.numberOfParticles = 0; 106 popsRoot.allocated = 0; 107 unitsDB_release( ); 108 return( 0 ); 109 } 110 /* 111 ======================================================================== 112 */ 113 PoP *PoPs_addParticleIfNeeded( statusMessageReporting *smr, PoP *pop ) { 114 /* 115 If particle with name pop->name is already in popsRoot, returns the pointer to the existing particle. 116 A NULL is returned if adding particle to popsRoot fails. 117 */ 118 int i, index = PoPs_sortedParticleIndex( pop->name ); 119 120 if( index >= 0 ) return( popsRoot.pops[PoPs_particleProperIndex( popsRoot.sorted[index]->index )] ); 121 if( popsRoot.numberOfParticles == popsRoot.allocated ) { 122 int size = popsRoot.allocated + incrementalSize; 123 PoP **sorted, **pops = (PoP **) smr_malloc2( smr, 2 * size * sizeof( PoPs * ), 0, "pops" ); 124 125 if( pops == NULL ) return( NULL ); 126 sorted = &(pops[size]); 127 for( i = 0; i < popsRoot.numberOfParticles; i++ ) { 128 pops[i] = popsRoot.pops[i]; 129 sorted[i] = popsRoot.sorted[i]; 130 } 131 smr_freeMemory( (void **) &(popsRoot.pops) ); 132 popsRoot.pops = pops; 133 popsRoot.sorted = sorted; 134 popsRoot.allocated = size; 135 } 136 popsRoot.pops[popsRoot.numberOfParticles] = pop; 137 index = -index - 1; 138 for( i = popsRoot.numberOfParticles; i > index; i-- ) popsRoot.sorted[i] = popsRoot.sorted[i-1]; 139 popsRoot.sorted[index] = pop; 140 pop->index = popsRoot.numberOfParticles; 141 popsRoot.numberOfParticles++; 142 if( pop->genre == PoPs_genre_alias ) { /* Add pop->index to end of list of particles aliased by pop->properIndex. */ 143 PoP *pop2; 144 145 for( pop2 = popsRoot.pops[pop->properIndex]; pop2->aliasIndex >= 0; pop2 = popsRoot.pops[pop2->aliasIndex] ) ; 146 pop2->aliasIndex = pop->index; 147 } 148 return( pop ); 149 } 150 /* 151 ======================================================================== 152 */ 153 PoP *PoPs_copyAddParticleIfNeeded( statusMessageReporting *smr, PoP *pop ) { 154 /* 155 If particle with name pop->name is already in popsRoot, return the address of the existing particle. 156 If particle is not in popsRoot then copy particle to a new 'PoP *', add the copied PoP to popsRoot and return its address. 157 A NULL is return if particle coping fails or adding particle to popsRoot fails. 158 */ 159 160 int index = PoPs_particleIndex( pop->name ); 161 PoP *newPoP; 162 163 if( index >= 0 ) return( popsRoot.pops[index] ); 164 165 if( ( newPoP = (PoP *) smr_malloc2( smr, sizeof( PoP ), 0, "newPoP" ) ) == NULL ) return( NULL ); 166 if( PoP_copyParticle( smr, newPoP, pop ) ) { 167 smr_freeMemory( (void **) &newPoP ); 168 return( NULL ); 169 } 170 if( PoPs_addParticleIfNeeded( smr, newPoP ) == NULL ) { 171 PoP_free( newPoP ); 172 return( NULL ); 173 } 174 return( newPoP ); 175 } 176 /* 177 ======================================================================== 178 */ 179 PoP *PoPs_addAliasIfNeeded( statusMessageReporting *smr, char const *name, char const *alias ) { 180 181 PoP *pop = PoP_makeAlias( smr, name, alias ); 182 183 if( pop != NULL ) { 184 if( pop->index < 0 ) { 185 if( PoPs_addParticleIfNeeded( smr, pop ) == NULL ) { 186 PoP_free( pop ); 187 return( NULL ); 188 } 189 } 190 } 191 192 return( pop ); 193 } 194 /* 195 ======================================================================== 196 */ 197 int PoPs_numberOfParticle( void ) { 198 199 return( popsRoot.numberOfParticles ); 200 } 201 /* 202 ======================================================================== 203 */ 204 int PoPs_particleIndex( char const *name ) { 205 /* 206 A negative number is return if particle is not in popsRoot. Else, the Id of the real (not aliased) particle is returned. 207 */ 208 int index = PoPs_sortedParticleIndex( name ); 209 210 if( index >= 0 ) index = PoPs_particleProperIndex( popsRoot.sorted[index]->index ); 211 return( index ); 212 } 213 /* 214 ======================================================================== 215 */ 216 int PoPs_particleIndex_smr( statusMessageReporting *smr, char const *name, char const *file, int line, char const *func ) { 217 218 int index = PoPs_particleIndex( name ); 219 220 if( index < 0 ) 221 smr_setReportError( smr, NULL, file, line, func, PoPs_smr_ID, PoPs_errorToken_badName, "particle '%s' not in PoPs", name ); 222 return( index ); 223 } 224 /* 225 ======================================================================== 226 */ 227 static int PoPs_particleProperIndex( int index ) { 228 229 while( popsRoot.pops[index]->properIndex >= 0 ) index = popsRoot.pops[index]->properIndex; /* For alias particles. */ // Loop checking, 11.05.2015, T. Koi 230 return( index ); 231 } 232 /* 233 ======================================================================== 234 */ 235 static int PoPs_sortedParticleIndex( char const *name ) { 236 /* 237 If name is a particle in popsRoot, its index in the sorted list is returned; otherwise, 238 a negative number is returned. For a particle not found, its index would be -returnValue + 1 if added; 239 */ 240 int low = 0, mid, high = popsRoot.numberOfParticles, iCmp; 241 242 if( high == 0 ) return( -1 ); 243 while( ( high - low ) > 1 ) { 244 mid = ( low + high ) >> 1; 245 iCmp = strcmp( name, popsRoot.sorted[mid]->name ); 246 if( iCmp == 0 ) return( mid ); 247 if( iCmp > 0 ) { 248 low = mid; } 249 else { 250 high = mid; 251 } 252 } // Loop checking, 11.05.2015, T. Koi 253 if( high == 1 ) { /* First point is not checked as loop exits when ( high = 1 ) - ( low = 0 ) <= 1 ). */ 254 if( !strcmp( name, popsRoot.sorted[0]->name ) ) return( 0 ); /* First name is a match. */ 255 if( strcmp( name, popsRoot.sorted[0]->name ) < 0 ) return( -1 ); /* name is less than first name. */ 256 } 257 if( high < popsRoot.numberOfParticles ) { 258 if( strcmp( name, popsRoot.sorted[high]->name ) == 0 ) return( high ); 259 } 260 return( -high - 1 ); 261 } 262 /* 263 ======================================================================== 264 */ 265 double PoPs_getMassInUnitOf( statusMessageReporting *smr, char const *name, char const *unit ) { 266 267 int index = PoPs_particleIndex_smr( smr, name, __FILE__, __LINE__, __func__ ); 268 269 if( index < 0 ) return( -1. ); 270 return( PoPs_getMassInUnitOf_atIndex( smr, index, unit ) ); 271 } 272 /* 273 ======================================================================== 274 */ 275 char const *PoPs_getName_atIndex( statusMessageReporting *smr, int index ) { 276 277 if( ( index < 0 ) || ( index >= popsRoot.numberOfParticles ) ) { 278 smr_setReportError2( smr, PoPs_smr_ID, PoPs_errorToken_badIndex, "index %d not in PoPs", index ); 279 return( NULL ); 280 } 281 return( popsRoot.pops[index]->name ); 282 } 283 /* 284 ======================================================================== 285 */ 286 double PoPs_getMassInUnitOf_atIndex( statusMessageReporting *smr, int index, char const *unit ) { 287 288 double mass = -1.; 289 290 if( ( index < 0 ) || ( index >= popsRoot.numberOfParticles ) ) { 291 smr_setReportError2( smr, PoPs_smr_ID, PoPs_errorToken_badIndex, "index %d not in PoPs", index ); } 292 else { 293 mass = PoP_getMassInUnitOf( smr, popsRoot.pops[index], unit ); 294 } 295 296 return( mass ); 297 } 298 /* 299 ======================================================================== 300 */ 301 enum PoPs_genre PoPs_getGenre( statusMessageReporting *smr, char const *name ) { 302 303 int index = PoPs_particleIndex_smr( smr, name, __FILE__, __LINE__, __func__ ); 304 305 if( index < 0 ) return( PoPs_genre_invalid ); 306 return( popsRoot.pops[index]->genre ); 307 } 308 /* 309 ======================================================================== 310 */ 311 enum PoPs_genre PoPs_getGenre_atIndex( statusMessageReporting *smr, int index ) { 312 313 enum PoPs_genre genre = PoPs_genre_invalid; 314 315 if( ( index < 0 ) || ( index >= popsRoot.numberOfParticles ) ) { 316 smr_setReportError2( smr, PoPs_smr_ID, PoPs_errorToken_badIndex, "index %d not in PoPs", index ); } 317 else { 318 genre = popsRoot.pops[index]->genre; 319 } 320 return( genre ); 321 } 322 /* 323 ======================================================================== 324 */ 325 int PoPs_getZ_A_l( statusMessageReporting *smr, char const *name, int *Z, int *A, int *l ) { 326 327 int index = PoPs_particleIndex_smr( smr, name, __FILE__, __LINE__, __func__ ); 328 329 if( index < 0 ) return( -1 ); 330 return( PoPs_getZ_A_l_atIndex( smr, index, Z, A, l ) ); 331 } 332 /* 333 ======================================================================== 334 */ 335 int PoPs_getZ_A_l_atIndex( statusMessageReporting *smr, int index, int *Z, int *A, int *l ) { 336 337 if( ( index < 0 ) || ( index >= popsRoot.numberOfParticles ) ) { 338 smr_setReportError2( smr, PoPs_smr_ID, PoPs_errorToken_badIndex, "index %d not in PoPs", index ); 339 return( -1 ); 340 } 341 *Z = popsRoot.pops[index]->Z; 342 *A = popsRoot.pops[index]->A; 343 *l = 0; 344 return( 0 ); 345 } 346 /* 347 ======================================================================== 348 */ 349 int PoPs_hasNucleus( statusMessageReporting *smr, char const *name, int protonIsNucleus ) { 350 351 int index = PoPs_particleIndex_smr( smr, name, __FILE__, __LINE__, __func__ ); 352 353 if( index < 0 ) return( -1 ); 354 return( PoPs_hasNucleus_atIndex( smr, index, protonIsNucleus ) ); 355 } 356 /* 357 ======================================================================== 358 */ 359 int PoPs_hasNucleus_atIndex( statusMessageReporting *smr, int index, int protonIsNucleus ) { 360 /* 361 * If an error is encountered, a negative value is returned. A value greater than 0 means the particle 362 * contains a nucleus (is an atom, ion or nucleus). Otherwise, a 0 is returned. 363 */ 364 if( ( index < 0 ) || ( index >= popsRoot.numberOfParticles ) ) { 365 smr_setReportError2( smr, PoPs_smr_ID, PoPs_errorToken_badIndex, "index %d not in PoPs", index ); 366 return( -1 ); 367 } 368 if( ( popsRoot.pops[index]->genre == PoPs_genre_nucleus ) || ( popsRoot.pops[index]->genre == PoPs_genre_atom ) ) return( 1 ); 369 if( protonIsNucleus ) { 370 if( strcmp( "p", popsRoot.pops[index]->name ) == 0 ) return( 1 ); 371 } 372 return( 0 ); 373 } 374 /* 375 ======================================================================== 376 */ 377 char const *PoPs_getAtomsName( statusMessageReporting *smr, char const *name ) { 378 379 int index = PoPs_particleIndex_smr( smr, name, __FILE__, __LINE__, __func__ ); 380 381 if( index < 0 ) return( NULL ); 382 return( PoPs_getAtomsName_atIndex( smr, index ) ); 383 } 384 /* 385 ======================================================================== 386 */ 387 char const *PoPs_getAtomsName_atIndex( statusMessageReporting *smr, int index ) { 388 389 int atomIndex = PoPs_getAtomsIndex_atIndex( smr, index ); 390 391 if( atomIndex < 0 ) return( NULL ); 392 return( popsRoot.pops[atomIndex]->name ); 393 } 394 /* 395 ======================================================================== 396 */ 397 int PoPs_getAtomsIndex( statusMessageReporting *smr, char const *name ) { 398 399 int index = PoPs_particleIndex_smr( smr, name, __FILE__, __LINE__, __func__ ); 400 401 if( index < 0 ) return( index ); 402 return( PoPs_getAtomsIndex_atIndex( smr, index ) ); 403 } 404 /* 405 ======================================================================== 406 */ 407 int PoPs_getAtomsIndex_atIndex( statusMessageReporting *smr, int index ) { 408 409 char const *p = NULL; 410 411 if( ( index < 0 ) || ( index >= popsRoot.numberOfParticles ) ) { 412 smr_setReportError2( smr, PoPs_smr_ID, PoPs_errorToken_badIndex, "index %d not in PoPs", index ); 413 return( -1 ); 414 } 415 416 if( popsRoot.pops[index]->genre == PoPs_genre_atom ) return( index ); 417 418 if( strcmp( "p", popsRoot.pops[index]->name ) == 0 ) { 419 p = "H1"; } 420 else { 421 if( popsRoot.pops[index]->genre != PoPs_genre_nucleus ) return( -1 ); 422 else if( strcmp( "h2", popsRoot.pops[index]->name ) == 0 ) { 423 p = "H2"; } 424 else if( strcmp( "h3", popsRoot.pops[index]->name ) == 0 ) { 425 p = "H3"; } 426 else if( strcmp( "he3", popsRoot.pops[index]->name ) == 0 ) { 427 p = "He3"; } 428 else if( strcmp( "he4", popsRoot.pops[index]->name ) == 0 ) { 429 p = "He4"; 430 } 431 } 432 if( p != NULL ) return( PoPs_particleIndex_smr( smr, p, __FILE__, __LINE__, __func__ ) ); 433 return( -1 ); 434 } 435 /* 436 ======================================================================== 437 */ 438 PoP *PoPs_getParticle_atIndex( int index ) { 439 440 if( ( index < 0 ) || ( index >= popsRoot.numberOfParticles ) ) return( NULL ); 441 return( popsRoot.pops[index] ); 442 } 443 /* 444 ======================================================================== 445 */ 446 char const *PoPs_genreTokenToString( enum PoPs_genre genre ) { 447 448 if( genre < PoPs_genre_invalid ) return( NULL ); 449 if( genre > PoPs_genre_atom ) return( NULL ); 450 return( PoPs_genreStrings[genre] ); 451 } 452 /* 453 ======================================================================== 454 */ 455 void PoPs_print( int sorted ) { 456 457 PoPs_write( stdout, sorted ); 458 } 459 /* 460 ======================================================================== 461 */ 462 void PoPs_write( FILE *f, int sorted ) { 463 464 int i1, properIndex; 465 PoP *pop; 466 467 fprintf( f, "Mass units: number of units = %d\n", unitsRoot.numberOfUnits ); 468 for( i1 = 0; i1 < unitsRoot.numberOfUnits; i1++ ) { 469 fprintf( f, " %s", unitsRoot.unsorted[i1] ); 470 } 471 fprintf( f, "\n\n" ); 472 fprintf( f, "Particles: number of particles = %d\n", popsRoot.numberOfParticles ); 473 fprintf( f, " name index genre mass hasNucleus alias info\n" ); 474 fprintf( f, " Z A l\n" ); 475 fprintf( f, " --------------------------------------------------------------------------------------------\n" ); 476 for( i1 = 0; i1 < popsRoot.numberOfParticles; i1++ ) { 477 if( sorted ) { 478 pop = popsRoot.sorted[i1]; } 479 else { 480 pop = popsRoot.pops[i1]; 481 } 482 properIndex = PoPs_particleProperIndex( pop->index ); 483 fprintf( f, " %-24s %6d %-10s %15.8e %-6s", pop->name, pop->index, PoPs_genreTokenToString( pop->genre ), 484 popsRoot.pops[properIndex]->mass, popsRoot.pops[properIndex]->massUnit ); 485 if( PoPs_hasNucleus( NULL, pop->name, 0 ) ) { 486 fprintf( f, " T" ); } 487 else { 488 fprintf( f, " " ); 489 } 490 if( PoPs_hasNucleus( NULL, pop->name, 1 ) ) { 491 fprintf( f, " T" ); } 492 else { 493 fprintf( f, " " ); 494 } 495 if( pop->Z + pop->A > 0 ) { 496 fprintf( f, " %3d %3d", pop->Z, pop->A ); 497 if( pop->l > 0 ) { 498 fprintf( f, " %d", pop->l ); } 499 else { 500 fprintf( f, " " ); 501 } } 502 else { 503 fprintf( f, " " ); 504 } 505 if( pop->genre == PoPs_genre_alias ) { 506 fprintf( f, " %s (%d)", popsRoot.pops[properIndex]->name, popsRoot.pops[properIndex]->index ); } 507 else { 508 int aliasIndex; 509 510 for( aliasIndex = pop->aliasIndex; aliasIndex >= 0; aliasIndex = popsRoot.pops[aliasIndex]->aliasIndex ) fprintf( f, " %d", aliasIndex ); 511 } 512 fprintf( f, "\n" ); 513 } 514 } 515 516 /* 517 ========================== PoP functions ========================== 518 */ 519 /* 520 ======================================================================== 521 */ 522 PoP *PoP_new( statusMessageReporting *smr ) { 523 524 PoP *pop; 525 526 if( ( pop = (PoP *) smr_malloc2( smr, sizeof( PoP ), 0, "pop" ) ) == NULL ) return( NULL ); 527 if( PoP_initialize( smr, pop ) != 0 ) pop = PoP_free( pop ); 528 return( pop ); 529 } 530 /* 531 ======================================================================== 532 */ 533 int PoP_initialize( statusMessageReporting * /*smr*/, PoP *pop ) { 534 535 pop->index = -1; 536 pop->properIndex = -1; 537 pop->aliasIndex = -1; 538 pop->genre = PoPs_genre_unknown; 539 pop->name = NULL; 540 pop->Z = 0; 541 pop->A = 0; 542 pop->mass = 0.0; 543 pop->massUnit = NULL; 544 return( 0 ); 545 } 546 /* 547 ======================================================================== 548 */ 549 int PoP_release( PoP *pop ) { 550 551 if( pop->name != NULL ) smr_freeMemory( (void **) &(pop->name ) ); 552 PoP_initialize( NULL, pop ); /* Make it clean in case someone trys to use if. */ 553 return( 0 ); 554 } 555 /* 556 ======================================================================== 557 */ 558 PoP *PoP_free( PoP *pop ) { 559 560 PoP_release( pop ); 561 smr_freeMemory( (void **) &pop ); 562 return( NULL ); 563 } 564 /* 565 ======================================================================== 566 */ 567 int PoP_copyParticle( statusMessageReporting *smr, PoP *desc, PoP *src ) { 568 569 desc->index = -1; 570 desc->properIndex = src->properIndex; 571 desc->aliasIndex = src->aliasIndex; 572 desc->genre = src->genre; 573 if( ( desc->name = smr_allocateCopyString2( smr, src->name, "desc->name" ) ) == NULL ) return( 1 ); 574 desc->Z = src->Z; 575 desc->A = src->A; 576 desc->l = src->l; 577 desc->mass = src->mass; 578 desc->massUnit = src->massUnit; 579 580 return( 0 ); 581 } 582 /* 583 ======================================================================== 584 */ 585 PoP *PoP_makeParticle( statusMessageReporting *smr, enum PoPs_genre genre, char const *name, double mass, char const *massUnit ) { 586 587 PoP *pop; 588 589 if( ( pop = PoP_new( smr ) ) == NULL ) return( NULL ); 590 if( ( pop->name = smr_allocateCopyString2( smr, name, "name" ) ) == NULL ) { 591 PoP_free( pop ); 592 return( NULL ); 593 } 594 pop->genre = genre; 595 pop->mass = mass; 596 if( ( pop->massUnit = unitsDB_addUnitIfNeeded( smr, massUnit ) ) == NULL ) pop = PoP_free( pop ); 597 return( pop ); 598 } 599 /* 600 ======================================================================== 601 */ 602 int PoP_setZ_A_l( statusMessageReporting * /*smr*/, PoP *pop, int Z, int A, int l ) { 603 604 pop->Z = Z; 605 pop->A = A; 606 pop->l = l; 607 return( 0 ); 608 } 609 /* 610 ======================================================================== 611 */ 612 int PoP_getIndex( PoP *pop ) { 613 614 return( pop->index ); 615 } 616 /* 617 ======================================================================== 618 */ 619 char const *PoP_getName( PoP *pop ) { 620 621 return( pop->name ); 622 } 623 /* 624 ======================================================================== 625 */ 626 double PoP_getMassInUnitOf( statusMessageReporting *smr, PoP *pop, char const *unit ) { 627 628 double mass = -1., ratio; 629 /* PoP *pop_ = pop;*/ 630 631 /*if( pop->genre == PoPs_genre_alias ) pop_ = popsRoot.pops[PoPs_particleProperIndex( pop->index )];*/ 632 if( PoPs_unitConversionRatio( pop->massUnit, unit, &ratio ) != 0 ) { 633 smr_setReportError2( smr, PoPs_smr_ID, PoPs_errorToken_badUnitConversion, "could not convert unit '%s' to '%s'", pop->massUnit, unit ); } 634 else { 635 mass = pop->mass * ratio; 636 } 637 638 return( mass ); 639 } 640 641 /* 642 ========================== alias functions ========================== 643 */ 644 /* 645 ======================================================================== 646 */ 647 PoP *PoP_makeAlias( statusMessageReporting *smr, char const *name, char const *alias ) { 648 649 int properIndex = PoPs_particleIndex( name ), aliasIndex = PoPs_particleIndex( alias ); 650 PoP *pop; 651 652 if( properIndex < 0 ) { 653 smr_setReportError2( smr, PoPs_smr_ID, PoPs_errorToken_badName, "proper particle '%s' not in PoPs for alias '%s'", name, alias ); 654 return( NULL ); 655 } 656 if( aliasIndex >= 0 ) { /* alias has already been defined. */ 657 PoP *truePop = popsRoot.pops[aliasIndex]; 658 659 for( pop = truePop; strcmp( alias, pop->name ); pop = popsRoot.pops[aliasIndex] ) aliasIndex = pop->aliasIndex; 660 if( pop->genre != PoPs_genre_alias ) { 661 smr_setReportError2( smr, PoPs_smr_ID, PoPs_errorToken_badName, "particle '%s' already in PoPs and not an alias", alias ); 662 return( NULL ); 663 } 664 if( pop->properIndex != properIndex ) { 665 smr_setReportError2( smr, PoPs_smr_ID, PoPs_errorToken_badName, "particle '%s' already an alias for '%s', cannot re-alias to '%s'", 666 alias, truePop->name, name ); 667 return( NULL ); 668 } } 669 else { 670 if( ( pop = PoP_new( smr ) ) == NULL ) return( NULL ); 671 if( ( pop->name = smr_allocateCopyString2( smr, alias, "name" ) ) == NULL ) { 672 PoP_free( pop ); 673 return( NULL ); 674 } 675 pop->properIndex = properIndex; 676 pop->genre = PoPs_genre_alias; 677 } 678 return( pop ); 679 } 680 681 /* 682 ========================== unitsDB functions ========================= 683 */ 684 /* 685 ======================================================================== 686 */ 687 static int unitsDB_release( void ) { 688 689 int i; 690 691 for( i = 0; i < unitsRoot.numberOfUnits; i++ ) smr_freeMemory( (void **) &(unitsRoot.unsorted[i]) ); 692 smr_freeMemory( (void **) &(unitsRoot.unsorted) ); 693 unitsRoot.numberOfUnits = 0; 694 unitsRoot.allocated = 0; 695 return( 0 ); 696 } 697 /* 698 ======================================================================== 699 */ 700 char const *unitsDB_addUnitIfNeeded( statusMessageReporting *smr, char const *unit ) { 701 702 int i; 703 704 for( i = 0; i < unitsRoot.numberOfUnits; i++ ) { 705 if( strcmp( unit, unitsRoot.unsorted[i] ) == 0 ) return( unitsRoot.unsorted[i] ); 706 } 707 if( unitsRoot.numberOfUnits == unitsRoot.allocated ) { 708 int size = unitsRoot.allocated + 20; 709 char const **unsorted = (char const **) smr_malloc2( smr, size * sizeof( char * ), 0, "unsorted" ); 710 711 if( unsorted == NULL ) return( NULL ); 712 for( i = 0; i < unitsRoot.numberOfUnits; i++ ) unsorted[i] = unitsRoot.unsorted[i]; 713 smr_freeMemory( (void **) &(unitsRoot.unsorted) ); 714 unitsRoot.unsorted = unsorted; 715 unitsRoot.allocated = size; 716 } 717 if( ( unitsRoot.unsorted[unitsRoot.numberOfUnits] = smr_allocateCopyString2( smr, unit, "unitsRoot.unsorted[unitsRoot.numberOfUnits]" ) ) == NULL ) 718 return( NULL ); 719 unitsRoot.numberOfUnits++; 720 return( unitsRoot.unsorted[unitsRoot.numberOfUnits - 1] ); 721 } 722 /* 723 ======================================================================== 724 */ 725 int unitsDB_index( statusMessageReporting * /*smr*/, char const *unit ) { 726 727 int i; 728 729 for( i = 0; i < unitsRoot.numberOfUnits; i++ ) { 730 if( !strcmp( unit, unitsRoot.unsorted[i] ) ) return( i ); 731 } 732 return( -1 ); 733 } 734 /* 735 ======================================================================== 736 */ 737 char const *unitsDB_stringFromIndex( statusMessageReporting *smr, int index ) { 738 739 if( ( index < 0 ) || ( index >= unitsRoot.numberOfUnits ) ) { 740 smr_setReportError2( smr, PoPs_smr_ID, 1, "index = %d out of baounds [0 to %d)", index, unitsRoot.numberOfUnits ); 741 return( NULL ); 742 } 743 return( unitsRoot.unsorted[index] ); 744 } 745 /* 746 ======================================================================== 747 */ 748 int PoPs_unitConversionRatio( char const *_from, char const *_to, double *ratio ) { 749 750 int i, n = sizeof( conversions ) / sizeof( conversions[0] ); 751 752 *ratio = 1.; 753 if( strcmp( _from, _to ) == 0 ) return( 0 ); 754 for( i = 0; i < n; i++ ) { 755 if( strcmp( conversions[i]._from, _from ) == 0 ) { 756 if( strcmp( conversions[i]._to, _to ) == 0 ) { 757 *ratio = conversions[i].ratio; 758 return( 0 ); 759 } } 760 else if( strcmp( conversions[i]._to, _from ) == 0 ) { 761 if( strcmp( conversions[i]._from, _to ) == 0 ) { 762 *ratio = 1. / conversions[i].ratio; 763 return( 0 ); 764 } 765 } 766 } 767 return( 1 ); 768 } 769 #ifdef PoPs_MPI 770 #include "PoPs_Bcast_private.h" 771 /* 772 ======================================================================== 773 */ 774 int PoPs_Bcast( statusMessageReporting *smr, MPI_Comm comm, int rank ) { 775 776 return( PoPs_Bcast2( smr, comm, rank, &unitsRoot, &popsRoot ) ); 777 } 778 #endif 779 780 #if defined __cplusplus 781 } 782 #endif 783