Fixed a bug in cell last update - #3849

Closed
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last
Closed

Fixed a bug in cell last update#3849
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last

Conversation

@GuySten

@GuyStenGuySten commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Description

Currently, cell_last is assigned only in surface crossing events.
This PR fix that and now this data is set also after collision.

EDIT:
This PR also fix material_last update to make CellFromFilter and MaterialFromFilter consistent.

@paulromano, can you look into this?
This is a subtle change and I am not 100 percent sure this fix the problem.
This issue does change regression tests.

Checklist

  • I have performed a self-review of my own code
  • I have run clang-format (version 18) on any C++ source files (if applicable)
  • I have followed the style guidelines for Python source files (if applicable)
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works (if applicable)

@GuySten
GuySten requested a review from paulromanoMarch 4, 2026 03:42
@GuyStenGuySten changed the title Fixed a bug in cell last assignment dataFixed a bug in cell last updateMar 4, 2026
@GuyStenGuySten added the Bugs label Mar 4, 2026

@paulromanopaulromano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cell_last change alters the physical meaning of volumetric tallies with CellFromFilter. Currently, using CellFromFilter for a volumetric tally in cell B answered: "How much of the score in B comes from particles that entered B from cell A?" To me, this is a physically meaningful decomposition of scores by source cell. With the PR, cell_last always equals the current cell, so CellFromFilter for volumetric tallies no longer provides "from where" information as far as I can tell. My opinion is that we should not change the current behavior.

That being said, the fix for material_last in event_cross_surface is a legitimate bug fix so I think we should trim the PR down to just that change.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Maybe I missed something but I think that if we only change cell last in surface crossing then when a particle cross from cell A to cell B cell last is cell A and everything is OK.
But currently if afterwards the particle collide in cell B multiple times then the cell last variable is still cell A because we did not cross any surface and did not update cell last.

Maybe I broke cell last but @paulromano do you at least agree that the current behavior of cell last is a bug?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Actually I did break cell last so I've added another unit test and edited the code until it passes.

@GuySten
GuySten requested a review from paulromanoMarch 6, 2026 07:11
@GuySten

Copy link
Copy Markdown
ContributorAuthor

Some notes:
The behavior of the code is made complicated by the fact that openmc know to recalculate macro xs by setting material_last to C_NONE.
To distinguish between material void I had to change its id to -2.

@GuySten
GuySten requested a review from nelsonag as a code ownerMarch 6, 2026 14:55
@GuySten
GuySten marked this pull request as draft March 6, 2026 16:31
@GuySten

Copy link
Copy Markdown
ContributorAuthor

This PR will need some serious digging.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I tried to make all the tests pass at the cost of always recalculating cross sections.
That attempt can be found here #3858 .
It almost succeeded (except one dagmc test).

I understand that the cost of always recalculating xs is too much.
@paulromano, can you help figure out what is going on?
Anytime I think I fixed the problem by fixing one test I break something else...

@JoffreyDorville

Copy link
Copy Markdown
Contributor

I have been working on this part of the code several months ago and I agree with @paulromano on what we expect for the cell_last behavior. I see this attribute as a way of tracking the cell where the particle was before the last surface crossing.

@GuySten If I understand correctly, you expect cell_last to update when a collision occurs or when a surface is crossed. What would be the application for such behavior? Do you have a particular tally process in mind?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, you understood me correctly.
I think that because every other attribute (E_last, r_last, ...) are updated after collision then the fact that cell isn't is unexpected.
This affects reaction tallies when using cellfromfilter.
I discovered this difference when I tried implementing forced collision.
I wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened.
I think the current behavior is weird.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

If the meaning of cell last and material last really should be the last cell and material before entering the current cell this should at least be better documented.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, I also noticed that your interpretation does not agree with one of the regression tests:
In test_cellfrom there is a check:

# Comparison to global from 3 assert_allclose(t3_3 + t3_4 + t4_3 + t4_4, tglobal, rtol=RTOL, atol=ATOL)

That the total reaction rate is the sum of the reaction rate from 3 to 3 from 3 to 4 from 4 to 4 and from 4 to 3.
In your interpretation from 3 to 3 and from 4 to 4 should be zero and because some particles start in 3 or 4 and interact there this check cannot pass because it cannot equal the total reaction rate.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I think a decision should be made about what the meaning of cell_last and material_last should be and then the relevant tests should be changed accordingly.

@paulromano, what do you think?

@vitmog

Copy link
Copy Markdown
Contributor

I would like to clarify the origin of the topic, which is seemingly related to a splitting scheme:

wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened

@GuySten What do you need to stop it for? Currently, you have a perfect chance to apply splitting more than one time to the same particle both before and after iteraction sampling. It can be valuable if you are able to know the splitting rate. If you skip splitting then, you will implement a worst scheme.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@vitmog, My understanding is that when a particle enter into a forced collision cell we split it into an uncollided history and collided history. If we apply forced collision again to the collided history we might enter a very long loop so I split only the original particle.

@vitmog

Copy link
Copy Markdown
Contributor

@GuySten You are right, the original MCNP forced collision (FC) scheme requires splitting once per cell visit only. The variant that I had in mind necessarily requires combining it with weight windows (WW) or an equivalent as a source of the importance/splitting rate. However, nothing prevents to combine both FC and WW on the user side.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@GuySten@JoffreyDorville@vitmog@paulromano
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Fixed a bug in cell last update - #3849

Closed
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last
Closed

Fixed a bug in cell last update#3849
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last

Conversation

@GuySten

@GuyStenGuySten commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Description

Currently, cell_last is assigned only in surface crossing events.
This PR fix that and now this data is set also after collision.

EDIT:
This PR also fix material_last update to make CellFromFilter and MaterialFromFilter consistent.

@paulromano, can you look into this?
This is a subtle change and I am not 100 percent sure this fix the problem.
This issue does change regression tests.

Checklist

  • I have performed a self-review of my own code
  • I have run clang-format (version 18) on any C++ source files (if applicable)
  • I have followed the style guidelines for Python source files (if applicable)
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works (if applicable)

@GuySten
GuySten requested a review from paulromanoMarch 4, 2026 03:42
@GuyStenGuySten changed the title Fixed a bug in cell last assignment dataFixed a bug in cell last updateMar 4, 2026
@GuyStenGuySten added the Bugs label Mar 4, 2026

@paulromanopaulromano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cell_last change alters the physical meaning of volumetric tallies with CellFromFilter. Currently, using CellFromFilter for a volumetric tally in cell B answered: "How much of the score in B comes from particles that entered B from cell A?" To me, this is a physically meaningful decomposition of scores by source cell. With the PR, cell_last always equals the current cell, so CellFromFilter for volumetric tallies no longer provides "from where" information as far as I can tell. My opinion is that we should not change the current behavior.

That being said, the fix for material_last in event_cross_surface is a legitimate bug fix so I think we should trim the PR down to just that change.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Maybe I missed something but I think that if we only change cell last in surface crossing then when a particle cross from cell A to cell B cell last is cell A and everything is OK.
But currently if afterwards the particle collide in cell B multiple times then the cell last variable is still cell A because we did not cross any surface and did not update cell last.

Maybe I broke cell last but @paulromano do you at least agree that the current behavior of cell last is a bug?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Actually I did break cell last so I've added another unit test and edited the code until it passes.

@GuySten
GuySten requested a review from paulromanoMarch 6, 2026 07:11
@GuySten

Copy link
Copy Markdown
ContributorAuthor

Some notes:
The behavior of the code is made complicated by the fact that openmc know to recalculate macro xs by setting material_last to C_NONE.
To distinguish between material void I had to change its id to -2.

@GuySten
GuySten requested a review from nelsonag as a code ownerMarch 6, 2026 14:55
@GuySten
GuySten marked this pull request as draft March 6, 2026 16:31
@GuySten

Copy link
Copy Markdown
ContributorAuthor

This PR will need some serious digging.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I tried to make all the tests pass at the cost of always recalculating cross sections.
That attempt can be found here #3858 .
It almost succeeded (except one dagmc test).

I understand that the cost of always recalculating xs is too much.
@paulromano, can you help figure out what is going on?
Anytime I think I fixed the problem by fixing one test I break something else...

@JoffreyDorville

Copy link
Copy Markdown
Contributor

I have been working on this part of the code several months ago and I agree with @paulromano on what we expect for the cell_last behavior. I see this attribute as a way of tracking the cell where the particle was before the last surface crossing.

@GuySten If I understand correctly, you expect cell_last to update when a collision occurs or when a surface is crossed. What would be the application for such behavior? Do you have a particular tally process in mind?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, you understood me correctly.
I think that because every other attribute (E_last, r_last, ...) are updated after collision then the fact that cell isn't is unexpected.
This affects reaction tallies when using cellfromfilter.
I discovered this difference when I tried implementing forced collision.
I wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened.
I think the current behavior is weird.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

If the meaning of cell last and material last really should be the last cell and material before entering the current cell this should at least be better documented.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, I also noticed that your interpretation does not agree with one of the regression tests:
In test_cellfrom there is a check:

# Comparison to global from 3 assert_allclose(t3_3 + t3_4 + t4_3 + t4_4, tglobal, rtol=RTOL, atol=ATOL)

That the total reaction rate is the sum of the reaction rate from 3 to 3 from 3 to 4 from 4 to 4 and from 4 to 3.
In your interpretation from 3 to 3 and from 4 to 4 should be zero and because some particles start in 3 or 4 and interact there this check cannot pass because it cannot equal the total reaction rate.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I think a decision should be made about what the meaning of cell_last and material_last should be and then the relevant tests should be changed accordingly.

@paulromano, what do you think?

@vitmog

Copy link
Copy Markdown
Contributor

I would like to clarify the origin of the topic, which is seemingly related to a splitting scheme:

wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened

@GuySten What do you need to stop it for? Currently, you have a perfect chance to apply splitting more than one time to the same particle both before and after iteraction sampling. It can be valuable if you are able to know the splitting rate. If you skip splitting then, you will implement a worst scheme.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@vitmog, My understanding is that when a particle enter into a forced collision cell we split it into an uncollided history and collided history. If we apply forced collision again to the collided history we might enter a very long loop so I split only the original particle.

@vitmog

Copy link
Copy Markdown
Contributor

@GuySten You are right, the original MCNP forced collision (FC) scheme requires splitting once per cell visit only. The variant that I had in mind necessarily requires combining it with weight windows (WW) or an equivalent as a source of the importance/splitting rate. However, nothing prevents to combine both FC and WW on the user side.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@GuySten@JoffreyDorville@vitmog@paulromano
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed a bug in cell last update - #3849

Closed
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last
Closed

Fixed a bug in cell last update#3849
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last

Conversation

@GuySten

@GuyStenGuySten commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Description

Currently, cell_last is assigned only in surface crossing events.
This PR fix that and now this data is set also after collision.

EDIT:
This PR also fix material_last update to make CellFromFilter and MaterialFromFilter consistent.

@paulromano, can you look into this?
This is a subtle change and I am not 100 percent sure this fix the problem.
This issue does change regression tests.

Checklist

  • I have performed a self-review of my own code
  • I have run clang-format (version 18) on any C++ source files (if applicable)
  • I have followed the style guidelines for Python source files (if applicable)
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works (if applicable)

@GuySten
GuySten requested a review from paulromanoMarch 4, 2026 03:42
@GuyStenGuySten changed the title Fixed a bug in cell last assignment dataFixed a bug in cell last updateMar 4, 2026
@GuyStenGuySten added the Bugs label Mar 4, 2026

@paulromanopaulromano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cell_last change alters the physical meaning of volumetric tallies with CellFromFilter. Currently, using CellFromFilter for a volumetric tally in cell B answered: "How much of the score in B comes from particles that entered B from cell A?" To me, this is a physically meaningful decomposition of scores by source cell. With the PR, cell_last always equals the current cell, so CellFromFilter for volumetric tallies no longer provides "from where" information as far as I can tell. My opinion is that we should not change the current behavior.

That being said, the fix for material_last in event_cross_surface is a legitimate bug fix so I think we should trim the PR down to just that change.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Maybe I missed something but I think that if we only change cell last in surface crossing then when a particle cross from cell A to cell B cell last is cell A and everything is OK.
But currently if afterwards the particle collide in cell B multiple times then the cell last variable is still cell A because we did not cross any surface and did not update cell last.

Maybe I broke cell last but @paulromano do you at least agree that the current behavior of cell last is a bug?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Actually I did break cell last so I've added another unit test and edited the code until it passes.

@GuySten
GuySten requested a review from paulromanoMarch 6, 2026 07:11
@GuySten

Copy link
Copy Markdown
ContributorAuthor

Some notes:
The behavior of the code is made complicated by the fact that openmc know to recalculate macro xs by setting material_last to C_NONE.
To distinguish between material void I had to change its id to -2.

@GuySten
GuySten requested a review from nelsonag as a code ownerMarch 6, 2026 14:55
@GuySten
GuySten marked this pull request as draft March 6, 2026 16:31
@GuySten

Copy link
Copy Markdown
ContributorAuthor

This PR will need some serious digging.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I tried to make all the tests pass at the cost of always recalculating cross sections.
That attempt can be found here #3858 .
It almost succeeded (except one dagmc test).

I understand that the cost of always recalculating xs is too much.
@paulromano, can you help figure out what is going on?
Anytime I think I fixed the problem by fixing one test I break something else...

@JoffreyDorville

Copy link
Copy Markdown
Contributor

I have been working on this part of the code several months ago and I agree with @paulromano on what we expect for the cell_last behavior. I see this attribute as a way of tracking the cell where the particle was before the last surface crossing.

@GuySten If I understand correctly, you expect cell_last to update when a collision occurs or when a surface is crossed. What would be the application for such behavior? Do you have a particular tally process in mind?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, you understood me correctly.
I think that because every other attribute (E_last, r_last, ...) are updated after collision then the fact that cell isn't is unexpected.
This affects reaction tallies when using cellfromfilter.
I discovered this difference when I tried implementing forced collision.
I wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened.
I think the current behavior is weird.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

If the meaning of cell last and material last really should be the last cell and material before entering the current cell this should at least be better documented.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, I also noticed that your interpretation does not agree with one of the regression tests:
In test_cellfrom there is a check:

# Comparison to global from 3 assert_allclose(t3_3 + t3_4 + t4_3 + t4_4, tglobal, rtol=RTOL, atol=ATOL)

That the total reaction rate is the sum of the reaction rate from 3 to 3 from 3 to 4 from 4 to 4 and from 4 to 3.
In your interpretation from 3 to 3 and from 4 to 4 should be zero and because some particles start in 3 or 4 and interact there this check cannot pass because it cannot equal the total reaction rate.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I think a decision should be made about what the meaning of cell_last and material_last should be and then the relevant tests should be changed accordingly.

@paulromano, what do you think?

@vitmog

Copy link
Copy Markdown
Contributor

I would like to clarify the origin of the topic, which is seemingly related to a splitting scheme:

wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened

@GuySten What do you need to stop it for? Currently, you have a perfect chance to apply splitting more than one time to the same particle both before and after iteraction sampling. It can be valuable if you are able to know the splitting rate. If you skip splitting then, you will implement a worst scheme.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@vitmog, My understanding is that when a particle enter into a forced collision cell we split it into an uncollided history and collided history. If we apply forced collision again to the collided history we might enter a very long loop so I split only the original particle.

@vitmog

Copy link
Copy Markdown
Contributor

@GuySten You are right, the original MCNP forced collision (FC) scheme requires splitting once per cell visit only. The variant that I had in mind necessarily requires combining it with weight windows (WW) or an equivalent as a source of the importance/splitting rate. However, nothing prevents to combine both FC and WW on the user side.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@GuySten@JoffreyDorville@vitmog@paulromano
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed a bug in cell last update - #3849

Closed
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last
Closed

Fixed a bug in cell last update#3849
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last

Conversation

@GuySten

@GuyStenGuySten commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Description

Currently, cell_last is assigned only in surface crossing events.
This PR fix that and now this data is set also after collision.

EDIT:
This PR also fix material_last update to make CellFromFilter and MaterialFromFilter consistent.

@paulromano, can you look into this?
This is a subtle change and I am not 100 percent sure this fix the problem.
This issue does change regression tests.

Checklist

  • I have performed a self-review of my own code
  • I have run clang-format (version 18) on any C++ source files (if applicable)
  • I have followed the style guidelines for Python source files (if applicable)
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works (if applicable)

@GuySten
GuySten requested a review from paulromanoMarch 4, 2026 03:42
@GuyStenGuySten changed the title Fixed a bug in cell last assignment dataFixed a bug in cell last updateMar 4, 2026
@GuyStenGuySten added the Bugs label Mar 4, 2026

@paulromanopaulromano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cell_last change alters the physical meaning of volumetric tallies with CellFromFilter. Currently, using CellFromFilter for a volumetric tally in cell B answered: "How much of the score in B comes from particles that entered B from cell A?" To me, this is a physically meaningful decomposition of scores by source cell. With the PR, cell_last always equals the current cell, so CellFromFilter for volumetric tallies no longer provides "from where" information as far as I can tell. My opinion is that we should not change the current behavior.

That being said, the fix for material_last in event_cross_surface is a legitimate bug fix so I think we should trim the PR down to just that change.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Maybe I missed something but I think that if we only change cell last in surface crossing then when a particle cross from cell A to cell B cell last is cell A and everything is OK.
But currently if afterwards the particle collide in cell B multiple times then the cell last variable is still cell A because we did not cross any surface and did not update cell last.

Maybe I broke cell last but @paulromano do you at least agree that the current behavior of cell last is a bug?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Actually I did break cell last so I've added another unit test and edited the code until it passes.

@GuySten
GuySten requested a review from paulromanoMarch 6, 2026 07:11
@GuySten

Copy link
Copy Markdown
ContributorAuthor

Some notes:
The behavior of the code is made complicated by the fact that openmc know to recalculate macro xs by setting material_last to C_NONE.
To distinguish between material void I had to change its id to -2.

@GuySten
GuySten requested a review from nelsonag as a code ownerMarch 6, 2026 14:55
@GuySten
GuySten marked this pull request as draft March 6, 2026 16:31
@GuySten

Copy link
Copy Markdown
ContributorAuthor

This PR will need some serious digging.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I tried to make all the tests pass at the cost of always recalculating cross sections.
That attempt can be found here #3858 .
It almost succeeded (except one dagmc test).

I understand that the cost of always recalculating xs is too much.
@paulromano, can you help figure out what is going on?
Anytime I think I fixed the problem by fixing one test I break something else...

@JoffreyDorville

Copy link
Copy Markdown
Contributor

I have been working on this part of the code several months ago and I agree with @paulromano on what we expect for the cell_last behavior. I see this attribute as a way of tracking the cell where the particle was before the last surface crossing.

@GuySten If I understand correctly, you expect cell_last to update when a collision occurs or when a surface is crossed. What would be the application for such behavior? Do you have a particular tally process in mind?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, you understood me correctly.
I think that because every other attribute (E_last, r_last, ...) are updated after collision then the fact that cell isn't is unexpected.
This affects reaction tallies when using cellfromfilter.
I discovered this difference when I tried implementing forced collision.
I wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened.
I think the current behavior is weird.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

If the meaning of cell last and material last really should be the last cell and material before entering the current cell this should at least be better documented.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, I also noticed that your interpretation does not agree with one of the regression tests:
In test_cellfrom there is a check:

# Comparison to global from 3 assert_allclose(t3_3 + t3_4 + t4_3 + t4_4, tglobal, rtol=RTOL, atol=ATOL)

That the total reaction rate is the sum of the reaction rate from 3 to 3 from 3 to 4 from 4 to 4 and from 4 to 3.
In your interpretation from 3 to 3 and from 4 to 4 should be zero and because some particles start in 3 or 4 and interact there this check cannot pass because it cannot equal the total reaction rate.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I think a decision should be made about what the meaning of cell_last and material_last should be and then the relevant tests should be changed accordingly.

@paulromano, what do you think?

@vitmog

Copy link
Copy Markdown
Contributor

I would like to clarify the origin of the topic, which is seemingly related to a splitting scheme:

wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened

@GuySten What do you need to stop it for? Currently, you have a perfect chance to apply splitting more than one time to the same particle both before and after iteraction sampling. It can be valuable if you are able to know the splitting rate. If you skip splitting then, you will implement a worst scheme.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@vitmog, My understanding is that when a particle enter into a forced collision cell we split it into an uncollided history and collided history. If we apply forced collision again to the collided history we might enter a very long loop so I split only the original particle.

@vitmog

Copy link
Copy Markdown
Contributor

@GuySten You are right, the original MCNP forced collision (FC) scheme requires splitting once per cell visit only. The variant that I had in mind necessarily requires combining it with weight windows (WW) or an equivalent as a source of the importance/splitting rate. However, nothing prevents to combine both FC and WW on the user side.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@GuySten@JoffreyDorville@vitmog@paulromano
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Fixed a bug in cell last update - #3849

Closed
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last
Closed

Fixed a bug in cell last update#3849
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last

Conversation

@GuySten

@GuyStenGuySten commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Description

Currently, cell_last is assigned only in surface crossing events.
This PR fix that and now this data is set also after collision.

EDIT:
This PR also fix material_last update to make CellFromFilter and MaterialFromFilter consistent.

@paulromano, can you look into this?
This is a subtle change and I am not 100 percent sure this fix the problem.
This issue does change regression tests.

Checklist

  • I have performed a self-review of my own code
  • I have run clang-format (version 18) on any C++ source files (if applicable)
  • I have followed the style guidelines for Python source files (if applicable)
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works (if applicable)

@GuySten
GuySten requested a review from paulromanoMarch 4, 2026 03:42
@GuyStenGuySten changed the title Fixed a bug in cell last assignment dataFixed a bug in cell last updateMar 4, 2026
@GuyStenGuySten added the Bugs label Mar 4, 2026

@paulromanopaulromano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cell_last change alters the physical meaning of volumetric tallies with CellFromFilter. Currently, using CellFromFilter for a volumetric tally in cell B answered: "How much of the score in B comes from particles that entered B from cell A?" To me, this is a physically meaningful decomposition of scores by source cell. With the PR, cell_last always equals the current cell, so CellFromFilter for volumetric tallies no longer provides "from where" information as far as I can tell. My opinion is that we should not change the current behavior.

That being said, the fix for material_last in event_cross_surface is a legitimate bug fix so I think we should trim the PR down to just that change.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Maybe I missed something but I think that if we only change cell last in surface crossing then when a particle cross from cell A to cell B cell last is cell A and everything is OK.
But currently if afterwards the particle collide in cell B multiple times then the cell last variable is still cell A because we did not cross any surface and did not update cell last.

Maybe I broke cell last but @paulromano do you at least agree that the current behavior of cell last is a bug?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Actually I did break cell last so I've added another unit test and edited the code until it passes.

@GuySten
GuySten requested a review from paulromanoMarch 6, 2026 07:11
@GuySten

Copy link
Copy Markdown
ContributorAuthor

Some notes:
The behavior of the code is made complicated by the fact that openmc know to recalculate macro xs by setting material_last to C_NONE.
To distinguish between material void I had to change its id to -2.

@GuySten
GuySten requested a review from nelsonag as a code ownerMarch 6, 2026 14:55
@GuySten
GuySten marked this pull request as draft March 6, 2026 16:31
@GuySten

Copy link
Copy Markdown
ContributorAuthor

This PR will need some serious digging.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I tried to make all the tests pass at the cost of always recalculating cross sections.
That attempt can be found here #3858 .
It almost succeeded (except one dagmc test).

I understand that the cost of always recalculating xs is too much.
@paulromano, can you help figure out what is going on?
Anytime I think I fixed the problem by fixing one test I break something else...

@JoffreyDorville

Copy link
Copy Markdown
Contributor

I have been working on this part of the code several months ago and I agree with @paulromano on what we expect for the cell_last behavior. I see this attribute as a way of tracking the cell where the particle was before the last surface crossing.

@GuySten If I understand correctly, you expect cell_last to update when a collision occurs or when a surface is crossed. What would be the application for such behavior? Do you have a particular tally process in mind?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, you understood me correctly.
I think that because every other attribute (E_last, r_last, ...) are updated after collision then the fact that cell isn't is unexpected.
This affects reaction tallies when using cellfromfilter.
I discovered this difference when I tried implementing forced collision.
I wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened.
I think the current behavior is weird.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

If the meaning of cell last and material last really should be the last cell and material before entering the current cell this should at least be better documented.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, I also noticed that your interpretation does not agree with one of the regression tests:
In test_cellfrom there is a check:

# Comparison to global from 3 assert_allclose(t3_3 + t3_4 + t4_3 + t4_4, tglobal, rtol=RTOL, atol=ATOL)

That the total reaction rate is the sum of the reaction rate from 3 to 3 from 3 to 4 from 4 to 4 and from 4 to 3.
In your interpretation from 3 to 3 and from 4 to 4 should be zero and because some particles start in 3 or 4 and interact there this check cannot pass because it cannot equal the total reaction rate.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I think a decision should be made about what the meaning of cell_last and material_last should be and then the relevant tests should be changed accordingly.

@paulromano, what do you think?

@vitmog

Copy link
Copy Markdown
Contributor

I would like to clarify the origin of the topic, which is seemingly related to a splitting scheme:

wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened

@GuySten What do you need to stop it for? Currently, you have a perfect chance to apply splitting more than one time to the same particle both before and after iteraction sampling. It can be valuable if you are able to know the splitting rate. If you skip splitting then, you will implement a worst scheme.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@vitmog, My understanding is that when a particle enter into a forced collision cell we split it into an uncollided history and collided history. If we apply forced collision again to the collided history we might enter a very long loop so I split only the original particle.

@vitmog

Copy link
Copy Markdown
Contributor

@GuySten You are right, the original MCNP forced collision (FC) scheme requires splitting once per cell visit only. The variant that I had in mind necessarily requires combining it with weight windows (WW) or an equivalent as a source of the importance/splitting rate. However, nothing prevents to combine both FC and WW on the user side.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@GuySten@JoffreyDorville@vitmog@paulromano
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed a bug in cell last update - #3849

Closed
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last
Closed

Fixed a bug in cell last update#3849
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last

Conversation

@GuySten

@GuyStenGuySten commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Description

Currently, cell_last is assigned only in surface crossing events.
This PR fix that and now this data is set also after collision.

EDIT:
This PR also fix material_last update to make CellFromFilter and MaterialFromFilter consistent.

@paulromano, can you look into this?
This is a subtle change and I am not 100 percent sure this fix the problem.
This issue does change regression tests.

Checklist

  • I have performed a self-review of my own code
  • I have run clang-format (version 18) on any C++ source files (if applicable)
  • I have followed the style guidelines for Python source files (if applicable)
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works (if applicable)

@GuySten
GuySten requested a review from paulromanoMarch 4, 2026 03:42
@GuyStenGuySten changed the title Fixed a bug in cell last assignment dataFixed a bug in cell last updateMar 4, 2026
@GuyStenGuySten added the Bugs label Mar 4, 2026

@paulromanopaulromano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cell_last change alters the physical meaning of volumetric tallies with CellFromFilter. Currently, using CellFromFilter for a volumetric tally in cell B answered: "How much of the score in B comes from particles that entered B from cell A?" To me, this is a physically meaningful decomposition of scores by source cell. With the PR, cell_last always equals the current cell, so CellFromFilter for volumetric tallies no longer provides "from where" information as far as I can tell. My opinion is that we should not change the current behavior.

That being said, the fix for material_last in event_cross_surface is a legitimate bug fix so I think we should trim the PR down to just that change.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Maybe I missed something but I think that if we only change cell last in surface crossing then when a particle cross from cell A to cell B cell last is cell A and everything is OK.
But currently if afterwards the particle collide in cell B multiple times then the cell last variable is still cell A because we did not cross any surface and did not update cell last.

Maybe I broke cell last but @paulromano do you at least agree that the current behavior of cell last is a bug?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Actually I did break cell last so I've added another unit test and edited the code until it passes.

@GuySten
GuySten requested a review from paulromanoMarch 6, 2026 07:11
@GuySten

Copy link
Copy Markdown
ContributorAuthor

Some notes:
The behavior of the code is made complicated by the fact that openmc know to recalculate macro xs by setting material_last to C_NONE.
To distinguish between material void I had to change its id to -2.

@GuySten
GuySten requested a review from nelsonag as a code ownerMarch 6, 2026 14:55
@GuySten
GuySten marked this pull request as draft March 6, 2026 16:31
@GuySten

Copy link
Copy Markdown
ContributorAuthor

This PR will need some serious digging.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I tried to make all the tests pass at the cost of always recalculating cross sections.
That attempt can be found here #3858 .
It almost succeeded (except one dagmc test).

I understand that the cost of always recalculating xs is too much.
@paulromano, can you help figure out what is going on?
Anytime I think I fixed the problem by fixing one test I break something else...

@JoffreyDorville

Copy link
Copy Markdown
Contributor

I have been working on this part of the code several months ago and I agree with @paulromano on what we expect for the cell_last behavior. I see this attribute as a way of tracking the cell where the particle was before the last surface crossing.

@GuySten If I understand correctly, you expect cell_last to update when a collision occurs or when a surface is crossed. What would be the application for such behavior? Do you have a particular tally process in mind?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, you understood me correctly.
I think that because every other attribute (E_last, r_last, ...) are updated after collision then the fact that cell isn't is unexpected.
This affects reaction tallies when using cellfromfilter.
I discovered this difference when I tried implementing forced collision.
I wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened.
I think the current behavior is weird.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

If the meaning of cell last and material last really should be the last cell and material before entering the current cell this should at least be better documented.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, I also noticed that your interpretation does not agree with one of the regression tests:
In test_cellfrom there is a check:

# Comparison to global from 3 assert_allclose(t3_3 + t3_4 + t4_3 + t4_4, tglobal, rtol=RTOL, atol=ATOL)

That the total reaction rate is the sum of the reaction rate from 3 to 3 from 3 to 4 from 4 to 4 and from 4 to 3.
In your interpretation from 3 to 3 and from 4 to 4 should be zero and because some particles start in 3 or 4 and interact there this check cannot pass because it cannot equal the total reaction rate.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I think a decision should be made about what the meaning of cell_last and material_last should be and then the relevant tests should be changed accordingly.

@paulromano, what do you think?

@vitmog

Copy link
Copy Markdown
Contributor

I would like to clarify the origin of the topic, which is seemingly related to a splitting scheme:

wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened

@GuySten What do you need to stop it for? Currently, you have a perfect chance to apply splitting more than one time to the same particle both before and after iteraction sampling. It can be valuable if you are able to know the splitting rate. If you skip splitting then, you will implement a worst scheme.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@vitmog, My understanding is that when a particle enter into a forced collision cell we split it into an uncollided history and collided history. If we apply forced collision again to the collided history we might enter a very long loop so I split only the original particle.

@vitmog

Copy link
Copy Markdown
Contributor

@GuySten You are right, the original MCNP forced collision (FC) scheme requires splitting once per cell visit only. The variant that I had in mind necessarily requires combining it with weight windows (WW) or an equivalent as a source of the importance/splitting rate. However, nothing prevents to combine both FC and WW on the user side.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@GuySten@JoffreyDorville@vitmog@paulromano
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed a bug in cell last update - #3849

Closed
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last
Closed

Fixed a bug in cell last update#3849
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last

Conversation

@GuySten

@GuyStenGuySten commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Description

Currently, cell_last is assigned only in surface crossing events.
This PR fix that and now this data is set also after collision.

EDIT:
This PR also fix material_last update to make CellFromFilter and MaterialFromFilter consistent.

@paulromano, can you look into this?
This is a subtle change and I am not 100 percent sure this fix the problem.
This issue does change regression tests.

Checklist

  • I have performed a self-review of my own code
  • I have run clang-format (version 18) on any C++ source files (if applicable)
  • I have followed the style guidelines for Python source files (if applicable)
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works (if applicable)

@GuySten
GuySten requested a review from paulromanoMarch 4, 2026 03:42
@GuyStenGuySten changed the title Fixed a bug in cell last assignment dataFixed a bug in cell last updateMar 4, 2026
@GuyStenGuySten added the Bugs label Mar 4, 2026

@paulromanopaulromano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cell_last change alters the physical meaning of volumetric tallies with CellFromFilter. Currently, using CellFromFilter for a volumetric tally in cell B answered: "How much of the score in B comes from particles that entered B from cell A?" To me, this is a physically meaningful decomposition of scores by source cell. With the PR, cell_last always equals the current cell, so CellFromFilter for volumetric tallies no longer provides "from where" information as far as I can tell. My opinion is that we should not change the current behavior.

That being said, the fix for material_last in event_cross_surface is a legitimate bug fix so I think we should trim the PR down to just that change.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Maybe I missed something but I think that if we only change cell last in surface crossing then when a particle cross from cell A to cell B cell last is cell A and everything is OK.
But currently if afterwards the particle collide in cell B multiple times then the cell last variable is still cell A because we did not cross any surface and did not update cell last.

Maybe I broke cell last but @paulromano do you at least agree that the current behavior of cell last is a bug?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Actually I did break cell last so I've added another unit test and edited the code until it passes.

@GuySten
GuySten requested a review from paulromanoMarch 6, 2026 07:11
@GuySten

Copy link
Copy Markdown
ContributorAuthor

Some notes:
The behavior of the code is made complicated by the fact that openmc know to recalculate macro xs by setting material_last to C_NONE.
To distinguish between material void I had to change its id to -2.

@GuySten
GuySten requested a review from nelsonag as a code ownerMarch 6, 2026 14:55
@GuySten
GuySten marked this pull request as draft March 6, 2026 16:31
@GuySten

Copy link
Copy Markdown
ContributorAuthor

This PR will need some serious digging.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I tried to make all the tests pass at the cost of always recalculating cross sections.
That attempt can be found here #3858 .
It almost succeeded (except one dagmc test).

I understand that the cost of always recalculating xs is too much.
@paulromano, can you help figure out what is going on?
Anytime I think I fixed the problem by fixing one test I break something else...

@JoffreyDorville

Copy link
Copy Markdown
Contributor

I have been working on this part of the code several months ago and I agree with @paulromano on what we expect for the cell_last behavior. I see this attribute as a way of tracking the cell where the particle was before the last surface crossing.

@GuySten If I understand correctly, you expect cell_last to update when a collision occurs or when a surface is crossed. What would be the application for such behavior? Do you have a particular tally process in mind?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, you understood me correctly.
I think that because every other attribute (E_last, r_last, ...) are updated after collision then the fact that cell isn't is unexpected.
This affects reaction tallies when using cellfromfilter.
I discovered this difference when I tried implementing forced collision.
I wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened.
I think the current behavior is weird.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

If the meaning of cell last and material last really should be the last cell and material before entering the current cell this should at least be better documented.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, I also noticed that your interpretation does not agree with one of the regression tests:
In test_cellfrom there is a check:

# Comparison to global from 3 assert_allclose(t3_3 + t3_4 + t4_3 + t4_4, tglobal, rtol=RTOL, atol=ATOL)

That the total reaction rate is the sum of the reaction rate from 3 to 3 from 3 to 4 from 4 to 4 and from 4 to 3.
In your interpretation from 3 to 3 and from 4 to 4 should be zero and because some particles start in 3 or 4 and interact there this check cannot pass because it cannot equal the total reaction rate.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I think a decision should be made about what the meaning of cell_last and material_last should be and then the relevant tests should be changed accordingly.

@paulromano, what do you think?

@vitmog

Copy link
Copy Markdown
Contributor

I would like to clarify the origin of the topic, which is seemingly related to a splitting scheme:

wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened

@GuySten What do you need to stop it for? Currently, you have a perfect chance to apply splitting more than one time to the same particle both before and after iteraction sampling. It can be valuable if you are able to know the splitting rate. If you skip splitting then, you will implement a worst scheme.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@vitmog, My understanding is that when a particle enter into a forced collision cell we split it into an uncollided history and collided history. If we apply forced collision again to the collided history we might enter a very long loop so I split only the original particle.

@vitmog

Copy link
Copy Markdown
Contributor

@GuySten You are right, the original MCNP forced collision (FC) scheme requires splitting once per cell visit only. The variant that I had in mind necessarily requires combining it with weight windows (WW) or an equivalent as a source of the importance/splitting rate. However, nothing prevents to combine both FC and WW on the user side.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@GuySten@JoffreyDorville@vitmog@paulromano
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Fixed a bug in cell last update - #3849

Closed
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last
Closed

Fixed a bug in cell last update#3849
GuySten wants to merge 23 commits into
openmc-dev:developfrom
GuySten:cell_last

Conversation

@GuySten

@GuyStenGuySten commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Description

Currently, cell_last is assigned only in surface crossing events.
This PR fix that and now this data is set also after collision.

EDIT:
This PR also fix material_last update to make CellFromFilter and MaterialFromFilter consistent.

@paulromano, can you look into this?
This is a subtle change and I am not 100 percent sure this fix the problem.
This issue does change regression tests.

Checklist

  • I have performed a self-review of my own code
  • I have run clang-format (version 18) on any C++ source files (if applicable)
  • I have followed the style guidelines for Python source files (if applicable)
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works (if applicable)

@GuySten
GuySten requested a review from paulromanoMarch 4, 2026 03:42
@GuyStenGuySten changed the title Fixed a bug in cell last assignment dataFixed a bug in cell last updateMar 4, 2026
@GuyStenGuySten added the Bugs label Mar 4, 2026

@paulromanopaulromano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cell_last change alters the physical meaning of volumetric tallies with CellFromFilter. Currently, using CellFromFilter for a volumetric tally in cell B answered: "How much of the score in B comes from particles that entered B from cell A?" To me, this is a physically meaningful decomposition of scores by source cell. With the PR, cell_last always equals the current cell, so CellFromFilter for volumetric tallies no longer provides "from where" information as far as I can tell. My opinion is that we should not change the current behavior.

That being said, the fix for material_last in event_cross_surface is a legitimate bug fix so I think we should trim the PR down to just that change.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Maybe I missed something but I think that if we only change cell last in surface crossing then when a particle cross from cell A to cell B cell last is cell A and everything is OK.
But currently if afterwards the particle collide in cell B multiple times then the cell last variable is still cell A because we did not cross any surface and did not update cell last.

Maybe I broke cell last but @paulromano do you at least agree that the current behavior of cell last is a bug?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

Actually I did break cell last so I've added another unit test and edited the code until it passes.

@GuySten
GuySten requested a review from paulromanoMarch 6, 2026 07:11
@GuySten

Copy link
Copy Markdown
ContributorAuthor

Some notes:
The behavior of the code is made complicated by the fact that openmc know to recalculate macro xs by setting material_last to C_NONE.
To distinguish between material void I had to change its id to -2.

@GuySten
GuySten requested a review from nelsonag as a code ownerMarch 6, 2026 14:55
@GuySten
GuySten marked this pull request as draft March 6, 2026 16:31
@GuySten

Copy link
Copy Markdown
ContributorAuthor

This PR will need some serious digging.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I tried to make all the tests pass at the cost of always recalculating cross sections.
That attempt can be found here #3858 .
It almost succeeded (except one dagmc test).

I understand that the cost of always recalculating xs is too much.
@paulromano, can you help figure out what is going on?
Anytime I think I fixed the problem by fixing one test I break something else...

@JoffreyDorville

Copy link
Copy Markdown
Contributor

I have been working on this part of the code several months ago and I agree with @paulromano on what we expect for the cell_last behavior. I see this attribute as a way of tracking the cell where the particle was before the last surface crossing.

@GuySten If I understand correctly, you expect cell_last to update when a collision occurs or when a surface is crossed. What would be the application for such behavior? Do you have a particular tally process in mind?

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, you understood me correctly.
I think that because every other attribute (E_last, r_last, ...) are updated after collision then the fact that cell isn't is unexpected.
This affects reaction tallies when using cellfromfilter.
I discovered this difference when I tried implementing forced collision.
I wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened.
I think the current behavior is weird.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

If the meaning of cell last and material last really should be the last cell and material before entering the current cell this should at least be better documented.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@JoffreyDorville, I also noticed that your interpretation does not agree with one of the regression tests:
In test_cellfrom there is a check:

# Comparison to global from 3 assert_allclose(t3_3 + t3_4 + t4_3 + t4_4, tglobal, rtol=RTOL, atol=ATOL)

That the total reaction rate is the sum of the reaction rate from 3 to 3 from 3 to 4 from 4 to 4 and from 4 to 3.
In your interpretation from 3 to 3 and from 4 to 4 should be zero and because some particles start in 3 or 4 and interact there this check cannot pass because it cannot equal the total reaction rate.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

I think a decision should be made about what the meaning of cell_last and material_last should be and then the relevant tests should be changed accordingly.

@paulromano, what do you think?

@vitmog

Copy link
Copy Markdown
Contributor

I would like to clarify the origin of the topic, which is seemingly related to a splitting scheme:

wanted to stop splitting the history when cell last is equal the current cell and I discovered that this never happened

@GuySten What do you need to stop it for? Currently, you have a perfect chance to apply splitting more than one time to the same particle both before and after iteraction sampling. It can be valuable if you are able to know the splitting rate. If you skip splitting then, you will implement a worst scheme.

@GuySten

Copy link
Copy Markdown
ContributorAuthor

@vitmog, My understanding is that when a particle enter into a forced collision cell we split it into an uncollided history and collided history. If we apply forced collision again to the collided history we might enter a very long loop so I split only the original particle.

@vitmog

Copy link
Copy Markdown
Contributor

@GuySten You are right, the original MCNP forced collision (FC) scheme requires splitting once per cell visit only. The variant that I had in mind necessarily requires combining it with weight windows (WW) or an equivalent as a source of the importance/splitting rate. However, nothing prevents to combine both FC and WW on the user side.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@GuySten@JoffreyDorville@vitmog@paulromano