Skip to content

Add cell_wise MGXS generation method - #3987

Open
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise
Open

Add cell_wise MGXS generation method#3987
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise

Conversation

@jon-proximafusion

@jon-proximafusionjon-proximafusion commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Add a cell_wise MGXS generation method

model.convert_to_multigroup(method="cell_wise", groups=...)

Like material_wise, but gives each cell its own multigroup cross sections, so it
captures the intra-material spatial variation that material_wise averages away
(for example a steel material reused in several cells).

Implementation

Full reuse of the material_wise path. Before generation, the material in every
material-filled cell is cloned (each clone gets a unique id via
Material.clone()). The standard per-material generation then produces and assigns
one cross section set per cell. The only new code is the per-cell cloning step in
convert_to_multigroup plus the dispatch entry (about 20 lines). material_wise
behavior is unchanged.

Works for both CSG and DAGMC. convert_to_multigroup already synchronizes DAGMC
cells before generation, so the per-cell clones become standard DAGMC per-cell
material overrides with no special handling.

Contents

  • openmc/model/model.py: the per-cell cloning step and dispatch entry.
  • tests/unit_tests/test_model.py: CSG unit test (two cells sharing a material get
    distinct macroscopics).
  • tests/unit_tests/dagmc/test_convert_to_multigroup.py: DAGMC unit test (a model
    with two fuel volumes sharing one material yields three distinct per-cell
    macroscopics).
  • docs/source/usersguide/random_ray.rst: adds cell_wise to the method
    list and to the "Comparison of Automatic MGXS Generation Methods" table.

Verification

  • CSG: a 4-shell single-material sphere produces four distinct per-cell cross
    section sets, while material_wise on the same model produces one (regression
    intact).
  • DAGMC: the 5-volume dagmc.h5m model (two fuel volumes sharing one material,
    plus water) yields three distinct per-cell macroscopics; void volumes are
    skipped.

Status

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 1f966fd to 8698b76CompareJune 30, 2026 16:32
@shimwell
shimwell requested a review from jtrammJune 30, 2026 16:33
Add method="cell_wise" to Model.convert_to_multigroup: like material_wise, but
gives each cell its own multigroup cross sections. The material in every
material-filled cell is cloned (each clone gets a unique id), then the standard
per-material generation runs, so per material becomes per cell. This captures the
intra-material spatial-spectrum variation that material_wise averages away when
one material spans a strong gradient.
The implementation reuses the material_wise path entirely; the only new code is
the per-cell cloning step in convert_to_multigroup plus the dispatch entry. Adds
unit tests (CSG and DAGMC: two cells sharing a material get distinct
macroscopics) and a user guide entry in the MGXS methods table.
Builds on the name+id library keying from openmc-dev#3984 (now in develop).
Co-authored-by: jon-proxima <jon@proximafusion.com>
@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 8698b76 to 3681d7cCompareJuly 1, 2026 07:42
@jon-proximafusionjon-proximafusion changed the title Add material_cell_wise MGXS generation methodAdd cell_wise MGXS generation methodJul 1, 2026

@jtrammjtramm 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.

This looks great @jon-proximafusion -- thanks so much for adding it in! I think it should be a cheap way of improving fidelity vs. the current material-wise method.

Just one small comment below on adding some extra clarifying discussions to the docs.

Additionally - we currently have end-to-end testing for all the MGXS generation techniques in tests/regression_tests/random_ray_auto_convert/test.py, so you could add the new method to the @parametrize list there to test it as well.

Comment on lines +678 to +686
* Like ``material_wise``, but clones the material in each cell so every
cell gets its own cross sections (each material-filled cell is assigned a
distinct macroscopic).
- * Resolves intra-material spatial variation that ``material_wise`` averages
away, e.g. a thick shield or a steep flux gradient within a single material
* Captures spatial self shielding between cells filled with the same material
- * Most expensive (one cross section set per cell) and a larger library
* Same far-from-source limitation as ``material_wise``: a cell that is not
tallied to yields zero cross sections for that cell

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.

We might want to add a note clarifying that it is generating unique MGXS data for each cell and not for each cell instance. Basically, it would be nice to alert the user that a cell that shows up in multiple locations of a lattice would have the same MGXS data set for all locations. If this type of discussion ends up being too wordy for the table formatting, perhaps it can be included as regular text elsewhere in the section.

  • Resolves intra-material spatial variation that material_wise averages
    away, e.g. a thick shield or a steep flux gradient within a single material
  • Captures spatial self shielding between cells filled with the same material

I don't completely agree with, as a cell may still be very large and have a steep gradient within it. A full shield wall may easily just be defined with one cell, in which case, you still are sharing the same MGXS throughout the full wall (even if you had applied a cell-under-voxel overlay to make smaller source regions). You only get an improvement if you had manually broken the shield wall down in your geometry definition into multiple cells that cover different depths of the wall. Basically, we don't want to oversell this method in terms of fidelity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks @jtramm yes good spot, I have updated the docs as suggested

@jtrammjtramm added the MGXS label Jul 20, 2026
@jon-proximafusion

Copy link
Copy Markdown
ContributorAuthor

Thanks @jtramm, good points on both. I've pushed a doc-only commit:

  • Reworded the fidelity claim so it no longer implies an arbitrary intra-cell gradient is resolved. It now states the gain is between distinct cells sharing a material, and added a cons bullet noting fidelity is bounded by the cell definitions (not the source region mesh), so a single large cell uses one cross section set throughout and a gradient is only resolved if the geometry is split into several cells.
  • Added a note after the table clarifying that cell_wise generates one cross section set per cell definition, not per cell instance, so a cell repeated across lattice locations shares a single set.

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 5d79377 to f8e3d36CompareJuly 21, 2026 09:52
# Conflicts:
#	docs/source/usersguide/random_ray.rst
#	openmc/model/model.py
#	tests/unit_tests/test_model.py
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jon-proximafusion@jtramm@shimwell
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
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;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Add cell_wise MGXS generation method by jon-proximafusion · Pull Request #3987 · openmc-dev/openmc · GitHub
Skip to content

Add cell_wise MGXS generation method - #3987

Open
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise
Open

Add cell_wise MGXS generation method#3987
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise

Conversation

@jon-proximafusion

@jon-proximafusionjon-proximafusion commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Add a cell_wise MGXS generation method

model.convert_to_multigroup(method="cell_wise", groups=...)

Like material_wise, but gives each cell its own multigroup cross sections, so it
captures the intra-material spatial variation that material_wise averages away
(for example a steel material reused in several cells).

Implementation

Full reuse of the material_wise path. Before generation, the material in every
material-filled cell is cloned (each clone gets a unique id via
Material.clone()). The standard per-material generation then produces and assigns
one cross section set per cell. The only new code is the per-cell cloning step in
convert_to_multigroup plus the dispatch entry (about 20 lines). material_wise
behavior is unchanged.

Works for both CSG and DAGMC. convert_to_multigroup already synchronizes DAGMC
cells before generation, so the per-cell clones become standard DAGMC per-cell
material overrides with no special handling.

Contents

  • openmc/model/model.py: the per-cell cloning step and dispatch entry.
  • tests/unit_tests/test_model.py: CSG unit test (two cells sharing a material get
    distinct macroscopics).
  • tests/unit_tests/dagmc/test_convert_to_multigroup.py: DAGMC unit test (a model
    with two fuel volumes sharing one material yields three distinct per-cell
    macroscopics).
  • docs/source/usersguide/random_ray.rst: adds cell_wise to the method
    list and to the "Comparison of Automatic MGXS Generation Methods" table.

Verification

  • CSG: a 4-shell single-material sphere produces four distinct per-cell cross
    section sets, while material_wise on the same model produces one (regression
    intact).
  • DAGMC: the 5-volume dagmc.h5m model (two fuel volumes sharing one material,
    plus water) yields three distinct per-cell macroscopics; void volumes are
    skipped.

Status

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 1f966fd to 8698b76CompareJune 30, 2026 16:32
@shimwell
shimwell requested a review from jtrammJune 30, 2026 16:33
Add method="cell_wise" to Model.convert_to_multigroup: like material_wise, but
gives each cell its own multigroup cross sections. The material in every
material-filled cell is cloned (each clone gets a unique id), then the standard
per-material generation runs, so per material becomes per cell. This captures the
intra-material spatial-spectrum variation that material_wise averages away when
one material spans a strong gradient.
The implementation reuses the material_wise path entirely; the only new code is
the per-cell cloning step in convert_to_multigroup plus the dispatch entry. Adds
unit tests (CSG and DAGMC: two cells sharing a material get distinct
macroscopics) and a user guide entry in the MGXS methods table.
Builds on the name+id library keying from openmc-dev#3984 (now in develop).
Co-authored-by: jon-proxima <jon@proximafusion.com>
@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 8698b76 to 3681d7cCompareJuly 1, 2026 07:42
@jon-proximafusionjon-proximafusion changed the title Add material_cell_wise MGXS generation methodAdd cell_wise MGXS generation methodJul 1, 2026

@jtrammjtramm 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.

This looks great @jon-proximafusion -- thanks so much for adding it in! I think it should be a cheap way of improving fidelity vs. the current material-wise method.

Just one small comment below on adding some extra clarifying discussions to the docs.

Additionally - we currently have end-to-end testing for all the MGXS generation techniques in tests/regression_tests/random_ray_auto_convert/test.py, so you could add the new method to the @parametrize list there to test it as well.

Comment on lines +678 to +686
* Like ``material_wise``, but clones the material in each cell so every
cell gets its own cross sections (each material-filled cell is assigned a
distinct macroscopic).
- * Resolves intra-material spatial variation that ``material_wise`` averages
away, e.g. a thick shield or a steep flux gradient within a single material
* Captures spatial self shielding between cells filled with the same material
- * Most expensive (one cross section set per cell) and a larger library
* Same far-from-source limitation as ``material_wise``: a cell that is not
tallied to yields zero cross sections for that cell

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.

We might want to add a note clarifying that it is generating unique MGXS data for each cell and not for each cell instance. Basically, it would be nice to alert the user that a cell that shows up in multiple locations of a lattice would have the same MGXS data set for all locations. If this type of discussion ends up being too wordy for the table formatting, perhaps it can be included as regular text elsewhere in the section.

  • Resolves intra-material spatial variation that material_wise averages
    away, e.g. a thick shield or a steep flux gradient within a single material
  • Captures spatial self shielding between cells filled with the same material

I don't completely agree with, as a cell may still be very large and have a steep gradient within it. A full shield wall may easily just be defined with one cell, in which case, you still are sharing the same MGXS throughout the full wall (even if you had applied a cell-under-voxel overlay to make smaller source regions). You only get an improvement if you had manually broken the shield wall down in your geometry definition into multiple cells that cover different depths of the wall. Basically, we don't want to oversell this method in terms of fidelity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks @jtramm yes good spot, I have updated the docs as suggested

@jtrammjtramm added the MGXS label Jul 20, 2026
@jon-proximafusion

Copy link
Copy Markdown
ContributorAuthor

Thanks @jtramm, good points on both. I've pushed a doc-only commit:

  • Reworded the fidelity claim so it no longer implies an arbitrary intra-cell gradient is resolved. It now states the gain is between distinct cells sharing a material, and added a cons bullet noting fidelity is bounded by the cell definitions (not the source region mesh), so a single large cell uses one cross section set throughout and a gradient is only resolved if the geometry is split into several cells.
  • Added a note after the table clarifying that cell_wise generates one cross section set per cell definition, not per cell instance, so a cell repeated across lattice locations shares a single set.

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 5d79377 to f8e3d36CompareJuly 21, 2026 09:52
# Conflicts:
#	docs/source/usersguide/random_ray.rst
#	openmc/model/model.py
#	tests/unit_tests/test_model.py
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jon-proximafusion@jtramm@shimwell
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add cell_wise MGXS generation method by jon-proximafusion · Pull Request #3987 · openmc-dev/openmc · GitHub
Skip to content

Add cell_wise MGXS generation method - #3987

Open
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise
Open

Add cell_wise MGXS generation method#3987
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise

Conversation

@jon-proximafusion

@jon-proximafusionjon-proximafusion commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Add a cell_wise MGXS generation method

model.convert_to_multigroup(method="cell_wise", groups=...)

Like material_wise, but gives each cell its own multigroup cross sections, so it
captures the intra-material spatial variation that material_wise averages away
(for example a steel material reused in several cells).

Implementation

Full reuse of the material_wise path. Before generation, the material in every
material-filled cell is cloned (each clone gets a unique id via
Material.clone()). The standard per-material generation then produces and assigns
one cross section set per cell. The only new code is the per-cell cloning step in
convert_to_multigroup plus the dispatch entry (about 20 lines). material_wise
behavior is unchanged.

Works for both CSG and DAGMC. convert_to_multigroup already synchronizes DAGMC
cells before generation, so the per-cell clones become standard DAGMC per-cell
material overrides with no special handling.

Contents

  • openmc/model/model.py: the per-cell cloning step and dispatch entry.
  • tests/unit_tests/test_model.py: CSG unit test (two cells sharing a material get
    distinct macroscopics).
  • tests/unit_tests/dagmc/test_convert_to_multigroup.py: DAGMC unit test (a model
    with two fuel volumes sharing one material yields three distinct per-cell
    macroscopics).
  • docs/source/usersguide/random_ray.rst: adds cell_wise to the method
    list and to the "Comparison of Automatic MGXS Generation Methods" table.

Verification

  • CSG: a 4-shell single-material sphere produces four distinct per-cell cross
    section sets, while material_wise on the same model produces one (regression
    intact).
  • DAGMC: the 5-volume dagmc.h5m model (two fuel volumes sharing one material,
    plus water) yields three distinct per-cell macroscopics; void volumes are
    skipped.

Status

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 1f966fd to 8698b76CompareJune 30, 2026 16:32
@shimwell
shimwell requested a review from jtrammJune 30, 2026 16:33
Add method="cell_wise" to Model.convert_to_multigroup: like material_wise, but
gives each cell its own multigroup cross sections. The material in every
material-filled cell is cloned (each clone gets a unique id), then the standard
per-material generation runs, so per material becomes per cell. This captures the
intra-material spatial-spectrum variation that material_wise averages away when
one material spans a strong gradient.
The implementation reuses the material_wise path entirely; the only new code is
the per-cell cloning step in convert_to_multigroup plus the dispatch entry. Adds
unit tests (CSG and DAGMC: two cells sharing a material get distinct
macroscopics) and a user guide entry in the MGXS methods table.
Builds on the name+id library keying from openmc-dev#3984 (now in develop).
Co-authored-by: jon-proxima <jon@proximafusion.com>
@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 8698b76 to 3681d7cCompareJuly 1, 2026 07:42
@jon-proximafusionjon-proximafusion changed the title Add material_cell_wise MGXS generation methodAdd cell_wise MGXS generation methodJul 1, 2026

@jtrammjtramm 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.

This looks great @jon-proximafusion -- thanks so much for adding it in! I think it should be a cheap way of improving fidelity vs. the current material-wise method.

Just one small comment below on adding some extra clarifying discussions to the docs.

Additionally - we currently have end-to-end testing for all the MGXS generation techniques in tests/regression_tests/random_ray_auto_convert/test.py, so you could add the new method to the @parametrize list there to test it as well.

Comment on lines +678 to +686
* Like ``material_wise``, but clones the material in each cell so every
cell gets its own cross sections (each material-filled cell is assigned a
distinct macroscopic).
- * Resolves intra-material spatial variation that ``material_wise`` averages
away, e.g. a thick shield or a steep flux gradient within a single material
* Captures spatial self shielding between cells filled with the same material
- * Most expensive (one cross section set per cell) and a larger library
* Same far-from-source limitation as ``material_wise``: a cell that is not
tallied to yields zero cross sections for that cell

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.

We might want to add a note clarifying that it is generating unique MGXS data for each cell and not for each cell instance. Basically, it would be nice to alert the user that a cell that shows up in multiple locations of a lattice would have the same MGXS data set for all locations. If this type of discussion ends up being too wordy for the table formatting, perhaps it can be included as regular text elsewhere in the section.

  • Resolves intra-material spatial variation that material_wise averages
    away, e.g. a thick shield or a steep flux gradient within a single material
  • Captures spatial self shielding between cells filled with the same material

I don't completely agree with, as a cell may still be very large and have a steep gradient within it. A full shield wall may easily just be defined with one cell, in which case, you still are sharing the same MGXS throughout the full wall (even if you had applied a cell-under-voxel overlay to make smaller source regions). You only get an improvement if you had manually broken the shield wall down in your geometry definition into multiple cells that cover different depths of the wall. Basically, we don't want to oversell this method in terms of fidelity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks @jtramm yes good spot, I have updated the docs as suggested

@jtrammjtramm added the MGXS label Jul 20, 2026
@jon-proximafusion

Copy link
Copy Markdown
ContributorAuthor

Thanks @jtramm, good points on both. I've pushed a doc-only commit:

  • Reworded the fidelity claim so it no longer implies an arbitrary intra-cell gradient is resolved. It now states the gain is between distinct cells sharing a material, and added a cons bullet noting fidelity is bounded by the cell definitions (not the source region mesh), so a single large cell uses one cross section set throughout and a gradient is only resolved if the geometry is split into several cells.
  • Added a note after the table clarifying that cell_wise generates one cross section set per cell definition, not per cell instance, so a cell repeated across lattice locations shares a single set.

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 5d79377 to f8e3d36CompareJuly 21, 2026 09:52
# Conflicts:
#	docs/source/usersguide/random_ray.rst
#	openmc/model/model.py
#	tests/unit_tests/test_model.py
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

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

Add cell_wise MGXS generation method - #3987

Open
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise
Open

Add cell_wise MGXS generation method#3987
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise

Conversation

@jon-proximafusion

@jon-proximafusionjon-proximafusion commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Add a cell_wise MGXS generation method

model.convert_to_multigroup(method="cell_wise", groups=...)

Like material_wise, but gives each cell its own multigroup cross sections, so it
captures the intra-material spatial variation that material_wise averages away
(for example a steel material reused in several cells).

Implementation

Full reuse of the material_wise path. Before generation, the material in every
material-filled cell is cloned (each clone gets a unique id via
Material.clone()). The standard per-material generation then produces and assigns
one cross section set per cell. The only new code is the per-cell cloning step in
convert_to_multigroup plus the dispatch entry (about 20 lines). material_wise
behavior is unchanged.

Works for both CSG and DAGMC. convert_to_multigroup already synchronizes DAGMC
cells before generation, so the per-cell clones become standard DAGMC per-cell
material overrides with no special handling.

Contents

  • openmc/model/model.py: the per-cell cloning step and dispatch entry.
  • tests/unit_tests/test_model.py: CSG unit test (two cells sharing a material get
    distinct macroscopics).
  • tests/unit_tests/dagmc/test_convert_to_multigroup.py: DAGMC unit test (a model
    with two fuel volumes sharing one material yields three distinct per-cell
    macroscopics).
  • docs/source/usersguide/random_ray.rst: adds cell_wise to the method
    list and to the "Comparison of Automatic MGXS Generation Methods" table.

Verification

  • CSG: a 4-shell single-material sphere produces four distinct per-cell cross
    section sets, while material_wise on the same model produces one (regression
    intact).
  • DAGMC: the 5-volume dagmc.h5m model (two fuel volumes sharing one material,
    plus water) yields three distinct per-cell macroscopics; void volumes are
    skipped.

Status

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 1f966fd to 8698b76CompareJune 30, 2026 16:32
@shimwell
shimwell requested a review from jtrammJune 30, 2026 16:33
Add method="cell_wise" to Model.convert_to_multigroup: like material_wise, but
gives each cell its own multigroup cross sections. The material in every
material-filled cell is cloned (each clone gets a unique id), then the standard
per-material generation runs, so per material becomes per cell. This captures the
intra-material spatial-spectrum variation that material_wise averages away when
one material spans a strong gradient.
The implementation reuses the material_wise path entirely; the only new code is
the per-cell cloning step in convert_to_multigroup plus the dispatch entry. Adds
unit tests (CSG and DAGMC: two cells sharing a material get distinct
macroscopics) and a user guide entry in the MGXS methods table.
Builds on the name+id library keying from openmc-dev#3984 (now in develop).
Co-authored-by: jon-proxima <jon@proximafusion.com>
@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 8698b76 to 3681d7cCompareJuly 1, 2026 07:42
@jon-proximafusionjon-proximafusion changed the title Add material_cell_wise MGXS generation methodAdd cell_wise MGXS generation methodJul 1, 2026

@jtrammjtramm 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.

This looks great @jon-proximafusion -- thanks so much for adding it in! I think it should be a cheap way of improving fidelity vs. the current material-wise method.

Just one small comment below on adding some extra clarifying discussions to the docs.

Additionally - we currently have end-to-end testing for all the MGXS generation techniques in tests/regression_tests/random_ray_auto_convert/test.py, so you could add the new method to the @parametrize list there to test it as well.

Comment on lines +678 to +686
* Like ``material_wise``, but clones the material in each cell so every
cell gets its own cross sections (each material-filled cell is assigned a
distinct macroscopic).
- * Resolves intra-material spatial variation that ``material_wise`` averages
away, e.g. a thick shield or a steep flux gradient within a single material
* Captures spatial self shielding between cells filled with the same material
- * Most expensive (one cross section set per cell) and a larger library
* Same far-from-source limitation as ``material_wise``: a cell that is not
tallied to yields zero cross sections for that cell

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.

We might want to add a note clarifying that it is generating unique MGXS data for each cell and not for each cell instance. Basically, it would be nice to alert the user that a cell that shows up in multiple locations of a lattice would have the same MGXS data set for all locations. If this type of discussion ends up being too wordy for the table formatting, perhaps it can be included as regular text elsewhere in the section.

  • Resolves intra-material spatial variation that material_wise averages
    away, e.g. a thick shield or a steep flux gradient within a single material
  • Captures spatial self shielding between cells filled with the same material

I don't completely agree with, as a cell may still be very large and have a steep gradient within it. A full shield wall may easily just be defined with one cell, in which case, you still are sharing the same MGXS throughout the full wall (even if you had applied a cell-under-voxel overlay to make smaller source regions). You only get an improvement if you had manually broken the shield wall down in your geometry definition into multiple cells that cover different depths of the wall. Basically, we don't want to oversell this method in terms of fidelity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks @jtramm yes good spot, I have updated the docs as suggested

@jtrammjtramm added the MGXS label Jul 20, 2026
@jon-proximafusion

Copy link
Copy Markdown
ContributorAuthor

Thanks @jtramm, good points on both. I've pushed a doc-only commit:

  • Reworded the fidelity claim so it no longer implies an arbitrary intra-cell gradient is resolved. It now states the gain is between distinct cells sharing a material, and added a cons bullet noting fidelity is bounded by the cell definitions (not the source region mesh), so a single large cell uses one cross section set throughout and a gradient is only resolved if the geometry is split into several cells.
  • Added a note after the table clarifying that cell_wise generates one cross section set per cell definition, not per cell instance, so a cell repeated across lattice locations shares a single set.

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 5d79377 to f8e3d36CompareJuly 21, 2026 09:52
# Conflicts:
#	docs/source/usersguide/random_ray.rst
#	openmc/model/model.py
#	tests/unit_tests/test_model.py
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

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

Add cell_wise MGXS generation method - #3987

Open
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise
Open

Add cell_wise MGXS generation method#3987
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise

Conversation

@jon-proximafusion

@jon-proximafusionjon-proximafusion commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Add a cell_wise MGXS generation method

model.convert_to_multigroup(method="cell_wise", groups=...)

Like material_wise, but gives each cell its own multigroup cross sections, so it
captures the intra-material spatial variation that material_wise averages away
(for example a steel material reused in several cells).

Implementation

Full reuse of the material_wise path. Before generation, the material in every
material-filled cell is cloned (each clone gets a unique id via
Material.clone()). The standard per-material generation then produces and assigns
one cross section set per cell. The only new code is the per-cell cloning step in
convert_to_multigroup plus the dispatch entry (about 20 lines). material_wise
behavior is unchanged.

Works for both CSG and DAGMC. convert_to_multigroup already synchronizes DAGMC
cells before generation, so the per-cell clones become standard DAGMC per-cell
material overrides with no special handling.

Contents

  • openmc/model/model.py: the per-cell cloning step and dispatch entry.
  • tests/unit_tests/test_model.py: CSG unit test (two cells sharing a material get
    distinct macroscopics).
  • tests/unit_tests/dagmc/test_convert_to_multigroup.py: DAGMC unit test (a model
    with two fuel volumes sharing one material yields three distinct per-cell
    macroscopics).
  • docs/source/usersguide/random_ray.rst: adds cell_wise to the method
    list and to the "Comparison of Automatic MGXS Generation Methods" table.

Verification

  • CSG: a 4-shell single-material sphere produces four distinct per-cell cross
    section sets, while material_wise on the same model produces one (regression
    intact).
  • DAGMC: the 5-volume dagmc.h5m model (two fuel volumes sharing one material,
    plus water) yields three distinct per-cell macroscopics; void volumes are
    skipped.

Status

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 1f966fd to 8698b76CompareJune 30, 2026 16:32
@shimwell
shimwell requested a review from jtrammJune 30, 2026 16:33
Add method="cell_wise" to Model.convert_to_multigroup: like material_wise, but
gives each cell its own multigroup cross sections. The material in every
material-filled cell is cloned (each clone gets a unique id), then the standard
per-material generation runs, so per material becomes per cell. This captures the
intra-material spatial-spectrum variation that material_wise averages away when
one material spans a strong gradient.
The implementation reuses the material_wise path entirely; the only new code is
the per-cell cloning step in convert_to_multigroup plus the dispatch entry. Adds
unit tests (CSG and DAGMC: two cells sharing a material get distinct
macroscopics) and a user guide entry in the MGXS methods table.
Builds on the name+id library keying from openmc-dev#3984 (now in develop).
Co-authored-by: jon-proxima <jon@proximafusion.com>
@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 8698b76 to 3681d7cCompareJuly 1, 2026 07:42
@jon-proximafusionjon-proximafusion changed the title Add material_cell_wise MGXS generation methodAdd cell_wise MGXS generation methodJul 1, 2026

@jtrammjtramm 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.

This looks great @jon-proximafusion -- thanks so much for adding it in! I think it should be a cheap way of improving fidelity vs. the current material-wise method.

Just one small comment below on adding some extra clarifying discussions to the docs.

Additionally - we currently have end-to-end testing for all the MGXS generation techniques in tests/regression_tests/random_ray_auto_convert/test.py, so you could add the new method to the @parametrize list there to test it as well.

Comment on lines +678 to +686
* Like ``material_wise``, but clones the material in each cell so every
cell gets its own cross sections (each material-filled cell is assigned a
distinct macroscopic).
- * Resolves intra-material spatial variation that ``material_wise`` averages
away, e.g. a thick shield or a steep flux gradient within a single material
* Captures spatial self shielding between cells filled with the same material
- * Most expensive (one cross section set per cell) and a larger library
* Same far-from-source limitation as ``material_wise``: a cell that is not
tallied to yields zero cross sections for that cell

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.

We might want to add a note clarifying that it is generating unique MGXS data for each cell and not for each cell instance. Basically, it would be nice to alert the user that a cell that shows up in multiple locations of a lattice would have the same MGXS data set for all locations. If this type of discussion ends up being too wordy for the table formatting, perhaps it can be included as regular text elsewhere in the section.

  • Resolves intra-material spatial variation that material_wise averages
    away, e.g. a thick shield or a steep flux gradient within a single material
  • Captures spatial self shielding between cells filled with the same material

I don't completely agree with, as a cell may still be very large and have a steep gradient within it. A full shield wall may easily just be defined with one cell, in which case, you still are sharing the same MGXS throughout the full wall (even if you had applied a cell-under-voxel overlay to make smaller source regions). You only get an improvement if you had manually broken the shield wall down in your geometry definition into multiple cells that cover different depths of the wall. Basically, we don't want to oversell this method in terms of fidelity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks @jtramm yes good spot, I have updated the docs as suggested

@jtrammjtramm added the MGXS label Jul 20, 2026
@jon-proximafusion

Copy link
Copy Markdown
ContributorAuthor

Thanks @jtramm, good points on both. I've pushed a doc-only commit:

  • Reworded the fidelity claim so it no longer implies an arbitrary intra-cell gradient is resolved. It now states the gain is between distinct cells sharing a material, and added a cons bullet noting fidelity is bounded by the cell definitions (not the source region mesh), so a single large cell uses one cross section set throughout and a gradient is only resolved if the geometry is split into several cells.
  • Added a note after the table clarifying that cell_wise generates one cross section set per cell definition, not per cell instance, so a cell repeated across lattice locations shares a single set.

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 5d79377 to f8e3d36CompareJuly 21, 2026 09:52
# Conflicts:
#	docs/source/usersguide/random_ray.rst
#	openmc/model/model.py
#	tests/unit_tests/test_model.py
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jon-proximafusion@jtramm@shimwell
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add cell_wise MGXS generation method by jon-proximafusion · Pull Request #3987 · openmc-dev/openmc · GitHub
Skip to content

Add cell_wise MGXS generation method - #3987

Open
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise
Open

Add cell_wise MGXS generation method#3987
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise

Conversation

@jon-proximafusion

@jon-proximafusionjon-proximafusion commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Add a cell_wise MGXS generation method

model.convert_to_multigroup(method="cell_wise", groups=...)

Like material_wise, but gives each cell its own multigroup cross sections, so it
captures the intra-material spatial variation that material_wise averages away
(for example a steel material reused in several cells).

Implementation

Full reuse of the material_wise path. Before generation, the material in every
material-filled cell is cloned (each clone gets a unique id via
Material.clone()). The standard per-material generation then produces and assigns
one cross section set per cell. The only new code is the per-cell cloning step in
convert_to_multigroup plus the dispatch entry (about 20 lines). material_wise
behavior is unchanged.

Works for both CSG and DAGMC. convert_to_multigroup already synchronizes DAGMC
cells before generation, so the per-cell clones become standard DAGMC per-cell
material overrides with no special handling.

Contents

  • openmc/model/model.py: the per-cell cloning step and dispatch entry.
  • tests/unit_tests/test_model.py: CSG unit test (two cells sharing a material get
    distinct macroscopics).
  • tests/unit_tests/dagmc/test_convert_to_multigroup.py: DAGMC unit test (a model
    with two fuel volumes sharing one material yields three distinct per-cell
    macroscopics).
  • docs/source/usersguide/random_ray.rst: adds cell_wise to the method
    list and to the "Comparison of Automatic MGXS Generation Methods" table.

Verification

  • CSG: a 4-shell single-material sphere produces four distinct per-cell cross
    section sets, while material_wise on the same model produces one (regression
    intact).
  • DAGMC: the 5-volume dagmc.h5m model (two fuel volumes sharing one material,
    plus water) yields three distinct per-cell macroscopics; void volumes are
    skipped.

Status

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 1f966fd to 8698b76CompareJune 30, 2026 16:32
@shimwell
shimwell requested a review from jtrammJune 30, 2026 16:33
Add method="cell_wise" to Model.convert_to_multigroup: like material_wise, but
gives each cell its own multigroup cross sections. The material in every
material-filled cell is cloned (each clone gets a unique id), then the standard
per-material generation runs, so per material becomes per cell. This captures the
intra-material spatial-spectrum variation that material_wise averages away when
one material spans a strong gradient.
The implementation reuses the material_wise path entirely; the only new code is
the per-cell cloning step in convert_to_multigroup plus the dispatch entry. Adds
unit tests (CSG and DAGMC: two cells sharing a material get distinct
macroscopics) and a user guide entry in the MGXS methods table.
Builds on the name+id library keying from openmc-dev#3984 (now in develop).
Co-authored-by: jon-proxima <jon@proximafusion.com>
@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 8698b76 to 3681d7cCompareJuly 1, 2026 07:42
@jon-proximafusionjon-proximafusion changed the title Add material_cell_wise MGXS generation methodAdd cell_wise MGXS generation methodJul 1, 2026

@jtrammjtramm 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.

This looks great @jon-proximafusion -- thanks so much for adding it in! I think it should be a cheap way of improving fidelity vs. the current material-wise method.

Just one small comment below on adding some extra clarifying discussions to the docs.

Additionally - we currently have end-to-end testing for all the MGXS generation techniques in tests/regression_tests/random_ray_auto_convert/test.py, so you could add the new method to the @parametrize list there to test it as well.

Comment on lines +678 to +686
* Like ``material_wise``, but clones the material in each cell so every
cell gets its own cross sections (each material-filled cell is assigned a
distinct macroscopic).
- * Resolves intra-material spatial variation that ``material_wise`` averages
away, e.g. a thick shield or a steep flux gradient within a single material
* Captures spatial self shielding between cells filled with the same material
- * Most expensive (one cross section set per cell) and a larger library
* Same far-from-source limitation as ``material_wise``: a cell that is not
tallied to yields zero cross sections for that cell

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.

We might want to add a note clarifying that it is generating unique MGXS data for each cell and not for each cell instance. Basically, it would be nice to alert the user that a cell that shows up in multiple locations of a lattice would have the same MGXS data set for all locations. If this type of discussion ends up being too wordy for the table formatting, perhaps it can be included as regular text elsewhere in the section.

  • Resolves intra-material spatial variation that material_wise averages
    away, e.g. a thick shield or a steep flux gradient within a single material
  • Captures spatial self shielding between cells filled with the same material

I don't completely agree with, as a cell may still be very large and have a steep gradient within it. A full shield wall may easily just be defined with one cell, in which case, you still are sharing the same MGXS throughout the full wall (even if you had applied a cell-under-voxel overlay to make smaller source regions). You only get an improvement if you had manually broken the shield wall down in your geometry definition into multiple cells that cover different depths of the wall. Basically, we don't want to oversell this method in terms of fidelity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks @jtramm yes good spot, I have updated the docs as suggested

@jtrammjtramm added the MGXS label Jul 20, 2026
@jon-proximafusion

Copy link
Copy Markdown
ContributorAuthor

Thanks @jtramm, good points on both. I've pushed a doc-only commit:

  • Reworded the fidelity claim so it no longer implies an arbitrary intra-cell gradient is resolved. It now states the gain is between distinct cells sharing a material, and added a cons bullet noting fidelity is bounded by the cell definitions (not the source region mesh), so a single large cell uses one cross section set throughout and a gradient is only resolved if the geometry is split into several cells.
  • Added a note after the table clarifying that cell_wise generates one cross section set per cell definition, not per cell instance, so a cell repeated across lattice locations shares a single set.

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 5d79377 to f8e3d36CompareJuly 21, 2026 09:52
# Conflicts:
#	docs/source/usersguide/random_ray.rst
#	openmc/model/model.py
#	tests/unit_tests/test_model.py
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jon-proximafusion@jtramm@shimwell
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add cell_wise MGXS generation method by jon-proximafusion · Pull Request #3987 · openmc-dev/openmc · GitHub
Skip to content

Add cell_wise MGXS generation method - #3987

Open
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise
Open

Add cell_wise MGXS generation method#3987
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise

Conversation

@jon-proximafusion

@jon-proximafusionjon-proximafusion commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Add a cell_wise MGXS generation method

model.convert_to_multigroup(method="cell_wise", groups=...)

Like material_wise, but gives each cell its own multigroup cross sections, so it
captures the intra-material spatial variation that material_wise averages away
(for example a steel material reused in several cells).

Implementation

Full reuse of the material_wise path. Before generation, the material in every
material-filled cell is cloned (each clone gets a unique id via
Material.clone()). The standard per-material generation then produces and assigns
one cross section set per cell. The only new code is the per-cell cloning step in
convert_to_multigroup plus the dispatch entry (about 20 lines). material_wise
behavior is unchanged.

Works for both CSG and DAGMC. convert_to_multigroup already synchronizes DAGMC
cells before generation, so the per-cell clones become standard DAGMC per-cell
material overrides with no special handling.

Contents

  • openmc/model/model.py: the per-cell cloning step and dispatch entry.
  • tests/unit_tests/test_model.py: CSG unit test (two cells sharing a material get
    distinct macroscopics).
  • tests/unit_tests/dagmc/test_convert_to_multigroup.py: DAGMC unit test (a model
    with two fuel volumes sharing one material yields three distinct per-cell
    macroscopics).
  • docs/source/usersguide/random_ray.rst: adds cell_wise to the method
    list and to the "Comparison of Automatic MGXS Generation Methods" table.

Verification

  • CSG: a 4-shell single-material sphere produces four distinct per-cell cross
    section sets, while material_wise on the same model produces one (regression
    intact).
  • DAGMC: the 5-volume dagmc.h5m model (two fuel volumes sharing one material,
    plus water) yields three distinct per-cell macroscopics; void volumes are
    skipped.

Status

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 1f966fd to 8698b76CompareJune 30, 2026 16:32
@shimwell
shimwell requested a review from jtrammJune 30, 2026 16:33
Add method="cell_wise" to Model.convert_to_multigroup: like material_wise, but
gives each cell its own multigroup cross sections. The material in every
material-filled cell is cloned (each clone gets a unique id), then the standard
per-material generation runs, so per material becomes per cell. This captures the
intra-material spatial-spectrum variation that material_wise averages away when
one material spans a strong gradient.
The implementation reuses the material_wise path entirely; the only new code is
the per-cell cloning step in convert_to_multigroup plus the dispatch entry. Adds
unit tests (CSG and DAGMC: two cells sharing a material get distinct
macroscopics) and a user guide entry in the MGXS methods table.
Builds on the name+id library keying from openmc-dev#3984 (now in develop).
Co-authored-by: jon-proxima <jon@proximafusion.com>
@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 8698b76 to 3681d7cCompareJuly 1, 2026 07:42
@jon-proximafusionjon-proximafusion changed the title Add material_cell_wise MGXS generation methodAdd cell_wise MGXS generation methodJul 1, 2026

@jtrammjtramm 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.

This looks great @jon-proximafusion -- thanks so much for adding it in! I think it should be a cheap way of improving fidelity vs. the current material-wise method.

Just one small comment below on adding some extra clarifying discussions to the docs.

Additionally - we currently have end-to-end testing for all the MGXS generation techniques in tests/regression_tests/random_ray_auto_convert/test.py, so you could add the new method to the @parametrize list there to test it as well.

Comment on lines +678 to +686
* Like ``material_wise``, but clones the material in each cell so every
cell gets its own cross sections (each material-filled cell is assigned a
distinct macroscopic).
- * Resolves intra-material spatial variation that ``material_wise`` averages
away, e.g. a thick shield or a steep flux gradient within a single material
* Captures spatial self shielding between cells filled with the same material
- * Most expensive (one cross section set per cell) and a larger library
* Same far-from-source limitation as ``material_wise``: a cell that is not
tallied to yields zero cross sections for that cell

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.

We might want to add a note clarifying that it is generating unique MGXS data for each cell and not for each cell instance. Basically, it would be nice to alert the user that a cell that shows up in multiple locations of a lattice would have the same MGXS data set for all locations. If this type of discussion ends up being too wordy for the table formatting, perhaps it can be included as regular text elsewhere in the section.

  • Resolves intra-material spatial variation that material_wise averages
    away, e.g. a thick shield or a steep flux gradient within a single material
  • Captures spatial self shielding between cells filled with the same material

I don't completely agree with, as a cell may still be very large and have a steep gradient within it. A full shield wall may easily just be defined with one cell, in which case, you still are sharing the same MGXS throughout the full wall (even if you had applied a cell-under-voxel overlay to make smaller source regions). You only get an improvement if you had manually broken the shield wall down in your geometry definition into multiple cells that cover different depths of the wall. Basically, we don't want to oversell this method in terms of fidelity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks @jtramm yes good spot, I have updated the docs as suggested

@jtrammjtramm added the MGXS label Jul 20, 2026
@jon-proximafusion

Copy link
Copy Markdown
ContributorAuthor

Thanks @jtramm, good points on both. I've pushed a doc-only commit:

  • Reworded the fidelity claim so it no longer implies an arbitrary intra-cell gradient is resolved. It now states the gain is between distinct cells sharing a material, and added a cons bullet noting fidelity is bounded by the cell definitions (not the source region mesh), so a single large cell uses one cross section set throughout and a gradient is only resolved if the geometry is split into several cells.
  • Added a note after the table clarifying that cell_wise generates one cross section set per cell definition, not per cell instance, so a cell repeated across lattice locations shares a single set.

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 5d79377 to f8e3d36CompareJuly 21, 2026 09:52
# Conflicts:
#	docs/source/usersguide/random_ray.rst
#	openmc/model/model.py
#	tests/unit_tests/test_model.py
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

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

Add cell_wise MGXS generation method - #3987

Open
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise
Open

Add cell_wise MGXS generation method#3987
jon-proximafusion wants to merge 4 commits into
openmc-dev:developfrom
shimwell:convert-to-multigroup-material-cell-wise

Conversation

@jon-proximafusion

@jon-proximafusionjon-proximafusion commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Add a cell_wise MGXS generation method

model.convert_to_multigroup(method="cell_wise", groups=...)

Like material_wise, but gives each cell its own multigroup cross sections, so it
captures the intra-material spatial variation that material_wise averages away
(for example a steel material reused in several cells).

Implementation

Full reuse of the material_wise path. Before generation, the material in every
material-filled cell is cloned (each clone gets a unique id via
Material.clone()). The standard per-material generation then produces and assigns
one cross section set per cell. The only new code is the per-cell cloning step in
convert_to_multigroup plus the dispatch entry (about 20 lines). material_wise
behavior is unchanged.

Works for both CSG and DAGMC. convert_to_multigroup already synchronizes DAGMC
cells before generation, so the per-cell clones become standard DAGMC per-cell
material overrides with no special handling.

Contents

  • openmc/model/model.py: the per-cell cloning step and dispatch entry.
  • tests/unit_tests/test_model.py: CSG unit test (two cells sharing a material get
    distinct macroscopics).
  • tests/unit_tests/dagmc/test_convert_to_multigroup.py: DAGMC unit test (a model
    with two fuel volumes sharing one material yields three distinct per-cell
    macroscopics).
  • docs/source/usersguide/random_ray.rst: adds cell_wise to the method
    list and to the "Comparison of Automatic MGXS Generation Methods" table.

Verification

  • CSG: a 4-shell single-material sphere produces four distinct per-cell cross
    section sets, while material_wise on the same model produces one (regression
    intact).
  • DAGMC: the 5-volume dagmc.h5m model (two fuel volumes sharing one material,
    plus water) yields three distinct per-cell macroscopics; void volumes are
    skipped.

Status

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 1f966fd to 8698b76CompareJune 30, 2026 16:32
@shimwell
shimwell requested a review from jtrammJune 30, 2026 16:33
Add method="cell_wise" to Model.convert_to_multigroup: like material_wise, but
gives each cell its own multigroup cross sections. The material in every
material-filled cell is cloned (each clone gets a unique id), then the standard
per-material generation runs, so per material becomes per cell. This captures the
intra-material spatial-spectrum variation that material_wise averages away when
one material spans a strong gradient.
The implementation reuses the material_wise path entirely; the only new code is
the per-cell cloning step in convert_to_multigroup plus the dispatch entry. Adds
unit tests (CSG and DAGMC: two cells sharing a material get distinct
macroscopics) and a user guide entry in the MGXS methods table.
Builds on the name+id library keying from openmc-dev#3984 (now in develop).
Co-authored-by: jon-proxima <jon@proximafusion.com>
@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 8698b76 to 3681d7cCompareJuly 1, 2026 07:42
@jon-proximafusionjon-proximafusion changed the title Add material_cell_wise MGXS generation methodAdd cell_wise MGXS generation methodJul 1, 2026

@jtrammjtramm 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.

This looks great @jon-proximafusion -- thanks so much for adding it in! I think it should be a cheap way of improving fidelity vs. the current material-wise method.

Just one small comment below on adding some extra clarifying discussions to the docs.

Additionally - we currently have end-to-end testing for all the MGXS generation techniques in tests/regression_tests/random_ray_auto_convert/test.py, so you could add the new method to the @parametrize list there to test it as well.

Comment on lines +678 to +686
* Like ``material_wise``, but clones the material in each cell so every
cell gets its own cross sections (each material-filled cell is assigned a
distinct macroscopic).
- * Resolves intra-material spatial variation that ``material_wise`` averages
away, e.g. a thick shield or a steep flux gradient within a single material
* Captures spatial self shielding between cells filled with the same material
- * Most expensive (one cross section set per cell) and a larger library
* Same far-from-source limitation as ``material_wise``: a cell that is not
tallied to yields zero cross sections for that cell

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.

We might want to add a note clarifying that it is generating unique MGXS data for each cell and not for each cell instance. Basically, it would be nice to alert the user that a cell that shows up in multiple locations of a lattice would have the same MGXS data set for all locations. If this type of discussion ends up being too wordy for the table formatting, perhaps it can be included as regular text elsewhere in the section.

  • Resolves intra-material spatial variation that material_wise averages
    away, e.g. a thick shield or a steep flux gradient within a single material
  • Captures spatial self shielding between cells filled with the same material

I don't completely agree with, as a cell may still be very large and have a steep gradient within it. A full shield wall may easily just be defined with one cell, in which case, you still are sharing the same MGXS throughout the full wall (even if you had applied a cell-under-voxel overlay to make smaller source regions). You only get an improvement if you had manually broken the shield wall down in your geometry definition into multiple cells that cover different depths of the wall. Basically, we don't want to oversell this method in terms of fidelity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks @jtramm yes good spot, I have updated the docs as suggested

@jtrammjtramm added the MGXS label Jul 20, 2026
@jon-proximafusion

Copy link
Copy Markdown
ContributorAuthor

Thanks @jtramm, good points on both. I've pushed a doc-only commit:

  • Reworded the fidelity claim so it no longer implies an arbitrary intra-cell gradient is resolved. It now states the gain is between distinct cells sharing a material, and added a cons bullet noting fidelity is bounded by the cell definitions (not the source region mesh), so a single large cell uses one cross section set throughout and a gradient is only resolved if the geometry is split into several cells.
  • Added a note after the table clarifying that cell_wise generates one cross section set per cell definition, not per cell instance, so a cell repeated across lattice locations shares a single set.

@jon-proximafusion
jon-proximafusionforce-pushed the convert-to-multigroup-material-cell-wise branch from 5d79377 to f8e3d36CompareJuly 21, 2026 09:52
# Conflicts:
#	docs/source/usersguide/random_ray.rst
#	openmc/model/model.py
#	tests/unit_tests/test_model.py
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jon-proximafusion@jtramm@shimwell