ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PoPs.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PoPs.cc
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 
28 
30  char const *_from;
31  char const *_to;
32  double ratio;
33 };
34 
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 ) sprintf( 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 ); }
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 */
89 
91  if( referenceCount != 0 ) return( referenceCount );
92  PoPs_releasePrivate( smr );
93  return( 0 );
94 }
95 /*
96 ========================================================================
97 */
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;
106  popsRoot.allocated = 0;
107  unitsDB_release( );
108  return( 0 );
109 }
110 /*
111 ========================================================================
112 */
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 )] );
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  }
137  index = -index - 1;
138  for( i = popsRoot.numberOfParticles; i > index; i-- ) popsRoot.sorted[i] = popsRoot.sorted[i-1];
139  popsRoot.sorted[index] = pop;
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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) );
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  }
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 );
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