5 from .nucleus_class
import nucleus
8 import matplotlib.pyplot
as plt
19 Analyze a rate file for a given path.
21 path - path to reaclib file
22 quiet - Do you want to have status informations of the progress?
25 pd.options.mode.chained_assignment =
None
27 warnings.filterwarnings(
'error')
35 self.
__column_names = [
'chapter',
'reactants',
'products',
'label',
'type',
'reverse',
'q value',
'error',
'reaction type'] + [
'a'+str(i)
for i
in range(7)]
56 read the whole reaclib file.
59 read1 =
lambda x : ([x[0]] , [x[1]])
60 read2 =
lambda x : ([x[0]] , [x[1],x[2]])
61 read3 =
lambda x : ([x[0]] , [x[1],x[2],x[3]])
if (len([a
for a
in x
if a !=
'']) == 4
or (
not self.
__format == 1))
else ([x[0]] , [x[1],x[2],x[3],x[4]])
62 read4 =
lambda x : ([x[0],x[1]] , [x[2]])
63 read5 =
lambda x : ([x[0],x[1]] , [x[2],x[3]])
64 read6 =
lambda x : ([x[0],x[1]] , [x[2],x[3],x[4]])
65 read7 =
lambda x : ([x[0],x[1]] , [x[2],x[3],x[4],x[5]])
66 read8 =
lambda x : ([x[0],x[1],x[2]] , [x[3]])
if (len([a
for a
in x
if a !=
'']) == 4
or (
not self.
__format == 1))
else ([x[0],x[1],x[2]] , [x[3],x[4]])
67 read9 =
lambda x : ([x[0],x[1],x[2]] , [x[3],x[4]])
68 read10 =
lambda x : ([x[0],x[1],x[2],x[3]] , [x[4],x[5]])
69 read11 =
lambda x : ([x[0]] , [x[1],x[2],x[3],x[4]])
72 r_parser = {1 : read1, 2 : read2, 3 : read3, 4 : read4, 5 : read5,
73 6 : read6, 7 : read7, 8 : read8, 9 : read9, 10 : read10,
79 with open(self.
__path,
'r')
as reaclib_file:
82 for line
in reaclib_file.readlines():
84 if not self.
__quiet and (count % 1000 == 0):
85 print(
'Reading line ' +str(count) +
" ",end=
'\r')
88 if line.strip().isdigit():
89 chapter = int(line.strip())
93 if line.strip() ==
'':
100 reactants, products = r_parser[chapter](involved)
103 label = line[loc:loc+self.
__lc]
105 r_type = line[loc:loc+1]
107 r_reverse = (line[loc:loc+1] ==
'v')
109 r_qval = float(line[loc:loc+12].replace(
'D',
'e').replace(
'd',
'e'))
112 error =
'Not matching its chapter!'
116 a_factors = [line[i:i+self.
__cpe]
for i
in range(0, 4*self.
__cpe, self.
__cpe)]
119 a_factors.extend([line[i:i+self.
__cpe]
for i
in range(0, 3*self.
__cpe, self.
__cpe)])
121 a_factors = [float(x.replace(
'D',
'e').replace(
'd',
'e'))
for x
in a_factors]
123 error =
'Fitting value is not a float!'
125 reaction_type = self.
__classify_reaction(chapter,reactants,products,r_type,label,a_factors)
129 reactants = sorted(reactants)
130 products = sorted(products)
132 rate_data = [chapter,reactants,products,label,r_type,r_reverse,r_qval,error,reaction_type]
133 rate_data.extend(a_factors)
135 reaclib_data.append(rate_data)
140 print(
'Reading line ' +str(count) +
" ")
152 Reset the reaclib to the loaded one.
160 Classify a reaction if it is gamma-n, n-gamma, ...
162 chapter - reaclib chapter of the reaction (int)
163 reactants - all reactants of the reaction (list of strings)
164 products - all products of the reaction (list of strings)
165 weak - 'w' if weak, else ''
166 label - reaction label to identify fission rates
167 afactors - check whether a rate is constant in dependence of the temperature
169 Returns a string, containing the type of reaction
174 reaction_type =
'fission'
176 elif (chapter == 2)
and (
'he4' in products)
and (sum(afactors[1:])==0):
177 reaction_type =
'a-decay'
179 elif weak.strip() ==
'w':
180 reaction_type =
'weak'
182 elif (chapter == 4)
and (
'n' in reactants):
183 reaction_type =
'n-gamma'
185 elif (chapter == 2)
and (
'n' in products):
186 reaction_type =
'gamma-n'
188 elif (chapter == 4)
and (
'p' in reactants):
189 reaction_type =
'p-gamma'
191 elif (chapter == 2)
and (
'p' in products):
192 reaction_type =
'gamma-p'
194 elif (chapter == 4)
and (
'he4' in reactants):
195 reaction_type =
'a-gamma'
197 elif (chapter == 2)
and (
'he4' in products)
and (sum(afactors[1:])!=0):
198 reaction_type =
'gamma-a'
200 elif (chapter == 5)
and (
'n' in reactants)
and (
'p' in products):
201 reaction_type =
'n-p'
203 elif (chapter == 5)
and (
'p' in reactants)
and (
'n' in products):
204 reaction_type =
'p-n'
206 elif (chapter == 5)
and (
'n' in reactants)
and (
'he4' in products):
207 reaction_type =
'n-a'
209 elif (chapter == 5)
and (
'he4' in reactants)
and (
'n' in products):
210 reaction_type =
'a-n'
212 elif (chapter == 5)
and (
'p' in reactants)
and (
'he4' in products):
213 reaction_type =
'p-a'
215 elif (chapter == 5)
and (
'he4' in reactants)
and (
'p' in products):
216 reaction_type =
'a-p'
218 reaction_type =
'other'
224 Get the amount of different rate types (n-gamma, gamma-n, weak ,alpha-n,...)
226 Returns a pandas series, containing the counts of the different reaction types and the total number of reactions
229 return (pd.value_counts(self.
__pd_reaclib[
'reaction type'].values).append(pd.Series({
'Total reactions' :self.
__pd_reaclib.count()[0]})))
234 Set the dataframe (containing all reactions) of the class with the given one
241 Returns the value of the rate for a given temperature
243 temperature - Temperature [GK]
244 coefficients - The 7 fit coefficients from the reaclib format
247 exponent = coefficients[0] + coefficients[6] * np.log(temperature)
250 exponent += coefficients[i+1]*temperature**((2.*(i+1)-5.)/3.)
253 rate = np.exp(exponent)
254 except RuntimeWarning:
258 def test_reaclib(self, test_weak=True, test_mass=True, test_overflow=True):
260 Test the reaclib for failures
267 if not self.
__quiet and (index % 100 == 0):
268 percentage = str(int((index+1.)/total_reactions * 10000.) / 100.).ljust(4)
269 print(
'Running tests: '+percentage.ljust(4) +
" done! ",end=
'\r')
272 if row[
'error'] !=
'':
282 self.
__pd_reaclib[
'error'].iloc[index] =
'Weak rate is not consistent!'
288 self.
__pd_reaclib[
'error'].iloc[index] =
'Mass inconsistency of the rate!'
298 print(
'Running tests: 100 done! ')
303 Get all nuclei contained in reaclib file.
305 list of strings, containing the names of all nuclei contained in the reaclib
307 flatten =
lambda l: [item
for sublist
in l
for item
in sublist]
311 return list(set(flatten(prods)))
315 Test if nuclei are included in the net file, but not in the reaclib. Be careful, reaclib contains nuclei where you are trapped in.
316 There are reactions producing that nuclei, but no reaction to destroy it. (e.g. "f16" in the 2017 version of reaclib)
318 path - path to net file of WinNet
320 list of strings, containing problematic nuclei. If all nuclei have a corresponding reaction, an empty list is returned
323 sunet_nucs = np.loadtxt(path,unpack=
True,dtype=str)
329 for nuc
in sunet_nucs:
330 if nuc
not in reaction_nucs:
331 problem_nuc.append(nuc)
337 Test the reaction rate for overflows!
340 reactants = list(row[
'reactants'])
341 products = list(row[
'products'])
344 reactants_A = [
nucleus(x).get_A()
for x
in reactants]
345 products_A = [
nucleus(x).get_A()
for x
in products]
347 if sum(reactants_A) != sum(products_A):
354 Test the reaction rate for overflows!
357 coefficients = list(row[
'a0':
'a6'])
359 if upper_lim
is None:
361 if temp_range
is None:
374 Test the reaction for consistency
377 reactants = list(row[
'reactants'])
378 products = list(row[
'products'])
381 reactants_Z = [
nucleus(x).get_Z()
for x
in reactants]
382 products_Z = [
nucleus(x).get_Z()
for x
in products]
384 if (row[
'reaction type'].strip() ==
'a-decay'):
387 if sum(reactants_Z) == sum(products_Z):
394 Get a reaction rate at given temperature
396 temperature - Temperature [GK]
397 reactants - list with reactants
398 products - list with products
400 Reaction rate at a given temperature
404 reactions = matching_reactants[[x == sorted(products)
for x
in matching_reactants.products.values]]
408 for index, row
in reactions.iterrows():
415 def plot_rate(self,reactants,products,figure=None,axlabel=True,temp_grid=None,**kwargs):
419 reactants - list of reactants (list of strings)
420 products - list of products (list of strings)
424 final_fig = plt.figure()
432 if temp_grid
is None:
437 ax.plot(temp_grid,rat_list,**kwargs)
440 ax.set_xlabel(
'Temperature [GK]')
441 ax.set_ylabel(
'Rate')
450 Get a list with all rates that produce errors
457 Get an html file with all rates that contain an error
459 path - Path to the html file that will be created
468 Convert a pandas series to a reaclib string.
470 series - pandas series of one reaction
473 clean_copy = series.copy()
474 merged_nuclei = list(clean_copy[
'reactants'])
475 merged_nuclei.extend(list(clean_copy[
'products']))
477 merged_nuclei = [x.rjust(5)
for x
in merged_nuclei]
479 if series[
'reverse']:
484 five_spaces = 5 *
' '
488 out = five_spaces +
''.join(merged_nuclei) +(6-len(merged_nuclei)) * five_spaces + 8*
' '+series[
'label'].ljust(4) + series[
'type'].ljust(1) + reverse + \
489 3*
' ' +
'%12.5e' % (series[
'q value']) + 10*
' '
493 out +=
''.join([
'%13.6e' % x
for x
in series[
'a0':
'a3']])+ 22*
' '
497 out +=
''.join([
'%13.6e' % x
for x
in series[
'a4':
'a6']])+ 35*
' '
503 Sort the products and reactants of a given dataframe.
504 A nucleus is greater if it has an higher proton number
506 helplist = [
nucleus(x)
for x
in in_list]
507 helplist = [x.get_input_name()
for x
in sorted(helplist)]
514 Save the pandas dataframe to a reaclib file with the correct format.
516 filename - Filename of the output.
517 dataframe - Pandas dataframe that contains reaction rates. If none, the reaction rates of the class are used
522 if dataframe
is None:
525 input_reaclib = dataframe.copy()
528 amount_reactions = input_reaclib.count()[0]
530 pd.set_option(
'display.max_colwidth', -1)
535 print(
"Sorting database. This may take a while!")
536 print(
"Sorting products.")
540 print(
"Sorting reactants.")
541 input_reaclib[
'reactants'] = input_reaclib[
'reactants'].apply(self.
__sort_prods_reacs)
543 input_reaclib[
'Z'] = input_reaclib[
'reactants'].apply(
lambda x:
nucleus(x[0]).get_Z() )
544 input_reaclib[
'A'] = input_reaclib[
'reactants'].apply(
lambda x:
nucleus(x[0]).get_A() )
545 input_reaclib.sort_values([
'Z',
'A'],inplace=
True)
551 print(
'Saving reaclib to file.')
552 print(
'Creating correct format, this may take a while.')
557 print(
'Saving chapterwise.')
560 max_chapter = input_reaclib[
'chapter'].max()
563 if not isinstance(max_chapter,int):
565 print(
'Warning: Chapter was not an integer, it was '+str(max_chapter)+
' instead!')
568 for i
in range(1,int(max_chapter)+1):
570 print(
'Saving chapter '+str(i)+
' of '+str(max_chapter)+
'. ',end=
'\r')
573 reaclib_out += str(i) +
'\n\n\n'
575 tmp = (input_reaclib[input_reaclib[
'chapter']==i])
576 reaclib_out +=(
''.join(tmp[
'tmp_out'].values))
579 print(
'Saving to file. ')
582 with open(filename,
'w')
as f_out:
583 f_out.write(reaclib_out)
586 del input_reaclib[
'tmp_out']
591 Get rates that are critical for low temperatures (< 1e-2 GK)
593 temp_points = np.logspace(np.log10(min_temperature),-2,num=amount_points)
598 problematic_index = []
604 if not self.
__quiet and (index % 100 == 0):
605 percentage = str(int((index+1.)/total_reactions * 10000.) / 100.).ljust(4)
606 print(
'Get critical rates: '+percentage.ljust(4) +
" done! ",end=
'\r')
610 problematic_index.append(index)
614 print(
'Running tests: 100 done! ')
615 problematic_index = np.array(problematic_index)
622 Drop errors from dataframe. Need to run test_reaclib() first
627 print(
'Dropped '+str(amount_errors)+
' rates.')
634 Returns the pandas dataframe, containing all reactions (after applying a filter) of the reaclib
636 reaction_type - only these reaction types (n-gamma,..), none for dont filter the type (list of strings or string)
637 chapter - only these chapters , none for dont filter the chapter (list of integers or integer)
644 Analyze a dataframe that contains the column "version".
646 Returns the amount of new inserted rates
649 count = pd.value_counts(dataframe[
'version'].values)
650 if 'new' in count.index:
651 new_count = count[
'new']
655 if 'old' in count.index:
656 old_count = count[
'old']
663 Get all types of reactions, necessary to write in "reaction_type" when filtering rates
665 List of strings, containing the possible reaction types
668 return (list(types.index)[:-1])
673 Is the rate included in the dataframe? Compared are only products and reactants.
674 Returns true if yes, false if not
678 reactants = series[
'reactants']
679 products = series[
'products']
682 rates = chapter_reactions[[r
in x
for x
in chapter_reactions[
'reactants']]]
686 rates = rates[[p
in x
for x
in rates[
'products']]]
698 Filter the reaction rates by type and chapter.
700 dataframe - Pandas dataframe that contains all reactions
701 reaction_type - only these reaction types (n-gamma,..), none for dont filter the type (list of strings or string)
702 chapter - only these chapters , none for dont filter the chapter (list of integers or integer)
704 Filtered dataframe, that contains only the reactions with given type and chapter
707 if isinstance(reaction_type,str):
708 reaction_type=[reaction_type]
709 if isinstance(chapter,int):
714 if reaction_type !=
None and chapter !=
None:
715 dataframe = dataframe[dataframe[
'chapter'].isin(chapter) & dataframe[
'reaction type'].isin(reaction_type)]
717 elif reaction_type ==
None and chapter !=
None:
718 dataframe = dataframe[dataframe[
'chapter'].isin(chapter)]
720 elif reaction_type !=
None and chapter ==
None:
721 dataframe = dataframe[dataframe[
'reaction type'].isin(reaction_type)]
726 def update(self,reaclib_path=None,dataframe=None,reaction_type=None,chapter=None,ignore_label=False,ignore_reverse=False,ignore_type=False,replace_specific_label=None):
728 Update the reaclib with rates from other reaclib. Dont include new rates in the file. Both reaclibs have to be in the "old version" (without chapter 9-10) or in the
729 "new version", with these chapters.
731 reaclib_path - path of the reaclib that contains new rates
732 dataframe - pandas dataframe that contains reactions. If this is given, you don't have to give a reaclib_path.
733 reaction_type - Reaction type that will be updated (string or list of strings), for possible values see ".get_statistics()"
734 chapter - Chapter that will be updated (list of integer or integer)
735 ignore_label - ignore the label for updating and only look at the reactions itself
736 ignore_reverse - ignore if the reaction is reverse
737 ignore_type - ignore the type
738 replace_specific_label- Should one specific label be replaced. E.g. Moeller 93 with Moeller 03 rates. For a list of the Jina labels see https://groups.nscl.msu.edu/jina/reaclib/db/labels.php
739 if yes, the input should be a list with [old label, new label]
744 if (
'new' in x)
and (
'old' in x):
747 if (
'new' in x)
and not (
'old' in x):
750 if not (
'new' in x)
and (
'old' in x):
754 print(
'Updating reaclib.')
758 if reaclib_path
is not None and dataframe
is None:
760 new_rates =
reaclib(reaclib_path,quiet=
True)
761 new_rates.read_reaclib()
762 new_rates_df = new_rates.get_dataframe()
764 elif reaclib_path
is None and dataframe
is not None:
765 new_rates_df = dataframe
767 elif reaclib_path
is None and dataframe
is None:
768 raise Exception(
'Pass either a path of a reaclib or a pandas dataframe.')
770 elif reaclib_path
is not None and dataframe
is not None:
771 raise Exception(
'Too much input. Pass either reaclib_path or pandas dataframe.')
774 new_rates_df= self.
__filter_rates(new_rates_df,reaction_type,chapter)
777 if not replace_specific_label
is None:
778 oldlabel = replace_specific_label[0]
779 newlabel = replace_specific_label[1]
787 reactant_string = new_rates_df[
'reactants'].apply(
lambda x:
''.join(x))
788 product_string = new_rates_df[
'products'].apply(
lambda x:
''.join(x))
790 new_rates_df[
'sort_string'] = new_rates_df[
'chapter'].astype(str) + reactant_string + product_string
793 if not replace_specific_label
is None:
794 new_rates_df.loc[new_rates_df[
'label']==newlabel,
'sort_string'] +=
'totaldummylabel'
795 new_rates_df.loc[new_rates_df[
'label']!=newlabel,
'sort_string'] +=
'dontreplacethis'
797 new_rates_df[
'sort_string'] += new_rates_df[
'label']
798 if not ignore_reverse:
799 new_rates_df[
'sort_string'] += new_rates_df[
'reverse'].astype(str)
801 new_rates_df[
'sort_string'] += new_rates_df[
'type'].astype(str)
803 new_rates_df[
'version'] =
'new'
807 reactant_string = self.
__pd_reaclib[
'reactants'].apply(
lambda x:
''.join(x))
808 product_string = self.
__pd_reaclib[
'products'].apply(
lambda x:
''.join(x))
814 if not replace_specific_label
is None:
818 if not ignore_reverse:
826 merged_frame = pd.concat(frames)
829 category = merged_frame.groupby(merged_frame[
'sort_string'])[
'version'].agg(
lambda col:
''.join(col)).apply(categorize)
831 merged_frame = merged_frame.join(category, on=
'sort_string',rsuffix=
'_cat')
833 self.
__pd_reaclib = merged_frame[((merged_frame[
'version'] ==
'old') & (merged_frame[
'version_cat'] == 3)) | ((merged_frame[
'version'] ==
'new') & (merged_frame[
'version_cat'] == 1))]
837 print(
'Updated '+str(new_rates_count)+
' rates.')
838 print(
'Updating done!')
841 if not replace_specific_label
is None:
851 def add_new_rates(self,reaclib_path=None,dataframe=None,reaction_type=None,chapter=None,ignore_label=True,ignore_reverse=True,ignore_type=False):
853 Add new rates to existing ones
855 reaclib_path - path of the reaclib that contains new rates
856 dataframe - pandas dataframe that contains reactions. If this is given, you don't have to give a reaclib_path.
857 reaction_type - Reaction type that will be updated (string or list of strings), for possible values see ".get_statistics()"
858 chapter - Chapter that will be updated (list of integer or integer)
859 ignore_label - ignore the label for updating and only look at the reactions itself
860 ignore_reverse - ignore if the reaction is reverse
861 ignore_type - ignore the type
862 replace_specific_label- Should one specific label be replaced. E.g. Moeller 93 with Moeller 03 rates. For a list of the Jina labels see https://groups.nscl.msu.edu/jina/reaclib/db/labels.php
863 if yes, the input should be a list with [old label, new label]
868 if (
'new' in x)
and (
'old' in x):
871 if (
'new' in x)
and not (
'old' in x):
874 if not (
'new' in x)
and (
'old' in x):
878 print(
'Updating reaclib.')
882 if reaclib_path
is not None and dataframe
is None:
884 new_rates =
reaclib(reaclib_path,quiet=
True)
885 new_rates.read_reaclib()
886 new_rates_df = new_rates.get_dataframe()
888 elif reaclib_path
is None and dataframe
is not None:
889 new_rates_df = dataframe
891 elif reaclib_path
is None and dataframe
is None:
892 raise Exception(
'Pass either a path of a reaclib or a pandas dataframe.')
894 elif reaclib_path
is not None and dataframe
is not None:
895 raise Exception(
'Too much input. Pass either reaclib_path or pandas dataframe.')
898 new_rates_df= self.
__filter_rates(new_rates_df,reaction_type,chapter)
901 reactant_string = new_rates_df[
'reactants'].apply(
lambda x:
''.join(x))
902 product_string = new_rates_df[
'products'].apply(
lambda x:
''.join(x))
904 new_rates_df[
'sort_string'] = new_rates_df[
'chapter'].astype(str) + reactant_string + product_string
907 new_rates_df[
'sort_string'] += new_rates_df[
'label']
908 if not ignore_reverse:
909 new_rates_df[
'sort_string'] += new_rates_df[
'reverse'].astype(str)
911 new_rates_df[
'sort_string'] += new_rates_df[
'type'].astype(str)
913 new_rates_df[
'version'] =
'new'
916 reactant_string = self.
__pd_reaclib[
'reactants'].apply(
lambda x:
''.join(x))
917 product_string = self.
__pd_reaclib[
'products'].apply(
lambda x:
''.join(x))
923 if not ignore_reverse:
931 merged_frame = pd.concat(frames)
934 category = merged_frame.groupby(merged_frame[
'sort_string'])[
'version'].agg(
lambda col:
''.join(col)).apply(categorize)
936 merged_frame = merged_frame.join(category, on=
'sort_string',rsuffix=
'_cat')
938 self.
__pd_reaclib = merged_frame[((merged_frame[
'version'] ==
'old') & (merged_frame[
'version_cat'] == 3)) | ((merged_frame[
'version'] ==
'new') & (merged_frame[
'version_cat'] == 2))]
942 print(
'Added '+str(new_rates_count)+
' rates.')
943 print(
'Adding done!')
957 Add a given dataframe to the reaclib
964 Filter the rates with contained nuclei.
966 Contained nuclei of the network
968 def contained(a_list,ref_list=None):
970 Check if all elements of a list(a_list) are contained in another list(ref_list)
973 ref_list = nucleus_names
975 for element
in a_list:
976 if element
not in ref_list:
985 pd_dataframe[
'filter_reactants'] = pd_dataframe[
'reactants'].apply(contained)
986 pd_dataframe[
'filter_products'] = pd_dataframe[
'products'].apply(contained)
988 pd_dataframe[
'keep'] = list(map(
lambda f_reac, f_prods: f_reac
and f_prods, pd_dataframe[
'filter_reactants'], pd_dataframe[
'filter_products'] ))
989 pd_dataframe = pd_dataframe[pd_dataframe[
'keep'] ==
True]
992 del pd_dataframe[
'filter_reactants']
993 del pd_dataframe[
'filter_products']
994 del pd_dataframe[
'keep']
1005 Get a statistic which labels are involved in the database. An overview of all labels an their meaning can be found
1006 at https://groups.nscl.msu.edu/jina/reaclib/db/labels.php
1009 return (pd.value_counts(self.
__pd_reaclib[
'label'].values).append(pd.Series({
'Total reactions' :self.
__pd_reaclib.count()[0]})))
1012 if __name__ ==
'__main__':
1014 print(
'Test reaclib class')
1015 r =
reaclib(
'../testfiles/reaclib_testfiles/reaclib.Christian.121204_beta_sf',quiet=
False)
1017 print(r.get_dataframe())
1018 print(r.get_statistics())