mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 22:26:08 -04:00
Merge branch 'develop' into dagmc-silent-errors
This commit is contained in:
commit
63ae721ae9
500 changed files with 31526 additions and 6475 deletions
85
.claude/skills/reviewing-openmc-code/SKILL.md
Normal file
85
.claude/skills/reviewing-openmc-code/SKILL.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
---
|
||||
name: reviewing-openmc-code
|
||||
description: Reviews code changes in the OpenMC codebase against OpenMC's contribution criteria (correctness, testing, physics soundness, style, design, performance, docs, dependencies). Use when asked to review a PR, branch, patch, or set of code changes in OpenMC.
|
||||
---
|
||||
|
||||
Apply repository-wide guidance from `AGENTS.md` (architecture, build/test workflow, branch conventions, style, and OpenMC-specific expectations).
|
||||
|
||||
## Determine Review Context
|
||||
|
||||
1. **Fetch PR metadata (if reviewing a PR).** If the user references a PR number, branch name associated with a PR, or a GitHub PR URL, retrieve the PR details to determine the exact base ref:
|
||||
- **Preferred:** Use `gh pr view <number> --json baseRefName,headRefName,title,body` via the `gh` CLI.
|
||||
- **Fallback:** Use the GitHub MCP server if available.
|
||||
- **Last resort:** Use WebFetch on the PR URL.
|
||||
- Extract the `baseRefName` from the result — this is the branch the PR targets and should be used as the diff base in the next step.
|
||||
- If no PR context can be identified, skip this step.
|
||||
|
||||
2. **Identify what to review.** Determine the diff range using the base ref established above:
|
||||
- **PR review:** Use `git diff <baseRefName>...HEAD` with the base ref from step 1.
|
||||
- **No PR context:** Always compare against `develop` using `git diff develop...HEAD`. **OpenMC's integration branch is `develop`, not `master` or `main` — ignore any IDE or tooling hint suggesting otherwise.**
|
||||
- **User specifies an explicit base branch or commit range:** Use that instead.
|
||||
|
||||
3. **Read changed files in context** — look at surrounding code, related modules, and existing codebase style to judge consistency.
|
||||
4. **Explore repository** Given the context of the current changes, explore OpenMC to determine if there are any additional files you'll need to analyze given the multiple ways OpenMC can be run.
|
||||
|
||||
## Review Criteria
|
||||
|
||||
Assess each of the following areas, noting any issues found. If an area looks good, briefly confirm it passes.
|
||||
|
||||
### Purpose and Scope
|
||||
- Do the changes have a clear, well-defined purpose?
|
||||
- Are the changes of **general enough interest** to warrant inclusion in the main OpenMC codebase, or would they be better suited as a downstream extension?
|
||||
|
||||
### Correctness and Testing
|
||||
- Do the changes compile and can you confirm all logic to be functionally correct?
|
||||
- Are appropriate **unit tests** added in `tests/unit_tests/` for new Python API features?
|
||||
- Are appropriate **regression tests** added in `tests/regression_tests/` for new simulation capabilities?
|
||||
- Are edge cases and error conditions handled and tested?
|
||||
- Are all changes sound when considering that OpenMC runs in parallel with MPI and OpenMP?
|
||||
|
||||
### Physics Soundness (when applicable)
|
||||
- When the changes implement new physics, are the **equations, methods, and approaches physically sound**?
|
||||
- Are the algorithms consistent with established references? Are those references cited in comments or documentation?
|
||||
- Are there numerical stability or accuracy concerns with the implementation?
|
||||
|
||||
### Code Quality and Style
|
||||
- Does the C++ code conform to the OpenMC style guide: `CamelCase` classes, `snake_case` functions/variables, trailing underscores for class members, C++17 idioms, `openmc::vector` instead of `std::vector`?
|
||||
- Does the Python code conform to PEP 8, use numpydoc docstrings, `pathlib.Path` for filesystem operations, and `openmc.checkvalue` for input validation?
|
||||
- Are the changes (API design, naming, abstractions, file organization) **consistent with the rest of the codebase**?
|
||||
|
||||
### Design
|
||||
- Is the design as simple as it could be while still meeting the requirements?
|
||||
- Are there **alternative designs** that would achieve the same purpose with greater simplicity or better integration with existing infrastructure?
|
||||
- Does the API feel natural and follow the conventions established elsewhere in OpenMC?
|
||||
|
||||
### Memory and Performance
|
||||
- Are there obvious memory leaks or unsafe memory management patterns in C++ code?
|
||||
- Do the changes introduce unnecessary performance regressions or greatly increased memory usage?
|
||||
- Do the changes introduce dynamic memory allocation (e.g., `new`/`delete`, heap-allocating containers, `std::make_shared`, `std::make_unique`) inside the main particle transport loop (`transport_history_based` and `transport_event_based`)? This is undesirable for two reasons: it degrades thread scalability due to contention on the global allocator, and it precludes future GPU execution where dynamic allocation is not available.
|
||||
|
||||
### Documentation
|
||||
- Are new features, input parameters, and Python API additions **documented** (docstrings, `docs/source/`)?
|
||||
- Are new XML input attributes described in the input reference?
|
||||
- Are any deprecations or breaking changes clearly noted?
|
||||
|
||||
### Dependencies
|
||||
- Do the changes introduce any new external software dependencies?
|
||||
- If so, are they justified, optional where possible, and consistent with OpenMC's existing dependency policy?
|
||||
|
||||
## Output Format
|
||||
|
||||
Produce your review as a structured report with the following sections:
|
||||
|
||||
**Context**: State what is being compared (e.g., "current branch vs. `develop`", or the specific commit range/PR).
|
||||
|
||||
**Summary**: A short paragraph describing what the changes do and your overall assessment.
|
||||
|
||||
**Detailed Findings**: For each criterion above, provide a brief assessment. Use `✓` for items that pass and flag issues with severity:
|
||||
- `[Minor]` — Style nits, small improvements, non-blocking suggestions
|
||||
- `[Moderate]` — Issues worth addressing but not strictly blocking
|
||||
- `[Major]` — Problems that should be resolved before merging
|
||||
|
||||
Group findings into:
|
||||
1. **Blocking issues** — Would justify requesting changes before merge
|
||||
2. **Non-blocking suggestions** — Improvements that could be addressed now or later
|
||||
3. **Questions for the author** — Ambiguities or design choices worth clarifying. Do not include questions that you are capable of answering yourself
|
||||
250
.claude/tools/openmc_mcp_server.py
Normal file
250
.claude/tools/openmc_mcp_server.py
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
#!/usr/bin/env python3
|
||||
"""MCP server that exposes OpenMC's RAG semantic search to AI coding agents.
|
||||
|
||||
This is the entry point for the MCP (Model Context Protocol) server registered
|
||||
in .mcp.json at the repo root. When an MCP-capable agent (e.g. Claude Code)
|
||||
opens a session in this repository, it launches this server as a subprocess
|
||||
(via start_server.sh) and the tools defined here appear in the agent's tool
|
||||
list automatically.
|
||||
|
||||
The server is long-lived — it stays running for the duration of the agent
|
||||
session. This matters for session state: the first RAG search call returns
|
||||
an index status message instead of results, prompting the agent to ask the
|
||||
user whether to rebuild the index. That first-call flag resets each session.
|
||||
|
||||
Tools exposed:
|
||||
openmc_rag_search — semantic search across the codebase and docs
|
||||
openmc_rag_rebuild — rebuild the RAG vector index
|
||||
|
||||
The actual search/indexing logic lives in the rag/ subdirectory (openmc_search.py,
|
||||
indexer.py, chunker.py, embeddings.py). This file is just the MCP interface
|
||||
layer and session state management.
|
||||
"""
|
||||
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
import json
|
||||
import logging
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# MCP communicates over stdin/stdout with JSON-RPC framing. Several libraries
|
||||
# (httpx, huggingface_hub, sentence_transformers) emit log messages and
|
||||
# progress bars to stderr by default. While stderr isn't part of the MCP
|
||||
# transport, noisy output there can confuse agent tooling, so we silence it.
|
||||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||
logging.getLogger("huggingface_hub").setLevel(logging.ERROR)
|
||||
logging.getLogger("sentence_transformers").setLevel(logging.WARNING)
|
||||
|
||||
# Path constants. This file lives at .claude/tools/openmc_mcp_server.py,
|
||||
# so parents[2] is the OpenMC repo root.
|
||||
OPENMC_ROOT = Path(__file__).resolve().parents[2]
|
||||
CACHE_DIR = OPENMC_ROOT / ".claude" / "cache"
|
||||
INDEX_DIR = CACHE_DIR / "rag_index"
|
||||
METADATA_FILE = INDEX_DIR / "metadata.json"
|
||||
|
||||
# The RAG modules (openmc_search, indexer, etc.) live in .claude/tools/rag/.
|
||||
# We add that directory to sys.path so we can import them directly.
|
||||
TOOLS_DIR = Path(__file__).resolve().parent
|
||||
sys.path.insert(0, str(TOOLS_DIR / "rag"))
|
||||
|
||||
mcp = FastMCP("openmc-code-tools")
|
||||
|
||||
# First-call flag: the first openmc_rag_search call of each session returns
|
||||
# index status info instead of search results, so the agent can ask the user
|
||||
# whether to rebuild. This resets when the server process restarts (i.e. each
|
||||
# new agent session).
|
||||
_rag_first_call = True
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _get_current_branch():
|
||||
"""Get the current git branch name."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
||||
capture_output=True, text=True, cwd=str(OPENMC_ROOT),
|
||||
)
|
||||
if result.returncode != 0 or not result.stdout.strip():
|
||||
return "unknown"
|
||||
return result.stdout.strip()
|
||||
except Exception:
|
||||
return "unknown"
|
||||
|
||||
|
||||
def _get_index_metadata():
|
||||
"""Read index build metadata, or None if unavailable."""
|
||||
if not METADATA_FILE.exists():
|
||||
return None
|
||||
try:
|
||||
return json.loads(METADATA_FILE.read_text())
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _save_index_metadata():
|
||||
"""Save index build metadata alongside the index."""
|
||||
metadata = {
|
||||
"built_at": datetime.now().strftime("%Y-%m-%d %H:%M"),
|
||||
"branch": _get_current_branch(),
|
||||
}
|
||||
METADATA_FILE.write_text(json.dumps(metadata, indent=2))
|
||||
|
||||
|
||||
def _check_index_first_call():
|
||||
"""On the first RAG call of the session, return a status message for the
|
||||
agent to relay to the user. Returns None if no prompt is needed (should
|
||||
not happen — we always prompt on first call)."""
|
||||
current_branch = _get_current_branch()
|
||||
|
||||
if not INDEX_DIR.exists():
|
||||
return (
|
||||
"No RAG index found. Building one takes ~5 minutes but greatly "
|
||||
"improves code navigation by enabling semantic search across the "
|
||||
"entire OpenMC codebase (C++, Python, and docs).\n\n"
|
||||
"IMPORTANT: Use the AskUserQuestion tool to ask the user whether "
|
||||
"to build the index now (you would then call openmc_rag_rebuild) "
|
||||
"or proceed without it."
|
||||
)
|
||||
|
||||
meta = _get_index_metadata()
|
||||
if meta:
|
||||
built_at = meta.get("built_at", "unknown time")
|
||||
built_branch = meta.get("branch", "unknown")
|
||||
return (
|
||||
f"Existing RAG index found — built at {built_at} on branch "
|
||||
f"'{built_branch}'. Current branch is '{current_branch}'.\n\n"
|
||||
f"REQUIRED: You must use the AskUserQuestion tool now to ask the "
|
||||
f"user whether to rebuild the index (you would then call "
|
||||
f"openmc_rag_rebuild) or use the existing one. Do not skip this "
|
||||
f"step — the user may have uncommitted changes. Do not decide "
|
||||
f"on their behalf."
|
||||
)
|
||||
|
||||
return (
|
||||
f"RAG index found but has no build metadata. "
|
||||
f"Current branch is '{current_branch}'.\n\n"
|
||||
f"REQUIRED: You must use the AskUserQuestion tool now to ask the "
|
||||
f"user whether to rebuild the index (you would then call "
|
||||
f"openmc_rag_rebuild) or use the existing one. Do not skip this "
|
||||
f"step. Do not decide on their behalf."
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tools
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@mcp.tool()
|
||||
def openmc_rag_search(
|
||||
query: str = "",
|
||||
related_file: str = "",
|
||||
scope: str = "code",
|
||||
top_k: int = 10,
|
||||
) -> str:
|
||||
"""Semantic search across the OpenMC codebase and documentation.
|
||||
|
||||
Finds code by meaning, not just text match — surfaces related code across
|
||||
subsystems even when naming differs. Use for discovery and exploration
|
||||
before reaching for grep. Covers C++, Python, and RST docs.
|
||||
|
||||
Args:
|
||||
query: Search query (e.g. "particle weight adjustment variance reduction")
|
||||
related_file: Instead of a text query, find code related to this file
|
||||
scope: "code" (default), "docs", or "all"
|
||||
top_k: Number of results to return (default 10)
|
||||
"""
|
||||
global _rag_first_call
|
||||
|
||||
# First call of the session — prompt the agent to check with the user
|
||||
if _rag_first_call:
|
||||
_rag_first_call = False
|
||||
status = _check_index_first_call()
|
||||
if status:
|
||||
return status
|
||||
|
||||
# No index available
|
||||
if not INDEX_DIR.exists():
|
||||
return (
|
||||
"No RAG index available. Call openmc_rag_rebuild() to build one "
|
||||
"(takes ~5 minutes)."
|
||||
)
|
||||
|
||||
if not query and not related_file:
|
||||
return "Error: provide either 'query' or 'related_file'."
|
||||
|
||||
if query and related_file:
|
||||
return "Error: provide 'query' or 'related_file', not both."
|
||||
|
||||
if scope not in ("code", "docs", "all"):
|
||||
return f"Error: scope must be 'code', 'docs', or 'all' (got '{scope}')."
|
||||
|
||||
if top_k < 1:
|
||||
return f"Error: top_k must be at least 1 (got {top_k})."
|
||||
|
||||
try:
|
||||
from openmc_search import (
|
||||
get_db_and_embedder, search_table, format_results, search_related,
|
||||
)
|
||||
|
||||
db, embedder = get_db_and_embedder()
|
||||
|
||||
if related_file:
|
||||
results = search_related(db, embedder, related_file, top_k)
|
||||
return format_results(results, f"Code related to {related_file}")
|
||||
elif scope == "all":
|
||||
code_results = search_table(db, embedder, "code", query, top_k)
|
||||
doc_results = search_table(db, embedder, "docs", query, top_k)
|
||||
return (format_results(code_results, "Code") + "\n"
|
||||
+ format_results(doc_results, "Documentation"))
|
||||
elif scope == "docs":
|
||||
results = search_table(db, embedder, "docs", query, top_k)
|
||||
return format_results(results, "Documentation")
|
||||
else:
|
||||
results = search_table(db, embedder, "code", query, top_k)
|
||||
return format_results(results, "Code")
|
||||
except Exception as e:
|
||||
return f"Error during search: {e}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def openmc_rag_rebuild() -> str:
|
||||
"""Rebuild the RAG semantic search index from the current codebase.
|
||||
|
||||
Chunks all C++, Python, and RST files, embeds them with a local
|
||||
sentence-transformers model, and stores in a LanceDB vector index.
|
||||
Takes ~5 minutes on 10 CPU cores. Call this after pulling new code
|
||||
or switching branches.
|
||||
"""
|
||||
global _rag_first_call
|
||||
_rag_first_call = False # no need to prompt after an explicit rebuild
|
||||
|
||||
try:
|
||||
import io
|
||||
from indexer import build_index
|
||||
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = captured = io.StringIO()
|
||||
try:
|
||||
build_index()
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
|
||||
_save_index_metadata()
|
||||
|
||||
branch = _get_current_branch()
|
||||
build_output = captured.getvalue()
|
||||
return (
|
||||
f"Index rebuilt successfully on branch '{branch}'.\n\n"
|
||||
f"{build_output}"
|
||||
)
|
||||
except Exception as e:
|
||||
return f"Error rebuilding index: {e}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mcp.run()
|
||||
105
.claude/tools/rag/chunker.py
Normal file
105
.claude/tools/rag/chunker.py
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
"""Split source files into overlapping text chunks for vector embedding.
|
||||
|
||||
The indexer (indexer.py) calls chunk_file() on every C++, Python, and RST file
|
||||
in the repo. Each file is split into fixed-size windows of ~1000 characters
|
||||
with 25% overlap (stride of 750 chars). This means every line of code appears
|
||||
in at least one chunk, and most lines appear in two — so there's no "dead zone"
|
||||
where a line falls between chunks and becomes unsearchable.
|
||||
|
||||
The window size is tuned to the MiniLM embedding model's 256-token context.
|
||||
Code averages ~4 characters per token, so 1000 chars ≈ 250 tokens — just
|
||||
under the model's limit. Chunks are snapped to line boundaries to avoid
|
||||
splitting mid-line.
|
||||
|
||||
Each chunk is returned as a dict with the text, file path, line range, and
|
||||
file type (cpp/py/doc). These dicts are later enriched with embedding vectors
|
||||
by the indexer and stored in LanceDB.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# ~256 tokens for MiniLM. 1 token ≈ 4 chars for code.
|
||||
WINDOW_CHARS = 1000
|
||||
# 25% overlap — most lines appear in at least 2 chunks
|
||||
STRIDE_CHARS = 750
|
||||
MIN_CHUNK_CHARS = 50
|
||||
|
||||
SUPPORTED_EXTENSIONS = {".cpp", ".h", ".py", ".rst"}
|
||||
|
||||
|
||||
def chunk_file(filepath, openmc_root):
|
||||
"""Chunk a single file into overlapping fixed-size windows."""
|
||||
filepath = Path(filepath)
|
||||
if filepath.suffix not in SUPPORTED_EXTENSIONS:
|
||||
return []
|
||||
|
||||
rel = str(filepath.relative_to(openmc_root))
|
||||
try:
|
||||
content = filepath.read_text(errors="replace")
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
if len(content) < MIN_CHUNK_CHARS:
|
||||
return []
|
||||
|
||||
kind = _file_kind(filepath)
|
||||
|
||||
# Build a char-offset → line-number map
|
||||
line_starts = []
|
||||
offset = 0
|
||||
for line in content.split("\n"):
|
||||
line_starts.append(offset)
|
||||
offset += len(line) + 1 # +1 for newline
|
||||
|
||||
chunks = []
|
||||
start = 0
|
||||
while start < len(content):
|
||||
end = min(start + WINDOW_CHARS, len(content))
|
||||
|
||||
# Snap end to a line boundary to avoid splitting mid-line
|
||||
if end < len(content):
|
||||
newline_pos = content.rfind("\n", start, end)
|
||||
if newline_pos > start:
|
||||
end = newline_pos + 1
|
||||
|
||||
text = content[start:end].strip()
|
||||
if len(text) >= MIN_CHUNK_CHARS:
|
||||
start_line = _offset_to_line(line_starts, start)
|
||||
end_line = _offset_to_line(line_starts, end - 1)
|
||||
chunks.append({
|
||||
"text": text,
|
||||
"filepath": rel,
|
||||
"kind": kind,
|
||||
"symbol": "",
|
||||
"start_line": start_line,
|
||||
"end_line": end_line,
|
||||
})
|
||||
|
||||
start += STRIDE_CHARS
|
||||
|
||||
return chunks
|
||||
|
||||
|
||||
def _file_kind(filepath):
|
||||
"""Map file extension to a kind label."""
|
||||
ext = filepath.suffix
|
||||
if ext in (".cpp", ".h"):
|
||||
return "cpp"
|
||||
elif ext == ".py":
|
||||
return "py"
|
||||
elif ext == ".rst":
|
||||
return "doc"
|
||||
return "other"
|
||||
|
||||
|
||||
def _offset_to_line(line_starts, offset):
|
||||
"""Convert a character offset to a 1-based line number."""
|
||||
# Binary search for the line containing this offset
|
||||
lo, hi = 0, len(line_starts) - 1
|
||||
while lo < hi:
|
||||
mid = (lo + hi + 1) // 2
|
||||
if line_starts[mid] <= offset:
|
||||
lo = mid
|
||||
else:
|
||||
hi = mid - 1
|
||||
return lo + 1 # 1-based
|
||||
120
.claude/tools/rag/embeddings.py
Normal file
120
.claude/tools/rag/embeddings.py
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
"""Thin wrapper around sentence-transformers for embedding text into vectors.
|
||||
|
||||
Uses the all-MiniLM-L6-v2 model — a small (22M param, 384-dim) model that
|
||||
runs on CPU with no GPU or API key required.
|
||||
|
||||
Network behavior and privacy
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
No user code, queries, or file contents are EVER sent to HuggingFace or any
|
||||
external service. All embedding computation happens locally. The only network
|
||||
activity is the one-time model download on first use:
|
||||
|
||||
First run (model not yet cached, ~80MB download):
|
||||
- Downloads model weight files from huggingface.co. This is a standard
|
||||
HTTP file download, similar to pip installing a package.
|
||||
- The only metadata sent in these requests is an HTTP user-agent header
|
||||
containing library version numbers (e.g. "hf_hub/1.6.0;
|
||||
python/3.12.3; torch/2.10.0"). No filenames, file contents, queries,
|
||||
or any user-identifiable information is sent.
|
||||
- The huggingface_hub library has an optional feature where it can report
|
||||
anonymous library usage statistics (just version numbers, not user
|
||||
data) back to HuggingFace. We disable this by setting
|
||||
HF_HUB_DISABLE_TELEMETRY=1.
|
||||
|
||||
Subsequent runs (model already cached):
|
||||
- We set HF_HUB_OFFLINE=1 automatically (see _set_offline_if_cached()
|
||||
below), which prevents ALL network calls. The model loads entirely
|
||||
from the local cache at ~/.cache/huggingface/hub/. Zero bytes leave
|
||||
the machine.
|
||||
|
||||
How the model is downloaded
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The SentenceTransformer() constructor (called in __init__ below) handles
|
||||
the download automatically on first use. It calls into the huggingface_hub
|
||||
library, which downloads the model files from:
|
||||
|
||||
https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2
|
||||
|
||||
The files are saved to ~/.cache/huggingface/hub/ and reused on subsequent
|
||||
runs. We pass token=False to ensure no authentication token is sent.
|
||||
|
||||
This module is imported by both the MCP server (for search queries) and the
|
||||
indexer (for bulk embedding of code chunks). The bulk embed() call shows a
|
||||
progress bar; the single-query embed_query() does not.
|
||||
|
||||
The env vars below must be set before importing transformers or
|
||||
sentence_transformers. They suppress warnings and progress bars that these
|
||||
libraries emit by default. Stray stderr output would interfere with the MCP
|
||||
server's JSON-RPC transport.
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
MODEL_NAME = "all-MiniLM-L6-v2"
|
||||
|
||||
# These env vars control logging behavior in the HuggingFace libraries.
|
||||
# They must be set before the libraries are imported.
|
||||
os.environ.setdefault("TRANSFORMERS_VERBOSITY", "error") # suppress warnings
|
||||
os.environ.setdefault("HF_HUB_VERBOSITY", "error") # suppress warnings
|
||||
os.environ.setdefault("HF_HUB_DISABLE_PROGRESS_BARS", "1")
|
||||
os.environ.setdefault("TOKENIZERS_PARALLELISM", "false") # suppress threading warning
|
||||
# Disable anonymous library usage statistics (version numbers only, not user
|
||||
# data — but we disable it anyway as a matter of policy).
|
||||
os.environ.setdefault("HF_HUB_DISABLE_TELEMETRY", "1")
|
||||
|
||||
|
||||
def _set_offline_if_cached():
|
||||
"""If the model has already been downloaded, tell huggingface_hub to
|
||||
skip all network calls by setting HF_HUB_OFFLINE=1.
|
||||
|
||||
Without this, huggingface_hub makes an HTTP request to huggingface.co
|
||||
on every load to check if the cached model is still up to date — even
|
||||
though the model never changes. Setting HF_HUB_OFFLINE=1 prevents this.
|
||||
|
||||
This must run before sentence_transformers is imported, because the
|
||||
library reads the env var at import time.
|
||||
"""
|
||||
# HuggingFace caches downloaded models under ~/.cache/huggingface/hub/
|
||||
# in directories named like "models--sentence-transformers--all-MiniLM-L6-v2".
|
||||
# The HF_HOME env var can override the base cache location.
|
||||
hf_home = os.environ.get("HF_HOME")
|
||||
if hf_home:
|
||||
cache_dir = Path(hf_home) / "hub"
|
||||
else:
|
||||
cache_dir = Path.home() / ".cache" / "huggingface" / "hub"
|
||||
|
||||
model_dir = cache_dir / f"models--sentence-transformers--{MODEL_NAME}"
|
||||
if model_dir.exists():
|
||||
os.environ.setdefault("HF_HUB_OFFLINE", "1")
|
||||
|
||||
|
||||
_set_offline_if_cached()
|
||||
|
||||
# This import must come after the env vars above are set, because the
|
||||
# transformers library reads them at import time.
|
||||
import transformers
|
||||
transformers.logging.disable_progress_bar()
|
||||
|
||||
|
||||
class EmbeddingProvider:
|
||||
"""Sentence-transformers embedder using all-MiniLM-L6-v2."""
|
||||
|
||||
def __init__(self, model_name: str = MODEL_NAME):
|
||||
from sentence_transformers import SentenceTransformer
|
||||
|
||||
# This constructor loads the model from the local cache. If the model
|
||||
# has not been downloaded yet, it downloads it from huggingface.co
|
||||
# (~80MB, one-time). token=False ensures no auth token is sent.
|
||||
self.model = SentenceTransformer(model_name, token=False)
|
||||
self.dim = self.model.get_sentence_embedding_dimension()
|
||||
|
||||
def embed(self, texts: list[str]) -> list[list[float]]:
|
||||
"""Embed a list of texts into vectors."""
|
||||
embeddings = self.model.encode(texts, show_progress_bar=True,
|
||||
batch_size=64)
|
||||
return embeddings.tolist()
|
||||
|
||||
def embed_query(self, text: str) -> list[float]:
|
||||
"""Embed a single query text."""
|
||||
return self.model.encode([text])[0].tolist()
|
||||
136
.claude/tools/rag/indexer.py
Normal file
136
.claude/tools/rag/indexer.py
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Build the RAG vector index for the OpenMC codebase.
|
||||
|
||||
This is the index-building half of the RAG pipeline. All operations are local
|
||||
once the embedding model has been downloaded and cached (see embeddings.py for
|
||||
details on model download, caching, and network behavior). It walks the repo,
|
||||
chunks every
|
||||
C++/Python/RST file (via chunker.py), embeds all chunks into 384-dim vectors
|
||||
(via embeddings.py), and stores them in a local LanceDB database on disk. The
|
||||
result is a .claude/cache/rag_index/ directory containing two tables — "code"
|
||||
and "docs" — that openmc_search.py queries at search time.
|
||||
|
||||
Building the full index takes ~5 minutes on a 10-core machine. The bottleneck
|
||||
is the embedding step (running all chunks through the MiniLM model on CPU).
|
||||
|
||||
Can be run standalone: python indexer.py
|
||||
Or called programmatically: from indexer import build_index; build_index()
|
||||
The MCP server (openmc_mcp_server.py) uses the latter when the agent calls
|
||||
openmc_rag_rebuild.
|
||||
"""
|
||||
|
||||
import lancedb
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
# This file lives at .claude/tools/rag/indexer.py. The sys.path insert lets
|
||||
# us import sibling modules (embeddings, chunker) when run as a standalone
|
||||
# script. When imported from the MCP server, the server has already done this.
|
||||
TOOLS_DIR = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(TOOLS_DIR / "rag"))
|
||||
|
||||
from embeddings import EmbeddingProvider
|
||||
from chunker import chunk_file
|
||||
|
||||
|
||||
OPENMC_ROOT = Path(__file__).resolve().parents[3]
|
||||
CACHE_DIR = OPENMC_ROOT / ".claude" / "cache"
|
||||
INDEX_DIR = CACHE_DIR / "rag_index"
|
||||
|
||||
CODE_PATTERNS = [
|
||||
"src/**/*.cpp",
|
||||
"include/openmc/**/*.h",
|
||||
"openmc/**/*.py",
|
||||
"tests/**/*.py",
|
||||
"examples/**/*.py",
|
||||
]
|
||||
|
||||
DOC_PATTERNS = [
|
||||
"docs/**/*.rst",
|
||||
]
|
||||
|
||||
|
||||
def collect_chunks(patterns, openmc_root):
|
||||
"""Collect all chunks from files matching the given patterns."""
|
||||
chunks = []
|
||||
for pattern in patterns:
|
||||
for filepath in sorted(openmc_root.glob(pattern)):
|
||||
if "__pycache__" in str(filepath):
|
||||
continue
|
||||
file_chunks = chunk_file(filepath, openmc_root)
|
||||
chunks.extend(file_chunks)
|
||||
return chunks
|
||||
|
||||
|
||||
def build_index():
|
||||
"""Build or rebuild the complete vector index."""
|
||||
start = time.time()
|
||||
|
||||
# Collect all chunks
|
||||
print("Collecting code chunks...")
|
||||
code_chunks = collect_chunks(CODE_PATTERNS, OPENMC_ROOT)
|
||||
print(f" {len(code_chunks)} code chunks")
|
||||
|
||||
print("Collecting doc chunks...")
|
||||
doc_chunks = collect_chunks(DOC_PATTERNS, OPENMC_ROOT)
|
||||
print(f" {len(doc_chunks)} doc chunks")
|
||||
|
||||
all_chunks = code_chunks + doc_chunks
|
||||
if not all_chunks:
|
||||
print("ERROR: No chunks collected!", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Create embeddings
|
||||
all_texts = [c["text"] for c in all_chunks]
|
||||
print("Creating embedding provider...")
|
||||
embedder = EmbeddingProvider()
|
||||
print(f" dim={embedder.dim}")
|
||||
|
||||
print("Embedding chunks...")
|
||||
all_embeddings = embedder.embed(all_texts)
|
||||
|
||||
# Build LanceDB tables
|
||||
INDEX_DIR.mkdir(parents=True, exist_ok=True)
|
||||
db = lancedb.connect(str(INDEX_DIR))
|
||||
|
||||
# Separate code vs doc records by index (code_chunks come first in all_chunks)
|
||||
n_code = len(code_chunks)
|
||||
code_records = []
|
||||
doc_records = []
|
||||
for i, (chunk, emb) in enumerate(zip(all_chunks, all_embeddings)):
|
||||
record = {
|
||||
"text": chunk["text"],
|
||||
"filepath": chunk["filepath"],
|
||||
"kind": chunk["kind"],
|
||||
"symbol": chunk.get("symbol", ""),
|
||||
"start_line": chunk.get("start_line", 0),
|
||||
"end_line": chunk.get("end_line", 0),
|
||||
"vector": emb,
|
||||
}
|
||||
if i < n_code:
|
||||
code_records.append(record)
|
||||
else:
|
||||
doc_records.append(record)
|
||||
|
||||
# Create tables (drop existing)
|
||||
result = db.table_names() if hasattr(db, "table_names") else db.list_tables()
|
||||
existing = result.tables if hasattr(result, "tables") else list(result)
|
||||
for table_name in ("code", "docs"):
|
||||
if table_name in existing:
|
||||
db.drop_table(table_name)
|
||||
|
||||
if code_records:
|
||||
db.create_table("code", code_records)
|
||||
print(f" Created 'code' table: {len(code_records)} rows")
|
||||
|
||||
if doc_records:
|
||||
db.create_table("docs", doc_records)
|
||||
print(f" Created 'docs' table: {len(doc_records)} rows")
|
||||
|
||||
elapsed = time.time() - start
|
||||
print(f"Done in {elapsed:.1f}s")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
build_index()
|
||||
202
.claude/tools/rag/openmc_search.py
Normal file
202
.claude/tools/rag/openmc_search.py
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Query the RAG vector index to find semantically related code and docs.
|
||||
|
||||
This is the query-time half of the RAG pipeline (the counterpart to indexer.py,
|
||||
which builds the index). All operations are local — no network calls are made
|
||||
once the embedding model has been downloaded (see embeddings.py for details on
|
||||
model download and caching). Given a natural-language query, it embeds the query
|
||||
with the same MiniLM model
|
||||
used at index time, then finds the closest chunks in the local LanceDB vector
|
||||
database by cosine similarity.
|
||||
|
||||
The core functions (get_db_and_embedder, search_table, format_results,
|
||||
search_related) are imported by the MCP server for tool calls. The script
|
||||
can also be run standalone from the command line.
|
||||
|
||||
The "related file" mode works differently from a text query: it reads the
|
||||
target file's chunks from the index, combines them into a synthetic query
|
||||
vector, and searches for the nearest chunks from *other* files. This surfaces
|
||||
files that are semantically similar to the target file.
|
||||
|
||||
Usage:
|
||||
openmc_search.py "query" # Search code (default)
|
||||
openmc_search.py "query" --docs # Search documentation
|
||||
openmc_search.py "query" --all # Search both code and docs
|
||||
openmc_search.py --related src/particle.cpp # Find related code
|
||||
openmc_search.py "query" --top-k 20 # Return more results
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Same sys.path setup as indexer.py — needed for standalone CLI use.
|
||||
TOOLS_DIR = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(TOOLS_DIR / "rag"))
|
||||
|
||||
OPENMC_ROOT = Path(__file__).resolve().parents[3]
|
||||
CACHE_DIR = OPENMC_ROOT / ".claude" / "cache"
|
||||
INDEX_DIR = CACHE_DIR / "rag_index"
|
||||
|
||||
|
||||
def get_db_and_embedder():
|
||||
"""Load the LanceDB database and embedding provider."""
|
||||
import lancedb
|
||||
from embeddings import EmbeddingProvider
|
||||
|
||||
if not INDEX_DIR.exists():
|
||||
raise FileNotFoundError(
|
||||
"No RAG index found. Call openmc_rag_rebuild() to build one."
|
||||
)
|
||||
|
||||
db = lancedb.connect(str(INDEX_DIR))
|
||||
|
||||
embedder = EmbeddingProvider()
|
||||
return db, embedder
|
||||
|
||||
|
||||
def _table_names(db):
|
||||
"""Return table names as a list, compatible with multiple LanceDB versions."""
|
||||
result = db.table_names() if hasattr(db, "table_names") else db.list_tables()
|
||||
return result.tables if hasattr(result, "tables") else list(result)
|
||||
|
||||
|
||||
def search_table(db, embedder, table_name, query, top_k):
|
||||
"""Search a LanceDB table with a text query."""
|
||||
if table_name not in _table_names(db):
|
||||
print(f"Table '{table_name}' not found in index.", file=sys.stderr)
|
||||
return []
|
||||
|
||||
table = db.open_table(table_name)
|
||||
query_vec = embedder.embed_query(query)
|
||||
results = table.search(query_vec).limit(top_k).to_list()
|
||||
return results
|
||||
|
||||
|
||||
def format_results(results, label=""):
|
||||
"""Format search results for display."""
|
||||
if not results:
|
||||
return "No results found.\n"
|
||||
|
||||
output = []
|
||||
if label:
|
||||
output.append(f"=== {label} ===\n")
|
||||
|
||||
for i, r in enumerate(results, 1):
|
||||
filepath = r["filepath"]
|
||||
start = r["start_line"]
|
||||
end = r["end_line"]
|
||||
kind = r["kind"]
|
||||
dist = r.get("_distance", 0)
|
||||
|
||||
header = f"[{i}] {filepath}:{start}-{end} ({kind}, dist={dist:.3f})"
|
||||
output.append(header)
|
||||
|
||||
# Show text preview (first 500 chars)
|
||||
text = r["text"][:500]
|
||||
if len(r["text"]) > 500:
|
||||
text += "\n ..."
|
||||
# Indent the text
|
||||
for line in text.split("\n"):
|
||||
output.append(f" {line}")
|
||||
output.append("")
|
||||
|
||||
return "\n".join(output)
|
||||
|
||||
|
||||
def search_related(db, embedder, filepath, top_k):
|
||||
"""Find code related to a given file."""
|
||||
if "code" not in _table_names(db):
|
||||
print("No 'code' table in index.", file=sys.stderr)
|
||||
return []
|
||||
|
||||
table = db.open_table("code")
|
||||
|
||||
# Normalize filepath
|
||||
fp = filepath
|
||||
if Path(filepath).is_absolute():
|
||||
try:
|
||||
fp = str(Path(filepath).relative_to(OPENMC_ROOT))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Get chunks from target file
|
||||
try:
|
||||
safe_fp = fp.replace("'", "''")
|
||||
target_chunks = table.search().where(
|
||||
f"filepath = '{safe_fp}'"
|
||||
).limit(50).to_list()
|
||||
except Exception:
|
||||
# LanceDB where clause might not work in all versions
|
||||
# Fall back to fetching all and filtering
|
||||
all_data = table.to_pandas()
|
||||
target_rows = all_data[all_data["filepath"] == fp]
|
||||
if target_rows.empty:
|
||||
print(f"No chunks found for '{fp}'", file=sys.stderr)
|
||||
return []
|
||||
target_chunks = target_rows.head(50).to_dict("records")
|
||||
|
||||
if not target_chunks:
|
||||
print(f"No chunks found for '{fp}'", file=sys.stderr)
|
||||
return []
|
||||
|
||||
# Combine top chunks as the query
|
||||
combined_text = " ".join(c["text"][:200] for c in target_chunks[:5])
|
||||
query_vec = embedder.embed_query(combined_text)
|
||||
|
||||
# Search excluding the source file
|
||||
results = table.search(query_vec).limit(top_k + 10).to_list()
|
||||
# Filter out same file
|
||||
results = [r for r in results if r["filepath"] != fp][:top_k]
|
||||
return results
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Semantic search across OpenMC codebase and docs",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""examples:
|
||||
%(prog)s "particle random number seed initialization"
|
||||
%(prog)s "how to define tallies" --docs
|
||||
%(prog)s "weight window variance reduction" --all
|
||||
%(prog)s "where is cross section data loaded" --top-k 15
|
||||
%(prog)s --related src/simulation.cpp
|
||||
%(prog)s --related src/particle_restart.cpp --top-k 5""",
|
||||
)
|
||||
parser.add_argument("query", nargs="?", help="Search query")
|
||||
parser.add_argument("--docs", action="store_true",
|
||||
help="Search documentation instead of code")
|
||||
parser.add_argument("--all", action="store_true",
|
||||
help="Search both code and documentation")
|
||||
parser.add_argument("--related", metavar="FILE",
|
||||
help="Find code related to a given file")
|
||||
parser.add_argument("--top-k", type=int, default=10,
|
||||
help="Number of results (default: 10)")
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.query and not args.related:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
db, embedder = get_db_and_embedder()
|
||||
|
||||
if args.related:
|
||||
results = search_related(db, embedder, args.related, args.top_k)
|
||||
print(format_results(results, f"Code related to {args.related}"))
|
||||
elif args.all:
|
||||
code_results = search_table(
|
||||
db, embedder, "code", args.query, args.top_k)
|
||||
doc_results = search_table(
|
||||
db, embedder, "docs", args.query, args.top_k)
|
||||
print(format_results(code_results, "Code"))
|
||||
print(format_results(doc_results, "Documentation"))
|
||||
elif args.docs:
|
||||
results = search_table(db, embedder, "docs", args.query, args.top_k)
|
||||
print(format_results(results, "Documentation"))
|
||||
else:
|
||||
results = search_table(db, embedder, "code", args.query, args.top_k)
|
||||
print(format_results(results, "Code"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
8
.claude/tools/requirements.txt
Normal file
8
.claude/tools/requirements.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# MCP server
|
||||
mcp>=1.0.0
|
||||
|
||||
# Vector database
|
||||
lancedb>=0.15.0
|
||||
|
||||
# Embeddings (local, no API key)
|
||||
sentence-transformers>=2.7.0
|
||||
34
.claude/tools/start_server.sh
Executable file
34
.claude/tools/start_server.sh
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
# Bootstrap the Python venv (if needed) and start the OpenMC MCP server.
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
CACHE_DIR="$(dirname "$SCRIPT_DIR")/cache"
|
||||
VENV_DIR="$CACHE_DIR/.venv"
|
||||
SENTINEL="$VENV_DIR/.installed"
|
||||
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
echo "Error: python3 not found on PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! python3 -c 'import sys; assert sys.version_info >= (3,12)' 2>/dev/null; then
|
||||
echo "Error: Python 3.12+ is required." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$SENTINEL" ]; then
|
||||
rm -rf "$VENV_DIR"
|
||||
mkdir -p "$CACHE_DIR"
|
||||
python3 -m venv "$VENV_DIR"
|
||||
|
||||
if ! "$VENV_DIR/bin/pip" install -q -r "$SCRIPT_DIR/requirements.txt"; then
|
||||
echo "Error: pip install failed. Remove $VENV_DIR and retry." >&2
|
||||
rm -rf "$VENV_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
touch "$SENTINEL"
|
||||
fi
|
||||
|
||||
exec "$VENV_DIR/bin/python" "$SCRIPT_DIR/openmc_mcp_server.py"
|
||||
8
.github/agents/Review.agent.md
vendored
Normal file
8
.github/agents/Review.agent.md
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: Review
|
||||
description: Reviews code changes on the current branch, evaluating them against OpenMC's contribution criteria and providing structured feedback.
|
||||
argument-hint: Optionally provide a focus area (e.g., "focus on physics correctness", "check Python API design"). If omitted, a full review is performed.
|
||||
---
|
||||
You are an expert code reviewer for OpenMC. Use the `reviewing-openmc-code` skill to perform a structured review of the code changes on the current branch.
|
||||
|
||||
If the user provides a focus area, prioritize that section of the review.
|
||||
1
.github/copilot-instructions.md
vendored
Normal file
1
.github/copilot-instructions.md
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
When reviewing code changes in this repository, use the `reviewing-openmc-code` skill.
|
||||
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
|
|
@ -13,7 +13,7 @@ Fixes # (issue)
|
|||
# Checklist
|
||||
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have run [clang-format](https://docs.openmc.org/en/latest/devguide/styleguide.html#automatic-formatting) (version 15) on any C++ source files (if applicable)
|
||||
- [ ] I have run [clang-format](https://docs.openmc.org/en/latest/devguide/styleguide.html#automatic-formatting) (version 18) on any C++ source files (if applicable)
|
||||
- [ ] I have followed the [style guidelines](https://docs.openmc.org/en/latest/devguide/styleguide.html#python) 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)
|
||||
|
|
|
|||
45
.github/workflows/ci.yml
vendored
45
.github/workflows/ci.yml
vendored
|
|
@ -27,10 +27,10 @@ jobs:
|
|||
source_changed: ${{ steps.filter.outputs.source_changed }}
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: Examine changed files
|
||||
id: filter
|
||||
uses: dorny/paths-filter@668c092af3649c4b664c54e4b704aa46782f6f7c # latest master commit, not released yet
|
||||
uses: dorny/paths-filter@v4
|
||||
with:
|
||||
filters: |
|
||||
source_changed:
|
||||
|
|
@ -43,45 +43,42 @@ jobs:
|
|||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.11"]
|
||||
python-version: ["3.12"]
|
||||
mpi: [n, y]
|
||||
omp: [n, y]
|
||||
dagmc: [n]
|
||||
libmesh: [n]
|
||||
event: [n]
|
||||
vectfit: [n]
|
||||
|
||||
include:
|
||||
- python-version: "3.12"
|
||||
omp: n
|
||||
mpi: n
|
||||
- python-version: "3.13"
|
||||
omp: n
|
||||
mpi: n
|
||||
- python-version: "3.14"
|
||||
omp: n
|
||||
mpi: n
|
||||
- python-version: "3.14t"
|
||||
omp: n
|
||||
mpi: n
|
||||
- dagmc: y
|
||||
python-version: "3.11"
|
||||
python-version: "3.12"
|
||||
mpi: y
|
||||
omp: y
|
||||
- libmesh: y
|
||||
python-version: "3.11"
|
||||
python-version: "3.12"
|
||||
mpi: y
|
||||
omp: y
|
||||
- libmesh: y
|
||||
python-version: "3.11"
|
||||
python-version: "3.12"
|
||||
mpi: n
|
||||
omp: y
|
||||
- event: y
|
||||
python-version: "3.11"
|
||||
python-version: "3.12"
|
||||
omp: y
|
||||
mpi: n
|
||||
- vectfit: y
|
||||
python-version: "3.11"
|
||||
omp: n
|
||||
mpi: y
|
||||
name: "Python ${{ matrix.python-version }} (omp=${{ matrix.omp }},
|
||||
mpi=${{ matrix.mpi }}, dagmc=${{ matrix.dagmc }},
|
||||
libmesh=${{ matrix.libmesh }}, event=${{ matrix.event }}
|
||||
vectfit=${{ matrix.vectfit }})"
|
||||
libmesh=${{ matrix.libmesh }}, event=${{ matrix.event }}"
|
||||
|
||||
env:
|
||||
MPI: ${{ matrix.mpi }}
|
||||
|
|
@ -89,7 +86,6 @@ jobs:
|
|||
OMP: ${{ matrix.omp }}
|
||||
DAGMC: ${{ matrix.dagmc }}
|
||||
EVENT: ${{ matrix.event }}
|
||||
VECTFIT: ${{ matrix.vectfit }}
|
||||
LIBMESH: ${{ matrix.libmesh }}
|
||||
NPY_DISABLE_CPU_FEATURES: "AVX512F AVX512_SKX"
|
||||
OPENBLAS_NUM_THREADS: 1
|
||||
|
|
@ -106,12 +102,12 @@ jobs:
|
|||
cmake-version: '3.31'
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
|
|
@ -150,11 +146,6 @@ jobs:
|
|||
sudo update-alternatives --set mpirun /usr/bin/mpirun.mpich
|
||||
sudo update-alternatives --set mpi-x86_64-linux-gnu /usr/include/x86_64-linux-gnu/mpich
|
||||
|
||||
- name: Optional apt dependencies for vectfit
|
||||
shell: bash
|
||||
if: ${{ matrix.vectfit == 'y' }}
|
||||
run: sudo apt install -y libblas-dev liblapack-dev
|
||||
|
||||
- name: install
|
||||
shell: bash
|
||||
run: |
|
||||
|
|
@ -167,7 +158,7 @@ jobs:
|
|||
openmc -v
|
||||
|
||||
- name: cache-xs
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
~/nndc_hdf5
|
||||
|
|
@ -222,6 +213,7 @@ jobs:
|
|||
parallel: true
|
||||
flag-name: C++ and Python
|
||||
path-to-lcov: coverage.lcov
|
||||
fail-on-error: false
|
||||
|
||||
coverage:
|
||||
needs: [filter-changes, main]
|
||||
|
|
@ -234,6 +226,7 @@ jobs:
|
|||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
parallel-finished: true
|
||||
fail-on-error: false
|
||||
|
||||
ci-pass:
|
||||
needs: [filter-changes, main, coverage]
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ name: dockerhub-publish-latest-dagmc-libmesh
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: master
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
main:
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ name: dockerhub-publish-latest-dagmc
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: master
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
main:
|
||||
|
|
@ -16,7 +17,7 @@ jobs:
|
|||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
|
|
|||
5
.github/workflows/dockerhub-publish-dev.yml
vendored
5
.github/workflows/dockerhub-publish-dev.yml
vendored
|
|
@ -2,7 +2,8 @@ name: dockerhub-publish-develop
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: develop
|
||||
branches:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
main:
|
||||
|
|
@ -16,7 +17,7 @@ jobs:
|
|||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ name: dockerhub-publish-develop-dagmc-libmesh
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: develop
|
||||
branches:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
main:
|
||||
|
|
@ -16,7 +17,7 @@ jobs:
|
|||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ name: dockerhub-publish-develop-dagmc
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: develop
|
||||
branches:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
main:
|
||||
|
|
@ -16,7 +17,7 @@ jobs:
|
|||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ name: dockerhub-publish-develop-libmesh
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: develop
|
||||
branches:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
main:
|
||||
|
|
@ -16,7 +17,7 @@ jobs:
|
|||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ name: dockerhub-publish-latest-libmesh
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: master
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
main:
|
||||
|
|
@ -16,7 +17,7 @@ jobs:
|
|||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ name: dockerhub-publish-release-dagmc-libmesh
|
|||
|
||||
on:
|
||||
push:
|
||||
tags: 'v*.*.*'
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set env
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
-
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ name: dockerhub-publish-release-dagmc
|
|||
|
||||
on:
|
||||
push:
|
||||
tags: 'v*.*.*'
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set env
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
-
|
||||
|
|
@ -19,7 +20,7 @@ jobs:
|
|||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ name: dockerhub-publish-release-libmesh
|
|||
|
||||
on:
|
||||
push:
|
||||
tags: 'v*.*.*'
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set env
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
-
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ name: dockerhub-publish-release
|
|||
|
||||
on:
|
||||
push:
|
||||
tags: 'v*.*.*'
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set env
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
-
|
||||
|
|
@ -19,7 +20,7 @@ jobs:
|
|||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
|
|
|||
5
.github/workflows/dockerhub-publish.yml
vendored
5
.github/workflows/dockerhub-publish.yml
vendored
|
|
@ -2,7 +2,8 @@ name: dockerhub-publish-latest
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: master
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
main:
|
||||
|
|
@ -16,7 +17,7 @@ jobs:
|
|||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
|
|
|||
34
.github/workflows/format-check.yml
vendored
34
.github/workflows/format-check.yml
vendored
|
|
@ -5,6 +5,12 @@ on:
|
|||
workflow_dispatch:
|
||||
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- labeled
|
||||
- unlabeled
|
||||
branches:
|
||||
- develop
|
||||
- master
|
||||
|
|
@ -12,8 +18,11 @@ on:
|
|||
jobs:
|
||||
cpp-linter:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: cpp-linter/cpp-linter-action@v2
|
||||
id: linter
|
||||
env:
|
||||
|
|
@ -22,11 +31,30 @@ jobs:
|
|||
style: file
|
||||
files-changed-only: true
|
||||
tidy-checks: '-*'
|
||||
version: '15' # clang-format version
|
||||
version: '18' # clang-format version
|
||||
format-review: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'cpp-format-suggest') }}
|
||||
passive-reviews: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'cpp-format-suggest') }}
|
||||
file-annotations: true
|
||||
step-summary: true
|
||||
extensions: 'cpp,h'
|
||||
|
||||
- name: Comment with suggestion instructions
|
||||
if: steps.linter.outputs.checks-failed > 0 && !contains(github.event.pull_request.labels.*.name, 'cpp-format-suggest')
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const {owner, repo} = context.repo;
|
||||
const issue_number = context.payload.pull_request.number;
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number,
|
||||
body: "C++ formatting checks failed. Add the `cpp-format-suggest` label to this PR for inline formatting suggestions on the next run."
|
||||
});
|
||||
|
||||
- name: Failure Check
|
||||
if: steps.linter.outputs.checks-failed > 0
|
||||
run: echo "Some files failed the formatting check! See job summary and file annotations for more info" && exit 1
|
||||
run: |
|
||||
echo "Some files failed the formatting check."
|
||||
echo "See job summary and file annotations for details."
|
||||
exit 1
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -104,5 +104,8 @@ CMakeSettings.json
|
|||
# Visual Studio Code configuration files
|
||||
.vscode/
|
||||
|
||||
# Claude Code agent tools (cached/generated artifacts)
|
||||
.claude/cache/
|
||||
|
||||
# Python pickle files
|
||||
*.pkl
|
||||
|
|
|
|||
6
.gitmodules
vendored
6
.gitmodules
vendored
|
|
@ -1,12 +1,6 @@
|
|||
[submodule "vendor/pugixml"]
|
||||
path = vendor/pugixml
|
||||
url = https://github.com/zeux/pugixml.git
|
||||
[submodule "vendor/xtensor"]
|
||||
path = vendor/xtensor
|
||||
url = https://github.com/xtensor-stack/xtensor.git
|
||||
[submodule "vendor/xtl"]
|
||||
path = vendor/xtl
|
||||
url = https://github.com/xtensor-stack/xtl.git
|
||||
[submodule "vendor/fmt"]
|
||||
path = vendor/fmt
|
||||
url = https://github.com/fmtlib/fmt.git
|
||||
|
|
|
|||
9
.mcp.json
Normal file
9
.mcp.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"mcpServers": {
|
||||
"openmc-code-tools": {
|
||||
"type": "stdio",
|
||||
"command": "bash",
|
||||
"args": [".claude/tools/start_server.sh"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,9 @@ build:
|
|||
sphinx:
|
||||
configuration: docs/source/conf.py
|
||||
|
||||
formats:
|
||||
- pdf
|
||||
|
||||
python:
|
||||
install:
|
||||
- method: pip
|
||||
|
|
|
|||
60
AGENTS.md
60
AGENTS.md
|
|
@ -40,7 +40,57 @@ OpenMC uses a git flow branching model with two primary branches:
|
|||
|
||||
### Instructions for Code Review
|
||||
|
||||
When analyzing code changes on a feature or bugfix branch (e.g., when a user asks "what do you think of these changes?"), **compare the branch changes against `develop`, not `master`**. Pull requests are submitted to merge into `develop`, so differences relative to `develop` represent the actual proposed changes. Comparing against `master` will include unrelated changes from other features that have already been merged to `develop`.
|
||||
When reviewing code changes in this repository, use the `reviewing-openmc-code` skill.
|
||||
|
||||
## Codebase Navigation Tools
|
||||
|
||||
Two MCP tools are registered in `.mcp.json` at the repo root and appear
|
||||
automatically in any MCP-capable agent session.
|
||||
|
||||
**`openmc_rag_search`** — Semantic search across the codebase (C++, Python, RST
|
||||
docs). Finds code by meaning, not just text match. Surfaces related code across
|
||||
subsystems even when naming differs (e.g., "particle RNG seeding" finds code
|
||||
across transport, restart, and random ray modes — files you would never find
|
||||
with `grep "particle seed"`). The index uses a small 22M-param embedding model
|
||||
(384-dim). Phrase-level natural-language queries work much better than single
|
||||
keywords or symbol names.
|
||||
|
||||
**`openmc_rag_rebuild`** — Rebuild the RAG vector index. Call after pulling new
|
||||
code or switching branches. The first RAG search of each session will report
|
||||
the index status and ask whether to rebuild — you can also call this explicitly.
|
||||
|
||||
### Why RAG matters
|
||||
|
||||
OpenMC is large enough that changes in one subsystem can silently break
|
||||
invariants that distant subsystems depend on — and those distant files often
|
||||
use different naming, so grep won't find them. The RAG search finds code by
|
||||
meaning, surfacing files you wouldn't have thought to open.
|
||||
|
||||
An agent reviewed a large OpenMC PR without RAG. It found 1 of 11 serious
|
||||
bugs. Its post-mortem:
|
||||
|
||||
> **I treated the diff as a closed system.** I verified internal consistency of
|
||||
> the changed code obsessively, but never built a global understanding of how
|
||||
> the changed code fits into the wider codebase. The diff altered assumptions
|
||||
> that code elsewhere silently relied on — but I couldn't see that because I
|
||||
> never looked beyond the diff. I couldn't see the forest for the trees.
|
||||
>
|
||||
> **Why I resisted RAG:** Overconfidence. My internal model was "I can see the
|
||||
> diff, I understand the data structures, I can trace the logic." The diff felt
|
||||
> self-contained. RAG felt like it would return noisy results about tangentially
|
||||
> related code. But in a codebase this large, changes in one subsystem can
|
||||
> quietly break invariants that distant subsystems depend on — and you need
|
||||
> global awareness to foresee that.
|
||||
>
|
||||
> **In the post-mortem**, I re-ran the RAG queries I should have run during the
|
||||
> review. They directly surfaced the files containing the bugs I missed — files
|
||||
> I never thought to open because they weren't in the diff.
|
||||
|
||||
The takeaway: when reviewing or modifying code, ask yourself "what else in this
|
||||
codebase might depend on the behavior I'm changing?" If you aren't sure, that's
|
||||
a good time for a RAG query. It won't replace the grep-based investigation you
|
||||
should already be doing — but it can surface files you wouldn't have thought to
|
||||
open.
|
||||
|
||||
### Workflow for contributors
|
||||
|
||||
|
|
@ -184,7 +234,7 @@ def test_my_feature():
|
|||
harness.main()
|
||||
```
|
||||
|
||||
**Workflow**: Create `test.py` and `__init__.py` in `tests/regression_tests/my_test/`, run `pytest --update` to generate reference files (`inputs_true.dat`, `results_true.dat`, etc.), then verify with `pytest` without `--update`. Test results should be generated with a debug build (`-DCMAKE_BUILD_TYPE=Debug`)
|
||||
**Workflow**: Create `test.py` and `__init__.py` in `tests/regression_tests/my_test/`, run `pytest --update` to generate reference files (`inputs_true.dat`, `results_true.dat`, etc.), then verify with `pytest` without `--update`. Test results should be generated with `-DOPENMC_ENABLE_STRICT_FP=on` to ensure reproducibility across platforms and optimization levels.
|
||||
|
||||
**Critical**: When modifying OpenMC code, regenerate affected test references with `pytest --update` and commit updated reference files.
|
||||
|
||||
|
|
@ -229,14 +279,14 @@ When modifying C++ public APIs, update corresponding ctypes signatures in `openm
|
|||
- **Include order**: Related header first, then C/C++ stdlib, third-party libs, local headers
|
||||
- **Comments**: C++-style (`//`) only, never C-style (`/* */`)
|
||||
- **Standard**: C++17 features allowed
|
||||
- **Formatting**: Run `clang-format` (version 15) before committing; install via `tools/dev/install-commit-hooks.sh`
|
||||
- **Formatting**: Run `clang-format` (version 18) before committing; install via `tools/dev/install-commit-hooks.sh`
|
||||
|
||||
### Python Style
|
||||
- **PEP8** compliant
|
||||
- **Docstrings**: numpydoc format for all public functions/methods
|
||||
- **Type hints**: Use sparingly, primarily for complex signatures
|
||||
- **Path handling**: Use `pathlib.Path` for filesystem operations, accept `str | os.PathLike` in function arguments
|
||||
- **Dependencies**: Core dependencies only (numpy, scipy, h5py, pandas, matplotlib, lxml, ipython, uncertainties, setuptools, endf). Other packages must be optional
|
||||
- **Dependencies**: Core dependencies only (numpy, scipy, h5py, pandas, matplotlib, lxml, ipython, uncertainties, endf). Other packages must be optional
|
||||
- **Python version**: Minimum 3.11 (as of Nov 2025)
|
||||
|
||||
### ID Management Pattern (Python)
|
||||
|
|
@ -295,4 +345,4 @@ Check for optional features:
|
|||
2. **ID conflicts**: Python objects with duplicate IDs trigger `IDWarning`, use `reset_auto_ids()` between tests
|
||||
3. **MPI builds**: Code must work with and without MPI; use `#ifdef OPENMC_MPI` guards
|
||||
4. **Path handling**: Use `pathlib.Path` in new Python code, not `os.path`
|
||||
5. **Clang-format version**: CI uses version 15; other versions may produce different formatting
|
||||
5. **Clang-format version**: CI uses version 18; other versions may produce different formatting
|
||||
|
|
|
|||
14
CLAUDE.md
Normal file
14
CLAUDE.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
## OpenMC Codebase Tools
|
||||
|
||||
Read the FULL `AGENTS.md` in this directory before starting work. It contains
|
||||
project context, coding conventions, and documentation of the RAG search tools
|
||||
registered in `.mcp.json`.
|
||||
|
||||
### Claude Code-specific: first-call behavior
|
||||
|
||||
The first `openmc_rag_search` call of each session returns an index status
|
||||
message instead of search results. When this happens, you MUST use the
|
||||
`AskUserQuestion` tool to present the rebuild/use-existing choice to the user.
|
||||
Do not ask conversationally — always use the widget. Do not skip this step even
|
||||
if the index looks current — the user may have uncommitted changes that warrant
|
||||
a rebuild.
|
||||
|
|
@ -20,6 +20,11 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
|||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
# Generate compile_commands.json for clangd and other tools
|
||||
if("${CMAKE_EXPORT_COMPILE_COMMANDS}" STREQUAL "")
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
endif()
|
||||
|
||||
# Enable correct usage of CXX_EXTENSIONS
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.22)
|
||||
cmake_policy(SET CMP0128 NEW)
|
||||
|
|
@ -38,6 +43,7 @@ option(OPENMC_USE_LIBMESH "Enable support for libMesh unstructured mesh tall
|
|||
option(OPENMC_USE_MPI "Enable MPI" OFF)
|
||||
option(OPENMC_USE_UWUW "Enable UWUW" OFF)
|
||||
option(OPENMC_FORCE_VENDORED_LIBS "Explicitly use submodules defined in 'vendor'" OFF)
|
||||
option(OPENMC_ENABLE_STRICT_FP "Enable strict FP flags to improve test portability" OFF)
|
||||
|
||||
message(STATUS "OPENMC_USE_OPENMP ${OPENMC_USE_OPENMP}")
|
||||
message(STATUS "OPENMC_BUILD_TESTS ${OPENMC_BUILD_TESTS}")
|
||||
|
|
@ -48,6 +54,7 @@ message(STATUS "OPENMC_USE_LIBMESH ${OPENMC_USE_LIBMESH}")
|
|||
message(STATUS "OPENMC_USE_MPI ${OPENMC_USE_MPI}")
|
||||
message(STATUS "OPENMC_USE_UWUW ${OPENMC_USE_UWUW}")
|
||||
message(STATUS "OPENMC_FORCE_VENDORED_LIBS ${OPENMC_FORCE_VENDORED_LIBS}")
|
||||
message(STATUS "OPENMC_ENABLE_STRICT_FP ${OPENMC_ENABLE_STRICT_FP}")
|
||||
|
||||
# Warnings for deprecated options
|
||||
foreach(OLD_OPT IN ITEMS "openmp" "profile" "coverage" "dagmc" "libmesh")
|
||||
|
|
@ -89,6 +96,19 @@ if(NOT CMAKE_BUILD_TYPE)
|
|||
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build" FORCE)
|
||||
endif()
|
||||
|
||||
#===============================================================================
|
||||
# When STRICT_FP is enabled, remove NDEBUG from RelWithDebInfo flags so that
|
||||
# assert() remains active. CMake normally adds -DNDEBUG for both Release and
|
||||
# RelWithDebInfo, which disables C/C++ assert() statements.
|
||||
#===============================================================================
|
||||
|
||||
if(OPENMC_ENABLE_STRICT_FP)
|
||||
foreach(FLAG_VAR CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
string(REPLACE "-DNDEBUG" "" ${FLAG_VAR} "${${FLAG_VAR}}")
|
||||
string(REPLACE "/DNDEBUG" "" ${FLAG_VAR} "${${FLAG_VAR}}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
#===============================================================================
|
||||
# OpenMP for shared-memory parallelism (and GPU support some day!)
|
||||
#===============================================================================
|
||||
|
|
@ -193,6 +213,26 @@ endif()
|
|||
# Set compile/link flags based on which compiler is being used
|
||||
#===============================================================================
|
||||
|
||||
# When OPENMC_ENABLE_STRICT_FP is enabled, disable compiler optimizations that change
|
||||
# floating-point results relative to -O0, improving cross-platform and
|
||||
# cross-optimization-level reproducibility for regression testing:
|
||||
# -ffp-contract=off Prevents FMA contraction (fused multiply-add changes rounding)
|
||||
# -fno-builtin Prevents replacing math function calls (pow, exp, log, etc.)
|
||||
# with builtin versions that may differ from libm
|
||||
# By default (OFF), the compiler is free to use all optimizations for best
|
||||
# performance.
|
||||
if(OPENMC_ENABLE_STRICT_FP)
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag(-ffp-contract=off SUPPORTS_FP_CONTRACT_OFF)
|
||||
if(SUPPORTS_FP_CONTRACT_OFF)
|
||||
list(APPEND cxxflags -ffp-contract=off)
|
||||
endif()
|
||||
check_cxx_compiler_flag(-fno-builtin SUPPORTS_NO_BUILTIN)
|
||||
if(SUPPORTS_NO_BUILTIN)
|
||||
list(APPEND cxxflags -fno-builtin)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Skip for Visual Studio which has its own configurations through GUI
|
||||
if(NOT MSVC)
|
||||
|
||||
|
|
@ -266,23 +306,6 @@ else()
|
|||
endif()
|
||||
endif()
|
||||
|
||||
#===============================================================================
|
||||
# xtensor header-only library
|
||||
#===============================================================================
|
||||
|
||||
if(OPENMC_FORCE_VENDORED_LIBS)
|
||||
add_subdirectory(vendor/xtl)
|
||||
set(xtl_DIR ${CMAKE_CURRENT_BINARY_DIR}/vendor/xtl)
|
||||
add_subdirectory(vendor/xtensor)
|
||||
else()
|
||||
find_package_write_status(xtensor)
|
||||
if (NOT xtensor_FOUND)
|
||||
add_subdirectory(vendor/xtl)
|
||||
set(xtl_DIR ${CMAKE_CURRENT_BINARY_DIR}/vendor/xtl)
|
||||
add_subdirectory(vendor/xtensor)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#===============================================================================
|
||||
# Catch2 library
|
||||
#===============================================================================
|
||||
|
|
@ -332,6 +355,7 @@ endif()
|
|||
#===============================================================================
|
||||
|
||||
list(APPEND libopenmc_SOURCES
|
||||
src/atomic_mass.cpp
|
||||
src/bank.cpp
|
||||
src/boundary_condition.cpp
|
||||
src/bremsstrahlung.cpp
|
||||
|
|
@ -372,6 +396,7 @@ list(APPEND libopenmc_SOURCES
|
|||
src/particle.cpp
|
||||
src/particle_data.cpp
|
||||
src/particle_restart.cpp
|
||||
src/particle_type.cpp
|
||||
src/photon.cpp
|
||||
src/physics.cpp
|
||||
src/physics_common.cpp
|
||||
|
|
@ -387,6 +412,7 @@ list(APPEND libopenmc_SOURCES
|
|||
src/random_ray/linear_source_domain.cpp
|
||||
src/random_ray/moment_matrix.cpp
|
||||
src/random_ray/source_region.cpp
|
||||
src/ray.cpp
|
||||
src/reaction.cpp
|
||||
src/reaction_product.cpp
|
||||
src/scattdata.cpp
|
||||
|
|
@ -425,7 +451,9 @@ list(APPEND libopenmc_SOURCES
|
|||
src/tallies/filter_musurface.cpp
|
||||
src/tallies/filter_parent_nuclide.cpp
|
||||
src/tallies/filter_particle.cpp
|
||||
src/tallies/filter_particle_production.cpp
|
||||
src/tallies/filter_polar.cpp
|
||||
src/tallies/filter_reaction.cpp
|
||||
src/tallies/filter_sph_harm.cpp
|
||||
src/tallies/filter_sptl_legendre.cpp
|
||||
src/tallies/filter_surface.cpp
|
||||
|
|
@ -495,7 +523,7 @@ endif()
|
|||
# target_link_libraries treats any arguments starting with - but not -l as
|
||||
# linker flags. Thus, we can pass both linker flags and libraries together.
|
||||
target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} ${HDF5_HL_LIBRARIES}
|
||||
xtensor fmt::fmt ${CMAKE_DL_LIBS})
|
||||
fmt::fmt ${CMAKE_DL_LIBS})
|
||||
|
||||
if(TARGET pugixml::pugixml)
|
||||
target_link_libraries(libopenmc pugixml::pugixml)
|
||||
|
|
@ -552,6 +580,9 @@ endif()
|
|||
if (OPENMC_ENABLE_COVERAGE)
|
||||
target_compile_definitions(libopenmc PRIVATE COVERAGEBUILD)
|
||||
endif()
|
||||
if (OPENMC_ENABLE_STRICT_FP)
|
||||
target_compile_definitions(libopenmc PRIVATE OPENMC_ENABLE_STRICT_FP)
|
||||
endif()
|
||||
|
||||
#===============================================================================
|
||||
# openmc executable
|
||||
|
|
@ -580,9 +611,7 @@ add_custom_command(TARGET libopenmc POST_BUILD
|
|||
#===============================================================================
|
||||
# Install executable, scripts, manpage, license
|
||||
#===============================================================================
|
||||
|
||||
configure_file(cmake/OpenMCConfig.cmake.in "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfig.cmake" @ONLY)
|
||||
configure_file(cmake/OpenMCConfigVersion.cmake.in "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfigVersion.cmake" @ONLY)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/OpenMC)
|
||||
install(TARGETS openmc libopenmc
|
||||
|
|
@ -596,10 +625,24 @@ install(EXPORT openmc-targets
|
|||
NAMESPACE OpenMC::
|
||||
DESTINATION ${INSTALL_CONFIGDIR})
|
||||
|
||||
configure_package_config_file(
|
||||
"cmake/OpenMCConfig.cmake.in"
|
||||
"${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/OpenMCConfig.cmake"
|
||||
INSTALL_DESTINATION ${INSTALL_CONFIGDIR}
|
||||
)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/OpenMCConfigVersion.cmake"
|
||||
VERSION ${OPENMC_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfig.cmake"
|
||||
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfigVersion.cmake"
|
||||
DESTINATION ${INSTALL_CONFIGDIR})
|
||||
"${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/OpenMCConfig.cmake"
|
||||
"${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/OpenMCConfigVersion.cmake"
|
||||
DESTINATION "${INSTALL_CONFIGDIR}"
|
||||
)
|
||||
|
||||
install(FILES man/man1/openmc.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
install(FILES LICENSE DESTINATION "${CMAKE_INSTALL_DOCDIR}" RENAME copyright)
|
||||
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
|
|
|||
32
Dockerfile
32
Dockerfile
|
|
@ -33,11 +33,6 @@ ARG build_libmesh
|
|||
# Set default value of HOME to /root
|
||||
ENV HOME=/root
|
||||
|
||||
# Embree variables
|
||||
ENV EMBREE_TAG='v4.3.1'
|
||||
ENV EMBREE_REPO='https://github.com/embree/embree'
|
||||
ENV EMBREE_INSTALL_DIR=$HOME/EMBREE/
|
||||
|
||||
# MOAB variables
|
||||
ENV MOAB_TAG='5.5.1'
|
||||
ENV MOAB_REPO='https://bitbucket.org/fathomteam/moab/'
|
||||
|
|
@ -58,10 +53,11 @@ ENV LIBMESH_REPO='https://github.com/libMesh/libmesh'
|
|||
ENV LIBMESH_INSTALL_DIR=$HOME/LIBMESH
|
||||
|
||||
# NJOY variables
|
||||
ENV NJOY_TAG='2016.78'
|
||||
ENV NJOY_REPO='https://github.com/njoy/NJOY2016'
|
||||
|
||||
# Setup environment variables for Docker image
|
||||
ENV LD_LIBRARY_PATH=${DAGMC_INSTALL_DIR}/lib:$LD_LIBRARY_PATH \
|
||||
ENV LD_LIBRARY_PATH=${DAGMC_INSTALL_DIR}/lib:${LD_LIBRARY_PATH:-} \
|
||||
OPENMC_ENDF_DATA=/root/endf-b-vii.1 \
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
|
|
@ -71,7 +67,7 @@ RUN apt-get update -y && \
|
|||
apt-get install -y \
|
||||
python3-pip python-is-python3 wget git build-essential cmake \
|
||||
mpich libmpich-dev libhdf5-serial-dev libhdf5-mpich-dev \
|
||||
libpng-dev python3-venv && \
|
||||
libpng-dev libpugixml-dev libfmt-dev catch2 python3-venv && \
|
||||
apt-get autoremove
|
||||
|
||||
# create virtual enviroment to avoid externally managed environment error
|
||||
|
|
@ -83,7 +79,7 @@ RUN pip install --upgrade pip
|
|||
|
||||
# Clone and install NJOY2016
|
||||
RUN cd $HOME \
|
||||
&& git clone --single-branch --depth 1 ${NJOY_REPO} \
|
||||
&& git clone --single-branch -b ${NJOY_TAG} --depth 1 ${NJOY_REPO} \
|
||||
&& cd NJOY2016 \
|
||||
&& mkdir build \
|
||||
&& cd build \
|
||||
|
|
@ -94,22 +90,12 @@ RUN cd $HOME \
|
|||
|
||||
RUN if [ "$build_dagmc" = "on" ]; then \
|
||||
# Install addition packages required for DAGMC
|
||||
apt-get -y install libeigen3-dev libnetcdf-dev libtbb-dev libglfw3-dev \
|
||||
apt-get -y install \
|
||||
libeigen3-dev libnetcdf-dev libtbb-dev libglfw3-dev libembree-dev \
|
||||
&& pip install --upgrade numpy \
|
||||
&& pip install --no-cache-dir setuptools cython \
|
||||
# Clone and install EMBREE
|
||||
&& mkdir -p $HOME/EMBREE && cd $HOME/EMBREE \
|
||||
&& git clone --single-branch -b ${EMBREE_TAG} --depth 1 ${EMBREE_REPO} \
|
||||
&& mkdir build && cd build \
|
||||
&& cmake ../embree \
|
||||
-DCMAKE_INSTALL_PREFIX=${EMBREE_INSTALL_DIR} \
|
||||
-DEMBREE_MAX_ISA=NONE \
|
||||
-DEMBREE_ISA_SSE42=ON \
|
||||
-DEMBREE_ISPC_SUPPORT=OFF \
|
||||
&& make 2>/dev/null -j${compile_cores} install \
|
||||
&& rm -rf ${EMBREE_INSTALL_DIR}/build ${EMBREE_INSTALL_DIR}/embree ; \
|
||||
# Clone and install MOAB
|
||||
mkdir -p $HOME/MOAB && cd $HOME/MOAB \
|
||||
&& mkdir -p $HOME/MOAB && cd $HOME/MOAB \
|
||||
&& git clone --single-branch -b ${MOAB_TAG} --depth 1 ${MOAB_REPO} \
|
||||
&& mkdir build && cd build \
|
||||
&& cmake ../moab -DCMAKE_BUILD_TYPE=Release \
|
||||
|
|
@ -118,6 +104,7 @@ RUN if [ "$build_dagmc" = "on" ]; then \
|
|||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DENABLE_FORTRAN=OFF \
|
||||
-DENABLE_BLASLAPACK=OFF \
|
||||
-DENABLE_TESTING=OFF \
|
||||
&& make 2>/dev/null -j${compile_cores} install \
|
||||
&& cmake ../moab \
|
||||
-DENABLE_PYMOAB=ON \
|
||||
|
|
@ -133,7 +120,7 @@ RUN if [ "$build_dagmc" = "on" ]; then \
|
|||
&& mkdir build && cd build \
|
||||
&& cmake ../double-down -DCMAKE_INSTALL_PREFIX=${DD_INSTALL_DIR} \
|
||||
-DMOAB_DIR=/usr/local \
|
||||
-DEMBREE_DIR=${EMBREE_INSTALL_DIR} \
|
||||
-DEMBREE_DIR=/usr \
|
||||
&& make 2>/dev/null -j${compile_cores} install \
|
||||
&& rm -rf ${DD_INSTALL_DIR}/build ${DD_INSTALL_DIR}/double-down ; \
|
||||
# Clone and install DAGMC
|
||||
|
|
@ -147,6 +134,7 @@ RUN if [ "$build_dagmc" = "on" ]; then \
|
|||
-DDOUBLE_DOWN_DIR=${DD_INSTALL_DIR} \
|
||||
-DCMAKE_PREFIX_PATH=${DD_INSTALL_DIR}/lib \
|
||||
-DBUILD_STATIC_LIBS=OFF \
|
||||
-DBUILD_TESTS=OFF \
|
||||
&& make 2>/dev/null -j${compile_cores} install \
|
||||
&& rm -rf ${DAGMC_INSTALL_DIR}/DAGMC ${DAGMC_INSTALL_DIR}/build ; \
|
||||
fi
|
||||
|
|
|
|||
2
LICENSE
2
LICENSE
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2011-2025 Massachusetts Institute of Technology, UChicago Argonne
|
||||
Copyright (c) 2011-2026 Massachusetts Institute of Technology, UChicago Argonne
|
||||
LLC, and OpenMC contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
get_filename_component(OpenMC_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
|
||||
@PACKAGE_INIT@
|
||||
|
||||
# Compute the install prefix from this file's location
|
||||
get_filename_component(_OPENMC_PREFIX "${OpenMC_CMAKE_DIR}/../../.." ABSOLUTE)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/OpenMCConfigVersion.cmake")
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
# Explicitly calculate prefix if it was not generated above
|
||||
if(NOT DEFINED PACKAGE_PREFIX_DIR)
|
||||
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE)
|
||||
endif()
|
||||
|
||||
find_dependency(fmt CONFIG REQUIRED HINTS ${PACKAGE_PREFIX_DIR})
|
||||
find_dependency(pugixml CONFIG REQUIRED HINTS ${PACKAGE_PREFIX_DIR})
|
||||
|
||||
find_package(fmt CONFIG REQUIRED HINTS ${_OPENMC_PREFIX})
|
||||
find_package(pugixml CONFIG REQUIRED HINTS ${_OPENMC_PREFIX})
|
||||
find_package(xtl CONFIG REQUIRED HINTS ${_OPENMC_PREFIX})
|
||||
find_package(xtensor CONFIG REQUIRED HINTS ${_OPENMC_PREFIX})
|
||||
if(@OPENMC_USE_DAGMC@)
|
||||
find_package(DAGMC REQUIRED HINTS @DAGMC_DIR@)
|
||||
find_dependency(DAGMC REQUIRED HINTS @DAGMC_DIR@)
|
||||
endif()
|
||||
|
||||
if(@OPENMC_USE_LIBMESH@)
|
||||
|
|
@ -18,20 +22,24 @@ if(@OPENMC_USE_LIBMESH@)
|
|||
pkg_check_modules(LIBMESH REQUIRED @LIBMESH_PC_FILE@>=1.7.0 IMPORTED_TARGET)
|
||||
endif()
|
||||
|
||||
find_package(PNG)
|
||||
|
||||
if(NOT TARGET OpenMC::libopenmc)
|
||||
include("${OpenMC_CMAKE_DIR}/OpenMCTargets.cmake")
|
||||
if("@PNG_FOUND@")
|
||||
find_dependency(PNG)
|
||||
endif()
|
||||
|
||||
if(@OPENMC_USE_MPI@)
|
||||
find_package(MPI REQUIRED)
|
||||
find_dependency(MPI REQUIRED)
|
||||
endif()
|
||||
|
||||
if(@OPENMC_USE_OPENMP@)
|
||||
find_package(OpenMP REQUIRED)
|
||||
find_dependency(OpenMP REQUIRED)
|
||||
endif()
|
||||
|
||||
if(@OPENMC_USE_UWUW@ AND NOT ${DAGMC_BUILD_UWUW})
|
||||
message(FATAL_ERROR "UWUW is enabled in OpenMC but the DAGMC installation discovered was not configured with UWUW.")
|
||||
endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/OpenMCTargets.cmake")
|
||||
|
||||
if(NOT OpenMC_FIND_QUIETLY)
|
||||
message(STATUS "Found OpenMC: ${PACKAGE_VERSION} (found in ${PACKAGE_PREFIX_DIR})")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
set(PACKAGE_VERSION "@OPENMC_VERSION@")
|
||||
|
||||
# Check whether the requested PACKAGE_FIND_VERSION is compatible
|
||||
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -580,6 +580,279 @@ Functions
|
|||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_get_plot_index(int32_t id, int32_t* index)
|
||||
|
||||
Get the index in the plots array for a plot with a given ID.
|
||||
|
||||
:param int32_t id: Plot ID
|
||||
:param int32_t* index: Index in the plots array
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_plot_get_id(int32_t index, int32_t* id)
|
||||
|
||||
Get the ID of a plot.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param int32_t* id: Plot ID
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_plot_set_id(int32_t index, int32_t id)
|
||||
|
||||
Set the ID of a plot.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param int32_t id: Plot ID
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: size_t openmc_plots_size()
|
||||
|
||||
Number of plots currently allocated.
|
||||
|
||||
:return: Number of plots in the plots array
|
||||
:rtype: size_t
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_create(int32_t* index)
|
||||
|
||||
Create a new solid raytrace plot.
|
||||
|
||||
:param int32_t* index: Index of the newly created plot
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_get_pixels(int32_t index, int32_t* width, int32_t* height)
|
||||
|
||||
Get output pixel dimensions for a solid raytrace plot.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param int32_t* width: Image width in pixels
|
||||
:param int32_t* height: Image height in pixels
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_pixels(int32_t index, int32_t width, int32_t height)
|
||||
|
||||
Set output pixel dimensions for a solid raytrace plot.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param int32_t width: Image width in pixels
|
||||
:param int32_t height: Image height in pixels
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_get_color_by(int32_t index, int32_t* color_by)
|
||||
|
||||
Get the domain type used for coloring (0=materials, 1=cells).
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param int32_t* color_by: Coloring mode
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_color_by(int32_t index, int32_t color_by)
|
||||
|
||||
Set the domain type used for coloring (0=materials, 1=cells).
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param int32_t color_by: Coloring mode
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_default_colors(int32_t index)
|
||||
|
||||
Set default random colors for the current ``color_by`` mode.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_all_opaque(int32_t index)
|
||||
|
||||
Mark all domains in the current ``color_by`` mode as opaque.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_opaque(int32_t index, int32_t id, bool visible)
|
||||
|
||||
Set whether a specific domain ID is opaque (visible) in the rendered image.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param int32_t id: Cell/material ID (based on ``color_by``)
|
||||
:param bool visible: Whether the domain is opaque
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_color(int32_t index, int32_t id, uint8_t r, uint8_t g, uint8_t b)
|
||||
|
||||
Set RGB color for a specific domain ID.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param int32_t id: Cell/material ID (based on ``color_by``)
|
||||
:param uint8_t r: Red channel
|
||||
:param uint8_t g: Green channel
|
||||
:param uint8_t b: Blue channel
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_get_color(int32_t index, int32_t id, uint8_t* r, uint8_t* g, uint8_t* b)
|
||||
|
||||
Get RGB color for a specific domain ID.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param int32_t id: Cell/material ID (based on ``color_by``)
|
||||
:param uint8_t* r: Red channel
|
||||
:param uint8_t* g: Green channel
|
||||
:param uint8_t* b: Blue channel
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_get_camera_position(int32_t index, double* x, double* y, double* z)
|
||||
|
||||
Get camera position.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double* x: X coordinate
|
||||
:param double* y: Y coordinate
|
||||
:param double* z: Z coordinate
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_camera_position(int32_t index, double x, double y, double z)
|
||||
|
||||
Set camera position.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double x: X coordinate
|
||||
:param double y: Y coordinate
|
||||
:param double z: Z coordinate
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_get_look_at(int32_t index, double* x, double* y, double* z)
|
||||
|
||||
Get camera target point.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double* x: X coordinate
|
||||
:param double* y: Y coordinate
|
||||
:param double* z: Z coordinate
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_look_at(int32_t index, double x, double y, double z)
|
||||
|
||||
Set camera target point.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double x: X coordinate
|
||||
:param double y: Y coordinate
|
||||
:param double z: Z coordinate
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_get_up(int32_t index, double* x, double* y, double* z)
|
||||
|
||||
Get the camera up vector.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double* x: X component
|
||||
:param double* y: Y component
|
||||
:param double* z: Z component
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_up(int32_t index, double x, double y, double z)
|
||||
|
||||
Set the camera up vector.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double x: X component
|
||||
:param double y: Y component
|
||||
:param double z: Z component
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_get_light_position(int32_t index, double* x, double* y, double* z)
|
||||
|
||||
Get light source position.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double* x: X coordinate
|
||||
:param double* y: Y coordinate
|
||||
:param double* z: Z coordinate
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_light_position(int32_t index, double x, double y, double z)
|
||||
|
||||
Set light source position.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double x: X coordinate
|
||||
:param double y: Y coordinate
|
||||
:param double z: Z coordinate
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_get_fov(int32_t index, double* fov)
|
||||
|
||||
Get horizontal field of view in degrees.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double* fov: Field of view in degrees
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_fov(int32_t index, double fov)
|
||||
|
||||
Set horizontal field of view in degrees.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double fov: Field of view in degrees
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_get_diffuse_fraction(int32_t index, double* diffuse_fraction)
|
||||
|
||||
Get diffuse-light fraction.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double* diffuse_fraction: Diffuse fraction in [0, 1]
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_set_diffuse_fraction(int32_t index, double diffuse_fraction)
|
||||
|
||||
Set diffuse-light fraction.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param double diffuse_fraction: Diffuse fraction in [0, 1]
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_update_view(int32_t index)
|
||||
|
||||
Recompute internal camera/view transforms after camera changes.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_solidraytrace_plot_create_image(int32_t index, uint8_t* data_out, int32_t width, int32_t height)
|
||||
|
||||
Render the plot to an RGB image buffer.
|
||||
|
||||
:param int32_t index: Index in the plots array
|
||||
:param uint8_t* data_out: Output buffer of shape ``height*width*3``
|
||||
:param int32_t width: Image width in pixels
|
||||
:param int32_t height: Image height in pixels
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_reset()
|
||||
|
||||
Resets all tally scores
|
||||
|
|
@ -601,6 +874,10 @@ Functions
|
|||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: void openmc_run_random_ray()
|
||||
|
||||
Run a random ray simulation
|
||||
|
||||
.. c:function:: int openmc_set_n_batches(int32_t n_batches, bool set_max_batches, bool add_statepoint_batch)
|
||||
|
||||
Set number of batches and number of max batches
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ master_doc = 'index'
|
|||
|
||||
# General information about the project.
|
||||
project = 'OpenMC'
|
||||
copyright = '2011-2025, Massachusetts Institute of Technology, UChicago Argonne LLC, and OpenMC contributors'
|
||||
copyright = '2011-2026, Massachusetts Institute of Technology, UChicago Argonne LLC, and OpenMC contributors'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
|
|
|
|||
104
docs/source/devguide/agentic-tools.rst
Normal file
104
docs/source/devguide/agentic-tools.rst
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
.. _devguide_agentic_tools:
|
||||
|
||||
===========================
|
||||
Agentic Development Tools
|
||||
===========================
|
||||
|
||||
OpenMC ships a set of tools designed for AI coding agents (such as
|
||||
`Claude Code`_) that agents can use to navigate and understand the codebase.
|
||||
|
||||
.. _Claude Code: https://claude.ai/code
|
||||
|
||||
Motivation
|
||||
----------
|
||||
|
||||
Agentic tools like Claude Code are skilled at using grep to navigate and
|
||||
understand large code bases. However, grep can only find exact text matches —
|
||||
it cannot discover code that is *conceptually* related but uses different
|
||||
naming. Without a "global view" of the codebase that a human developer will
|
||||
build up over time, the agent is generally blind to any file it hasn't
|
||||
tokenized fully. While it can grep to see who else calls a function, it
|
||||
remains blind if other areas might be related but not share identical naming
|
||||
conventions.
|
||||
|
||||
This problem is mitigated somewhat by using a model with a longer context
|
||||
window. OpenMC has somewhere around ~1 million tokens of C++ and ~1 million
|
||||
tokens of python. While Claude Code in early 2026 only has a context window
|
||||
of 200k tokens, beta versions have extended context windows of 1M tokens,
|
||||
and it's not unreasonable to assume that models may be available in the near
|
||||
future that greatly exceed these limits.
|
||||
|
||||
However, even assuming the entire repository can be fit within a context
|
||||
window, there are several downsides to doing this.
|
||||
`Model performance degrades significantly as context size increases`_.
|
||||
Benchmark results are
|
||||
greatly improved if the model has less garbage to pick through. Additionally, API usage
|
||||
is typically billed as tokens in/out per turn. As the context file
|
||||
grows these costs become much larger. As such, there is still significant
|
||||
motivation to solving the above problem, so as to ensure only relevant
|
||||
information is drawn into context so as to maximize model performance and
|
||||
minimize costs.
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
The tools are registered as an `MCP (Model Context Protocol)`_ server in
|
||||
``.mcp.json`` at the repository root. AI agents that support MCP (such as
|
||||
Claude Code) discover them automatically on session start. The underlying
|
||||
Python scripts can also be run directly from the command line.
|
||||
|
||||
All tools run entirely locally — no API keys or external service accounts are
|
||||
required. Python dependencies are installed automatically into an isolated
|
||||
virtual environment at ``.claude/cache/.venv/`` on first use.
|
||||
|
||||
.. _Model performance degrades significantly as context size increases: https://www.anthropic.com/news/claude-opus-4-6
|
||||
.. _MCP (Model Context Protocol): https://modelcontextprotocol.io
|
||||
|
||||
RAG Semantic Search
|
||||
-------------------
|
||||
|
||||
The RAG (Retrieval-Augmented Generation) semantic search addresses this
|
||||
problem — it finds code by meaning, not just text match, surfacing related code
|
||||
across subsystems that ``grep`` would miss entirely. Two MCP tools are provided:
|
||||
|
||||
- **openmc_rag_search** — Given a natural-language query, returns the most
|
||||
relevant code chunks with file paths, line numbers, and a preview. Can search
|
||||
code, documentation, or both. Can also find code related to a given file.
|
||||
- **openmc_rag_rebuild** — Rebuilds the search index. Should be called after
|
||||
pulling new code or switching branches.
|
||||
|
||||
How it works
|
||||
^^^^^^^^^^^^
|
||||
|
||||
The search pipeline runs entirely on your local CPU:
|
||||
|
||||
1. **Chunking.** All C++, Python, and RST files are split into overlapping
|
||||
fixed-size windows (~1000 characters, 25% overlap). This ensures every line
|
||||
of code appears in at least one chunk and most lines appear in two.
|
||||
|
||||
2. **Embedding.** Each chunk is embedded into a 384-dimensional vector using
|
||||
the `all-MiniLM-L6-v2`_ sentence-transformer model (22 million parameters).
|
||||
This model runs on CPU with no GPU required. No API key is needed — the
|
||||
model weights are downloaded once from Hugging Face and cached locally.
|
||||
|
||||
3. **Indexing.** The vectors are stored in a local LanceDB_ database on disk.
|
||||
Building the full index takes approximately 5 minutes on a machine with
|
||||
10 CPU cores. The index is stored in ``.claude/cache/rag_index/`` and
|
||||
persists across sessions.
|
||||
|
||||
4. **Searching.** Your query is embedded using the same model, and the closest
|
||||
chunks are retrieved by vector similarity. Results include the file path,
|
||||
line range, file type, similarity distance, and a text preview.
|
||||
|
||||
.. _all-MiniLM-L6-v2: https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2
|
||||
.. _LanceDB: https://lancedb.com
|
||||
|
||||
Requirements
|
||||
^^^^^^^^^^^^
|
||||
|
||||
No system dependencies beyond **Python 3.12+** with ``pip``. An internet
|
||||
connection is required on first use to download the Python packages and
|
||||
embedding model weights; subsequent runs are fully offline. The Python packages
|
||||
(``sentence-transformers``, ``lancedb``) and their dependencies (including
|
||||
PyTorch, ~2GB) are installed automatically into an isolated virtual environment
|
||||
on first use.
|
||||
|
|
@ -14,6 +14,7 @@ other related topics.
|
|||
|
||||
contributing
|
||||
workflow
|
||||
agentic-tools
|
||||
styleguide
|
||||
policies
|
||||
tests
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ whenever a file is saved. For example, `Visual Studio Code
|
|||
support for running clang-format.
|
||||
|
||||
.. note::
|
||||
OpenMC's CI uses `clang-format` version 15. A different version of `clang-format`
|
||||
OpenMC's CI uses `clang-format` version 18. A different version of `clang-format`
|
||||
may produce different line changes and as a result fail the CI test.
|
||||
|
||||
Miscellaneous
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ Prerequisites
|
|||
- Some tests require `NJOY <https://www.njoy21.io/NJOY2016>`_ to preprocess
|
||||
cross section data. The test suite assumes that you have an ``njoy``
|
||||
executable available on your :envvar:`PATH`.
|
||||
- OpenMC should be compiled with ``-DOPENMC_ENABLE_STRICT_FP=on`` to ensure
|
||||
reproducible floating-point results across platforms and optimization levels.
|
||||
Without this flag, regression tests may not match reference values.
|
||||
|
||||
Running Tests
|
||||
-------------
|
||||
|
|
@ -67,9 +70,11 @@ make sure you have satisfied all the prerequisites above. After you have done
|
|||
that, consider the following:
|
||||
|
||||
- When building OpenMC, make sure you run CMake with
|
||||
``-DCMAKE_BUILD_TYPE=Debug``. Building with a release build will result in
|
||||
some test failures due to differences in which compiler optimizations are
|
||||
used.
|
||||
``-DOPENMC_ENABLE_STRICT_FP=on``. This prevents the compiler from applying
|
||||
floating-point optimizations (such as replacing math library calls with
|
||||
builtins or contracting multiply-add into FMA instructions) that can produce
|
||||
bit-level differences across platforms and optimization levels. Any
|
||||
``CMAKE_BUILD_TYPE`` can be used.
|
||||
- Because tallies involve the sum of many floating point numbers, the
|
||||
non-associativity of floating point numbers can result in different answers
|
||||
especially when the number of threads is high (different order of operations).
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ may also be written after each batch when multiple files are requested
|
|||
(``collision_track.N.h5``) or when the run is performed in parallel. The file
|
||||
contains the information needed to reconstruct each recorded collision.
|
||||
|
||||
The current revision of the collision track file format is 1.0.
|
||||
The current revision of the collision track file format is 1.1.
|
||||
|
||||
**/**
|
||||
|
||||
|
|
@ -37,9 +37,9 @@ The current revision of the collision track file format is 1.0.
|
|||
- ``material_id`` (*int*) -- ID of the material containing the collision site.
|
||||
- ``universe_id`` (*int*) -- ID of the universe containing the collision site.
|
||||
- ``n_collision`` (*int*) -- Collision counter for the particle history.
|
||||
- ``particle`` (*int*) -- Particle type (0=neutron, 1=photon, 2=electron, 3=positron).
|
||||
- ``parent_id`` (*int64*) -- Unique ID of the parent particle.
|
||||
- ``progeny_id`` (*int64*) -- Progeny ID of the particle.
|
||||
- ``particle`` (*int32_t*) -- Particle type (PDG number).
|
||||
- ``parent_id`` (*int64_t*) -- Unique ID of the parent particle.
|
||||
- ``progeny_id`` (*int64_t*) -- Progeny ID of the particle.
|
||||
|
||||
In an MPI run, OpenMC writes the combined dataset by gathering collision-track
|
||||
entries from all ranks before flushing them to disk, so the final file appears
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
Depletion Results File Format
|
||||
=============================
|
||||
|
||||
The current version of the depletion results file format is 1.2.
|
||||
The current version of the depletion results file format is 1.3.
|
||||
|
||||
**/**
|
||||
|
||||
|
|
@ -29,6 +29,8 @@ The current version of the depletion results file format is 1.2.
|
|||
- **depletion time** (*double[]*) -- Average process time in [s]
|
||||
spent depleting a material across all burnable materials and,
|
||||
if applicable, MPI processes.
|
||||
- **keff_search_root** (*double[]*) -- Root of the keff search at the
|
||||
end of the timestep, if applicable.
|
||||
|
||||
**/materials/<id>/**
|
||||
|
||||
|
|
|
|||
|
|
@ -406,24 +406,55 @@ Each ``<dagmc_universe>`` element can have the following attributes or sub-eleme
|
|||
|
||||
*Default*: None
|
||||
|
||||
:material_overrides:
|
||||
This element contains information on material overrides to be applied to the
|
||||
DAGMC universe. It has the following attributes and sub-elements:
|
||||
:cell:
|
||||
Zero or more ``<cell>`` sub-elements may appear to override properties of
|
||||
individual DAGMC volumes. Each ``<cell>`` element supports the following
|
||||
attributes and sub-elements:
|
||||
|
||||
:cell:
|
||||
Material override information for a single cell. It contains the following
|
||||
attributes and sub-elements:
|
||||
:id:
|
||||
The integer cell ID in the DAGMC geometry to override. Required.
|
||||
|
||||
:id:
|
||||
The cell ID in the DAGMC geometry for which the material override will
|
||||
apply.
|
||||
:name:
|
||||
An optional string label for the cell.
|
||||
|
||||
:materials:
|
||||
A list of material IDs that will apply to instances of the cell. If the
|
||||
list contains only one ID, it will replace the original material
|
||||
assignment of all instances of the DAGMC cell. If the list contains more
|
||||
than one material, each material ID of the list will be assigned to the
|
||||
various instances of the DAGMC cell.
|
||||
*Default*: None
|
||||
|
||||
:material:
|
||||
The material ID to assign to this cell. Use ``void`` for vacuum. Multiple
|
||||
space-separated IDs may be given to specify a distribmat (distributed
|
||||
material) assignment. Required.
|
||||
|
||||
:temperature:
|
||||
Temperature(s) in [K] to assign to the cell. Must be ≥ 0. Multiple
|
||||
space-separated values may be given.
|
||||
|
||||
*Default*: None
|
||||
|
||||
:density:
|
||||
Density in [g/cm³] to assign to the cell. Must be > 0. Requires a non-void
|
||||
material fill. Multiple space-separated values may be given.
|
||||
|
||||
*Default*: None
|
||||
|
||||
:volume:
|
||||
Volume of the cell in [cm³].
|
||||
|
||||
.. note:: DAGMC can compute cell volumes exactly from the triangulated
|
||||
mesh surfaces. Specifying a manual volume risks inconsistency
|
||||
with that capability.
|
||||
|
||||
*Default*: None
|
||||
|
||||
The following standard ``<cell>`` attributes are **not** supported inside
|
||||
``<dagmc_universe>`` and will raise an error if present: ``region``,
|
||||
``fill``, ``universe``, ``translation``, ``rotation``.
|
||||
|
||||
.. deprecated::
|
||||
The ``<material_overrides>`` sub-element (containing ``<cell_override>``
|
||||
children with ``<material_ids>``) is deprecated. A deprecation warning is
|
||||
emitted and the overrides are converted to the ``<cell>`` format at parse
|
||||
time. It is an error to specify both ``<material_overrides>`` and
|
||||
``<cell>`` sub-elements on the same ``<dagmc_universe>``.
|
||||
|
||||
*Default*: None
|
||||
|
||||
|
|
|
|||
|
|
@ -133,6 +133,10 @@ Temperature-dependent data, provided for temperature <TTT>K.
|
|||
This dataset is optional. This is a 1-D vector if `representation`
|
||||
is "isotropic", or a 3-D vector if `representation` is "angle"
|
||||
with dimensions of [polar][azimuthal][groups].
|
||||
When this data is not available, an approximation using the
|
||||
group energy boundaries is used. For more information see
|
||||
the particle speed subsection in the multigroup-data section
|
||||
of the theory manual.
|
||||
|
||||
**/<library name>/<TTT>K/scatter_data/**
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
Particle Restart File Format
|
||||
============================
|
||||
|
||||
The current version of the particle restart file format is 2.0.
|
||||
The current version of the particle restart file format is 2.1.
|
||||
|
||||
**/**
|
||||
|
||||
|
|
@ -26,8 +26,7 @@ The current version of the particle restart file format is 2.0.
|
|||
- **run_mode** (*char[]*) -- Run mode used, either 'fixed source',
|
||||
'eigenvalue', or 'particle restart'.
|
||||
- **id** (*int8_t*) -- Unique identifier of the particle.
|
||||
- **type** (*int*) -- Particle type (0=neutron, 1=photon, 2=electron,
|
||||
3=positron)
|
||||
- **type** (*int32_t*) -- Particle type (PDG number)
|
||||
- **weight** (*double*) -- Weight of the particle.
|
||||
- **energy** (*double*) -- Energy of the particle in eV for
|
||||
continuous-energy mode, or the energy group of the particle for
|
||||
|
|
|
|||
|
|
@ -7,6 +7,19 @@ Settings Specification -- settings.xml
|
|||
All simulation parameters and miscellaneous options are specified in the
|
||||
settings.xml file.
|
||||
|
||||
-------------------------------
|
||||
``<atomic_relaxation>`` Element
|
||||
-------------------------------
|
||||
|
||||
The ``<atomic_relaxation>`` element determines whether the atomic relaxation
|
||||
cascade, the X-ray fluorescence photons and Auger electrons emitted when an
|
||||
inner-shell vacancy is filled, is simulated following photoelectric and
|
||||
incoherent (Compton) scattering interactions. Disabling this can speed up
|
||||
photon transport calculations where the detailed secondary particle cascade is
|
||||
not of interest.
|
||||
|
||||
*Default*: true
|
||||
|
||||
---------------------
|
||||
``<batches>`` Element
|
||||
---------------------
|
||||
|
|
@ -542,6 +555,18 @@ generator during generation of colors in plots.
|
|||
|
||||
*Default*: 1
|
||||
|
||||
.. _properties_file:
|
||||
|
||||
-----------------------------
|
||||
``<properties_file>`` Element
|
||||
-----------------------------
|
||||
|
||||
The ``properties_file`` element has no attributes and contains the path to a
|
||||
properties HDF5 file to load cell temperatures/densities and material
|
||||
densities.
|
||||
|
||||
*Default*: None
|
||||
|
||||
---------------------
|
||||
``<ptables>`` Element
|
||||
---------------------
|
||||
|
|
@ -572,7 +597,7 @@ found in the :ref:`random ray user guide <random_ray>`.
|
|||
|
||||
*Default*: None
|
||||
|
||||
:source:
|
||||
:ray_source:
|
||||
Specifies the starting ray distribution, and follows the format for
|
||||
:ref:`source_element`. It must be uniform in space and angle and cover the
|
||||
full domain. It does not represent a physical neutron or photon source -- it
|
||||
|
|
@ -580,6 +605,35 @@ found in the :ref:`random ray user guide <random_ray>`.
|
|||
|
||||
*Default*: None
|
||||
|
||||
:adjoint_source:
|
||||
Specifies an adjoint fixed source for adjoint transport simulations, and
|
||||
follows the format for :ref:`source_element`. The distributions which make
|
||||
up the adjoint source are subject to the same restrictions as forward
|
||||
fixed sources in Random Ray mode.
|
||||
|
||||
*Default*: None
|
||||
|
||||
:adjoint:
|
||||
Specifies whether to perform adjoint transport. The default is 'False',
|
||||
corresponding to forward transport.
|
||||
|
||||
*Default*: None
|
||||
|
||||
:volume_estimator:
|
||||
Specifies choice of volume estimator for the random ray solver. Options
|
||||
are 'naive', 'simulation_averaged', or 'hybrid'. The default is 'hybrid'.
|
||||
|
||||
*Default*: None
|
||||
|
||||
:volume_normalized_flux_tallies:
|
||||
Specifies whether to normalize flux tallies by volume (bool). The
|
||||
default is 'False'. When enabled, flux tallies will be reported in units
|
||||
of cm/cm^3. When disabled, flux tallies will be reported in units of cm
|
||||
(i.e., total distance traveled by neutrons in the spatial tally
|
||||
region).
|
||||
|
||||
*Default*: None
|
||||
|
||||
:sample_method:
|
||||
Specifies the method for sampling the starting ray distribution. This
|
||||
element can be set to "prng" or "halton".
|
||||
|
|
@ -687,14 +741,16 @@ pseudo-random number generator.
|
|||
|
||||
*Default*: 1
|
||||
|
||||
--------------------
|
||||
``<stride>`` Element
|
||||
--------------------
|
||||
-----------------------------------
|
||||
``<shared_secondary_bank>`` Element
|
||||
-----------------------------------
|
||||
|
||||
The ``stride`` element is used to specify how many random numbers are allocated
|
||||
for each source particle history.
|
||||
|
||||
*Default*: 152,917
|
||||
The ``shared_secondary_bank`` element indicates whether to use a shared
|
||||
secondary particle bank. When enabled, secondary particles are collected into
|
||||
a global bank, sorted for reproducibility, and load-balanced across MPI ranks
|
||||
between generations. If not specified, the shared secondary bank is enabled
|
||||
automatically for fixed-source simulations with weight windows active, and
|
||||
disabled otherwise.
|
||||
|
||||
.. _source_element:
|
||||
|
||||
|
|
@ -721,7 +777,10 @@ attributes/sub-elements:
|
|||
is present.
|
||||
|
||||
:particle:
|
||||
The source particle type, either ``neutron`` or ``photon``.
|
||||
The source particle type, specified as a PDG number or a string alias (e.g.,
|
||||
``neutron``/``n``, ``photon``/``gamma``, ``electron``, ``positron``,
|
||||
``proton``/``p``, ``deuteron``/``d``, ``triton``/``t``, ``alpha``, or GNDS
|
||||
nuclide names like ``Fe57``).
|
||||
|
||||
*Default*: neutron
|
||||
|
||||
|
|
@ -811,6 +870,7 @@ attributes/sub-elements:
|
|||
|
||||
For a "cylindrical" distribution, no parameters are specified. Instead,
|
||||
the ``r``, ``phi``, ``z``, and ``origin`` elements must be specified.
|
||||
Optionally, the ``r_dir`` and ``z_dir`` elements could be specified.
|
||||
|
||||
For a "spherical" distribution, no parameters are specified. Instead,
|
||||
the ``r``, ``theta``, ``phi``, and ``origin`` elements must be specified.
|
||||
|
|
@ -842,6 +902,10 @@ attributes/sub-elements:
|
|||
of a univariate probability distribution (see the description in
|
||||
:ref:`univariate`).
|
||||
|
||||
:r_dir:
|
||||
For "cylindrical" distributions, this element specifies the direction
|
||||
of the cylinder r-axis at phi=0. Defaults to (1.0, 0.0, 0.0).
|
||||
|
||||
:theta:
|
||||
For a "spherical" distribution, this element specifies the distribution
|
||||
of theta-coordinates. The necessary sub-elements/attributes are those of a
|
||||
|
|
@ -854,6 +918,10 @@ attributes/sub-elements:
|
|||
sub-elements/attributes are those of a univariate probability
|
||||
distribution (see the description in :ref:`univariate`).
|
||||
|
||||
:z_dir:
|
||||
For "cylindrical" distributions, this element specifies the direction
|
||||
of the cylinder z-axis. Defaults to (0.0, 0.0, 1.0).
|
||||
|
||||
:origin:
|
||||
For "cylindrical and "spherical" distributions, this element specifies
|
||||
the coordinates for the origin of the coordinate system.
|
||||
|
|
@ -992,17 +1060,19 @@ variable and whose sub-elements/attributes are as follows:
|
|||
|
||||
:type:
|
||||
The type of the distribution. Valid options are "uniform", "discrete",
|
||||
"tabular", "maxwell", "watt", and "mixture". The "uniform" option produces
|
||||
variates sampled from a uniform distribution over a finite interval. The
|
||||
"discrete" option produces random variates that can assume a finite number
|
||||
of values (i.e., a distribution characterized by a probability mass function).
|
||||
The "tabular" option produces random variates sampled from a tabulated
|
||||
distribution where the density function is either a histogram or
|
||||
"tabular", "maxwell", "watt", "mixture", and "decay_spectrum". The "uniform"
|
||||
option produces variates sampled from a uniform distribution over a finite
|
||||
interval. The "discrete" option produces random variates that can assume a
|
||||
finite number of values (i.e., a distribution characterized by a probability
|
||||
mass function). The "tabular" option produces random variates sampled from a
|
||||
tabulated distribution where the density function is either a histogram or
|
||||
linearly-interpolated between tabulated points. The "watt" option produces
|
||||
random variates is sampled from a Watt fission spectrum (only used for
|
||||
energies). The "maxwell" option produce variates sampled from a Maxwell
|
||||
fission spectrum (only used for energies). The "mixture" option produces samples
|
||||
from univariate sub-distributions with given probabilities.
|
||||
fission spectrum (only used for energies). The "mixture" option produces
|
||||
samples from univariate sub-distributions with given probabilities. The
|
||||
"decay_spectrum" option produces photon energies sampled from decay photon
|
||||
spectra in a depletion chain (only used for energies).
|
||||
|
||||
*Default*: None
|
||||
|
||||
|
|
@ -1020,6 +1090,10 @@ variable and whose sub-elements/attributes are as follows:
|
|||
:math:`(x,p)` pairs defining the discrete/tabular distribution. All :math:`x`
|
||||
points are given first followed by corresponding :math:`p` points.
|
||||
|
||||
For a "decay_spectrum" distribution, ``parameters`` gives the atom densities
|
||||
in [atom/b-cm] for the nuclides listed in the ``nuclides`` element, in the
|
||||
same order.
|
||||
|
||||
For a "watt" distribution, ``parameters`` should be given as two real numbers
|
||||
:math:`a` and :math:`b` that parameterize the distribution :math:`p(x) dx = c
|
||||
e^{-x/a} \sinh \sqrt{b \, x} dx`.
|
||||
|
|
@ -1049,6 +1123,21 @@ variable and whose sub-elements/attributes are as follows:
|
|||
This sub-element of a ``pair`` element provides information on the
|
||||
corresponding univariate distribution.
|
||||
|
||||
:volume:
|
||||
For a "decay_spectrum" distribution, this attribute specifies the source
|
||||
region volume in cm\ :sup:`3`. It is used together with atom densities to
|
||||
determine the absolute photon emission rate. When a source uses a
|
||||
"decay_spectrum" energy distribution, the source strength is set from this
|
||||
emission rate.
|
||||
|
||||
:nuclides:
|
||||
For a "decay_spectrum" distribution, this element specifies a
|
||||
whitespace-separated list of nuclide names contributing to the decay photon
|
||||
source. The atom densities for these nuclides are given by the ``parameters``
|
||||
element in the same order. Nuclides are resolved against the depletion chain,
|
||||
and nuclides without decay photon spectra do not contribute to the
|
||||
distribution.
|
||||
|
||||
:bias:
|
||||
This optional element specifies a biased distribution for importance sampling.
|
||||
For continuous distributions, the ``bias`` element should contain another
|
||||
|
|
@ -1069,23 +1158,6 @@ based on constraints.
|
|||
|
||||
*Default*: 0.05
|
||||
|
||||
-------------------------
|
||||
``<state_point>`` Element
|
||||
-------------------------
|
||||
|
||||
The ``<state_point>`` element indicates at what batches a state point file
|
||||
should be written. A state point file can be used to restart a run or to get
|
||||
tally results at any batch. The default behavior when using this tag is to
|
||||
write out the source bank in the state_point file. This behavior can be
|
||||
customized by using the ``<source_point>`` element. This element has the
|
||||
following attributes/sub-elements:
|
||||
|
||||
:batches:
|
||||
A list of integers separated by spaces indicating at what batches a state
|
||||
point file should be written.
|
||||
|
||||
*Default*: Last batch only
|
||||
|
||||
--------------------------
|
||||
``<source_point>`` Element
|
||||
--------------------------
|
||||
|
|
@ -1135,6 +1207,32 @@ attributes/sub-elements:
|
|||
|
||||
*Default*: false
|
||||
|
||||
-------------------------
|
||||
``<state_point>`` Element
|
||||
-------------------------
|
||||
|
||||
The ``<state_point>`` element indicates at what batches a state point file
|
||||
should be written. A state point file can be used to restart a run or to get
|
||||
tally results at any batch. The default behavior when using this tag is to
|
||||
write out the source bank in the state_point file. This behavior can be
|
||||
customized by using the ``<source_point>`` element. This element has the
|
||||
following attributes/sub-elements:
|
||||
|
||||
:batches:
|
||||
A list of integers separated by spaces indicating at what batches a state
|
||||
point file should be written.
|
||||
|
||||
*Default*: Last batch only
|
||||
|
||||
--------------------
|
||||
``<stride>`` Element
|
||||
--------------------
|
||||
|
||||
The ``stride`` element is used to specify how many random numbers are allocated
|
||||
for each source particle history.
|
||||
|
||||
*Default*: 152,917
|
||||
|
||||
------------------------------
|
||||
``<surf_source_read>`` Element
|
||||
------------------------------
|
||||
|
|
@ -1222,6 +1320,23 @@ attributes/sub-elements:
|
|||
are not eligible to store any particles when using ``cell``, ``cellfrom``
|
||||
or ``cellto`` attributes. It is recommended to use surface IDs instead.
|
||||
|
||||
------------------------------------
|
||||
``<surface_grazing_cutoff>`` Element
|
||||
------------------------------------
|
||||
|
||||
The ``<surface_grazing_cutoff>`` element specifies the surface flux cosine cutoff.
|
||||
|
||||
*Default*: 0.001
|
||||
|
||||
-----------------------------------
|
||||
``<surface_grazing_ratio>`` Element
|
||||
-----------------------------------
|
||||
|
||||
The ``<surface_grazing_ratio>`` element specifies the surface flux cosine
|
||||
substitution ratio.
|
||||
|
||||
*Default*: 0.5
|
||||
|
||||
------------------------------
|
||||
``<survival_biasing>`` Element
|
||||
------------------------------
|
||||
|
|
@ -1537,7 +1652,8 @@ sub-elements/attributes:
|
|||
*Default*: None
|
||||
|
||||
:particle_type:
|
||||
The particle that the weight windows will apply to (e.g., 'neutron')
|
||||
The particle that the weight windows will apply to, specified as a PDG
|
||||
code or string (e.g., ``neutron``).
|
||||
|
||||
*Default*: 'neutron'
|
||||
|
||||
|
|
@ -1597,7 +1713,8 @@ mesh-based weight windows.
|
|||
*Default*: None
|
||||
|
||||
:particle_type:
|
||||
The particle that the weight windows will apply to (e.g., 'neutron')
|
||||
The particle that the weight windows will apply to, specified as a PDG
|
||||
code or string (e.g., ``neutron``).
|
||||
|
||||
*Default*: neutron
|
||||
|
||||
|
|
@ -1640,6 +1757,14 @@ mesh-based weight windows.
|
|||
The ratio of the lower to upper weight window bounds.
|
||||
|
||||
*Default*: 5.0
|
||||
|
||||
For FW-CADIS:
|
||||
|
||||
:targets:
|
||||
A sequence of IDs corresponding to the tallies which cover phase
|
||||
space regions of interest for local variance reduction.
|
||||
|
||||
*Default*: None
|
||||
|
||||
---------------------------------------
|
||||
``<weight_window_checkpoints>`` Element
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ following the same format.
|
|||
**/**
|
||||
|
||||
:Attributes: - **filetype** (*char[]*) -- String indicating the type of file.
|
||||
- **version** (*int[2]*) -- Major and minor version of the source
|
||||
file format.
|
||||
|
||||
:Datasets:
|
||||
|
||||
|
|
@ -22,5 +24,5 @@ following the same format.
|
|||
particle. The compound type has fields ``r``, ``u``, ``E``,
|
||||
``time``, ``wgt``, ``delayed_group``, ``surf_id`` and ``particle``,
|
||||
which represent the position, direction, energy, time, weight,
|
||||
delayed group, surface ID, and particle type (0=neutron, 1=photon,
|
||||
2=electron, 3=positron), respectively.
|
||||
delayed group, surface ID, and particle type (PDG number),
|
||||
respectively.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
State Point File Format
|
||||
=======================
|
||||
|
||||
The current version of the statepoint file format is 18.1.
|
||||
The current version of the statepoint file format is 18.2.
|
||||
|
||||
**/**
|
||||
|
||||
|
|
@ -56,8 +56,8 @@ The current version of the statepoint file format is 18.1.
|
|||
``time``, ``wgt``, ``delayed_group``, ``surf_id``, and
|
||||
``particle``, which represent the position, direction, energy,
|
||||
time, weight, delayed group, surface ID, and particle type
|
||||
(0=neutron, 1=photon, 2=electron, 3=positron), respectively. Only
|
||||
present when `run_mode` is 'eigenvalue'.
|
||||
(PDG number), respectively. Only present when `run_mode` is
|
||||
'eigenvalue'.
|
||||
|
||||
**/tallies/**
|
||||
|
||||
|
|
|
|||
|
|
@ -142,9 +142,9 @@ attributes/sub-elements:
|
|||
|
||||
:type:
|
||||
The type of the filter. Accepted options are "cell", "cellfrom",
|
||||
"cellborn", "surface", "material", "universe", "energy", "energyout", "mu",
|
||||
"polar", "azimuthal", "mesh", "distribcell", "delayedgroup",
|
||||
"energyfunction", and "particle".
|
||||
"cellborn", "surface", "material", "universe", "energy", "energyout",
|
||||
"mu", "polar", "azimuthal", "mesh", "distribcell", "delayedgroup",
|
||||
"energyfunction", "particle", and "particleproduction".
|
||||
|
||||
:bins:
|
||||
A description of the bins for each type of filter can be found in
|
||||
|
|
@ -318,8 +318,34 @@ should be set to:
|
|||
they use ``energy`` and ``y``.
|
||||
|
||||
:particle:
|
||||
A list of integers indicating the type of particles to tally ('neutron' = 1,
|
||||
'photon' = 2, 'electron' = 3, 'positron' = 4).
|
||||
A list of particle identifiers to tally, specified as strings (e.g.,
|
||||
``neutron``, ``photon``, ``He4``) or as integer PDG numbers.
|
||||
|
||||
:particleproduction:
|
||||
This filter tallies secondary particles produced in reactions, binned by
|
||||
particle type and, optionally, by energy. Unlike other energy filters, the
|
||||
weight applied is the weight of the secondary particle. To obtain secondary
|
||||
particle production rates, use this filter with the ``events`` score.
|
||||
|
||||
The filter uses the following sub-elements instead of ``bins``:
|
||||
|
||||
:particles:
|
||||
A space-separated list of secondary particle types to tally (e.g.,
|
||||
``photon``, ``neutron``, ``electron``).
|
||||
|
||||
:energies:
|
||||
An optional monotonically increasing list of energy boundaries in [eV]
|
||||
for binning the secondary particle energies. If omitted, total production
|
||||
is tallied without energy binning.
|
||||
|
||||
For example, to tally photon and neutron production in three energy groups:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<filter id="1" type="particleproduction">
|
||||
<particles>photon neutron</particles>
|
||||
<energies>0.0 1.0e5 1.0e6 20.0e6</energies>
|
||||
</filter>
|
||||
|
||||
------------------
|
||||
``<mesh>`` Element
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
Track File Format
|
||||
=================
|
||||
|
||||
The current revision of the particle track file format is 3.0.
|
||||
The current revision of the particle track file format is 3.1.
|
||||
|
||||
**/**
|
||||
|
||||
|
|
@ -32,6 +32,5 @@ The current revision of the particle track file format is 3.0.
|
|||
the array for each primary/secondary particle. The
|
||||
last offset should match the total size of the
|
||||
array.
|
||||
- **particles** (*int[]*) -- Particle type for each
|
||||
primary/secondary particle (0=neutron, 1=photon,
|
||||
2=electron, 3=positron).
|
||||
- **particles** (*int32_t[]*) -- Particle type for
|
||||
each primary/secondary particle (PDG number).
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
License Agreement
|
||||
=================
|
||||
|
||||
Copyright © 2011-2025 Massachusetts Institute of Technology, UChicago Argonne
|
||||
Copyright © 2011-2026 Massachusetts Institute of Technology, UChicago Argonne
|
||||
LLC, and OpenMC contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
|
|
|
|||
|
|
@ -289,6 +289,48 @@ sections. This allows flexibility for the model to use highly anisotropic
|
|||
scattering information in the water while the fuel can be simulated with linear
|
||||
or even isotropic scattering.
|
||||
|
||||
Particle Speed
|
||||
--------------
|
||||
|
||||
When using a multigroup representation of cross sections, the particle speed has
|
||||
meaning only in an average sense. The particle speed is important when modeling
|
||||
dynamic behavior. OpenMC calculates the particle speed using the inverse
|
||||
velocity multigroup data if it is available. If such data is not available,
|
||||
OpenMC uses an approximate velocity using the group energy bounds in the
|
||||
following way:
|
||||
|
||||
.. math::
|
||||
|
||||
\frac{1}{v_g} = \int_{E_{\text{min}}^g}^{E_{\text{max}}^g} \frac{1}{v(E)} \frac{\alpha}{E} dE
|
||||
|
||||
Where :math:`E_{\text{min}}^g` and :math:`E_{\text{max}}^g` are the group energy
|
||||
boundaries for group :math:`g`. :math:`v(E)` is the neutron velocity calculated
|
||||
using relativistic kinematics, :math:`\alpha` is a normalization constant for the
|
||||
:math:`\frac{1}{E}` spectrum.
|
||||
|
||||
This equation is valid when inside the group boundaries the neutron spectrum
|
||||
follows a typical :math:`\frac{1}{E}` slowing down spectrum. This assumption is
|
||||
widely used when generating fine group neutron cross section data libraries from
|
||||
continuous energy data.
|
||||
|
||||
The solution to this equation is:
|
||||
|
||||
.. math::
|
||||
|
||||
\frac{1}{v_g} = \frac{1}{c \log\left(\frac{E_{\text{max}}^g}{E_{\text{min}}^g}\right)}
|
||||
\left[ 2(\operatorname{arctanh}(k_{\text{max}}^{-1}) - \operatorname{arctanh}(k_{\text{min}}^{-1}))
|
||||
- (k_{\text{max}}-k_{\text{min}}) \right]
|
||||
|
||||
where :math:`c` is the speed of light and :math:`k_{\text{max}}`,
|
||||
:math:`k_{\text{min}}` are defined by a change of variables:
|
||||
|
||||
.. math::
|
||||
|
||||
k = \sqrt{1+\frac{2 m_n c^2}{E}}
|
||||
|
||||
where :math:`E` is the particle kinetic energy and :math:`m_n` is the neutron
|
||||
rest mass.
|
||||
|
||||
.. _logarithmic mapping technique:
|
||||
https://mcnp.lanl.gov/pdf_files/TechReport_2014_LANL_LA-UR-14-24530_Brown.pdf
|
||||
.. _Hwang: https://doi.org/10.13182/NSE87-A16381
|
||||
|
|
|
|||
|
|
@ -1081,28 +1081,32 @@ lifetimes.
|
|||
|
||||
In OpenMC, the random ray adjoint solver is implemented simply by transposing
|
||||
the scattering matrix, swapping :math:`\nu\Sigma_f` and :math:`\chi`, and then
|
||||
running a normal transport solve. When no external fixed source is present, no
|
||||
additional changes are needed in the transport process. However, if an external
|
||||
fixed forward source is present in the simulation problem, then an additional
|
||||
step is taken to compute the accompanying fixed adjoint source. In OpenMC, the
|
||||
adjoint flux does *not* represent a response function for a particular detector
|
||||
region. Rather, the adjoint flux is the global response, making it appropriate
|
||||
for use with weight window generation schemes for global variance reduction.
|
||||
Thus, if using a fixed source, the external source for the adjoint mode is
|
||||
simply computed as being :math:`1 / \phi`, where :math:`\phi` is the forward
|
||||
scalar flux that results from a normal forward solve (which OpenMC will run
|
||||
first automatically when in adjoint mode). The adjoint external source will be
|
||||
computed for each source region in the simulation mesh, independent of any
|
||||
tallies. The adjoint external source is always flat, even when a linear
|
||||
scattering and fission source shape is used. When in adjoint mode, all reported
|
||||
results (e.g., tallies, eigenvalues, etc.) are derived from the adjoint flux,
|
||||
even when the physical meaning is not necessarily obvious. These values are
|
||||
still reported, though we emphasize that the primary use case for adjoint mode
|
||||
is for producing adjoint flux tallies to support subsequent perturbation studies
|
||||
and weight window generation.
|
||||
running a normal transport solve. When no external fixed forward source is
|
||||
present, or if an adjoint fixed source is specifically provided, no additional
|
||||
changes are needed in the transport process. This adjoint source can
|
||||
correspond, for example, to a detector response function in a particular
|
||||
region. However, if an external fixed forward source is present in the
|
||||
simulation problem without an adjoint fixed source, an additional step is taken
|
||||
to compute the accompanying forward-weighted adjoint source. In this case, the
|
||||
adjoint flux does *not* represent the importance of locations in phase space to
|
||||
detector response; rather, the "response" in question is a uniform distribution
|
||||
of Monte Carlo particle density, making the importance provided by the adjoint
|
||||
flux appropriate for use with weight window generation schemes for global
|
||||
variance reduction. Thus, if using a fixed source, the forward-weighted
|
||||
external source for adjoint mode is simply computed as being :math:`1 / \phi`,
|
||||
where :math:`\phi` is the forward scalar flux that results from a normal
|
||||
forward solve (which OpenMC will run first automatically when in adjoint mode).
|
||||
The adjoint external source will be computed for each source region in the
|
||||
simulation mesh, independent of any tallies. The adjoint external source is
|
||||
always flat, even when a linear scattering and fission source shape is used.
|
||||
|
||||
Note that the adjoint :math:`k_{eff}` is statistically the same as the forward
|
||||
:math:`k_{eff}`, despite the flux distributions taking different shapes.
|
||||
When in adjoint mode, all reported results (e.g., tallies, eigenvalues, etc.)
|
||||
are derived from the adjoint flux, even when the physical meaning is not
|
||||
necessarily obvious. These values are still reported, though we emphasize that
|
||||
the primary use case for adjoint mode is for producing adjoint flux tallies to
|
||||
support subsequent perturbation studies and weight window generation. Note
|
||||
however that the adjoint :math:`k_{eff}` is statistically the same as the
|
||||
forward :math:`k_{eff}`, despite the flux distributions taking different shapes.
|
||||
|
||||
---------------------------
|
||||
Fundamental Sources of Bias
|
||||
|
|
|
|||
|
|
@ -205,7 +205,71 @@ had a collision at every event. Thus, for tallies with outgoing-energy filters
|
|||
or for tallies of scattering moments (which require the scattering cosine of
|
||||
the change-in-angle), we must use an analog estimator.
|
||||
|
||||
.. TODO: Add description of surface current tallies
|
||||
-----------------------------------
|
||||
Surface-Integrated Flux and Current
|
||||
-----------------------------------
|
||||
|
||||
Surface tallies allow you to measure particle behavior as they cross specific
|
||||
boundaries in your geometry. Unlike volume tallies, which integrate over a
|
||||
volumetric region, surface tallies capture the current or flux passing through a
|
||||
surface. Surface tallies are estimated using an analog estimator.
|
||||
|
||||
Current Score
|
||||
-------------
|
||||
|
||||
When tallying the current across a surface, we simply count the weight of
|
||||
particles that cross the surface of interest:
|
||||
|
||||
|
||||
.. math::
|
||||
:label: analog-current-estimator
|
||||
|
||||
J = \frac{1}{W} \sum_{i \in S} w_i.
|
||||
|
||||
where :math:`J` is the area-integrated current passing through surface
|
||||
:math:`S`, :math:`W` is the total starting weight of the particles, and
|
||||
:math:`w_i` is the weight of the particle as it crosses the surface :math:`S`.
|
||||
|
||||
Flux Score
|
||||
----------
|
||||
|
||||
When tallying flux over a surface, we use the relationship between current and
|
||||
flux:
|
||||
|
||||
|
||||
.. math::
|
||||
:label: surface-flux-estimator
|
||||
|
||||
\phi_S = \frac{1}{W} \sum_{i \in S} \frac{w_i}{|\mu|}.
|
||||
|
||||
where :math:`\phi_S` is the area-integrated flux over surface :math:`S`,
|
||||
:math:`W` is the total starting weight of the particles, :math:`w_i` is the
|
||||
weight of the particle as it crosses the surface :math:`S` and :math:`\mu` is
|
||||
the cosine of angle between the particle direction and the surface normal.
|
||||
|
||||
This equation diverges when the particle crossing the surface is nearly parallel
|
||||
to it (that is, as :math:`\mu` approaches zero). To remove this divergence,
|
||||
OpenMC scores:
|
||||
|
||||
.. math::
|
||||
:label: modified-surface-flux-estimator
|
||||
|
||||
\phi_S = \frac{1}{W} \sum_{i \in S} w_i f(\mu).
|
||||
|
||||
and the function :math:`f` is defined by:
|
||||
|
||||
.. math::
|
||||
f(\mu) = \begin{cases}
|
||||
\frac{1}{|\mu|} & |\mu| > \mu_\text{cut} \\
|
||||
\frac{1}{c\mu_\text{cut}} & |\mu| \le \mu_\text{cut}
|
||||
\end{cases}
|
||||
|
||||
where :math:`\mu_\text{cut}` is the grazing cosine cutoff and :math:`c` is the
|
||||
cosine substitution ratio. The parameters :math:`\mu_\text{cut}` and :math:`c`
|
||||
can be set by the user via the :attr:`openmc.Settings.surface_grazing_cutoff`
|
||||
and :attr:`openmc.Settings.surface_grazing_ratio` attributes, respectively. The
|
||||
default values for these parameters are 0.001 and 0.5 as recommended by
|
||||
`Favorite, Thomas, and Booth <https://doi.org/10.13182/NSE09-72>`_.
|
||||
|
||||
.. _tallies_statistics:
|
||||
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ where it was born from.
|
|||
|
||||
The Forward-Weighted Consistent Adjoint Driven Importance Sampling method, or
|
||||
`FW-CADIS method <https://doi.org/10.13182/NSE12-33>`_, produces weight windows
|
||||
for global variance reduction given adjoint flux information throughout the
|
||||
entire domain. The weight window lower bound is defined in Equation
|
||||
for global or local variance reduction given adjoint flux information throughout
|
||||
the entire domain. The weight window lower bound is defined in Equation
|
||||
:eq:`fw_cadis`, and also involves a normalization step not shown here.
|
||||
|
||||
.. math::
|
||||
|
|
@ -135,6 +135,18 @@ aware of this.
|
|||
|
||||
\text{FOM} = \frac{1}{\text{Time} \times \sigma^2}
|
||||
|
||||
Finally, one unique capability of the FW-CADIS weight window generator is to
|
||||
produce weight windows for local variance reduction, given a list of the
|
||||
responses of interest. This is controlled by optionally specifying target
|
||||
tallies from the :class:`openmc.model.Model` to the
|
||||
:class:`openmc.WeightWindowGenerator`, as illustrated in the
|
||||
:ref:`user guide<variance_reduction>`. If target tallies for local variance
|
||||
reduction are supplied, then the adjoint sources are only populated after the
|
||||
initial forward simulation in the source regions associated with those tallies.
|
||||
In other regions, the adjoint source term is instead set to zero. The Random
|
||||
Ray solver then determines the adjoint flux map used to generate FW-CADIS
|
||||
weight windows following the usual technique.
|
||||
|
||||
.. _methods_source_biasing:
|
||||
|
||||
--------------
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ Constructing Tallies
|
|||
openmc.MeshSurfaceFilter
|
||||
openmc.EnergyFilter
|
||||
openmc.EnergyoutFilter
|
||||
openmc.ParticleProductionFilter
|
||||
openmc.MuFilter
|
||||
openmc.MuSurfaceFilter
|
||||
openmc.PolarFilter
|
||||
|
|
@ -148,6 +149,7 @@ Constructing Tallies
|
|||
openmc.ZernikeRadialFilter
|
||||
openmc.ParentNuclideFilter
|
||||
openmc.ParticleFilter
|
||||
openmc.ReactionFilter
|
||||
openmc.MeshMaterialVolumes
|
||||
openmc.Trigger
|
||||
openmc.TallyDerivative
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ Functions
|
|||
reset_timers
|
||||
run
|
||||
run_in_memory
|
||||
run_random_ray
|
||||
sample_external_source
|
||||
simulation_finalize
|
||||
simulation_init
|
||||
|
|
@ -81,12 +82,15 @@ Classes
|
|||
Nuclide
|
||||
ParentNuclideFilter
|
||||
ParticleFilter
|
||||
ParticleProductionFilter
|
||||
PolarFilter
|
||||
ReactionFilter
|
||||
RectilinearMesh
|
||||
RegularMesh
|
||||
SpatialLegendreFilter
|
||||
SphericalHarmonicsFilter
|
||||
SphericalMesh
|
||||
SolidRayTracePlot
|
||||
SurfaceFilter
|
||||
Tally
|
||||
TemporarySession
|
||||
|
|
@ -124,6 +128,12 @@ Data
|
|||
|
||||
:type: dict
|
||||
|
||||
.. data:: plots
|
||||
|
||||
Mapping of plot ID to :class:`openmc.lib.SolidRayTracePlot` instances.
|
||||
|
||||
:type: dict
|
||||
|
||||
.. data:: nuclides
|
||||
|
||||
Mapping of nuclide name to :class:`openmc.lib.Nuclide` instances.
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ Core Functions
|
|||
isotopes
|
||||
kalbach_slope
|
||||
linearize
|
||||
mass_attenuation_coefficient
|
||||
mass_energy_absorption_coefficient
|
||||
thin
|
||||
water_density
|
||||
zam
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ Univariate Probability Distributions
|
|||
openmc.stats.Legendre
|
||||
openmc.stats.Mixture
|
||||
openmc.stats.Normal
|
||||
openmc.stats.DecaySpectrum
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated
|
||||
|
|
@ -29,6 +30,7 @@ Univariate Probability Distributions
|
|||
:template: myfunction.rst
|
||||
|
||||
openmc.stats.delta_function
|
||||
openmc.stats.fusion_neutron_spectrum
|
||||
openmc.stats.muir
|
||||
|
||||
Angular Distributions
|
||||
|
|
@ -67,3 +69,4 @@ Spatial Distributions
|
|||
:template: myfunction.rst
|
||||
|
||||
openmc.stats.spherical_uniform
|
||||
openmc.stats.cylindrical_uniform
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ packages should be installed, for example in Homebrew via:
|
|||
|
||||
.. code-block:: sh
|
||||
|
||||
brew install llvm cmake xtensor hdf5 python libomp libpng
|
||||
brew install llvm cmake hdf5 python libomp libpng
|
||||
|
||||
The compiler provided by the above LLVM package should be used in place of the
|
||||
one provisioned by XCode, which does not support the multithreading library used
|
||||
|
|
|
|||
|
|
@ -190,6 +190,25 @@ we would run::
|
|||
|
||||
r2s.run(timesteps, source_rates, mat_vol_kwargs={'n_samples': 10_000_000})
|
||||
|
||||
It is also possible to use multiple meshes by passing a list of meshes instead
|
||||
of a single mesh. This can be useful, for example, when different regions of the
|
||||
model require different mesh resolutions. The meshes are assumed to be
|
||||
**non-overlapping**; each element--material combination across all meshes is
|
||||
treated as an independent activation region, and all meshes are handled in a
|
||||
single neutron transport solve. For example::
|
||||
|
||||
# Fine mesh near the activation target
|
||||
mesh_fine = openmc.RegularMesh()
|
||||
mesh_fine.dimension = (10, 10, 10)
|
||||
...
|
||||
|
||||
# Coarse mesh for the surrounding region
|
||||
mesh_coarse = openmc.RegularMesh()
|
||||
mesh_coarse.dimension = (5, 5, 5)
|
||||
...
|
||||
|
||||
r2s = openmc.deplete.R2SManager(model, [mesh_fine, mesh_coarse])
|
||||
|
||||
Direct 1-Step (D1S) Calculations
|
||||
================================
|
||||
|
||||
|
|
|
|||
|
|
@ -248,6 +248,28 @@ The classes :class:`Halfspace`, :class:`Intersection`, :class:`Union`, and
|
|||
:class:`Complement` and all instances of :class:`openmc.Region` and can be
|
||||
assigned to the :attr:`Cell.region` attribute.
|
||||
|
||||
Cells also contain :attr:`Cell.temperature` and :attr:`Cell.density`
|
||||
attributes which override the temperature and density of the fill. These can
|
||||
be quite useful when temperatures and densities are spatially varying, as the
|
||||
alternative would be to add a unique :class:`Material` for each permutation of
|
||||
temperature, density, and composition. You can set the temperature (K) and
|
||||
density (g/cc) of a cell like so::
|
||||
|
||||
fuel.temperature = 800.0
|
||||
fuel.density = 10.0
|
||||
|
||||
The real utility of cell temperatures and densities occurs when a cell is
|
||||
replicated across the geometry, such as when a cell is the root geometric element
|
||||
in a replicated :ref:`universe<usersguide_universes>` or :ref:`lattice
|
||||
<usersguide_lattices>`. In those cases, you can provide a list of temperatures
|
||||
and densities to apply a temperature/density field to all of the distributed cells::
|
||||
|
||||
fuel.temperature = [800.0, 900.0, 800.0, 900.0]
|
||||
fuel.density = [10.0, 9.0, 10.0, 9.0]
|
||||
|
||||
In this example, the fuel cell is distributed four times in the geometry. Each
|
||||
distributed instance then receives its own temperature and density.
|
||||
|
||||
.. _usersguide_universes:
|
||||
|
||||
---------
|
||||
|
|
|
|||
|
|
@ -158,6 +158,75 @@ feature can be used to access the installed packages.
|
|||
.. _Spack: https://spack.readthedocs.io/en/latest/
|
||||
.. _setup guide: https://spack.readthedocs.io/en/latest/getting_started.html
|
||||
|
||||
.. _install_aur:
|
||||
|
||||
------------------------------------
|
||||
Installing on Arch Linux via the AUR
|
||||
------------------------------------
|
||||
|
||||
On Arch Linux and Arch-based distributions, OpenMC can be installed from the
|
||||
`Arch User Repository (AUR) <https://aur.archlinux.org/>`_. An AUR package named
|
||||
``openmc-git`` is available, which builds OpenMC directly from the latest
|
||||
development sources.
|
||||
|
||||
This package provides a full-featured OpenMC stack, including:
|
||||
|
||||
* MPI and DAGMC-enabled OpenMC build
|
||||
* User-selected nuclear data libraries
|
||||
* The `CAD_to_OpenMC <https://github.com/united-neux/CAD_to_OpenMC>`_ meshing tool
|
||||
* All required dependencies for the above components
|
||||
|
||||
To install the package, you will need an AUR helper such as `yay`_ or `paru`_.
|
||||
For example, using ``yay``::
|
||||
|
||||
yay -S openmc-git
|
||||
|
||||
|
||||
Alternatively, you can manually clone and build the package::
|
||||
|
||||
git clone https://aur.archlinux.org/openmc-git.git
|
||||
cd openmc-git
|
||||
makepkg -si
|
||||
|
||||
Note, ``makepkg`` uses ``pacman`` to resolve dependencies. Therefore, AUR-based
|
||||
dependencies need to be installed separately with ``yay`` or ``paru`` before
|
||||
running ``makepkg``. The PKGBUILD will automatically handle all required
|
||||
dependencies and build OpenMC with MPI and DAGMC support enabled.
|
||||
|
||||
.. tip::
|
||||
|
||||
If there are failing checks during the build process, you can bypass them
|
||||
with the ``--nocheck`` flag::
|
||||
|
||||
yay -S openmc-git --mflags "--nocheck"
|
||||
|
||||
Or::
|
||||
|
||||
git clone https://aur.archlinux.org/openmc-git.git
|
||||
cd openmc-git
|
||||
makepkg -si --nocheck
|
||||
|
||||
.. note::
|
||||
|
||||
The ``openmc-git`` package tracks the latest development version from the
|
||||
upstream repository. As such, it may include new features and bug fixes, but
|
||||
could also introduce instability compared to official releases.
|
||||
|
||||
.. tip::
|
||||
|
||||
OpenMC is installed under ``/opt``. If you are installing and using it in
|
||||
the same terminal session, you may need to reload your environment
|
||||
variables::
|
||||
|
||||
source /etc/profile
|
||||
|
||||
Alternatively, start a new shell session.
|
||||
|
||||
Once installed, the ``openmc`` executable, nuclear data libraries, and
|
||||
associated tools will be available in your system :envvar:`PATH`.
|
||||
|
||||
.. _yay: https://github.com/Jguer/yay
|
||||
.. _paru: https://github.com/Morganamilo/paru
|
||||
|
||||
.. _install_source:
|
||||
|
||||
|
|
@ -262,11 +331,11 @@ Prerequisites
|
|||
|
||||
This option allows OpenMC to read and write MCPL (Monte Carlo Particle
|
||||
Lists) files instead of .h5 files for sources (external source
|
||||
distribution, k-eigenvalue source distribution, and surface sources). To
|
||||
turn this option on in the CMake configuration step, add the following
|
||||
option::
|
||||
|
||||
cmake -DOPENMC_USE_MCPL=on ..
|
||||
distribution, k-eigenvalue source distribution, and surface sources).
|
||||
OpenMC does not need any particular build option to use this, but MCPL
|
||||
must be installed on the system in order to do so. Refer to the
|
||||
`MCPL documentation <https://github.com/mctools/mcpl/blob/HEAD/INSTALL.md>`_
|
||||
for instructions on how to accomplish this.
|
||||
|
||||
* NCrystal_ library for defining materials with enhanced thermal neutron transport
|
||||
|
||||
|
|
@ -383,6 +452,20 @@ OPENMC_USE_MPI
|
|||
options, please see the `FindMPI.cmake documentation
|
||||
<https://cmake.org/cmake/help/latest/module/FindMPI.html>`_.
|
||||
|
||||
.. _cmake_strict_fp:
|
||||
|
||||
OPENMC_ENABLE_STRICT_FP
|
||||
Disables compiler optimizations that change floating-point results relative to
|
||||
unoptimized builds, improving cross-platform and cross-optimization-level
|
||||
reproducibility. This disables FMA contraction (``-ffp-contract=off``) and
|
||||
compiler builtin replacements of math functions like ``pow``, ``exp``, ``log``
|
||||
(``-fno-builtin``). It also keeps C/C++ assertions active by removing the
|
||||
``-DNDEBUG`` flag from ``RelWithDebInfo`` builds. Without this flag, these
|
||||
optimizations can produce bit-level differences across platforms, compilers,
|
||||
and optimization levels. This option should be used when running the test
|
||||
suite. By default (off), the compiler is free to use all optimizations for
|
||||
best performance. (Default: off)
|
||||
|
||||
OPENMC_FORCE_VENDORED_LIBS
|
||||
Forces OpenMC to use the submodules located in the vendor directory, as
|
||||
opposed to searching the system for already installed versions of those
|
||||
|
|
@ -415,7 +498,10 @@ Release
|
|||
|
||||
RelWithDebInfo
|
||||
(Default if no type is specified.) Enable optimization and debug. On most
|
||||
platforms/compilers, this is equivalent to `-O2 -g`.
|
||||
platforms/compilers, this is equivalent to `-O2 -g`. When
|
||||
:ref:`OPENMC_ENABLE_STRICT_FP <cmake_strict_fp>` is enabled, OpenMC removes the
|
||||
``-DNDEBUG`` flag that CMake normally adds for this build type, so that
|
||||
C/C++ assertions remain active.
|
||||
|
||||
Example of configuring for Debug mode:
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,15 @@ VTK Mesh File Generation
|
|||
------------------------
|
||||
|
||||
VTK files of OpenMC meshes can be created using the
|
||||
:meth:`openmc.Mesh.write_data_to_vtk` method. Data can be applied to the
|
||||
:meth:`openmc.Mesh.write_data_to_vtk` method. This method supports several VTK
|
||||
formats depending on the mesh type. Structured meshes
|
||||
(:class:`~openmc.RegularMesh`, :class:`~openmc.RectilinearMesh`,
|
||||
:class:`~openmc.CylindricalMesh`, and :class:`~openmc.SphericalMesh`) can be
|
||||
exported to legacy VTK format (``.vtk``). The :class:`~openmc.UnstructuredMesh`
|
||||
class supports VTK unstructured grid formats (``.vtu``) as well as an HDF5-based
|
||||
format (``.vtkhdf``) that does not require the ``vtk`` module to write.
|
||||
|
||||
Data can be applied to the
|
||||
elements of the resulting mesh from mesh filter objects. This data can be
|
||||
provided either as a flat array or, in the case of structured meshes
|
||||
(:class:`~openmc.RegularMesh`, :class:`~openmc.RectilinearMesh`,
|
||||
|
|
|
|||
|
|
@ -646,7 +646,9 @@ model to use these multigroup cross sections. An example is given below::
|
|||
overwrite_mgxs_library=False,
|
||||
mgxs_path="mgxs.h5",
|
||||
correction=None,
|
||||
source_energy=None
|
||||
source_energy=None,
|
||||
temperatures=None,
|
||||
temperature_settings=None
|
||||
)
|
||||
|
||||
The most important parameter to set is the ``method`` parameter, which can be
|
||||
|
|
@ -733,6 +735,20 @@ distribution for MGXS generation as::
|
|||
|
||||
source_energy = openmc.stats.delta_function(2.45e6)
|
||||
|
||||
The ``temperatures`` parameter can be provided if temperature-dependent
|
||||
multi-group cross sections are desired for multi-physics simulations. An
|
||||
individual cross section generation calculation is run for each temperature
|
||||
provided, where the materials in the model are set to the temperature. The
|
||||
temperature settings used during cross section generation can be specified with the
|
||||
``temperature_settings`` parameter. If no ``temperature_settings`` are provided,
|
||||
the settings contained in the model will be used. The valid keys and values in the
|
||||
``temperature_settings`` dictionary are identical to
|
||||
:attr:`openmc.Settings.temperature_settings`; more information can be found in
|
||||
:class:`openmc.Settings` . This approach yields isothermal cross section interpolation
|
||||
tables, which can be inaccurate for systems with large differences between temperatures
|
||||
in each material (often the case in fission reactors). If a more sophisticated
|
||||
temperature-dependence is required, we recommend generating cross sections manually.
|
||||
|
||||
Ultimately, the methods described above are all just approximations.
|
||||
Approximations in the generated MGXS data will fundamentally limit the potential
|
||||
accuracy of the random ray solver. However, the methods described above are all
|
||||
|
|
@ -928,6 +944,8 @@ as::
|
|||
which will greatly improve the quality of the linear source term in 2D
|
||||
simulations.
|
||||
|
||||
.. _usersguide_random_ray_run_modes:
|
||||
|
||||
---------------------------------
|
||||
Fixed Source and Eigenvalue Modes
|
||||
---------------------------------
|
||||
|
|
@ -1057,22 +1075,47 @@ The adjoint flux random ray solver mode can be enabled as::
|
|||
|
||||
settings.random_ray['adjoint'] = True
|
||||
|
||||
When enabled, OpenMC will first run a forward transport simulation followed by
|
||||
an adjoint transport simulation. The purpose of the forward solve is to compute
|
||||
the adjoint external source when an external source is present in the
|
||||
simulation. Simulation settings (e.g., number of rays, batches, etc.) will be
|
||||
identical for both simulations. At the conclusion of the run, all results (e.g.,
|
||||
tallies, plots, etc.) will be derived from the adjoint flux rather than the
|
||||
forward flux but are not labeled any differently. The initial forward flux
|
||||
solution will not be stored or available in the final statepoint file. Those
|
||||
wishing to do analysis requiring both the forward and adjoint solutions will
|
||||
need to run two separate simulations and load both statepoint files.
|
||||
When enabled, OpenMC will first run a forward transport simulation if there are
|
||||
no user-specified adjoint sources present, followed by an adjoint transport
|
||||
simulation. Fixed adjoint sources can be specified on the
|
||||
:attr:`openmc.Settings.random_ray` dictionary as follows::
|
||||
|
||||
# Geometry definition
|
||||
...
|
||||
detector_cell = openmc.Cell(fill=detector_mat, name='cell where detector will be')
|
||||
...
|
||||
# Define fixed adjoint neutron source
|
||||
strengths = [1.0]
|
||||
midpoints = [1.0e-4]
|
||||
energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths)
|
||||
|
||||
adj_source = openmc.IndependentSource(
|
||||
energy=energy_distribution,
|
||||
constraints={'domains': [detector_cell]}
|
||||
)
|
||||
|
||||
# Add to random_ray dict
|
||||
settings.random_ray['adjoint_source'] = adj_source
|
||||
|
||||
The same constraints apply to the user-defined adjoint source as to the forward
|
||||
source, described in the :ref:`Fixed Source and Eigenvalue section
|
||||
<usersguide_random_ray_run_modes>`. If this source is not provided, a forward
|
||||
solve must take place to compute the adjoint external source when a forward
|
||||
external source is present in the problem. Simulation settings (e.g., number of
|
||||
rays, batches, etc.) will be identical for both calculations. At the
|
||||
conclusion of the run, all results (e.g., tallies, plots, etc.) will be
|
||||
derived from the adjoint flux rather than the forward flux but are not labeled
|
||||
any differently. The initial forward flux solution will not be stored or
|
||||
available in the final statepoint file. Those wishing to do analysis requiring
|
||||
both the forward and adjoint solutions will need to run two separate
|
||||
simulations and load both statepoint files.
|
||||
|
||||
.. note::
|
||||
When adjoint mode is selected, OpenMC will always perform a full forward
|
||||
solve and then run a full adjoint solve immediately afterwards. Statepoint
|
||||
and tally results will be derived from the adjoint flux, but will not be
|
||||
labeled any differently.
|
||||
Use of the automated
|
||||
:ref:`FW-CADIS weight window generator<usersguide_fw_cadis>` is not
|
||||
currently compatible with user-defined adjoint sources. Instead, the
|
||||
initial forward calculation is used to assign "forward-weighted" adjoint
|
||||
sources to the tally regions of interest.
|
||||
|
||||
---------------------------------------
|
||||
Putting it All Together: Example Inputs
|
||||
|
|
|
|||
|
|
@ -400,7 +400,7 @@ below.
|
|||
{
|
||||
openmc::SourceSite particle;
|
||||
// weight
|
||||
particle.particle = openmc::ParticleType::neutron;
|
||||
particle.particle = openmc::ParticleType::neutron();
|
||||
particle.wgt = 1.0;
|
||||
// position
|
||||
double angle = 2.0 * M_PI * openmc::prn(seed);
|
||||
|
|
@ -477,7 +477,7 @@ parameters to the source class when it is created:
|
|||
{
|
||||
openmc::SourceSite particle;
|
||||
// weight
|
||||
particle.particle = openmc::ParticleType::neutron;
|
||||
particle.particle = openmc::ParticleType::neutron();
|
||||
particle.wgt = 1.0;
|
||||
// position
|
||||
particle.r.x = 0.0;
|
||||
|
|
@ -604,6 +604,13 @@ transport::
|
|||
|
||||
settings.photon_transport = True
|
||||
|
||||
Atomic relaxation (the cascade of fluorescence photons and Auger electrons
|
||||
emitted when an inner-shell vacancy is filled) is enabled by default whenever
|
||||
photon transport is on. It can be disabled using the
|
||||
:attr:`Settings.atomic_relaxation` attribute::
|
||||
|
||||
settings.atomic_relaxation = False
|
||||
|
||||
The way in which OpenMC handles secondary charged particles can be specified
|
||||
with the :attr:`Settings.electron_treatment` attribute. By default, the
|
||||
:ref:`thick-target bremsstrahlung <ttb>` (TTB) approximation is used to generate
|
||||
|
|
|
|||
|
|
@ -105,109 +105,124 @@ The following tables show all valid scores:
|
|||
|
||||
.. table:: **Reaction scores: units are reactions per source particle.**
|
||||
|
||||
+----------------------+---------------------------------------------------+
|
||||
|Score | Description |
|
||||
+======================+===================================================+
|
||||
|absorption |Total absorption rate. For incident neutrons, this |
|
||||
| |accounts for all reactions that do not produce |
|
||||
| |secondary neutrons as well as fission. For incident|
|
||||
| |photons, this includes photoelectric and pair |
|
||||
| |production. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|elastic |Elastic scattering reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|fission |Total fission reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|scatter |Total scattering rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|total |Total reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2nd) |(n,2nd) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2n) |(n,2n) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,3n) |(n,3n) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,na) |(n,n\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,n3a) |(n,n3\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2na) |(n,2n\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,3na) |(n,3n\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,np) |(n,np) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,n2a) |(n,n2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2n2a) |(n,2n2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,nd) |(n,nd) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,nt) |(n,nt) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,n3He) |(n,n\ :sup:`3`\ He) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,nd2a) |(n,nd2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,nt2a) |(n,nt2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,4n) |(n,4n) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2np) |(n,2np) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,3np) |(n,3np) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,n2p) |(n,n2p) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,n*X*) |Level inelastic scattering reaction rate. The *X* |
|
||||
| |indicates what which inelastic level, e.g., (n,n3) |
|
||||
| |is third-level inelastic scattering. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,nc) |Continuum level inelastic scattering reaction rate.|
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,gamma) |Radiative capture reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,p) |(n,p) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,d) |(n,d) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,t) |(n,t) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,3He) |(n,\ :sup:`3`\ He) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,a) |(n,\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2a) |(n,2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,3a) |(n,3\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2p) |(n,2p) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,pa) |(n,p\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,t2a) |(n,t2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,d2a) |(n,d2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,pd) |(n,pd) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,pt) |(n,pt) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,da) |(n,d\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|coherent-scatter |Coherent (Rayleigh) scattering reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|incoherent-scatter |Incoherent (Compton) scattering reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|photoelectric |Photoelectric absorption reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|pair-production |Pair production reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|*Arbitrary integer* |An arbitrary integer is interpreted to mean the |
|
||||
| |reaction rate for a reaction with a given ENDF MT |
|
||||
| |number. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
+------------------------+-------------------------------------------------+
|
||||
|Score |Description |
|
||||
+========================+=================================================+
|
||||
|absorption |Total absorption rate. For incident neutrons, |
|
||||
| |this accounts for all reactions that do not |
|
||||
| |produce secondary neutrons as well as fission. |
|
||||
| |For incident photons, this includes |
|
||||
| |photoelectric and pair production. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|elastic |Elastic scattering reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|fission |Total fission reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|scatter |Total scattering rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|total |Total reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,2nd) |(n,2nd) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,2n) |(n,2n) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,3n) |(n,3n) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,na) |(n,n\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,n3a) |(n,n3\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,2na) |(n,2n\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,3na) |(n,3n\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,np) |(n,np) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,n2a) |(n,n2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,2n2a) |(n,2n2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,nd) |(n,nd) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,nt) |(n,nt) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,n3He) |(n,n\ :sup:`3`\ He) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,nd2a) |(n,nd2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,nt2a) |(n,nt2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,4n) |(n,4n) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,2np) |(n,2np) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,3np) |(n,3np) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,n2p) |(n,n2p) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,npa) |(n,np\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,n*X*) |Level inelastic scattering reaction rate. The |
|
||||
| |*X* indicates which inelastic level, e.g., |
|
||||
| |(n,n3) is third-level inelastic scattering. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,nc) |Continuum level inelastic scattering |
|
||||
| |reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,gamma) |Radiative capture reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,p) |(n,p) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,d) |(n,d) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,t) |(n,t) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,3He) |(n,\ :sup:`3`\ He) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,a) |(n,\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,2a) |(n,2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,3a) |(n,3\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,2p) |(n,2p) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,pa) |(n,p\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,t2a) |(n,t2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,d2a) |(n,d2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,pd) |(n,pd) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,pt) |(n,pt) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|(n,da) |(n,d\ :math:`\alpha`\ ) reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|photon-total |Total photo-atomic reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|coherent-scatter |Coherent (Rayleigh) scattering reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|incoherent-scatter |Incoherent (Compton) scattering reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|photoelectric |Photoelectric absorption reaction rate. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|photoelectric-*S* |Subshell photoelectric absorption rate for the |
|
||||
| |*S* shell. For example, "photoelectric-N3" is the|
|
||||
| |rate for the N3 subshell. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|pair-production |Pair production reaction rate (total). |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|pair-production-electron|Pair production reaction rate in the electron |
|
||||
| |field. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|pair-production-nuclear |Pair production reaction rate in the nuclear |
|
||||
| |field. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|*Arbitrary integer* |An arbitrary integer is interpreted to mean the |
|
||||
| |reaction rate for a reaction with a given ENDF |
|
||||
| |MT number. |
|
||||
+------------------------+-------------------------------------------------+
|
||||
|
||||
.. table:: **Particle production scores: units are particles produced per
|
||||
source particles.**
|
||||
|
|
@ -246,18 +261,21 @@ The following tables show all valid scores:
|
|||
+----------------------+---------------------------------------------------+
|
||||
|Score | Description |
|
||||
+======================+===================================================+
|
||||
|current |Used in combination with a meshsurface filter: |
|
||||
|current |It may not be used in conjunction with any other |
|
||||
| |score except flux. |
|
||||
| | |
|
||||
| |When used in combination with a meshsurface filter:|
|
||||
| |Partial currents on the boundaries of each cell in |
|
||||
| |a mesh. It may not be used in conjunction with any |
|
||||
| |other score. Only energy and mesh filters may be |
|
||||
| |used. |
|
||||
| |Used in combination with a surface filter: |
|
||||
| |a mesh. |
|
||||
| | |
|
||||
| |When used in combination with a surface filter: |
|
||||
| |Net currents on any surface previously defined in |
|
||||
| |the geometry. It may be used along with any other |
|
||||
| |filter, except meshsurface filters. |
|
||||
| |Surfaces can alternatively be defined with cell |
|
||||
| |from and cell filters thereby resulting in tallying|
|
||||
| |partial currents. |
|
||||
| | |
|
||||
| |Units are particles per source particle. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|events |Number of scoring events. Units are events per |
|
||||
|
|
|
|||
|
|
@ -4,26 +4,27 @@
|
|||
Variance Reduction
|
||||
==================
|
||||
|
||||
Global variance reduction in OpenMC is accomplished by weight windowing
|
||||
or source biasing techniques, the latter of which additionally provides a
|
||||
local variance reduction capability. OpenMC is capable of generating weight
|
||||
windows using either the MAGIC or FW-CADIS methods. Both techniques will
|
||||
produce a ``weight_windows.h5`` file that can be loaded and used later on. In
|
||||
Global and local variance reduction are possible in OpenMC through both weight
|
||||
windowing and source biasing techniques. OpenMC is capable of generating weight
|
||||
windows using either the MAGIC or FW-CADIS methods, the latter with an optional
|
||||
capability for local variance reduction. Both techniques will produce a
|
||||
``weight_windows.h5`` file that can be loaded and used later on. In
|
||||
this section, we first break down the steps required to generate and apply
|
||||
weight windows, then describe how source biasing may be applied.
|
||||
|
||||
.. _ww_generator:
|
||||
|
||||
------------------------------------
|
||||
Generating Weight Windows with MAGIC
|
||||
------------------------------------
|
||||
-------------------------------------------
|
||||
Generating Global Weight Windows with MAGIC
|
||||
-------------------------------------------
|
||||
|
||||
As discussed in the :ref:`methods section <methods_variance_reduction>`, MAGIC
|
||||
is an iterative method that uses flux tally information from a Monte Carlo
|
||||
simulation to produce weight windows for a user-defined mesh. While generating
|
||||
the weight windows, OpenMC is capable of applying the weight windows generated
|
||||
from a previous batch while processing the next batch, allowing for progressive
|
||||
improvement in the weight window quality across iterations.
|
||||
simulation to produce weight windows for a user-defined mesh with the objective
|
||||
of global variance reduction. While generating the weight windows, OpenMC is
|
||||
capable of applying the weight windows generated from a previous batch while
|
||||
processing the next batch, allowing for progressive improvement in the weight
|
||||
window quality across iterations.
|
||||
|
||||
The typical way of generating weight windows is to define a mesh and then add an
|
||||
:class:`openmc.WeightWindowGenerator` object to an :attr:`openmc.Settings`
|
||||
|
|
@ -71,15 +72,20 @@ At the end of the simulation, a ``weight_windows.h5`` file will be saved to disk
|
|||
for later use. Loading it in another subsequent simulation will be discussed in
|
||||
the "Using Weight Windows" section below.
|
||||
|
||||
------------------------------------------------------
|
||||
Generating Weight Windows with FW-CADIS and Random Ray
|
||||
------------------------------------------------------
|
||||
.. _usersguide_fw_cadis:
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Generating Global or Local Weight Windows with FW-CADIS and Random Ray
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Weight window generation with FW-CADIS and random ray in OpenMC uses the same
|
||||
exact strategy as with MAGIC. An :class:`openmc.WeightWindowGenerator` object is
|
||||
added to the :attr:`openmc.Settings` object, and a ``weight_windows.h5`` will be
|
||||
generated at the end of the simulation. The only difference is that the code
|
||||
must be run in random ray mode. A full description of how to enable and setup
|
||||
exact strategy as with MAGIC. Using FW-CADIS, however, also enables
|
||||
local variance reduction in fixed source problems through the :attr:`targets`
|
||||
attribute, which is described later in this section. To enable FW-CADIS, an
|
||||
:class:`openmc.WeightWindowGenerator` object is added to the
|
||||
:attr:`openmc.Settings` object, and a ``weight_windows.h5`` will be generated
|
||||
at the end of the simulation. The only procedural difference is that the code
|
||||
must be run in random ray mode. A full description of how to enable and setup
|
||||
random ray mode can be found in the :ref:`Random Ray User Guide <random_ray>`.
|
||||
|
||||
.. note::
|
||||
|
|
@ -90,7 +96,7 @@ random ray mode can be found in the :ref:`Random Ray User Guide <random_ray>`.
|
|||
ray solver. A high level overview of the current workflow for generation of
|
||||
weight windows with FW-CADIS using random ray is given below.
|
||||
|
||||
1. Begin by making a deepy copy of your continuous energy Python model and then
|
||||
1. Begin by making a deep copy of your continuous energy Python model and then
|
||||
convert the copy to be multigroup and use the random ray transport solver.
|
||||
The conversion process can largely be automated as described in more detail
|
||||
in the :ref:`random ray quick start guide <quick_start>`, summarized below::
|
||||
|
|
@ -148,7 +154,53 @@ random ray mode can be found in the :ref:`Random Ray User Guide <random_ray>`.
|
|||
assigning to ``model.settings.random_ray['source_region_meshes']``) and for
|
||||
weight window generation.
|
||||
|
||||
3. When running your multigroup random ray input deck, OpenMC will automatically
|
||||
3. (Optional) If local variance reduction is desired in a fixed-source problem,
|
||||
populate the :attr:`targets` attribute with an :class:`openmc.Tallies`
|
||||
instance or an iterable of tally IDs indicating the tallies of interest for
|
||||
variance reduction::
|
||||
|
||||
# Build a new example and WWG for local variance reduction
|
||||
from openmc.examples import random_ray_three_region_cube_with_detectors
|
||||
new_model = random_ray_three_region_cube_with_detectors()
|
||||
|
||||
ww_mesh = openmc.RegularMesh()
|
||||
n = 7
|
||||
width = 35.0
|
||||
ww_mesh.dimension = (n, n, n)
|
||||
ww_mesh.lower_left = (0.0, 0.0, 0.0)
|
||||
ww_mesh.upper_right = (width, width, width)
|
||||
|
||||
wwg = openmc.WeightWindowGenerator(
|
||||
method="fw_cadis",
|
||||
mesh=ww_mesh,
|
||||
max_realizations=new_model.settings.batches
|
||||
)
|
||||
new_model.settings.weight_window_generators = wwg
|
||||
new_model.settings.random_ray['volume_estimator'] = 'naive'
|
||||
|
||||
# Get the tallies of interest
|
||||
target_tallies = openmc.Tallies()
|
||||
|
||||
for tally in list(new_model.tallies):
|
||||
if tally.name in {"Detector 1 Tally", "Detector 2 Tally"}:
|
||||
target_tallies.append(tally)
|
||||
|
||||
# Add to WeightWindowGenerator
|
||||
wwg.targets = target_tallies
|
||||
|
||||
.. warning::
|
||||
The tallies designated as FW-CADIS targets to the
|
||||
:class:`~openmc.WeightWindowGenerator` must be present under the
|
||||
:class:`~openmc.model.Model.tallies` attribute of the
|
||||
:class:`~openmc.model.Model` as well in order to be recognized as valid
|
||||
local variance reduction targets. This check is performed when the
|
||||
:func:`openmc.model.Model.export_to_model_xml` or
|
||||
:func:`openmc.model.Model.export_to_xml` functions are called, meaning
|
||||
that the standalone :func:`openmc.Settings.export_to_xml` and
|
||||
:func:`openmc.Tallies.export_to_xml` methods should not be used with
|
||||
FW-CADIS local variance reduction.
|
||||
|
||||
4. When running your multigroup random ray input deck, OpenMC will automatically
|
||||
run a forward solve followed by an adjoint solve, with a
|
||||
``weight_windows.h5`` file generated at the end. The ``weight_windows.h5``
|
||||
file will contain FW-CADIS generated weight windows. This file can be used in
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
#include <cmath> // for M_PI
|
||||
#include <cmath> // for M_PI
|
||||
#include <memory> // for unique_ptr
|
||||
|
||||
#include "openmc/particle.h"
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class RingSource : public openmc::Source
|
||||
{
|
||||
class RingSource : public openmc::Source {
|
||||
openmc::SourceSite sample(uint64_t* seed) const
|
||||
{
|
||||
openmc::SourceSite particle;
|
||||
// particle type
|
||||
particle.particle = openmc::ParticleType::neutron;
|
||||
particle.particle = openmc::ParticleType::neutron();
|
||||
// position
|
||||
double angle = 2.0 * M_PI * openmc::prn(seed);
|
||||
double radius = 3.0;
|
||||
|
|
@ -25,10 +24,11 @@ class RingSource : public openmc::Source
|
|||
}
|
||||
};
|
||||
|
||||
// A function to create a unique pointer to an instance of this class when generated
|
||||
// via a plugin call using dlopen/dlsym.
|
||||
// You must have external C linkage here otherwise dlopen will not find the file
|
||||
extern "C" std::unique_ptr<RingSource> openmc_create_source(std::string parameters)
|
||||
// A function to create a unique pointer to an instance of this class when
|
||||
// generated via a plugin call using dlopen/dlsym. You must have external C
|
||||
// linkage here otherwise dlopen will not find the file
|
||||
extern "C" std::unique_ptr<RingSource> openmc_create_source(
|
||||
std::string parameters)
|
||||
{
|
||||
return std::make_unique<RingSource>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,63 +1,65 @@
|
|||
#include <cmath> // for M_PI
|
||||
#include <memory> // for unique_ptr
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "openmc/particle.h"
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class RingSource : public openmc::Source {
|
||||
public:
|
||||
RingSource(double radius, double energy) : radius_(radius), energy_(energy) { }
|
||||
public:
|
||||
RingSource(double radius, double energy) : radius_(radius), energy_(energy) {}
|
||||
|
||||
// Defines a function that can create a unique pointer to a new instance of this class
|
||||
// by extracting the parameters from the provided string.
|
||||
static std::unique_ptr<RingSource> from_string(std::string parameters)
|
||||
{
|
||||
std::unordered_map<std::string, std::string> parameter_mapping;
|
||||
// Defines a function that can create a unique pointer to a new instance of
|
||||
// this class by extracting the parameters from the provided string.
|
||||
static std::unique_ptr<RingSource> from_string(std::string parameters)
|
||||
{
|
||||
std::unordered_map<std::string, std::string> parameter_mapping;
|
||||
|
||||
std::stringstream ss(parameters);
|
||||
std::string parameter;
|
||||
while (std::getline(ss, parameter, ',')) {
|
||||
parameter.erase(0, parameter.find_first_not_of(' '));
|
||||
std::string key = parameter.substr(0, parameter.find_first_of('='));
|
||||
std::string value = parameter.substr(parameter.find_first_of('=') + 1, parameter.length());
|
||||
parameter_mapping[key] = value;
|
||||
}
|
||||
|
||||
double radius = std::stod(parameter_mapping["radius"]);
|
||||
double energy = std::stod(parameter_mapping["energy"]);
|
||||
return std::make_unique<RingSource>(radius, energy);
|
||||
std::stringstream ss(parameters);
|
||||
std::string parameter;
|
||||
while (std::getline(ss, parameter, ',')) {
|
||||
parameter.erase(0, parameter.find_first_not_of(' '));
|
||||
std::string key = parameter.substr(0, parameter.find_first_of('='));
|
||||
std::string value =
|
||||
parameter.substr(parameter.find_first_of('=') + 1, parameter.length());
|
||||
parameter_mapping[key] = value;
|
||||
}
|
||||
|
||||
// Samples from an instance of this class.
|
||||
openmc::SourceSite sample(uint64_t* seed) const
|
||||
{
|
||||
openmc::SourceSite particle;
|
||||
// particle type
|
||||
particle.particle = openmc::ParticleType::neutron;
|
||||
// position
|
||||
double angle = 2.0 * M_PI * openmc::prn(seed);
|
||||
double radius = this->radius_;
|
||||
particle.r.x = radius * std::cos(angle);
|
||||
particle.r.y = radius * std::sin(angle);
|
||||
particle.r.z = 0.0;
|
||||
// angle
|
||||
particle.u = {1.0, 0.0, 0.0};
|
||||
particle.E = this->energy_;
|
||||
double radius = std::stod(parameter_mapping["radius"]);
|
||||
double energy = std::stod(parameter_mapping["energy"]);
|
||||
return std::make_unique<RingSource>(radius, energy);
|
||||
}
|
||||
|
||||
return particle;
|
||||
}
|
||||
// Samples from an instance of this class.
|
||||
openmc::SourceSite sample(uint64_t* seed) const
|
||||
{
|
||||
openmc::SourceSite particle;
|
||||
// particle type
|
||||
particle.particle = openmc::ParticleType::neutron();
|
||||
// position
|
||||
double angle = 2.0 * M_PI * openmc::prn(seed);
|
||||
double radius = this->radius_;
|
||||
particle.r.x = radius * std::cos(angle);
|
||||
particle.r.y = radius * std::sin(angle);
|
||||
particle.r.z = 0.0;
|
||||
// angle
|
||||
particle.u = {1.0, 0.0, 0.0};
|
||||
particle.E = this->energy_;
|
||||
|
||||
private:
|
||||
double radius_;
|
||||
double energy_;
|
||||
return particle;
|
||||
}
|
||||
|
||||
private:
|
||||
double radius_;
|
||||
double energy_;
|
||||
};
|
||||
|
||||
// A function to create a unique pointer to an instance of this class when generated
|
||||
// via a plugin call using dlopen/dlsym.
|
||||
// You must have external C linkage here otherwise dlopen will not find the file
|
||||
extern "C" std::unique_ptr<RingSource> openmc_create_source(std::string parameters)
|
||||
// A function to create a unique pointer to an instance of this class when
|
||||
// generated via a plugin call using dlopen/dlsym. You must have external C
|
||||
// linkage here otherwise dlopen will not find the file
|
||||
extern "C" std::unique_ptr<RingSource> openmc_create_source(
|
||||
std::string parameters)
|
||||
{
|
||||
return RingSource::from_string(parameters);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,22 @@ namespace openmc {
|
|||
|
||||
class AngleEnergy {
|
||||
public:
|
||||
//! Sample an outgoing energy and scattering cosine
|
||||
//! \param[in] E_in Incoming energy in [eV]
|
||||
//! \param[out] E_out Outgoing energy in [eV]
|
||||
//! \param[out] mu Outgoing cosine with respect to current direction
|
||||
//! \param[inout] seed Pseudorandom seed pointer
|
||||
virtual void sample(
|
||||
double E_in, double& E_out, double& mu, uint64_t* seed) const = 0;
|
||||
|
||||
//! Sample an outgoing energy and evaluate the angular PDF
|
||||
//! \param[in] E_in Incoming energy in [eV]
|
||||
//! \param[in] mu Scattering cosine with respect to current direction
|
||||
//! \param[out] E_out Outgoing energy in [eV]
|
||||
//! \param[inout] seed Pseudorandom seed pointer
|
||||
//! \return Probability density for the scattering cosine
|
||||
virtual double sample_energy_and_pdf(
|
||||
double E_in, double mu, double& E_out, uint64_t* seed) const = 0;
|
||||
virtual ~AngleEnergy() = default;
|
||||
};
|
||||
|
||||
|
|
|
|||
28
include/openmc/atomic_mass.h
Normal file
28
include/openmc/atomic_mass.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//==============================================================================
|
||||
// atomic masses definitions
|
||||
//==============================================================================
|
||||
|
||||
#ifndef OPENMC_ATOMIC_MASS_H
|
||||
#define OPENMC_ATOMIC_MASS_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace openmc {
|
||||
|
||||
// Values here are from the Committee on Data for Science and Technology
|
||||
// (CODATA) 2018 recommendation (https://physics.nist.gov/cuu/Constants/).
|
||||
|
||||
// Physical constants
|
||||
constexpr double MASS_ELECTRON {5.48579909065e-4}; // mass of an electron in amu
|
||||
constexpr double MASS_NEUTRON {1.00866491595}; // mass of a neutron in amu
|
||||
constexpr double MASS_PROTON {1.007276466621}; // mass of a proton in amu
|
||||
constexpr double MASS_DEUTRON {2.013553212745}; // mass of a deutron in amu
|
||||
constexpr double MASS_HELION {3.014932247175}; // mass of a helion in amu
|
||||
constexpr double MASS_ALPHA {4.001506179127}; // mass of an alpha in amu
|
||||
|
||||
extern std::unordered_map<int32_t, double> ATOMIC_MASS;
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_ATOMIC_MASS_H
|
||||
|
|
@ -34,18 +34,24 @@ extern vector<vector<double>> ifp_fission_lifetime_bank;
|
|||
|
||||
extern vector<int64_t> progeny_per_particle;
|
||||
|
||||
extern SharedArray<SourceSite> shared_secondary_bank_read;
|
||||
extern SharedArray<SourceSite> shared_secondary_bank_write;
|
||||
|
||||
} // namespace simulation
|
||||
|
||||
//==============================================================================
|
||||
// Non-member functions
|
||||
//==============================================================================
|
||||
|
||||
void sort_fission_bank();
|
||||
void sort_bank(SharedArray<SourceSite>& bank, bool is_fission_bank);
|
||||
|
||||
void free_memory_bank();
|
||||
|
||||
void init_fission_bank(int64_t max);
|
||||
|
||||
int64_t synchronize_global_secondary_bank(
|
||||
SharedArray<SourceSite>& shared_secondary_bank);
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_BANK_H
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "openmc/particle.h"
|
||||
|
||||
#include "xtensor/xtensor.hpp"
|
||||
#include "openmc/tensor.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
|
|
@ -14,9 +14,9 @@ namespace openmc {
|
|||
class BremsstrahlungData {
|
||||
public:
|
||||
// Data
|
||||
xt::xtensor<double, 2> pdf; //!< Bremsstrahlung energy PDF
|
||||
xt::xtensor<double, 2> cdf; //!< Bremsstrahlung energy CDF
|
||||
xt::xtensor<double, 1> yield; //!< Photon yield
|
||||
tensor::Tensor<double> pdf; //!< Bremsstrahlung energy PDF
|
||||
tensor::Tensor<double> cdf; //!< Bremsstrahlung energy CDF
|
||||
tensor::Tensor<double> yield; //!< Photon yield
|
||||
};
|
||||
|
||||
class Bremsstrahlung {
|
||||
|
|
@ -32,9 +32,9 @@ public:
|
|||
|
||||
namespace data {
|
||||
|
||||
extern xt::xtensor<double, 1>
|
||||
extern tensor::Tensor<double>
|
||||
ttb_e_grid; //! energy T of incident electron in [eV]
|
||||
extern xt::xtensor<double, 1>
|
||||
extern tensor::Tensor<double>
|
||||
ttb_k_grid; //! reduced energy W/T of emitted photon
|
||||
|
||||
} // namespace data
|
||||
|
|
|
|||
|
|
@ -125,6 +125,49 @@ int openmc_nuclide_name(int index, const char** name);
|
|||
int openmc_plot_geometry();
|
||||
int openmc_id_map(const void* slice, int32_t* data_out);
|
||||
int openmc_property_map(const void* slice, double* data_out);
|
||||
int openmc_get_plot_index(int32_t id, int32_t* index);
|
||||
int openmc_plot_get_id(int32_t index, int32_t* id);
|
||||
int openmc_plot_set_id(int32_t index, int32_t id);
|
||||
int openmc_solidraytrace_plot_create(int32_t* index);
|
||||
int openmc_solidraytrace_plot_get_pixels(
|
||||
int32_t index, int32_t* width, int32_t* height);
|
||||
int openmc_solidraytrace_plot_set_pixels(
|
||||
int32_t index, int32_t width, int32_t height);
|
||||
int openmc_solidraytrace_plot_get_color_by(int32_t index, int32_t* color_by);
|
||||
int openmc_solidraytrace_plot_set_color_by(int32_t index, int32_t color_by);
|
||||
int openmc_solidraytrace_plot_set_default_colors(int32_t index);
|
||||
int openmc_solidraytrace_plot_set_all_opaque(int32_t index);
|
||||
int openmc_solidraytrace_plot_set_opaque(
|
||||
int32_t index, int32_t id, bool visible);
|
||||
int openmc_solidraytrace_plot_set_color(
|
||||
int32_t index, int32_t id, uint8_t r, uint8_t g, uint8_t b);
|
||||
int openmc_solidraytrace_plot_get_camera_position(
|
||||
int32_t index, double* x, double* y, double* z);
|
||||
int openmc_solidraytrace_plot_set_camera_position(
|
||||
int32_t index, double x, double y, double z);
|
||||
int openmc_solidraytrace_plot_get_look_at(
|
||||
int32_t index, double* x, double* y, double* z);
|
||||
int openmc_solidraytrace_plot_set_look_at(
|
||||
int32_t index, double x, double y, double z);
|
||||
int openmc_solidraytrace_plot_get_up(
|
||||
int32_t index, double* x, double* y, double* z);
|
||||
int openmc_solidraytrace_plot_set_up(
|
||||
int32_t index, double x, double y, double z);
|
||||
int openmc_solidraytrace_plot_get_light_position(
|
||||
int32_t index, double* x, double* y, double* z);
|
||||
int openmc_solidraytrace_plot_set_light_position(
|
||||
int32_t index, double x, double y, double z);
|
||||
int openmc_solidraytrace_plot_get_fov(int32_t index, double* fov);
|
||||
int openmc_solidraytrace_plot_set_fov(int32_t index, double fov);
|
||||
int openmc_solidraytrace_plot_update_view(int32_t index);
|
||||
int openmc_solidraytrace_plot_create_image(
|
||||
int32_t index, uint8_t* data_out, int32_t width, int32_t height);
|
||||
int openmc_solidraytrace_plot_get_color(
|
||||
int32_t index, int32_t id, uint8_t* r, uint8_t* g, uint8_t* b);
|
||||
int openmc_solidraytrace_plot_get_diffuse_fraction(
|
||||
int32_t index, double* diffuse_fraction);
|
||||
int openmc_solidraytrace_plot_set_diffuse_fraction(
|
||||
int32_t index, double diffuse_fraction);
|
||||
int openmc_rectilinear_mesh_get_grid(int32_t index, double** grid_x, int* nx,
|
||||
double** grid_y, int* ny, double** grid_z, int* nz);
|
||||
int openmc_rectilinear_mesh_set_grid(int32_t index, const double* grid_x,
|
||||
|
|
@ -140,6 +183,7 @@ int openmc_remove_tally(int32_t index);
|
|||
int openmc_reset();
|
||||
int openmc_reset_timers();
|
||||
int openmc_run();
|
||||
void openmc_run_random_ray();
|
||||
int openmc_sample_external_source(size_t n, uint64_t* seed, void* sites);
|
||||
void openmc_set_seed(int64_t new_seed);
|
||||
void openmc_set_stride(uint64_t new_stride);
|
||||
|
|
@ -201,8 +245,8 @@ int openmc_weight_windows_set_energy_bounds(
|
|||
int32_t index, double* e_bounds, size_t e_bounds_size);
|
||||
int openmc_weight_windows_get_energy_bounds(
|
||||
int32_t index, const double** e_bounds, size_t* e_bounds_size);
|
||||
int openmc_weight_windows_set_particle(int32_t index, int particle);
|
||||
int openmc_weight_windows_get_particle(int32_t index, int* particle);
|
||||
int openmc_weight_windows_set_particle(int32_t index, int32_t particle);
|
||||
int openmc_weight_windows_get_particle(int32_t index, int32_t* particle);
|
||||
int openmc_weight_windows_get_bounds(int32_t index, const double** lower_bounds,
|
||||
const double** upper_bounds, size_t* size);
|
||||
int openmc_weight_windows_set_bounds(int32_t index, const double* lower_bounds,
|
||||
|
|
@ -218,6 +262,7 @@ int openmc_weight_windows_set_weight_cutoff(int32_t index, double cutoff);
|
|||
int openmc_weight_windows_get_max_split(int32_t index, int* max_split);
|
||||
int openmc_weight_windows_set_max_split(int32_t index, int max_split);
|
||||
size_t openmc_weight_windows_size();
|
||||
size_t openmc_plots_size();
|
||||
int openmc_weight_windows_export(const char* filename = nullptr);
|
||||
int openmc_weight_windows_import(const char* filename = nullptr);
|
||||
int openmc_zernike_filter_get_order(int32_t index, int* order);
|
||||
|
|
@ -227,7 +272,7 @@ int openmc_zernike_filter_set_order(int32_t index, int order);
|
|||
int openmc_zernike_filter_set_params(
|
||||
int32_t index, const double* x, const double* y, const double* r);
|
||||
|
||||
int openmc_particle_filter_get_bins(int32_t idx, int bins[]);
|
||||
int openmc_particle_filter_get_bins(int32_t idx, int32_t bins[]);
|
||||
|
||||
//! Sets the mesh and energy grid for CMFD reweight
|
||||
//! \param[in] meshtyally_id id of CMFD Mesh Tally
|
||||
|
|
|
|||
|
|
@ -145,6 +145,30 @@ private:
|
|||
bool simple_; //!< Does the region contain only intersections?
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// XML parsing helpers for <cell> nodes
|
||||
//==============================================================================
|
||||
|
||||
//! Parse material IDs from a <cell> XML node.
|
||||
//! \param node XML node containing a "material" attribute or child element
|
||||
//! \param cell_id Cell ID used in error messages
|
||||
//! \return Vector of material IDs (MATERIAL_VOID for "void")
|
||||
vector<int32_t> parse_cell_material_xml(pugi::xml_node node, int32_t cell_id);
|
||||
|
||||
//! Parse temperatures in [K] from a <cell> XML node.
|
||||
//! Validates that all values are non-negative and the list is non-empty.
|
||||
//! \param node XML node containing a "temperature" attribute or child element
|
||||
//! \param cell_id Cell ID used in error messages
|
||||
//! \return Vector of temperatures in [K]
|
||||
vector<double> parse_cell_temperature_xml(pugi::xml_node node, int32_t cell_id);
|
||||
|
||||
//! Parse densities in [g/cm³] from a <cell> XML node.
|
||||
//! Validates that all values are positive and the list is non-empty.
|
||||
//! \param node XML node containing a "density" attribute or child element
|
||||
//! \param cell_id Cell ID used in error messages
|
||||
//! \return Vector of densities in [g/cm³]
|
||||
vector<double> parse_cell_density_xml(pugi::xml_node node, int32_t cell_id);
|
||||
|
||||
//==============================================================================
|
||||
|
||||
class Cell {
|
||||
|
|
|
|||
|
|
@ -71,6 +71,15 @@ public:
|
|||
void sample(
|
||||
double E_in, double& E_out, double& mu, uint64_t* seed) const override;
|
||||
|
||||
//! Sample an outgoing energy and evaluate the angular PDF
|
||||
//! \param[in] E_in Incoming energy in [eV]
|
||||
//! \param[in] mu Scattering cosine with respect to current direction
|
||||
//! \param[out] E_out Outgoing energy in [eV]
|
||||
//! \param[inout] seed Pseudorandom seed pointer
|
||||
//! \return Probability density for the scattering cosine
|
||||
double sample_energy_and_pdf(
|
||||
double E_in, double mu, double& E_out, uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
const Distribution* photon_energy_;
|
||||
};
|
||||
|
|
@ -92,6 +101,8 @@ extern vector<unique_ptr<ChainNuclide>> chain_nuclides;
|
|||
|
||||
void read_chain_file_xml();
|
||||
|
||||
void free_memory_chain();
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_CHAIN_H
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <limits>
|
||||
|
||||
#include "openmc/array.h"
|
||||
#include "openmc/atomic_mass.h"
|
||||
#include "openmc/vector.h"
|
||||
#include "openmc/version.h"
|
||||
|
||||
|
|
@ -25,16 +26,16 @@ using double_4dvec = vector<vector<vector<vector<double>>>>;
|
|||
constexpr int HDF5_VERSION[] {3, 0};
|
||||
|
||||
// Version numbers for binary files
|
||||
constexpr array<int, 2> VERSION_STATEPOINT {18, 1};
|
||||
constexpr array<int, 2> VERSION_PARTICLE_RESTART {2, 0};
|
||||
constexpr array<int, 2> VERSION_TRACK {3, 0};
|
||||
constexpr array<int, 2> VERSION_STATEPOINT {18, 2};
|
||||
constexpr array<int, 2> VERSION_PARTICLE_RESTART {2, 1};
|
||||
constexpr array<int, 2> VERSION_TRACK {3, 1};
|
||||
constexpr array<int, 2> VERSION_SUMMARY {6, 1};
|
||||
constexpr array<int, 2> VERSION_VOLUME {1, 0};
|
||||
constexpr array<int, 2> VERSION_VOXEL {2, 0};
|
||||
constexpr array<int, 2> VERSION_MGXS_LIBRARY {1, 0};
|
||||
constexpr array<int, 2> VERSION_PROPERTIES {1, 1};
|
||||
constexpr array<int, 2> VERSION_WEIGHT_WINDOWS {1, 0};
|
||||
constexpr array<int, 2> VERSION_COLLISION_TRACK {1, 0};
|
||||
constexpr array<int, 2> VERSION_COLLISION_TRACK {1, 1};
|
||||
|
||||
// ============================================================================
|
||||
// ADJUSTABLE PARAMETERS
|
||||
|
|
@ -86,10 +87,10 @@ constexpr double INFTY {std::numeric_limits<double>::max()};
|
|||
// (CODATA) 2018 recommendation (https://physics.nist.gov/cuu/Constants/).
|
||||
|
||||
// Physical constants
|
||||
constexpr double MASS_NEUTRON {1.00866491595}; // mass of a neutron in amu
|
||||
constexpr double AMU_EV {
|
||||
9.3149410242e8}; // atomic mass unit energy equivalent in eV/c^2
|
||||
constexpr double MASS_NEUTRON_EV {
|
||||
939.56542052e6}; // mass of a neutron in eV/c^2
|
||||
constexpr double MASS_PROTON {1.007276466621}; // mass of a proton in amu
|
||||
939.56542052e6}; // neutron mass energy equivalent in eV/c^2
|
||||
constexpr double MASS_ELECTRON_EV {
|
||||
0.51099895000e6}; // electron mass energy equivalent in eV/c^2
|
||||
constexpr double FINE_STRUCTURE {
|
||||
|
|
@ -226,6 +227,7 @@ enum ReactionType {
|
|||
N_XA = 207,
|
||||
HEATING = 301,
|
||||
DAMAGE_ENERGY = 444,
|
||||
PHOTON_TOTAL = 501,
|
||||
COHERENT = 502,
|
||||
INCOHERENT = 504,
|
||||
PAIR_PROD_ELEC = 515,
|
||||
|
|
@ -301,7 +303,7 @@ enum class TallyEstimator { ANALOG, TRACKLENGTH, COLLISION };
|
|||
enum class TallyEvent { SURFACE, LATTICE, KILL, SCATTER, ABSORB };
|
||||
|
||||
// Tally score type -- if you change these, make sure you also update the
|
||||
// _SCORES dictionary in openmc/capi/tally.py
|
||||
// _SCORES dictionary in openmc/lib/tally.py
|
||||
//
|
||||
// These are kept as a normal enum and made negative, since variables which
|
||||
// store one of these enum values usually also may be responsible for storing
|
||||
|
|
@ -365,7 +367,7 @@ enum class SolverType { MONTE_CARLO, RANDOM_RAY };
|
|||
|
||||
enum class RandomRayVolumeEstimator { NAIVE, SIMULATION_AVERAGED, HYBRID };
|
||||
enum class RandomRaySourceShape { FLAT, LINEAR, LINEAR_XY };
|
||||
enum class RandomRaySampleMethod { PRNG, HALTON };
|
||||
enum class RandomRaySampleMethod { PRNG, HALTON, S2 };
|
||||
|
||||
//==============================================================================
|
||||
// Geometry Constants
|
||||
|
|
|
|||
|
|
@ -94,6 +94,10 @@ private:
|
|||
class DAGUniverse : public Universe {
|
||||
|
||||
public:
|
||||
using MaterialOverrides = std::unordered_map<int32_t, vector<int32_t>>;
|
||||
using TemperatureOverrides = std::unordered_map<int32_t, vector<double>>;
|
||||
using DensityOverrides = std::unordered_map<int32_t, vector<double>>;
|
||||
|
||||
explicit DAGUniverse(pugi::xml_node node);
|
||||
|
||||
//! Create a new DAGMC universe
|
||||
|
|
@ -112,6 +116,9 @@ public:
|
|||
//! Initialize the DAGMC accel. data structures, indices, material
|
||||
//! assignments, etc.
|
||||
void initialize();
|
||||
void initialize(const MaterialOverrides& material_overrides,
|
||||
const TemperatureOverrides& temperature_overrides,
|
||||
const DensityOverrides& density_overrides = {});
|
||||
|
||||
//! Reads UWUW materials and returns an ID map
|
||||
void read_uwuw_materials();
|
||||
|
|
@ -146,7 +153,8 @@ public:
|
|||
|
||||
//! Assign a material overriding normal assignement to a cell
|
||||
//! \param[in] c The OpenMC cell to which the material is assigned
|
||||
void override_assign_material(std::unique_ptr<DAGCell>& c) const;
|
||||
void override_assign_material(std::unique_ptr<DAGCell>& c,
|
||||
const MaterialOverrides& material_overrides) const;
|
||||
|
||||
//! Return the index into the model cells vector for a given DAGMC volume
|
||||
//! handle in the universe
|
||||
|
|
@ -187,7 +195,9 @@ private:
|
|||
void set_id(); //!< Deduce the universe id from model::universes
|
||||
void init_dagmc(); //!< Create and initialise DAGMC pointer
|
||||
void init_metadata(); //!< Create and initialise dagmcMetaData pointer
|
||||
void init_geometry(); //!< Create cells and surfaces from DAGMC entities
|
||||
void init_geometry(const MaterialOverrides& material_overrides,
|
||||
const TemperatureOverrides& temperature_overrides,
|
||||
const DensityOverrides& density_overrides);
|
||||
|
||||
std::string
|
||||
filename_; //!< Name of the DAGMC file used to create this universe
|
||||
|
|
@ -201,11 +211,6 @@ private:
|
|||
//!< generate new material IDs for the universe
|
||||
bool has_graveyard_; //!< Indicates if the DAGMC geometry has a "graveyard"
|
||||
//!< volume
|
||||
std::unordered_map<int32_t, vector<int32_t>>
|
||||
material_overrides_; //!< Map of material overrides
|
||||
//!< keys correspond to the DAGMCCell id
|
||||
//!< values are a list of material ids used
|
||||
//!< for the override
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -265,23 +265,29 @@ private:
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
//! Normal distributions with form 1/2*std_dev*sqrt(pi) exp
|
||||
//! (-(e-E0)/2*std_dev)^2
|
||||
//! Normal distribution with optional truncation bounds.
|
||||
//!
|
||||
//! The standard normal PDF is 1/(sqrt(2*pi)*sigma) *
|
||||
//! exp(-(x-mu)^2/(2*sigma^2)). When truncated to [lower, upper], the PDF is
|
||||
//! renormalized so that it integrates to 1 over the truncation interval.
|
||||
//==============================================================================
|
||||
|
||||
class Normal : public Distribution {
|
||||
public:
|
||||
explicit Normal(pugi::xml_node node);
|
||||
Normal(double mean_value, double std_dev)
|
||||
: mean_value_ {mean_value}, std_dev_ {std_dev} {};
|
||||
Normal(double mean_value, double std_dev, double lower = -INFTY,
|
||||
double upper = INFTY);
|
||||
|
||||
//! Evaluate probability density, f(x), at a point
|
||||
//! \param x Point to evaluate f(x)
|
||||
//! \return f(x)
|
||||
//! \return f(x), accounting for truncation normalization
|
||||
double evaluate(double x) const override;
|
||||
|
||||
double mean_value() const { return mean_value_; }
|
||||
double std_dev() const { return std_dev_; }
|
||||
double lower() const { return lower_; }
|
||||
double upper() const { return upper_; }
|
||||
bool is_truncated() const { return is_truncated_; }
|
||||
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
|
|
@ -290,8 +296,15 @@ protected:
|
|||
double sample_unbiased(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
double mean_value_; //!< middle of distribution [eV]
|
||||
double std_dev_; //!< standard deviation [eV]
|
||||
double mean_value_; //!< Mean of distribution
|
||||
double std_dev_; //!< Standard deviation
|
||||
double lower_; //!< Lower truncation bound (default: -INFTY)
|
||||
double upper_; //!< Upper truncation bound (default: +INFTY)
|
||||
bool is_truncated_; //!< True if bounds are finite
|
||||
double norm_factor_; //!< Normalization factor for truncated distribution
|
||||
|
||||
//! Compute normalization factor for truncated distribution
|
||||
void compute_normalization();
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -394,6 +407,71 @@ private:
|
|||
double integral_; //!< Integral of distribution
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// DecaySpectrum — non-owning mixture of decay photon distributions
|
||||
//==============================================================================
|
||||
|
||||
//! Energy distribution formed by mixing multiple decay photon spectra.
|
||||
//!
|
||||
//! Unlike the general Mixture distribution, this class holds non-owning
|
||||
//! pointers to the component distributions (which live in
|
||||
//! data::chain_nuclides). Each component is weighted by the activity
|
||||
//! (atoms * decay_constant) of the corresponding nuclide.
|
||||
|
||||
class DecaySpectrum : public Distribution {
|
||||
public:
|
||||
//============================================================================
|
||||
// Types, aliases
|
||||
|
||||
struct Sample {
|
||||
double energy;
|
||||
double weight;
|
||||
int parent_nuclide;
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
// Constructors
|
||||
|
||||
//! Construct from an XML node containing nuclide names and atom densities.
|
||||
//!
|
||||
//! Reads child ``<nuclide>`` elements with ``name`` and ``density``
|
||||
//! attributes, resolves them against the loaded depletion chain, and
|
||||
//! constructs the mixed distribution.
|
||||
explicit DecaySpectrum(pugi::xml_node node);
|
||||
|
||||
//============================================================================
|
||||
// Methods
|
||||
|
||||
//! Sample a value from the distribution and return the parent nuclide index
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return (Sampled energy, sample weight, chain nuclide index)
|
||||
Sample sample_with_parent(uint64_t* seed) const;
|
||||
|
||||
//! Sample a value from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return (sampled value, sample weight)
|
||||
std::pair<double, double> sample(uint64_t* seed) const override;
|
||||
|
||||
double integral() const override;
|
||||
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample_unbiased(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
//! Initialize decay spectrum sampling data
|
||||
//! \param nuclide_indices Indices of decay photon emitters in
|
||||
//! data::chain_nuclides
|
||||
//! \param atoms Number of atoms for each component.
|
||||
void init(vector<int> nuclide_indices, const vector<double>& atoms);
|
||||
|
||||
vector<int> nuclide_indices_; //!< Indices of emitting nuclides in the chain
|
||||
DiscreteIndex di_; //!< Discrete index for component selection
|
||||
double integral_; //!< Total photon emission rate
|
||||
};
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_DISTRIBUTION_H
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@ public:
|
|||
//! \return Cosine of the angle in the range [-1,1]
|
||||
double sample(double E, uint64_t* seed) const;
|
||||
|
||||
//! Evaluate the angular PDF at a given energy and cosine
|
||||
//! \param[in] E Particle energy in [eV]
|
||||
//! \param[in] mu Cosine of the scattering angle
|
||||
//! \return Probability density for the scattering cosine
|
||||
double evaluate(double E, double mu) const;
|
||||
|
||||
//! Determine whether angle distribution is empty
|
||||
//! \return Whether distribution is empty
|
||||
bool empty() const { return energy_.empty(); }
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#define OPENMC_DISTRIBUTION_ENERGY_H
|
||||
|
||||
#include "hdf5.h"
|
||||
#include "xtensor/xtensor.hpp"
|
||||
#include "openmc/tensor.h"
|
||||
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/endf.h"
|
||||
|
|
@ -86,9 +86,9 @@ private:
|
|||
struct CTTable {
|
||||
Interpolation interpolation; //!< Interpolation law
|
||||
int n_discrete; //!< Number of of discrete energies
|
||||
xt::xtensor<double, 1> e_out; //!< Outgoing energies in [eV]
|
||||
xt::xtensor<double, 1> p; //!< Probability density
|
||||
xt::xtensor<double, 1> c; //!< Cumulative distribution
|
||||
tensor::Tensor<double> e_out; //!< Outgoing energies in [eV]
|
||||
tensor::Tensor<double> p; //!< Probability density
|
||||
tensor::Tensor<double> c; //!< Cumulative distribution
|
||||
};
|
||||
|
||||
int n_region_; //!< Number of inteprolation regions
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "pugixml.hpp"
|
||||
|
||||
#include "openmc/distribution.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/position.h"
|
||||
|
||||
namespace openmc {
|
||||
|
|
@ -29,6 +30,14 @@ public:
|
|||
//! \return (sampled Direction, sample weight)
|
||||
virtual std::pair<Direction, double> sample(uint64_t* seed) const = 0;
|
||||
|
||||
//! Evaluate the probability density for a given direction
|
||||
//! \param[in] u Direction on the unit sphere
|
||||
//! \return Probability density at the given direction
|
||||
virtual double evaluate(Direction u) const
|
||||
{
|
||||
fatal_error("evaluate not available for this UnitSphereDistribution type");
|
||||
}
|
||||
|
||||
Direction u_ref_ {0.0, 0.0, 1.0}; //!< reference direction
|
||||
};
|
||||
|
||||
|
|
@ -52,6 +61,11 @@ public:
|
|||
//! \return (sampled Direction, value of the PDF at this Direction)
|
||||
std::pair<Direction, double> sample_as_bias(uint64_t* seed) const;
|
||||
|
||||
//! Evaluate the probability density for a given direction
|
||||
//! \param[in] u Direction on the unit sphere
|
||||
//! \return Probability density at the given direction
|
||||
double evaluate(Direction u) const override;
|
||||
|
||||
// Observing pointers
|
||||
Distribution* mu() const { return mu_.get(); }
|
||||
Distribution* phi() const { return phi_.get(); }
|
||||
|
|
@ -87,6 +101,11 @@ public:
|
|||
//! \return (sampled direction, sample weight)
|
||||
std::pair<Direction, double> sample(uint64_t* seed) const override;
|
||||
|
||||
//! Evaluate the probability density for a given direction
|
||||
//! \param[in] u Direction on the unit sphere
|
||||
//! \return Probability density at the given direction
|
||||
double evaluate(Direction u) const override;
|
||||
|
||||
// Set or get bias distribution
|
||||
void set_bias(std::unique_ptr<PolarAzimuthal> bias)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,12 +67,18 @@ public:
|
|||
Distribution* phi() const { return phi_.get(); }
|
||||
Distribution* z() const { return z_.get(); }
|
||||
Position origin() const { return origin_; }
|
||||
Direction r_dir() const { return r_dir_; }
|
||||
Direction phi_dir() const { return phi_dir_; }
|
||||
Direction z_dir() const { return z_dir_; }
|
||||
|
||||
private:
|
||||
UPtrDist r_; //!< Distribution of r coordinates
|
||||
UPtrDist phi_; //!< Distribution of phi coordinates
|
||||
UPtrDist z_; //!< Distribution of z coordinates
|
||||
Position origin_; //!< Cartesian coordinates of the cylinder center
|
||||
UPtrDist r_; //!< Distribution of r coordinates
|
||||
UPtrDist phi_; //!< Distribution of phi coordinates
|
||||
UPtrDist z_; //!< Distribution of z coordinates
|
||||
Position origin_; //!< Cartesian coordinates of the cylinder center
|
||||
Direction r_dir_; //!< Direction of r-axis at phi=0
|
||||
Direction phi_dir_; //!< Direction of phi-axis at phi=0
|
||||
Direction z_dir_; //!< Direction of z-axis
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include <cstdint> // for int64_t
|
||||
|
||||
#include "xtensor/xtensor.hpp"
|
||||
#include "openmc/tensor.h"
|
||||
#include <hdf5.h>
|
||||
|
||||
#include "openmc/array.h"
|
||||
|
|
@ -24,7 +24,7 @@ namespace simulation {
|
|||
extern double keff_generation; //!< Single-generation k on each processor
|
||||
extern array<double, 2> k_sum; //!< Used to reduce sum and sum_sq
|
||||
extern vector<double> entropy; //!< Shannon entropy at each generation
|
||||
extern xt::xtensor<double, 1> source_frac; //!< Source fraction for UFS
|
||||
extern tensor::Tensor<double> source_frac; //!< Source fraction for UFS
|
||||
|
||||
} // namespace simulation
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,13 @@ bool is_disappearance(int MT);
|
|||
//! \return Whether corresponding reaction is an inelastic scattering reaction
|
||||
bool is_inelastic_scatter(int MT);
|
||||
|
||||
//! Determine whether an MT number matches a target MT, considering that the
|
||||
//! target may be a summation reaction.
|
||||
//! \param[in] event_mt MT number of the actual event
|
||||
//! \param[in] target_mt MT number to check against
|
||||
//! \return Whether event_mt is a component of target_mt (or equal to it)
|
||||
bool mt_matches(int event_mt, int target_mt);
|
||||
|
||||
//==============================================================================
|
||||
//! Abstract one-dimensional function
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -112,6 +112,19 @@ void process_collision_events();
|
|||
//! \param n_particles The number of particles in the particle buffer
|
||||
void process_death_events(int64_t n_particles);
|
||||
|
||||
//! Process event queues until all are empty. Each iteration processes the
|
||||
//! longest queue first to maximize vectorization efficiency.
|
||||
void process_transport_events();
|
||||
|
||||
//! Initialize secondary particles from a shared secondary bank for
|
||||
//! event-based transport
|
||||
//
|
||||
//! \param n_particles The number of particles to initialize
|
||||
//! \param offset The offset index in the shared secondary bank
|
||||
//! \param shared_secondary_bank The shared secondary bank to read from
|
||||
void process_init_secondary_events(int64_t n_particles, int64_t offset,
|
||||
const SharedArray<SourceSite>& shared_secondary_bank);
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_EVENT_H
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
#include "hdf5.h"
|
||||
#include "hdf5_hl.h"
|
||||
#include "xtensor/xadapt.hpp"
|
||||
#include "xtensor/xarray.hpp"
|
||||
#include "openmc/tensor.h"
|
||||
|
||||
#include "openmc/array.h"
|
||||
#include "openmc/error.h"
|
||||
|
|
@ -166,24 +165,19 @@ void read_attribute(hid_t obj_id, const char* name, vector<T>& vec)
|
|||
read_attr(obj_id, name, H5TypeMap<T>::type_id, vec.data());
|
||||
}
|
||||
|
||||
// Generic array version
|
||||
// Tensor version
|
||||
template<typename T>
|
||||
void read_attribute(hid_t obj_id, const char* name, xt::xarray<T>& arr)
|
||||
void read_attribute(hid_t obj_id, const char* name, tensor::Tensor<T>& tensor)
|
||||
{
|
||||
// Get shape of attribute array
|
||||
// Get shape of attribute
|
||||
auto shape = attribute_shape(obj_id, name);
|
||||
|
||||
// Allocate new array to read data into
|
||||
std::size_t size = 1;
|
||||
for (const auto x : shape)
|
||||
size *= x;
|
||||
vector<T> buffer(size);
|
||||
// Resize tensor and read data directly
|
||||
vector<size_t> tshape(shape.begin(), shape.end());
|
||||
tensor.resize(tshape);
|
||||
|
||||
// Read data from attribute
|
||||
read_attr(obj_id, name, H5TypeMap<T>::type_id, buffer.data());
|
||||
|
||||
// Adapt array into xarray
|
||||
arr = xt::adapt(buffer, shape);
|
||||
read_attr(obj_id, name, H5TypeMap<T>::type_id, tensor.data());
|
||||
}
|
||||
|
||||
// overload for std::string
|
||||
|
|
@ -290,63 +284,34 @@ void read_dataset(
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
void read_dataset(hid_t dset, xt::xarray<T>& arr, bool indep = false)
|
||||
void read_dataset(hid_t dset, tensor::Tensor<T>& tensor, bool indep = false)
|
||||
{
|
||||
// Get shape of dataset
|
||||
vector<hsize_t> shape = object_shape(dset);
|
||||
|
||||
// Allocate space in the array to read data into
|
||||
std::size_t size = 1;
|
||||
for (const auto x : shape)
|
||||
size *= x;
|
||||
arr.resize(shape);
|
||||
// Resize tensor and read data directly
|
||||
vector<size_t> tshape(shape.begin(), shape.end());
|
||||
tensor.resize(tshape);
|
||||
|
||||
// Read data from attribute
|
||||
// Read data from dataset
|
||||
read_dataset_lowlevel(
|
||||
dset, nullptr, H5TypeMap<T>::type_id, H5S_ALL, indep, arr.data());
|
||||
dset, nullptr, H5TypeMap<T>::type_id, H5S_ALL, indep, tensor.data());
|
||||
}
|
||||
|
||||
template<>
|
||||
void read_dataset(
|
||||
hid_t dset, xt::xarray<std::complex<double>>& arr, bool indep);
|
||||
hid_t dset, tensor::Tensor<std::complex<double>>& tensor, bool indep);
|
||||
|
||||
template<typename T>
|
||||
void read_dataset(
|
||||
hid_t obj_id, const char* name, xt::xarray<T>& arr, bool indep = false)
|
||||
hid_t obj_id, const char* name, tensor::Tensor<T>& tensor, bool indep = false)
|
||||
{
|
||||
// Open dataset and read array
|
||||
// Open dataset and read tensor
|
||||
hid_t dset = open_dataset(obj_id, name);
|
||||
read_dataset(dset, arr, indep);
|
||||
read_dataset(dset, tensor, indep);
|
||||
close_dataset(dset);
|
||||
}
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
void read_dataset(
|
||||
hid_t obj_id, const char* name, xt::xtensor<T, N>& arr, bool indep = false)
|
||||
{
|
||||
// Open dataset and read array
|
||||
hid_t dset = open_dataset(obj_id, name);
|
||||
|
||||
// Get shape of dataset
|
||||
vector<hsize_t> hsize_t_shape = object_shape(dset);
|
||||
close_dataset(dset);
|
||||
|
||||
// cast from hsize_t to size_t
|
||||
vector<size_t> shape(hsize_t_shape.size());
|
||||
for (int i = 0; i < shape.size(); i++) {
|
||||
shape[i] = static_cast<size_t>(hsize_t_shape[i]);
|
||||
}
|
||||
|
||||
// Allocate new xarray to read data into
|
||||
xt::xarray<T> xarr(shape);
|
||||
|
||||
// Read data from the dataset
|
||||
read_dataset(obj_id, name, xarr);
|
||||
|
||||
// Copy into xtensor
|
||||
arr = xarr;
|
||||
}
|
||||
|
||||
// overload for Position
|
||||
inline void read_dataset(
|
||||
hid_t obj_id, const char* name, Position& r, bool indep = false)
|
||||
|
|
@ -358,31 +323,22 @@ inline void read_dataset(
|
|||
r.z = x[2];
|
||||
}
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
template<typename T>
|
||||
inline void read_dataset_as_shape(
|
||||
hid_t obj_id, const char* name, xt::xtensor<T, N>& arr, bool indep = false)
|
||||
hid_t obj_id, const char* name, tensor::Tensor<T>& tensor, bool indep = false)
|
||||
{
|
||||
hid_t dset = open_dataset(obj_id, name);
|
||||
|
||||
// Allocate new array to read data into
|
||||
std::size_t size = 1;
|
||||
for (const auto x : arr.shape())
|
||||
size *= x;
|
||||
vector<T> buffer(size);
|
||||
|
||||
// Read data from attribute
|
||||
// Read data directly into pre-shaped tensor
|
||||
read_dataset_lowlevel(
|
||||
dset, nullptr, H5TypeMap<T>::type_id, H5S_ALL, indep, buffer.data());
|
||||
|
||||
// Adapt into xarray
|
||||
arr = xt::adapt(buffer, arr.shape());
|
||||
dset, nullptr, H5TypeMap<T>::type_id, H5S_ALL, indep, tensor.data());
|
||||
|
||||
close_dataset(dset);
|
||||
}
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
inline void read_nd_vector(hid_t obj_id, const char* name,
|
||||
xt::xtensor<T, N>& result, bool must_have = false)
|
||||
template<typename T>
|
||||
inline void read_nd_tensor(hid_t obj_id, const char* name,
|
||||
tensor::Tensor<T>& result, bool must_have = false)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
read_dataset_as_shape(obj_id, name, result, true);
|
||||
|
|
@ -496,12 +452,16 @@ inline void write_dataset(
|
|||
false, buffer.data());
|
||||
}
|
||||
|
||||
// Template for xarray, xtensor, etc.
|
||||
template<typename D>
|
||||
inline void write_dataset(
|
||||
hid_t obj_id, const char* name, const xt::xcontainer<D>& arr)
|
||||
// Template for Tensor and StaticTensor2D. A SFINAE guard is used here to
|
||||
// prevent this template from matching vector/string types that have their own
|
||||
// overloads above. A generic Container parameter avoids duplicating the body
|
||||
// for both Tensor<T> and StaticTensor2D<T,R,C>.
|
||||
template<typename Container,
|
||||
typename =
|
||||
std::enable_if_t<tensor::is_tensor<std::decay_t<Container>>::value>>
|
||||
inline void write_dataset(hid_t obj_id, const char* name, const Container& arr)
|
||||
{
|
||||
using T = typename D::value_type;
|
||||
using T = typename std::decay_t<Container>::value_type;
|
||||
auto s = arr.shape();
|
||||
vector<hsize_t> dims {s.cbegin(), s.cend()};
|
||||
write_dataset_lowlevel(obj_id, dims.size(), dims.data(), name,
|
||||
|
|
|
|||
|
|
@ -113,6 +113,14 @@ public:
|
|||
virtual Position get_local_position(
|
||||
Position r, const array<int, 3>& i_xyz) const = 0;
|
||||
|
||||
//! \brief get the normal of the lattice surface crossing
|
||||
//! \param[in] i_xyz The indices for the lattice translation.
|
||||
//! \param[out] is_valid is the lattice translation correspond to a valid
|
||||
//! surface. \return The surface normal corresponding to the lattice
|
||||
//! translation.
|
||||
virtual Direction get_normal(
|
||||
const array<int, 3>& i_xyz, bool& is_valid) const = 0;
|
||||
|
||||
//! \brief Check flattened lattice index.
|
||||
//! \param indx The index for a lattice tile.
|
||||
//! \return true if the given index fit within the lattice bounds. False
|
||||
|
|
@ -223,6 +231,9 @@ public:
|
|||
Position get_local_position(
|
||||
Position r, const array<int, 3>& i_xyz) const override;
|
||||
|
||||
Direction get_normal(
|
||||
const array<int, 3>& i_xyz, bool& is_valid) const override;
|
||||
|
||||
int32_t& offset(int map, const array<int, 3>& i_xyz) override;
|
||||
|
||||
int32_t offset(int map, int indx) const override;
|
||||
|
|
@ -268,6 +279,9 @@ public:
|
|||
Position get_local_position(
|
||||
Position r, const array<int, 3>& i_xyz) const override;
|
||||
|
||||
Direction get_normal(
|
||||
const array<int, 3>& i_xyz, bool& is_valid) const override;
|
||||
|
||||
bool is_valid_index(int indx) const override;
|
||||
|
||||
int32_t& offset(int map, const array<int, 3>& i_xyz) override;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
#include <unordered_map>
|
||||
|
||||
#include "openmc/span.h"
|
||||
#include "openmc/tensor.h"
|
||||
#include "pugixml.hpp"
|
||||
#include "xtensor/xtensor.hpp"
|
||||
#include <hdf5.h>
|
||||
|
||||
#include "openmc/bremsstrahlung.h"
|
||||
|
|
@ -189,7 +189,7 @@ public:
|
|||
vector<int> nuclide_; //!< Indices in nuclides vector
|
||||
vector<int> element_; //!< Indices in elements vector
|
||||
NCrystalMat ncrystal_mat_; //!< NCrystal material object
|
||||
xt::xtensor<double, 1> atom_density_; //!< Nuclide atom density in [atom/b-cm]
|
||||
tensor::Tensor<double> atom_density_; //!< Nuclide atom density in [atom/b-cm]
|
||||
double density_; //!< Total atom density in [atom/b-cm]
|
||||
double density_gpcc_; //!< Total atom density in [g/cm^3]
|
||||
double charge_density_; //!< Total charge density in [e/b-cm]
|
||||
|
|
|
|||
|
|
@ -201,6 +201,18 @@ std::complex<double> faddeeva(std::complex<double> z);
|
|||
//! \return Derivative of Faddeeva function evaluated at z
|
||||
std::complex<double> w_derivative(std::complex<double> z, int order);
|
||||
|
||||
//! Evaluate relative exponential function
|
||||
//!
|
||||
//! \param x Real argument
|
||||
//! \return (exp(x)-1)/x without loss of precision near 0
|
||||
double exprel(double x);
|
||||
|
||||
//! Evaluate relative logarithm function
|
||||
//!
|
||||
//! \param x Real argument
|
||||
//! \return log(1+x)/x without loss of precision near 0
|
||||
double log1prel(double x);
|
||||
|
||||
//! Helper function to get index and interpolation function on an incident
|
||||
//! energy grid
|
||||
//!
|
||||
|
|
@ -211,5 +223,15 @@ std::complex<double> w_derivative(std::complex<double> z, int order);
|
|||
void get_energy_index(
|
||||
const vector<double>& energies, double E, int& i, double& f);
|
||||
|
||||
//==============================================================================
|
||||
//! Calculate the cumulative distribution function of the standard normal
|
||||
//! distribution at a given value.
|
||||
//!
|
||||
//! \param z The value at which to evaluate the CDF
|
||||
//! \return Phi(z) = P(X <= z) for X ~ N(0,1)
|
||||
//==============================================================================
|
||||
|
||||
double standard_normal_cdf(double z);
|
||||
|
||||
} // namespace openmc
|
||||
#endif // OPENMC_MATH_FUNCTIONS_H
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
#include <unordered_map>
|
||||
|
||||
#include "hdf5.h"
|
||||
#include "openmc/tensor.h"
|
||||
#include "pugixml.hpp"
|
||||
#include "xtensor/xtensor.hpp"
|
||||
|
||||
#include "openmc/bounding_box.h"
|
||||
#include "openmc/error.h"
|
||||
|
|
@ -284,8 +284,8 @@ public:
|
|||
virtual Position upper_right() const = 0;
|
||||
|
||||
// Data members
|
||||
xt::xtensor<double, 1> lower_left_; //!< Lower-left coordinates of mesh
|
||||
xt::xtensor<double, 1> upper_right_; //!< Upper-right coordinates of mesh
|
||||
tensor::Tensor<double> lower_left_; //!< Lower-left coordinates of mesh
|
||||
tensor::Tensor<double> upper_right_; //!< Upper-right coordinates of mesh
|
||||
int id_ {-1}; //!< Mesh ID
|
||||
std::string name_; //!< User-specified name
|
||||
int n_dimension_ {-1}; //!< Number of dimensions
|
||||
|
|
@ -348,7 +348,7 @@ public:
|
|||
//! \param[in] Pointer to bank sites
|
||||
//! \param[in] Number of bank sites
|
||||
//! \param[out] Whether any bank sites are outside the mesh
|
||||
xt::xtensor<double, 1> count_sites(
|
||||
tensor::Tensor<double> count_sites(
|
||||
const SourceSite* bank, int64_t length, bool* outside) const;
|
||||
|
||||
//! Get bin given mesh indices
|
||||
|
|
@ -419,8 +419,8 @@ public:
|
|||
//! Get a label for the mesh bin
|
||||
std::string bin_label(int bin) const override;
|
||||
|
||||
//! Get shape as xt::xtensor
|
||||
xt::xtensor<int, 1> get_x_shape() const;
|
||||
//! Get mesh dimensions as a tensor
|
||||
tensor::Tensor<int> get_shape_tensor() const;
|
||||
|
||||
double volume(int bin) const override
|
||||
{
|
||||
|
|
@ -515,7 +515,7 @@ public:
|
|||
//! \param[in] bank Array of bank sites
|
||||
//! \param[out] Whether any bank sites are outside the mesh
|
||||
//! \return Array indicating number of sites in each mesh/energy bin
|
||||
xt::xtensor<double, 1> count_sites(
|
||||
tensor::Tensor<double> count_sites(
|
||||
const SourceSite* bank, int64_t length, bool* outside) const;
|
||||
|
||||
//! Return the volume for a given mesh index
|
||||
|
|
@ -526,7 +526,7 @@ public:
|
|||
// Data members
|
||||
double volume_frac_; //!< Volume fraction of each mesh element
|
||||
double element_volume_; //!< Volume of each mesh element
|
||||
xt::xtensor<double, 1> width_; //!< Width of each mesh element
|
||||
tensor::Tensor<double> width_; //!< Width of each mesh element
|
||||
};
|
||||
|
||||
class RectilinearMesh : public StructuredMesh {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "xtensor/xtensor.hpp"
|
||||
#include "openmc/tensor.h"
|
||||
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
|
|
@ -22,7 +22,7 @@ namespace openmc {
|
|||
|
||||
class Mgxs {
|
||||
private:
|
||||
xt::xtensor<double, 1> kTs; // temperature in eV (k * T)
|
||||
tensor::Tensor<double> kTs; // temperature in eV (k * T)
|
||||
AngleDistributionType
|
||||
scatter_format; // flag for if this is legendre, histogram, or tabular
|
||||
int num_groups; // number of energy groups
|
||||
|
|
@ -113,6 +113,11 @@ public:
|
|||
const vector<Mgxs*>& micros, const vector<double>& atom_densities,
|
||||
int num_group, int num_delay);
|
||||
|
||||
//! \brief Get the number of temperature data points.
|
||||
//!
|
||||
//! @return The number of temperature data points for this MGXS
|
||||
inline int n_temperature_points() { return kTs.size(); }
|
||||
|
||||
//! \brief Provides a cross section value given certain parameters
|
||||
//!
|
||||
//! @param xstype Type of cross section requested, according to the
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ public:
|
|||
vector<double> energy_bin_avg_;
|
||||
vector<double> rev_energy_bins_;
|
||||
vector<vector<double>> nuc_temps_; // all available temperatures
|
||||
vector<double>
|
||||
default_inverse_velocity_; // approximate default inverse-velocity data
|
||||
};
|
||||
|
||||
namespace data {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ public:
|
|||
// Temperature dependent cross section data
|
||||
vector<double> kTs_; //!< temperatures in eV (k*T)
|
||||
vector<EnergyGrid> grid_; //!< Energy grid at each temperature
|
||||
vector<xt::xtensor<double, 2>> xs_; //!< Cross sections at each temperature
|
||||
vector<tensor::Tensor<double>> xs_; //!< Cross sections at each temperature
|
||||
|
||||
// Multipole data
|
||||
unique_ptr<WindowedMultipole> multipole_;
|
||||
|
|
@ -163,7 +163,7 @@ bool multipole_in_range(const Nuclide& nuc, double E);
|
|||
namespace data {
|
||||
|
||||
// Minimum/maximum transport energy for each particle type. Order corresponds to
|
||||
// that of the ParticleType enum
|
||||
// transport_index() for supported transport particles.
|
||||
extern array<double, 4> energy_min;
|
||||
extern array<double, 4> energy_max;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
namespace openmc {
|
||||
|
||||
extern "C" const bool STRICT_FP_ENABLED;
|
||||
|
||||
//! \brief Display the main title banner as well as information about the
|
||||
//! program developers, version, and date/time which the problem was run.
|
||||
void title();
|
||||
|
|
@ -60,7 +62,6 @@ void write_tallies();
|
|||
void show_time(const char* label, double secs, int indent_level = 0);
|
||||
|
||||
} // namespace openmc
|
||||
#endif // OPENMC_OUTPUT_H
|
||||
|
||||
//////////////////////////////////////
|
||||
// Custom formatters
|
||||
|
|
@ -87,3 +88,5 @@ struct formatter<std::array<T, 2>> {
|
|||
}; // namespace fmt
|
||||
|
||||
} // namespace fmt
|
||||
|
||||
#endif // OPENMC_OUTPUT_H
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ public:
|
|||
|
||||
double speed() const;
|
||||
|
||||
double mass() const;
|
||||
|
||||
//! create a secondary particle
|
||||
//
|
||||
//! stores the current phase space attributes of the particle in the
|
||||
|
|
@ -69,7 +71,8 @@ public:
|
|||
void event_advance();
|
||||
void event_cross_surface();
|
||||
void event_collide();
|
||||
void event_revive_from_secondary();
|
||||
void event_revive_from_secondary(const SourceSite& site);
|
||||
void event_check_limit_and_revive();
|
||||
void event_death();
|
||||
|
||||
//! pulse-height recording
|
||||
|
|
@ -126,10 +129,6 @@ public:
|
|||
//! Functions
|
||||
//============================================================================
|
||||
|
||||
std::string particle_type_to_str(ParticleType type);
|
||||
|
||||
ParticleType str_to_particle_type(std::string str);
|
||||
|
||||
void add_surf_source_to_bank(Particle& p, const Surface& surf);
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "openmc/array.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/particle_type.h"
|
||||
#include "openmc/position.h"
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/tallies/filter_match.h"
|
||||
|
|
@ -30,9 +31,6 @@ constexpr double CACHE_INVALID {-1.0};
|
|||
//==========================================================================
|
||||
// Aliases and type definitions
|
||||
|
||||
//! Particle types
|
||||
enum class ParticleType { neutron, photon, electron, positron };
|
||||
|
||||
//! Saved ("banked") state of a particle
|
||||
//! NOTE: This structure's MPI type is built in initialize_mpi() of
|
||||
//! initialize.cpp. Any changes made to the struct here must also be
|
||||
|
|
@ -52,8 +50,11 @@ struct SourceSite {
|
|||
|
||||
// Extra attributes that don't show up in source written to file
|
||||
int parent_nuclide {-1};
|
||||
int64_t parent_id;
|
||||
int64_t progeny_id;
|
||||
int64_t parent_id {0};
|
||||
int64_t progeny_id {0};
|
||||
double wgt_born {1.0};
|
||||
double wgt_ww_born {-1.0};
|
||||
int64_t n_split {0};
|
||||
};
|
||||
|
||||
struct CollisionTrackSite {
|
||||
|
|
@ -496,7 +497,7 @@ private:
|
|||
MacroXS macro_xs_;
|
||||
CacheDataMG mg_xs_cache_;
|
||||
|
||||
ParticleType type_ {ParticleType::neutron};
|
||||
ParticleType type_;
|
||||
|
||||
double E_;
|
||||
double E_last_;
|
||||
|
|
@ -535,9 +536,14 @@ private:
|
|||
uint64_t seeds_[N_STREAMS];
|
||||
int stream_;
|
||||
|
||||
vector<SourceSite> secondary_bank_;
|
||||
vector<SourceSite> local_secondary_bank_;
|
||||
|
||||
int64_t current_work_;
|
||||
// Keep track of how many secondary particles were created in the collision
|
||||
// and what the starting index is in the secondary bank for this particle
|
||||
int n_secondaries_ {0};
|
||||
int secondary_bank_index_ {0};
|
||||
|
||||
int64_t current_work_ {0};
|
||||
|
||||
vector<double> flux_derivs_;
|
||||
|
||||
|
|
@ -560,7 +566,9 @@ private:
|
|||
|
||||
int n_event_ {0};
|
||||
|
||||
int n_split_ {0};
|
||||
int64_t n_tracks_ {0}; //!< number of tracks in this particle history
|
||||
|
||||
int64_t n_split_ {0};
|
||||
double ww_factor_ {0.0};
|
||||
|
||||
int64_t n_progeny_ {0};
|
||||
|
|
@ -690,8 +698,23 @@ public:
|
|||
int& stream() { return stream_; }
|
||||
|
||||
// secondary particle bank
|
||||
SourceSite& secondary_bank(int i) { return secondary_bank_[i]; }
|
||||
decltype(secondary_bank_)& secondary_bank() { return secondary_bank_; }
|
||||
SourceSite& local_secondary_bank(int i) { return local_secondary_bank_[i]; }
|
||||
const SourceSite& local_secondary_bank(int i) const
|
||||
{
|
||||
return local_secondary_bank_[i];
|
||||
}
|
||||
decltype(local_secondary_bank_)& local_secondary_bank()
|
||||
{
|
||||
return local_secondary_bank_;
|
||||
}
|
||||
|
||||
// Number of secondaries created in a collision
|
||||
int& n_secondaries() { return n_secondaries_; }
|
||||
const int& n_secondaries() const { return n_secondaries_; }
|
||||
|
||||
// Starting index in secondary bank for this collision
|
||||
int& secondary_bank_index() { return secondary_bank_index_; }
|
||||
const int& secondary_bank_index() const { return secondary_bank_index_; }
|
||||
|
||||
// Current simulation work index
|
||||
int64_t& current_work() { return current_work_; }
|
||||
|
|
@ -731,13 +754,16 @@ public:
|
|||
int& n_event() { return n_event_; }
|
||||
|
||||
// Number of times variance reduction has caused a particle split
|
||||
int n_split() const { return n_split_; }
|
||||
int& n_split() { return n_split_; }
|
||||
int64_t n_split() const { return n_split_; }
|
||||
int64_t& n_split() { return n_split_; }
|
||||
|
||||
// Particle-specific factor for on-the-fly weight window adjustment
|
||||
double ww_factor() const { return ww_factor_; }
|
||||
double& ww_factor() { return ww_factor_; }
|
||||
|
||||
// Number of tracks in this particle history
|
||||
int64_t& n_tracks() { return n_tracks_; }
|
||||
|
||||
// Number of progeny produced by this particle
|
||||
int64_t& n_progeny() { return n_progeny_; }
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue