Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/hadronic/models/lend/src/PoPs.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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