Handling isomers produced beyond (n,n*) reactions#229
Handling isomers produced beyond (n,n*) reactions#229eitan-weinstein wants to merge 26 commits intosvalinn:mainfrom
Conversation
| """ | ||
|
|
||
| return M == 0 | ||
| return M == 0 and dKZA % 10 == 0 |
There was a problem hiding this comment.
should we have set M correctly before this in these circumstances?
There was a problem hiding this comment.
The way that we define M in reaction_data.py determines if a daughter is left in an excited state by specific emitted particle tags from the MT string formatting. However, that formatting does not account for cases where the parent is already excited, meaning the del_KZA value would calculate an excited daughter as well. M is generally parent-ambivalent, so I think I'll need to do a parent-by-parent recalculation of M at the start of the MT for loop to account for excited parents.
| _is_ground_state_nuc(rxn['isomer']) or | ||
| _is_isomer_with_decay_data(dKZA, radionucs, rxn['isomer']) | ||
| _is_ground_state_daughter(rxn['isomer'], dKZA) or | ||
| _is_isomer_with_decay_data(dKZA, pKZA, radionucs, rxn['isomer']) |
There was a problem hiding this comment.
do we care if its an isomer anymore? given this or we only care that it has decay data, right?
There was a problem hiding this comment.
I don't think we can only go decay data because then we would be excluding all stable nuclides from the standard processing and directing them incorrectly to the special isomer handling in the else block.
There was a problem hiding this comment.
But all stable nuclides are in the ground state, so they should be handled by the first condition.
I guess my point is, we've already captured all the ground state nuclides in the first condition, so we know that any nuclides we are testing must be an isomer
There was a problem hiding this comment.
Ok, I agree with what you are saying about stable nuclides all being handled by the first condition, but I'm not sure I understand what change you are requesting.
There was a problem hiding this comment.
_is_isomer_with_decay_data can just be refactored to be _has_decay_data and doesn't need to check if it's an isomer
| else: | ||
| if to_ground: | ||
| decay_KZA = f'{pKZA // 10}*' | ||
| div_KZA = pKZA if rxn['emitted'] == 'n' else dKZA |
There was a problem hiding this comment.
cant we always use dkza? for an emitted neutron, I assume pkza == dkza
There was a problem hiding this comment.
Yes, I think you're right. Although, after closer inspection, I realized the assignment of decay_KZA was reversed, based on the actual meaning of the to_ground Boolean, which I'll have updated in the next commit.
| return sigma_list[::-1] | ||
|
|
||
| def _is_ground_state_nuc(M): | ||
| def _is_ground_state_daughter(M): |
There was a problem hiding this comment.
I don't this it's correct to name this about daughters. You are only passing in M which could theoretically come from anywhere. The fact that you may only use it for daughters should not affect its name.
| _is_ground_state_nuc(rxn['isomer']) or | ||
| _is_isomer_with_decay_data(dKZA, radionucs, rxn['isomer']) | ||
| _is_ground_state_daughter(rxn['isomer'], dKZA) or | ||
| _is_isomer_with_decay_data(dKZA, pKZA, radionucs, rxn['isomer']) |
There was a problem hiding this comment.
But all stable nuclides are in the ground state, so they should be handled by the first condition.
I guess my point is, we've already captured all the ground state nuclides in the first condition, so we know that any nuclides we are testing must be an isomer
gonuke
left a comment
There was a problem hiding this comment.
continued cleanup of the isomer checking
| """ | ||
|
|
||
| return dKZA in radionucs and M in range(1,10) | ||
| return dKZA in radionucs and ((pKZA % 10) + M in range(1,10)) |
There was a problem hiding this comment.
do we still need to test the isomeric state of the parent?
There was a problem hiding this comment.
In principle, yes, although I don't know if we'd ever actually run into a case where this would come up, which would be having a parent whose excitation level is 10 and somehow still has decay data. This is obviously very unlikely to happen, given that I don't think there is decay data beyond any M=2, but technically this covers a physical case that could exist.
There was a problem hiding this comment.
But didn't we just decide that this method only cares whether there is decay data or not?
This is called in one place: to decide whether we keep the cross-section as-is or collapse it. It seems to me that we should keep all cross-sections where the daughter is ground state (you have a function for that) or where the daughter has decay data (this function). It shouldn't matter whether it's an isomer or not.
There was a problem hiding this comment.
Maybe I'm not defining the function clearly enough, but I think the problem that I am trying to address here is that the KZA arithmetic allows for the production of daughters that could appear to have decay data, but only as a result of the limitations of the KZA convention, not because the actual daughter produced is represented in the radionucs dictionary. The simplest example of this would an (n,n10) reaction of a ground state parent, like what I have in the _has_decay_data() docstring: 6Li(n,n10) -> 6,m10Li + n, but in KZA notation it would be 30060 + n10 -> 300610 + n. The problem here is that the KZA of the daughter does correspond to a nuclide with decay data, just not the correct daughter because 300610 = 61Zn. Perhaps my implementation is not capturing this accurately, but what I am trying to capture the parameters of the problem of not allowing any double digit excited states because the isomeric properties inescapably affect the legitimacy of a KZA value, and by extension our ability to use that KZA to cross-reference the decay data.
There was a problem hiding this comment.
I think we should be creating some clear metadata about these cases sooner then, perhaps? As soon as we determine what the daughter KZA is, we should also set some metadata to capture this.
| else: | ||
| if to_ground: | ||
| decay_KZA = f'{pKZA // 10}*' | ||
| decay_KZA = (dKZA // 10 - rxn['isomer'] // 10) * 10 |
There was a problem hiding this comment.
I realized that the version of this formula that I had in previous commits for this PR was incorrect.
Previously it was:
decay_KZA = (dKZA // 10) * 10
When benchmarking the FNS data, I was noticing a number of non-physical reaction pathways represented (specifically it was 51V(n,n*)->53V which caught my attention as being obviously incorrect). I realized that the reason for this was that for double digit excited states, this rounding-down to 10 method would not account for the dKZA already being corrupted by the unallowed KZA operation with a double-digit M. Therefore, I changed it to:
decay_KZA = (dKZA // 10 - rxn['isomer'] // 10) * 10
to bring the tens-digit back to appropriate value after any isomeric corruption may occur (unaffected by any M < 10)
gonuke
left a comment
There was a problem hiding this comment.
The suggestion we discussed today
gonuke
left a comment
There was a problem hiding this comment.
Can you provide a handful of examples of the kinds of reactions that need the special treatment of the isomer data? It seems like we keep ratcheting up the value of or isomeric information.
| if parent_excitation > 0 and MT not in EXCITATION_REACTIONS: | ||
| M += parent_excitation |
There was a problem hiding this comment.
This surprises me a little - that we're adding the parent excitation to the isomeric state that we already had in the MT table? Or does this only occur when rxn['isomer'] == 0?
|
|
||
| # Force isomeric daughters with high excitation levels or without known | ||
| # half-lives to their ground state, and flag the change | ||
| if pKZA % 10 + M >= 10 or dKZA not in radionucs: |
There was a problem hiding this comment.
Below, we've already added the parent excitation to M and it seems like we do it again here?
|
Per my Thread in the Slack channel, I think on top of figuring out whether isomeric parents' reaction residuals default to the ground state or the equivalent isomeric state, I also think that I need to recalibrate the forced-ground accumulation in general, because I think that I was overlooking that MTs 4 and 103-107 were already accumulated, so to calculate just the ground state, I would have to subtract from the accumulated isomeric cross-sections instead. |
46c3585 to
34d6595
Compare
gonuke
left a comment
There was a problem hiding this comment.
The cognitive burden of our processing of these excitation reactions is getting hard to follow. I've requested that we pull some parts out into separate functions to make it clearer.
| if MT in excitation_pathways[pKZA]: | ||
| return excitation_pathways[pKZA][MT], excitation_pathways | ||
| else: | ||
| return 0, excitation_pathways |
There was a problem hiding this comment.
(Magic number)
Let's define a variable
default_state = 0
And return that instead of just returning 0 so that we can easily change it later.
| # Parse File 10 for allowed daughter excitations from a given reaction | ||
| excitation_pathways[pKZA] = {} | ||
|
|
||
| za = f'{(pKZA // 10) * 10 + delKZA}'[:-1] |
There was a problem hiding this comment.
I need to be reminded (again?) when we every produce pKZA values that need this treatment...
I suppose that we sometimes have a parent nuclide in an isomeric state and we want to block that isomeric state when we apply the MT-specific change in KZA. This is particularly true given recent discussion of not assuming that reaction products are in the same isomeric state as their parents.
| for line in section.content.split('\n'): | ||
| if za in line: | ||
| excitation_levels.append(int( | ||
| line.split(za)[1].strip().split(' ')[0] |
There was a problem hiding this comment.
Can we add a comment somewhere with the format of the line we are parsing here? This is compact/concise, but a little obtuse.
| # Reset deLKZA for (n,n*) excitation reactions | ||
| if delKZA >= 0 and MT in EXCITATION_REACTIONS: |
There was a problem hiding this comment.
The EXCITATION_REACTIONS are no longer just (n,n*) so don't some of them still have a non-zero delKZA?
| return excitation_pathways[pKZA][MT], excitation_pathways | ||
|
|
||
| def iterate_MTs(MTs, file_obj, mt_dict, pKZA, all_rxns, radionucs, to_ground): | ||
| def iterate_MTs(MTs, file_obj, mt_dict, pKZA, all_rxns, eaf_nucs, endf_path): |
There was a problem hiding this comment.
I think it will lower cognitive burden if we break some of the code in this method into different functions.
Originally, the purpose of this function was just to iterate through the data and extract simple cross-sections for writing to the final file.
Now we do a lot of cleanup and cross-checking. It would be great if those steps were done in their own functions to make the overall flow of this method more clear and isolate where we perform those operations.
We might end up passing around a lot of data (which makes me feel like we should probably think about making this object oriented some day but not now).
This PR expands on the isomer handling methods for ALARAJOYWrapper developed over the past month to properly address isomer daughters produced from pathways other than (n,n*) reactions. I came across this issue when doing inventory benchmarking against FISPACT-II and the JAEA FNS experimental data and noticed certain isomers appearing to be stable when they obviously were not, just like before. The old method failed to include cases where the parent itself is an isomer, which can subsequently produce excited daughters by normal reaction pathways.